Initial mirror of gmp library to third-party-mirror

PiperOrigin-RevId: 722724718
Change-Id: I3e40b965dda5bdb3cb4beb3fc84c9483dfc4d31e
diff --git a/README.google.md b/README.google.md
new file mode 100644
index 0000000..8bb7b73
--- /dev/null
+++ b/README.google.md
@@ -0,0 +1,7 @@
+This is GMP, the GNU Multiple Precision Arithmetic Library. It is the primary
+bignum library used in google3 C++.
+
+Google tools generally treat GMP as if it were licensed under the GNU GPL.
+However, it is actually licensed under the LGPL--only its unit tests are covered
+by the GPL. You may thus use GMP in your product just as you would use any other
+LGPL'd library.
diff --git a/asl.h b/asl.h
new file mode 100644
index 0000000..64deea0
--- /dev/null
+++ b/asl.h
@@ -0,0 +1,127 @@
+/* asl.h -- artificially small limbs support by means of C++ operator
+   overloading.
+
+Copyright 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <cstdint>
+#include <cstdlib>
+// #include <stdexcept>
+
+#ifndef GMP_ASSERT_ALWAYS
+#define GMP_ASSERT_ALWAYS(cc) do {if (!(cc)) abort();} while (0)
+#endif
+
+// Missing: post++ post-- ++pre --prec bool(limb) !limb
+
+#ifndef GMP_LIMB_BITS
+#define GMP_LIMB_BITS 4
+#endif
+
+#define GMP_NUMB_MASK (2 * (1ul << (GMP_LIMB_BITS - 1)) - 1)
+
+#define BINOP_MASK(op, type)				\
+  mp_limb_t& operator op##=(const type& rhs) {		\
+    limbo = (limbo op rhs.limbo) & GMP_NUMB_MASK;	\
+    return *this;					\
+  }
+#define BINOP_NOMASK(op, type)				\
+  mp_limb_t& operator op##=(const type& rhs) {		\
+    limbo = limbo op rhs.limbo;				\
+    return *this;					\
+  }
+
+typedef std::conditional<(GMP_NUMB_MASK <= 0xffff), uint16_t, uint32_t >::type type24;
+typedef std::conditional<(GMP_NUMB_MASK <= 0xff), uint8_t, type24>::type mtype;
+
+class mp_limb_t {
+public:
+  mp_limb_t() {}	// put random garbage in limbo?
+  mp_limb_t(const unsigned int rhs) { limbo = rhs & GMP_NUMB_MASK; }
+  // mp_limb_t(const mp_limb_t& rhs) { limbo = rhs.limbo; } // Causes havoc
+  BINOP_MASK(+, mp_limb_t)
+  BINOP_MASK(-, mp_limb_t)
+  BINOP_MASK(*, mp_limb_t)
+  BINOP_NOMASK(/, mp_limb_t)
+  BINOP_NOMASK(%, mp_limb_t)
+  BINOP_NOMASK(&, mp_limb_t)
+  BINOP_NOMASK(|, mp_limb_t)
+  BINOP_NOMASK(^, mp_limb_t)
+  mp_limb_t& operator<<=(const unsigned int rhs) {
+    GMP_ASSERT_ALWAYS (rhs < GMP_LIMB_BITS);
+    limbo = (limbo << rhs) & GMP_NUMB_MASK;
+    return *this;
+  }
+  mp_limb_t& operator>>=(const unsigned int rhs) {
+    GMP_ASSERT_ALWAYS (rhs < GMP_LIMB_BITS);
+    limbo = limbo >> rhs;
+    return *this;
+  }
+  mp_limb_t operator-() {
+    return static_cast<mp_limb_t>((-limbo) & GMP_NUMB_MASK);
+    // mp_limb_t x;  x.limbo = (-limbo) & GMP_NUMB_MASK;  return x;
+  }
+  mp_limb_t operator~() {
+    return static_cast<mp_limb_t>((~limbo) & GMP_NUMB_MASK);
+    // mp_limb_t x;  x.limbo = (~limbo) & GMP_NUMB_MASK;  return x;
+  }
+  operator unsigned int() const { return limbo; }
+  operator          int() const { return limbo; }
+
+#define RELOP(op)							\
+  inline bool operator op(const mp_limb_t rhs) {			\
+    return limbo op rhs.limbo;						\
+  }
+  RELOP(==)
+  RELOP(!=)
+  RELOP(<)
+  RELOP(>)
+  RELOP(<=)
+  RELOP(>=)
+
+private:
+  mtype limbo;
+};
+
+#define BINOP2(op, type)						\
+  inline mp_limb_t operator op(mp_limb_t lhs, const type& rhs) {	\
+    lhs op##= rhs;							\
+    return lhs;								\
+  }
+
+BINOP2(+, mp_limb_t)
+BINOP2(-, mp_limb_t)
+BINOP2(*, mp_limb_t)
+BINOP2(/, mp_limb_t)
+BINOP2(%, mp_limb_t)
+BINOP2(&, mp_limb_t)
+BINOP2(|, mp_limb_t)
+BINOP2(^, mp_limb_t)
+BINOP2(<<, unsigned int)
+BINOP2(>>, unsigned int)
diff --git a/assert.c b/assert.c
new file mode 100644
index 0000000..aef95b2
--- /dev/null
+++ b/assert.c
@@ -0,0 +1,58 @@
+/* GMP assertion failure handler.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+
+
+void
+__gmp_assert_header (const char *filename, int linenum)
+{
+  if (filename != NULL && filename[0] != '\0')
+    {
+      fprintf (stderr, "%s:", filename);
+      if (linenum != -1)
+        fprintf (stderr, "%d: ", linenum);
+    }
+}
+
+void
+__gmp_assert_fail (const char *filename, int linenum,
+                   const char *expr)
+{
+  __gmp_assert_header (filename, linenum);
+  fprintf (stderr, "GNU MP assertion failed: %s\n", expr);
+  abort();
+}
diff --git a/bootstrap.c b/bootstrap.c
new file mode 100644
index 0000000..07eb416
--- /dev/null
+++ b/bootstrap.c
@@ -0,0 +1,133 @@
+/* Functions needed for bootstrapping the gmp build, based on mini-gmp.
+
+Copyright 2001, 2002, 2004, 2011, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define MINI_GMP_DONT_USE_FLOAT_H 1
+#include "mini-gmp/mini-gmp.c"
+
+#define MIN(l,o) ((l) < (o) ? (l) : (o))
+#define PTR(x)   ((x)->_mp_d)
+#define SIZ(x)   ((x)->_mp_size)
+
+#define xmalloc gmp_default_alloc
+
+int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  if (t < 32)
+    return (0xa08a28acUL >> t) & 1;
+  if ((t & 1) == 0)
+    return 0;
+
+  if (t % 3 == 0)
+    return 0;
+  if (t % 5 == 0)
+    return 0;
+  if (t % 7 == 0)
+    return 0;
+
+  for (d = 11;;)
+    {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 2;
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 4;
+    }
+  return 0;
+}
+
+int
+log2_ceil (int n)
+{
+  int  e;
+  assert (n >= 1);
+  for (e = 0; ; e++)
+    if ((1 << e) >= n)
+      break;
+  return e;
+}
+
+/* Set inv to the inverse of d, in the style of invert_limb, ie. for
+   udiv_qrnnd_preinv.  */
+void
+mpz_preinv_invert (mpz_t inv, const mpz_t d, int numb_bits)
+{
+  mpz_t  t;
+  int    norm;
+  assert (SIZ(d) > 0);
+
+  norm = numb_bits - mpz_sizeinbase (d, 2);
+  assert (norm >= 0);
+  mpz_init (t);
+  mpz_setbit (t, 2*numb_bits - norm);
+  mpz_tdiv_q (inv, t, d);
+  mpz_clrbit (inv, numb_bits);
+
+  mpz_clear (t);
+}
+
+/* Calculate r satisfying r*a == 1 mod 2^n. */
+void
+mpz_invert_2exp (mpz_t r, const mpz_t a, unsigned long n)
+{
+  mpz_t  mod;
+
+  assert (mpz_odd_p (a));
+
+  mpz_init (mod);
+  mpz_setbit (mod, n);
+
+  mpz_invert (r, a, mod);
+
+  mpz_clear (mod);
+}
+
+/* Calculate inv satisfying r*a == 1 mod 2^n. */
+void
+mpz_invert_ui_2exp (mpz_t r, unsigned long a, unsigned long n)
+{
+  mpz_t  az;
+
+  mpz_init_set_ui (az, a);
+  mpz_invert_2exp (r, az, n);
+  mpz_clear (az);
+}
diff --git a/build_defs.bzl b/build_defs.bzl
new file mode 100644
index 0000000..0faa537
--- /dev/null
+++ b/build_defs.bzl
@@ -0,0 +1,144 @@
+"""Build extensions for //third_party/gmp.
+
+Architectures: Several macros in this file refer to "architecture names". These
+are the names for architectures used by GMP, not the names for architectures
+used at Google. Available names are defined by directories in
+third_party/gmp/mpn.
+"""
+
+def gmp_assembly(src, out, architectures, operation = None, included_srcs = []):
+    """Converts a GMP .asm file into architecture-specific .s files.
+
+    GMP's assembly code is not written directly in assembly (files ending in .s)
+    but rather in a slightly higher-level mixture of assembly and M4 (files
+    ending in .asm). The M4 is really just for configuration tweaks and some
+    quality-of-life improvements; it doesn't make the assembly any less
+    architecture-specific. This Starlark macro creates genrules to preprocess
+    the .asm files with M4.
+
+    Args:
+      src: The path to the input .asm file.
+      out: The path to the output .s file.
+      architectures: The list of architecture names (strings) for which .s files
+        should be generated.
+      operation: Optional. The name of the function defined in the .asm file. If
+        specified, M4 will be invoked with `-DOPERATION_{operation}`. (This is
+        necessary because GMP can generate multiple functions from the same
+        assembly skeleton.)
+      included_srcs: Optional. A list of all .asm files that are included (via
+        M4 inclusion) by the .asm file in `src`. Files in this list are copied
+        into the genrule sandbox but are not passed on the command line to M4.
+        Specify this if .s generation fails with M4 complaining about missing
+        files.
+
+    Example:
+      gmp_assembly(
+          src = "mpn/{architecture}/aors_n.asm",
+          out = "mpn/{architecture}/add_n.s",
+          architectures = [
+              "arm",
+              "arm64",
+              "x86",
+              "x86_64",
+          ],
+          operation = "add_n",
+      )
+    """
+    for architecture in architectures:
+        full_src = src.format(architecture = architecture)
+        native.genrule(
+            name = out.format(architecture = architecture).replace("/", "_").replace(".", "_"),
+            srcs = [
+                full_src,
+                "google-config-%s/config.m4" % architecture,
+                "mpn/asm-defs.m4",
+                "mpn/%s/%s-defs.m4" % (architecture, architecture),
+            ] + [src.format(architecture = architecture) for src in included_srcs],
+            outs = [out.format(architecture = architecture)],
+            tools = ["//third_party/m4"],
+            cmd = """
+                $(location //third_party/m4) -DHAVE_CONFIG_H -D__GMP_WITHIN_GMP {operation} -DPIC -I $(RULEDIR)/mpn/{architecture} -I third_party/gmp/mpn/{architecture} -I $(RULEDIR)/mpn -I third_party/gmp/mpn -I $(RULEDIR)/google-config-{architecture} {full_src} >$@
+            """.format(
+                architecture = architecture,
+                full_src = full_src,
+                operation = "-DOPERATION_" + operation if operation else "",
+            ) + select({
+                # Add noexec stack note to the generated assembly
+                "//third_party/bazel_platforms/cpu:armv7": """printf '\t.section\t.note.GNU-stack,"",%%progbits\n' >>$@""",
+                "//conditions:default": """printf '\t.section\t.note.GNU-stack,"",@progbits\n' >>$@""",
+            }),
+        )
+
+def gmp_mpn_assembly(src, out, architectures, included_srcs = []):
+    """Converts a GMP MPN .asm file into architecture-specific .s files.
+
+    MPN is GMP's architecture-specific layer and where most of its assembly code
+    exists. This macro is a convenience macro for invoking `gmp_assembly` on MPN
+    files. It allows you to simply specify the basenames of the .asm and .s
+    files, and it infers the desired operation from the output file name.
+
+    Args:
+      src: The basename of the input .asm file (inside `mpn/{architecture}`).
+      out: The basename of the output .s file (inside `mpn/{architecture}`).
+      architectures: The list of architecture names (strings) for which .s files
+        should be generated.
+      included_srcs: Optional. Basenames of all .asm files (inside
+        `mpn/{architecture}`) that are included (via M4 inclusion) by the .asm
+        file in `src`. Files in this list are copied into the genrule sandbox
+        but are not passed on the command line to M4. Specify this if .s
+        generation fails with M4 complaining about missing files.
+
+    Example:
+      gmp_mpn_assembly(
+          src = "aors_n.asm",
+          out = "add_n.s",
+          architectures = [
+              "arm",
+              "arm64",
+              "x86",
+              "x86_64",
+          ],
+      )
+    """
+    gmp_assembly(
+        src = "mpn/{architecture}/%s" % src,
+        out = "mpn/{architecture}/%s" % out,
+        architectures = architectures,
+        operation = out[:out.rfind(".")],
+        included_srcs = ["mpn/{architecture}/%s" % src for src in included_srcs],
+    )
+
+def gmp_mpn_library(name, srcs, operation, deps = []):
+    """Runs the C++ compiler to generate a GMP MPN object.
+
+    MPN is GMP's architecture-specific layer. MPN libraries require some special
+    compiler flags; this macro wraps `cc_library` to add them. Use it instead of
+    `cc_library` to compile libraries inside third_party/gmp/mpn.
+
+    Args:
+      name: A unique name for this target.
+      srcs: The list of C and assembly files that are processed to create the
+        library target.
+      operation: The name of the function defined in the C or assembly file. The
+        C preprocessor will be invoked with `-DOPERATION_{operation}`. (This is
+        necessary because GMP can generate multiple functions from the same
+        skeleton.)
+      deps: The list of other libraries that the library target depends on.
+    """
+    native.cc_library(
+        name = name,
+        srcs = [
+            "longlong.h",
+        ] + srcs,
+        local_defines = [
+            "HAVE_CONFIG_H",
+            "__GMP_WITHIN_GMP",
+            "OPERATION_" + operation,
+        ],
+        deps = [":gmp-stage2"] + deps,
+        includes = [
+            "",
+            "mpn",
+        ],
+        copts = ["-w"],
+    )
diff --git a/compat.c b/compat.c
new file mode 100644
index 0000000..b4b44ce
--- /dev/null
+++ b/compat.c
@@ -0,0 +1,59 @@
+/* Old function entrypoints retained for binary compatibility.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* mpn_divexact_by3 was a function in gmp 3.0.1, but as of gmp 3.1 it's a
+   macro calling mpn_divexact_by3c.  */
+mp_limb_t
+__MPN (divexact_by3) (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  return mpn_divexact_by3 (dst, src, size);
+}
+
+
+/* mpn_divmod_1 was a function in gmp 3.0.1 and earlier, but marked obsolete
+   in both gmp 2 and 3.  As of gmp 3.1 it's a macro calling mpn_divrem_1. */
+mp_limb_t
+__MPN (divmod_1) (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
+{
+  return mpn_divmod_1 (dst, src, size, divisor);
+}
+
+
+/* mpz_legendre was a separate function in gmp 3.1.1 and earlier, but as of
+   4.0 it's a #define alias for mpz_jacobi.  */
+int
+__gmpz_legendre (mpz_srcptr a, mpz_srcptr b)
+{
+  return mpz_jacobi (a, b);
+}
diff --git a/config.in b/config.in
new file mode 100644
index 0000000..ee1ef8c
--- /dev/null
+++ b/config.in
@@ -0,0 +1,671 @@
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/*
+
+Copyright 1996-2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+*/
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* The gmp-mparam.h file (a string) the tune program should suggest updating.
+   */
+#undef GMP_MPARAM_H_SUGGEST
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if alloca() works (via gmp-impl.h). */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((const)) */
+#undef HAVE_ATTRIBUTE_CONST
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((malloc)) */
+#undef HAVE_ATTRIBUTE_MALLOC
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX)))
+   */
+#undef HAVE_ATTRIBUTE_MODE
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn)) */
+#undef HAVE_ATTRIBUTE_NORETURN
+
+/* Define to 1 if you have the `attr_get' function. */
+#undef HAVE_ATTR_GET
+
+/* Define to 1 if tests/libtests has calling conventions checking for the CPU
+   */
+#undef HAVE_CALLING_CONVENTIONS
+
+/* Define to 1 if you have the `clock' function. */
+#undef HAVE_CLOCK
+
+/* Define to 1 if you have the `clock_gettime' function */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `cputime' function. */
+#undef HAVE_CPUTIME
+
+/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't.
+   */
+#undef HAVE_DECL_FGETC
+
+/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't.
+   */
+#undef HAVE_DECL_FSCANF
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+   */
+#undef HAVE_DECL_OPTARG
+
+/* Define to 1 if you have the declaration of `sys_errlist', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SYS_ERRLIST
+
+/* Define to 1 if you have the declaration of `sys_nerr', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SYS_NERR
+
+/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't.
+   */
+#undef HAVE_DECL_UNGETC
+
+/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VFPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define one of the following to 1 for the format of a `double'.
+   If your format is not among these choices, or you don't know what it is,
+   then leave all undefined.
+   IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves
+   swapped, as used by ARM CPUs in little endian mode.  */
+#undef HAVE_DOUBLE_IEEE_BIG_ENDIAN
+#undef HAVE_DOUBLE_IEEE_LITTLE_ENDIAN
+#undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED
+#undef HAVE_DOUBLE_VAX_D
+#undef HAVE_DOUBLE_VAX_G
+#undef HAVE_DOUBLE_CRAY_CFP
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <float.h> header file. */
+#undef HAVE_FLOAT_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the `getsysinfo' function. */
+#undef HAVE_GETSYSINFO
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((visibility))
+   and __attribute__ ((alias)) */
+#undef HAVE_HIDDEN_ALIAS
+
+/* Define one of these to 1 for the host CPU family.
+   If your CPU is not in any of these families, leave all undefined.
+   For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */
+#undef HAVE_HOST_CPU_FAMILY_alpha
+#undef HAVE_HOST_CPU_FAMILY_m68k
+#undef HAVE_HOST_CPU_FAMILY_power
+#undef HAVE_HOST_CPU_FAMILY_powerpc
+#undef HAVE_HOST_CPU_FAMILY_x86
+#undef HAVE_HOST_CPU_FAMILY_x86_64
+
+/* Define one of the following to 1 for the host CPU, as per the output of
+   ./config.guess.  If your CPU is not listed here, leave all undefined.  */
+#undef HAVE_HOST_CPU_alphaev67
+#undef HAVE_HOST_CPU_alphaev68
+#undef HAVE_HOST_CPU_alphaev7
+#undef HAVE_HOST_CPU_m68020
+#undef HAVE_HOST_CPU_m68030
+#undef HAVE_HOST_CPU_m68040
+#undef HAVE_HOST_CPU_m68060
+#undef HAVE_HOST_CPU_m68360
+#undef HAVE_HOST_CPU_powerpc604
+#undef HAVE_HOST_CPU_powerpc604e
+#undef HAVE_HOST_CPU_powerpc750
+#undef HAVE_HOST_CPU_powerpc7400
+#undef HAVE_HOST_CPU_supersparc
+#undef HAVE_HOST_CPU_i386
+#undef HAVE_HOST_CPU_i586
+#undef HAVE_HOST_CPU_i686
+#undef HAVE_HOST_CPU_pentium
+#undef HAVE_HOST_CPU_pentiummmx
+#undef HAVE_HOST_CPU_pentiumpro
+#undef HAVE_HOST_CPU_pentium2
+#undef HAVE_HOST_CPU_pentium3
+#undef HAVE_HOST_CPU_pentium4
+#undef HAVE_HOST_CPU_core2
+#undef HAVE_HOST_CPU_nehalem
+#undef HAVE_HOST_CPU_westmere
+#undef HAVE_HOST_CPU_sandybridge
+#undef HAVE_HOST_CPU_ivybridge
+#undef HAVE_HOST_CPU_haswell
+#undef HAVE_HOST_CPU_broadwell
+#undef HAVE_HOST_CPU_skylake
+#undef HAVE_HOST_CPU_silvermont
+#undef HAVE_HOST_CPU_goldmont
+#undef HAVE_HOST_CPU_tremont
+#undef HAVE_HOST_CPU_k8
+#undef HAVE_HOST_CPU_k10
+#undef HAVE_HOST_CPU_bulldozer
+#undef HAVE_HOST_CPU_piledriver
+#undef HAVE_HOST_CPU_steamroller
+#undef HAVE_HOST_CPU_excavator
+#undef HAVE_HOST_CPU_zen
+#undef HAVE_HOST_CPU_bobcat
+#undef HAVE_HOST_CPU_jaguar
+#undef HAVE_HOST_CPU_s390_z900
+#undef HAVE_HOST_CPU_s390_z990
+#undef HAVE_HOST_CPU_s390_z9
+#undef HAVE_HOST_CPU_s390_z10
+#undef HAVE_HOST_CPU_s390_z196
+#undef HAVE_HOST_CPU_s390_z13
+#undef HAVE_HOST_CPU_s390_z14
+#undef HAVE_HOST_CPU_s390_z15
+
+/* Define to 1 iff we have a s390 with 64-bit registers.  */
+#undef HAVE_HOST_CPU_s390_zarch
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#undef HAVE_INTMAX_T
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#undef HAVE_INTPTR_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <invent.h> header file. */
+#undef HAVE_INVENT_H
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#undef HAVE_LANGINFO_H
+
+/* Define one of these to 1 for the endianness of `mp_limb_t'.
+   If the endianness is not a simple big or little, or you don't know what
+   it is, then leave both undefined. */
+#undef HAVE_LIMB_BIG_ENDIAN
+#undef HAVE_LIMB_LITTLE_ENDIAN
+
+/* Define to 1 if you have the `localeconv' function. */
+#undef HAVE_LOCALECONV
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the <machine/hal_sysinfo.h> header file. */
+#undef HAVE_MACHINE_HAL_SYSINFO_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `mprotect' function. */
+#undef HAVE_MPROTECT
+
+/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#undef HAVE_NATIVE_mpn_add_n
+#undef HAVE_NATIVE_mpn_add_n_sub_n
+#undef HAVE_NATIVE_mpn_add_nc
+#undef HAVE_NATIVE_mpn_addaddmul_1msb0
+#undef HAVE_NATIVE_mpn_addlsh1_n
+#undef HAVE_NATIVE_mpn_addlsh2_n
+#undef HAVE_NATIVE_mpn_addlsh_n
+#undef HAVE_NATIVE_mpn_addlsh1_nc
+#undef HAVE_NATIVE_mpn_addlsh2_nc
+#undef HAVE_NATIVE_mpn_addlsh_nc
+#undef HAVE_NATIVE_mpn_addlsh1_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh2_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh1_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh2_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh1_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh2_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh1_nc_ip2
+#undef HAVE_NATIVE_mpn_addlsh2_nc_ip2
+#undef HAVE_NATIVE_mpn_addlsh_nc_ip2
+#undef HAVE_NATIVE_mpn_addmul_1c
+#undef HAVE_NATIVE_mpn_addmul_2
+#undef HAVE_NATIVE_mpn_addmul_3
+#undef HAVE_NATIVE_mpn_addmul_4
+#undef HAVE_NATIVE_mpn_addmul_5
+#undef HAVE_NATIVE_mpn_addmul_6
+#undef HAVE_NATIVE_mpn_addmul_7
+#undef HAVE_NATIVE_mpn_addmul_8
+#undef HAVE_NATIVE_mpn_addmul_2s
+#undef HAVE_NATIVE_mpn_and_n
+#undef HAVE_NATIVE_mpn_andn_n
+#undef HAVE_NATIVE_mpn_bdiv_dbm1c
+#undef HAVE_NATIVE_mpn_bdiv_q_1
+#undef HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#undef HAVE_NATIVE_mpn_cnd_add_n
+#undef HAVE_NATIVE_mpn_cnd_sub_n
+#undef HAVE_NATIVE_mpn_com
+#undef HAVE_NATIVE_mpn_copyd
+#undef HAVE_NATIVE_mpn_copyi
+#undef HAVE_NATIVE_mpn_div_qr_1n_pi1
+#undef HAVE_NATIVE_mpn_div_qr_2
+#undef HAVE_NATIVE_mpn_divexact_1
+#undef HAVE_NATIVE_mpn_divexact_by3c
+#undef HAVE_NATIVE_mpn_divrem_1
+#undef HAVE_NATIVE_mpn_divrem_1c
+#undef HAVE_NATIVE_mpn_divrem_2
+#undef HAVE_NATIVE_mpn_gcd_1
+#undef HAVE_NATIVE_mpn_gcd_11
+#undef HAVE_NATIVE_mpn_gcd_22
+#undef HAVE_NATIVE_mpn_hamdist
+#undef HAVE_NATIVE_mpn_invert_limb
+#undef HAVE_NATIVE_mpn_ior_n
+#undef HAVE_NATIVE_mpn_iorn_n
+#undef HAVE_NATIVE_mpn_lshift
+#undef HAVE_NATIVE_mpn_lshiftc
+#undef HAVE_NATIVE_mpn_lshsub_n
+#undef HAVE_NATIVE_mpn_mod_1
+#undef HAVE_NATIVE_mpn_mod_1_1p
+#undef HAVE_NATIVE_mpn_mod_1c
+#undef HAVE_NATIVE_mpn_mod_1s_2p
+#undef HAVE_NATIVE_mpn_mod_1s_4p
+#undef HAVE_NATIVE_mpn_mod_34lsub1
+#undef HAVE_NATIVE_mpn_modexact_1_odd
+#undef HAVE_NATIVE_mpn_modexact_1c_odd
+#undef HAVE_NATIVE_mpn_mul_1
+#undef HAVE_NATIVE_mpn_mul_1c
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_mul_3
+#undef HAVE_NATIVE_mpn_mul_4
+#undef HAVE_NATIVE_mpn_mul_5
+#undef HAVE_NATIVE_mpn_mul_6
+#undef HAVE_NATIVE_mpn_mul_basecase
+#undef HAVE_NATIVE_mpn_mullo_basecase
+#undef HAVE_NATIVE_mpn_nand_n
+#undef HAVE_NATIVE_mpn_nior_n
+#undef HAVE_NATIVE_mpn_popcount
+#undef HAVE_NATIVE_mpn_preinv_divrem_1
+#undef HAVE_NATIVE_mpn_preinv_mod_1
+#undef HAVE_NATIVE_mpn_redc_1
+#undef HAVE_NATIVE_mpn_redc_2
+#undef HAVE_NATIVE_mpn_rsblsh1_n
+#undef HAVE_NATIVE_mpn_rsblsh2_n
+#undef HAVE_NATIVE_mpn_rsblsh_n
+#undef HAVE_NATIVE_mpn_rsblsh1_nc
+#undef HAVE_NATIVE_mpn_rsblsh2_nc
+#undef HAVE_NATIVE_mpn_rsblsh_nc
+#undef HAVE_NATIVE_mpn_rsh1add_n
+#undef HAVE_NATIVE_mpn_rsh1add_nc
+#undef HAVE_NATIVE_mpn_rsh1sub_n
+#undef HAVE_NATIVE_mpn_rsh1sub_nc
+#undef HAVE_NATIVE_mpn_rshift
+#undef HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#undef HAVE_NATIVE_mpn_sqr_basecase
+#undef HAVE_NATIVE_mpn_sqr_diagonal
+#undef HAVE_NATIVE_mpn_sqr_diag_addlsh1
+#undef HAVE_NATIVE_mpn_sub_n
+#undef HAVE_NATIVE_mpn_sub_nc
+#undef HAVE_NATIVE_mpn_sublsh1_n
+#undef HAVE_NATIVE_mpn_sublsh2_n
+#undef HAVE_NATIVE_mpn_sublsh_n
+#undef HAVE_NATIVE_mpn_sublsh1_nc
+#undef HAVE_NATIVE_mpn_sublsh2_nc
+#undef HAVE_NATIVE_mpn_sublsh_nc
+#undef HAVE_NATIVE_mpn_sublsh1_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh2_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh1_nc_ip1
+#undef HAVE_NATIVE_mpn_sublsh2_nc_ip1
+#undef HAVE_NATIVE_mpn_sublsh_nc_ip1
+#undef HAVE_NATIVE_mpn_submul_1c
+#undef HAVE_NATIVE_mpn_tabselect
+#undef HAVE_NATIVE_mpn_udiv_qrnnd
+#undef HAVE_NATIVE_mpn_udiv_qrnnd_r
+#undef HAVE_NATIVE_mpn_umul_ppmm
+#undef HAVE_NATIVE_mpn_umul_ppmm_r
+#undef HAVE_NATIVE_mpn_xor_n
+#undef HAVE_NATIVE_mpn_xnor_n
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#undef HAVE_NL_LANGINFO
+
+/* Define to 1 if you have the <nl_types.h> header file. */
+#undef HAVE_NL_TYPES_H
+
+/* Define to 1 if you have the `obstack_vprintf' function. */
+#undef HAVE_OBSTACK_VPRINTF
+
+/* Define to 1 if you have the `popen' function. */
+#undef HAVE_POPEN
+
+/* Define to 1 if you have the `processor_info' function. */
+#undef HAVE_PROCESSOR_INFO
+
+/* Define to 1 if <sys/pstat.h> `struct pst_processor' exists and contains
+   `psp_iticksperclktick'. */
+#undef HAVE_PSP_ITICKSPERCLKTICK
+
+/* Define to 1 if you have the `pstat_getprocessor' function. */
+#undef HAVE_PSTAT_GETPROCESSOR
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#undef HAVE_PTRDIFF_T
+
+/* Define to 1 if the system has the type `quad_t'. */
+#undef HAVE_QUAD_T
+
+/* Define to 1 if you have the `raise' function. */
+#undef HAVE_RAISE
+
+/* Define to 1 if you have the `read_real_time' function. */
+#undef HAVE_READ_REAL_TIME
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigaltstack' function. */
+#undef HAVE_SIGALTSTACK
+
+/* Define to 1 if you have the `sigstack' function. */
+#undef HAVE_SIGSTACK
+
+/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */
+#undef HAVE_SPEED_CYCLECOUNTER
+
+/* Define to 1 if you have the <sstream> header file. */
+#undef HAVE_SSTREAM
+
+/* Define to 1 if the system has the type `stack_t'. */
+#undef HAVE_STACK_T
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if the system has the type `std::locale'. */
+#undef HAVE_STD__LOCALE
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the `sysconf' function. */
+#undef HAVE_SYSCONF
+
+/* Define to 1 if you have the `sysctl' function. */
+#undef HAVE_SYSCTL
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+#undef HAVE_SYSCTLBYNAME
+
+/* Define to 1 if you have the `syssgi' function. */
+#undef HAVE_SYSSGI
+
+/* Define to 1 if you have the <sys/attributes.h> header file. */
+#undef HAVE_SYS_ATTRIBUTES_H
+
+/* Define to 1 if you have the <sys/iograph.h> header file. */
+#undef HAVE_SYS_IOGRAPH_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/processor.h> header file. */
+#undef HAVE_SYS_PROCESSOR_H
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+#undef HAVE_SYS_PSTAT_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#undef HAVE_SYS_SYSCTL_H
+
+/* Define to 1 if you have the <sys/sysinfo.h> header file. */
+#undef HAVE_SYS_SYSINFO_H
+
+/* Define to 1 if you have the <sys/syssgi.h> header file. */
+#undef HAVE_SYS_SYSSGI_H
+
+/* Define to 1 if you have the <sys/systemcfg.h> header file. */
+#undef HAVE_SYS_SYSTEMCFG_H
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `times' function. */
+#undef HAVE_TIMES
+
+/* Define to 1 if the system has the type `uint_least32_t'. */
+#undef HAVE_UINT_LEAST32_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vsnprintf' function and it works properly. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 for Windos/64 */
+#undef HOST_DOS64
+
+/* Assembler local label prefix */
+#undef LSYM_PREFIX
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Define to 1 to disable the use of inline assembly */
+#undef NO_ASM
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* The size of `mp_limb_t', as computed by sizeof. */
+#undef SIZEOF_MP_LIMB_T
+
+/* The size of `unsigned', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED
+
+/* The size of `unsigned long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* The size of `unsigned short', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_SHORT
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* Define to 1 if sscanf requires writable inputs */
+#undef SSCANF_WRITABLE_INPUT
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Maximum size the tune program can test for SQR_TOOM2_THRESHOLD */
+#undef TUNE_SQR_TOOM2_MAX
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 to enable ASSERT checking, per --enable-assert */
+#undef WANT_ASSERT
+
+/* Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid */
+#undef WANT_FAKE_CPUID
+
+/* Define to 1 when building a fat binary. */
+#undef WANT_FAT_BINARY
+
+/* Define to 1 to enable FFTs for multiplication, per --enable-fft */
+#undef WANT_FFT
+
+/* Define to 1 to enable old mpn_mul_fft_full for multiplication, per
+   --enable-old-fft-full */
+#undef WANT_OLD_FFT_FULL
+
+/* Define to 1 if --enable-profiling=gprof */
+#undef WANT_PROFILING_GPROF
+
+/* Define to 1 if --enable-profiling=instrument */
+#undef WANT_PROFILING_INSTRUMENT
+
+/* Define to 1 if --enable-profiling=prof */
+#undef WANT_PROFILING_PROF
+
+/* Define one of these to 1 for the desired temporary memory allocation
+   method, per --enable-alloca. */
+#undef WANT_TMP_ALLOCA
+#undef WANT_TMP_REENTRANT
+#undef WANT_TMP_NOTREENTRANT
+#undef WANT_TMP_DEBUG
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if the assembler understands the mulx instruction */
+#undef X86_ASM_MULX
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#undef restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+#undef volatile
diff --git a/cxx/dummy.cc b/cxx/dummy.cc
new file mode 100644
index 0000000..8b728ca
--- /dev/null
+++ b/cxx/dummy.cc
@@ -0,0 +1,33 @@
+/* Dummy file to make automake treat libgmpxx.la as C++.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* some compilers reputedly dislike completely empty files */
+typedef int  foo;
diff --git a/cxx/isfuns.cc b/cxx/isfuns.cc
new file mode 100644
index 0000000..0cc0db0
--- /dev/null
+++ b/cxx/isfuns.cc
@@ -0,0 +1,115 @@
+/* Auxiliary functions for C++-style input of GMP types.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+int
+__gmp_istream_set_base (istream &i, char &c, bool &zero, bool &showbase)
+{
+  int base;
+
+  zero = showbase = false;
+  switch (i.flags() & ios::basefield)
+    {
+    case ios::dec:
+      base = 10;
+      break;
+    case ios::hex:
+      base = 16;
+      break;
+    case ios::oct:
+      base = 8;
+      break;
+    default:
+      showbase = true; // look for initial "0" or "0x" or "0X"
+      if (c == '0')
+	{
+	  if (! i.get(c))
+	    c = 0; // reset or we might loop indefinitely
+
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      i.get(c);
+	    }
+	  else
+	    {
+	      base = 8;
+	      zero = true; // if no other digit is read, the "0" counts
+	    }
+	}
+      else
+	base = 10;
+      break;
+    }
+
+  return base;
+}
+
+void
+__gmp_istream_set_digits (string &s, istream &i, char &c, bool &ok, int base)
+{
+  switch (base)
+    {
+    case 10:
+      while (isdigit(c))
+	{
+	  ok = true; // at least a valid digit was read
+	  s += c;
+	  if (! i.get(c))
+	    break;
+	}
+      break;
+    case 8:
+      while (isdigit(c) && c != '8' && c != '9')
+	{
+	  ok = true; // at least a valid digit was read
+	  s += c;
+	  if (! i.get(c))
+	    break;
+	}
+      break;
+    case 16:
+      while (isxdigit(c))
+	{
+	  ok = true; // at least a valid digit was read
+	  s += c;
+	  if (! i.get(c))
+	    break;
+	}
+      break;
+    }
+}
diff --git a/cxx/ismpf.cc b/cxx/ismpf.cc
new file mode 100644
index 0000000..9ff25eb
--- /dev/null
+++ b/cxx/ismpf.cc
@@ -0,0 +1,144 @@
+/* operator>> -- C++-style input of mpf_t.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include <clocale>    // for localeconv
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_float
+// in include/bits/locale_facets.tcc.
+//
+// There are no plans to accept hex or octal floats, not unless the standard
+// C++ library does so.  Although such formats might be of use, it's
+// considered more important to be compatible with what the normal
+// operator>> does on "double"s etc.
+
+istream &
+operator>> (istream &i, mpf_ptr f)
+{
+  int base;
+  char c = 0;
+  string s;
+  bool ok = false;
+
+  // C decimal point, as expected by mpf_set_str
+  const char *lconv_point = GMP_DECIMAL_POINT;
+
+  // C++ decimal point
+#if HAVE_STD__LOCALE
+  const locale& loc = i.getloc();
+  char point_char = use_facet< numpunct<char> >(loc).decimal_point();
+#else
+  const char *point = lconv_point;
+  char point_char = *point;
+#endif
+
+  i.get(c); // start reading
+
+  if (i.flags() & ios::skipws) // skip initial whitespace
+    {
+      // C++ isspace
+#if HAVE_STD__LOCALE
+      const ctype<char>& ct = use_facet< ctype<char> >(loc);
+#define cxx_isspace(c)  (ct.is(ctype_base::space,(c)))
+#else
+#define cxx_isspace(c)  isspace(c)
+#endif
+
+      while (cxx_isspace(c) && i.get(c))
+        ;
+    }
+
+  if (c == '-' || c == '+') // sign
+    {
+      if (c == '-')
+	s = "-";
+      i.get(c);
+    }
+
+  base = 10;
+  __gmp_istream_set_digits(s, i, c, ok, base); // read the number
+
+  // look for the C++ radix point, but put the C one in for mpf_set_str
+  if (c == point_char)
+    {
+#if HAVE_STD__LOCALE
+      i.get(c);
+#else // lconv point can be multi-char
+      for (;;)
+        {
+          i.get(c);
+          point++;
+          if (*point == '\0')
+            break;
+          if (c != *point)
+            goto fail;
+        }
+#endif
+      s += lconv_point;
+      __gmp_istream_set_digits(s, i, c, ok, base); // read the mantissa
+    }
+
+  if (ok && (c == 'e' || c == 'E')) // exponent
+    {
+      s += c;
+      i.get(c);
+      ok = false; // exponent is mandatory
+
+      if (c == '-' || c == '+') // sign
+	{
+	  s += c;
+	  i.get(c);
+	}
+
+      __gmp_istream_set_digits(s, i, c, ok, base); // read the exponent
+    }
+
+  if (i.good()) // last character read was non-numeric
+    i.putback(c);
+  else if (i.eof() && ok) // stopped just before eof
+    i.clear(ios::eofbit);
+
+  if (ok)
+    ASSERT_NOCARRY (mpf_set_str(f, s.c_str(), base)); // extract the number
+  else
+    {
+    fail:
+      i.setstate(ios::failbit); // read failed
+    }
+
+  return i;
+}
diff --git a/cxx/ismpq.cc b/cxx/ismpq.cc
new file mode 100644
index 0000000..8cd5121
--- /dev/null
+++ b/cxx/ismpq.cc
@@ -0,0 +1,66 @@
+/* operator>> -- C++-style input of mpq_t.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+istream &
+operator>> (istream &i, mpq_ptr q)
+{
+  if (! (i >> mpq_numref(q)))
+    return i;
+
+  char  c = 0;
+  i.get(c); // start reading
+
+  if (c == '/')
+    {
+      // skip slash, read denominator
+      i.get(c);
+      return __gmpz_operator_in_nowhite (i, mpq_denref(q), c);
+    }
+  else
+    {
+      // no denominator, set 1
+      q->_mp_den._mp_size = 1;
+      q->_mp_den._mp_d[0] = 1;
+      if (i.good())
+        i.putback(c);
+      else if (i.eof())
+        i.clear(ios::eofbit);
+    }
+
+  return i;
+}
diff --git a/cxx/ismpz.cc b/cxx/ismpz.cc
new file mode 100644
index 0000000..263ced1
--- /dev/null
+++ b/cxx/ismpz.cc
@@ -0,0 +1,62 @@
+/* operator>> -- C++-style input of mpz_t.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_int in
+// include/bits/locale_facets.tcc.
+
+istream &
+operator>> (istream &i, mpz_ptr z)
+{
+  char c = 0;
+  i.get(c); // start reading
+
+  if (i.flags() & ios::skipws) // skip initial whitespace
+    {
+#if HAVE_STD__LOCALE
+      const ctype<char>& ct = use_facet< ctype<char> >(i.getloc());
+#define cxx_isspace(c)  (ct.is(ctype_base::space,(c)))
+#else
+#define cxx_isspace(c)  isspace(c)
+#endif
+
+      while (cxx_isspace(c) && i.get(c))
+        ;
+    }
+
+  return __gmpz_operator_in_nowhite (i, z, c);
+}
diff --git a/cxx/ismpznw.cc b/cxx/ismpznw.cc
new file mode 100644
index 0000000..84f2806
--- /dev/null
+++ b/cxx/ismpznw.cc
@@ -0,0 +1,72 @@
+/* __gmpz_operator_in_nowhite -- C++-style input of mpz_t, no whitespace skip.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_int in
+// include/bits/locale_facets.tcc.
+
+istream &
+__gmpz_operator_in_nowhite (istream &i, mpz_ptr z, char c)
+{
+  int base;
+  string s;
+  bool ok = false, zero, showbase;
+
+  if (c == '-' || c == '+') // sign
+    {
+      if (c == '-') // mpz_set_str doesn't accept '+'
+	s = "-";
+      i.get(c);
+    }
+
+  base = __gmp_istream_set_base(i, c, zero, showbase); // select the base
+  __gmp_istream_set_digits(s, i, c, ok, base);         // read the number
+
+  if (i.good()) // last character read was non-numeric
+    i.putback(c);
+  else if (i.eof() && (ok || zero)) // stopped just before eof
+    i.clear(ios::eofbit);
+
+  if (ok)
+    ASSERT_NOCARRY (mpz_set_str (z, s.c_str(), base)); // extract the number
+  else if (zero)
+    mpz_set_ui(z, 0);
+  else
+    i.setstate(ios::failbit); // read failed
+
+  return i;
+}
diff --git a/cxx/limits.cc b/cxx/limits.cc
new file mode 100644
index 0000000..3004e16
--- /dev/null
+++ b/cxx/limits.cc
@@ -0,0 +1,62 @@
+/* instantiation of numeric_limits specializations.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+
+namespace std {
+#define GMPXX_INSTANTIATE_LIMITS(T) \
+  const bool numeric_limits<T>::is_specialized; \
+  const int  numeric_limits<T>::digits; \
+  const int  numeric_limits<T>::digits10; \
+  const int  numeric_limits<T>::max_digits10; \
+  const bool numeric_limits<T>::is_signed; \
+  const bool numeric_limits<T>::is_integer; \
+  const bool numeric_limits<T>::is_exact; \
+  const int  numeric_limits<T>::radix; \
+  const int  numeric_limits<T>::min_exponent; \
+  const int  numeric_limits<T>::min_exponent10; \
+  const int  numeric_limits<T>::max_exponent; \
+  const int  numeric_limits<T>::max_exponent10; \
+  const bool numeric_limits<T>::has_infinity; \
+  const bool numeric_limits<T>::has_quiet_NaN; \
+  const bool numeric_limits<T>::has_signaling_NaN; \
+  const float_denorm_style numeric_limits<T>::has_denorm; \
+  const bool numeric_limits<T>::has_denorm_loss; \
+  const bool numeric_limits<T>::is_iec559; \
+  const bool numeric_limits<T>::is_bounded; \
+  const bool numeric_limits<T>::is_modulo; \
+  const bool numeric_limits<T>::traps; \
+  const bool numeric_limits<T>::tinyness_before; \
+  const float_round_style numeric_limits<T>::round_style
+
+  GMPXX_INSTANTIATE_LIMITS(mpz_class);
+  GMPXX_INSTANTIATE_LIMITS(mpq_class);
+  GMPXX_INSTANTIATE_LIMITS(mpf_class);
+}
diff --git a/cxx/osdoprnti.cc b/cxx/osdoprnti.cc
new file mode 100644
index 0000000..00dee15
--- /dev/null
+++ b/cxx/osdoprnti.cc
@@ -0,0 +1,67 @@
+/* __gmp_doprnt_integer_ios -- integer formatted output to an ostream.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>   /* for va_list and hence doprnt_funs_t */
+#include <string.h>   /* for strlen */
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+/* The gmp_asprintf support routines never give an error, so
+   __gmp_doprnt_integer shouldn't fail and it's return can just be checked
+   with an ASSERT.  */
+
+ostream&
+__gmp_doprnt_integer_ostream (ostream &o, struct doprnt_params_t *p,
+                              char *s)
+{
+  struct gmp_asprintf_t   d;
+  char  *result;
+  int   ret;
+
+  /* don't show leading zeros the way printf does */
+  p->prec = -1;
+
+  GMP_ASPRINTF_T_INIT (d, &result);
+  ret = __gmp_doprnt_integer (&__gmp_asprintf_funs_noformat, &d, p, s);
+  ASSERT (ret != -1);
+  __gmp_asprintf_final (&d);
+  (*__gmp_free_func) (s, strlen(s)+1);
+
+  gmp_allocated_string  t (result);
+  return o.write (t.str, t.len);
+}
diff --git a/cxx/osfuns.cc b/cxx/osfuns.cc
new file mode 100644
index 0000000..81590a8
--- /dev/null
+++ b/cxx/osfuns.cc
@@ -0,0 +1,123 @@
+/* Support for operator<< routines.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+/* Don't need "format" for operator<< routines, just "memory" and "reps".
+   Omitting gmp_asprintf_format lets us avoid dragging vsnprintf into the
+   link.  __gmp_asprintf_final will be called directly and doesn't need to
+   be in the struct.  */
+
+const struct doprnt_funs_t  __gmp_asprintf_funs_noformat = {
+  NULL,
+  (doprnt_memory_t) __gmp_asprintf_memory,
+  (doprnt_reps_t)   __gmp_asprintf_reps,
+  NULL
+};
+
+
+void
+__gmp_doprnt_params_from_ios (struct doprnt_params_t *p, ios &o)
+{
+  if ((o.flags() & ios::basefield) == ios::hex)
+    {
+      p->expfmt = "@%c%02d";
+      p->base = (o.flags() & ios::uppercase ? -16 : 16);
+    }
+  else
+    {
+      p->expfmt = (o.flags() & ios::uppercase ? "E%c%02d" : "e%c%02d");
+      if ((o.flags() & ios::basefield) == ios::oct)
+        p->base = 8;
+      else
+        p->base = 10;
+    }
+
+  /* "general" if none or more than one bit set */
+  if ((o.flags() & ios::floatfield) == ios::fixed)
+    p->conv = DOPRNT_CONV_FIXED;
+  else if ((o.flags() & ios::floatfield) == ios::scientific)
+    p->conv = DOPRNT_CONV_SCIENTIFIC;
+  else
+    p->conv = DOPRNT_CONV_GENERAL;
+
+  p->exptimes4 = 0;
+
+  p->fill = o.fill();
+
+  /* "right" if more than one bit set */
+  if ((o.flags() & ios::adjustfield) == ios::left)
+    p->justify = DOPRNT_JUSTIFY_LEFT;
+  else if ((o.flags() & ios::adjustfield) == ios::internal)
+    p->justify = DOPRNT_JUSTIFY_INTERNAL;
+  else
+    p->justify = DOPRNT_JUSTIFY_RIGHT;
+
+  /* ios::fixed allows prec==0, others take 0 as the default 6.
+     Don't allow negatives (they do bad things to __gmp_doprnt_float_cxx).  */
+  p->prec = MAX (0, o.precision());
+  if (p->prec == 0 && p->conv != DOPRNT_CONV_FIXED)
+    p->prec = 6;
+
+  /* for hex showbase is always, for octal only non-zero */
+  if (o.flags() & ios::showbase)
+    p->showbase = ((o.flags() & ios::basefield) == ios::hex
+                   ? DOPRNT_SHOWBASE_YES : DOPRNT_SHOWBASE_NONZERO);
+  else
+    p->showbase = DOPRNT_SHOWBASE_NO;
+
+  p->showpoint = ((o.flags() & ios::showpoint) != 0);
+
+  /* in fixed and scientific always show trailing zeros, in general format
+     show them if showpoint is set (or so it seems) */
+  if ((o.flags() & ios::floatfield) == ios::fixed
+      || (o.flags() & ios::floatfield) == ios::scientific)
+    p->showtrailing = 1;
+  else
+    p->showtrailing = p->showpoint;
+
+  p->sign = (o.flags() & ios::showpos ? '+' : '\0');
+
+  p->width = o.width();
+
+  /* reset on each output */
+  o.width (0);
+}
diff --git a/cxx/osmpf.cc b/cxx/osmpf.cc
new file mode 100644
index 0000000..fd875db
--- /dev/null
+++ b/cxx/osmpf.cc
@@ -0,0 +1,70 @@
+/* operator<< -- mpf formatted output to an ostream.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <clocale>
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+/* The gmp_asprintf support routines never give an error, so
+   __gmp_doprnt_mpf shouldn't fail and it's return can just be checked with
+   an ASSERT.  */
+
+ostream&
+operator<< (ostream &o, mpf_srcptr f)
+{
+  struct doprnt_params_t  param;
+  struct gmp_asprintf_t   d;
+  char  *result;
+  int   ret;
+
+  __gmp_doprnt_params_from_ios (&param, o);
+
+#if HAVE_STD__LOCALE
+  char  point[2];
+  point[0] = use_facet< numpunct<char> >(o.getloc()).decimal_point();
+  point[1] = '\0';
+#else
+  const char *point = GMP_DECIMAL_POINT;
+#endif
+
+  GMP_ASPRINTF_T_INIT (d, &result);
+  ret = __gmp_doprnt_mpf (&__gmp_asprintf_funs_noformat, &d, &param, point, f);
+  ASSERT (ret != -1);
+  __gmp_asprintf_final (&d);
+
+  gmp_allocated_string  t (result);
+  return o.write (t.str, t.len);
+}
diff --git a/cxx/osmpq.cc b/cxx/osmpq.cc
new file mode 100644
index 0000000..0c97557
--- /dev/null
+++ b/cxx/osmpq.cc
@@ -0,0 +1,47 @@
+/* operator<< -- mpq formatted output to an ostream.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+ostream&
+operator<< (ostream &o, mpq_srcptr q)
+{
+  struct doprnt_params_t  param;
+  __gmp_doprnt_params_from_ios (&param, o);
+  return __gmp_doprnt_integer_ostream (o, &param,
+                                       mpq_get_str (NULL, param.base, q));
+}
diff --git a/cxx/osmpz.cc b/cxx/osmpz.cc
new file mode 100644
index 0000000..2ee71d3
--- /dev/null
+++ b/cxx/osmpz.cc
@@ -0,0 +1,47 @@
+/* operator<< -- mpz formatted output to an ostream.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+ostream&
+operator<< (ostream &o, mpz_srcptr z)
+{
+  struct doprnt_params_t  param;
+  __gmp_doprnt_params_from_ios (&param, o);
+  return __gmp_doprnt_integer_ostream (o, &param,
+                                       mpz_get_str (NULL, param.base, z));
+}
diff --git a/errno.c b/errno.c
new file mode 100644
index 0000000..d71c146
--- /dev/null
+++ b/errno.c
@@ -0,0 +1,77 @@
+/* gmp_errno, __gmp_exception -- exception handling and reporting.
+
+   THE FUNCTIONS IN THIS FILE, APART FROM gmp_errno, ARE FOR INTERNAL USE
+   ONLY.  THEY'RE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR
+   DISAPPEAR COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2001, 2003, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+
+#include <signal.h>
+
+#include "gmp-impl.h"
+
+int gmp_errno = 0;
+
+
+/* Use SIGFPE on systems which have it. Otherwise, deliberate divide
+   by zero, which triggers an exception on most systems. On those
+   where it doesn't, for example power and powerpc, use abort instead. */
+void
+__gmp_exception (int error_bit)
+{
+  gmp_errno |= error_bit;
+#ifdef SIGFPE
+  raise (SIGFPE);
+#else
+  __gmp_junk = 10 / __gmp_0;
+#endif
+  abort ();
+}
+
+
+/* These functions minimize the amount of code required in functions raising
+   exceptions.  Since they're "noreturn" and don't take any parameters, a
+   test and call might even come out as a simple conditional jump.  */
+void
+__gmp_sqrt_of_negative (void)
+{
+  __gmp_exception (GMP_ERROR_SQRT_OF_NEGATIVE);
+}
+void
+__gmp_divide_by_zero (void)
+{
+  __gmp_exception (GMP_ERROR_DIVISION_BY_ZERO);
+}
+void
+__gmp_overflow_in_mpz (void)
+{
+  __gmp_exception (GMP_ERROR_MPZ_OVERFLOW);
+}
diff --git a/extract-dbl.c b/extract-dbl.c
new file mode 100644
index 0000000..e44d6fa
--- /dev/null
+++ b/extract-dbl.c
@@ -0,0 +1,310 @@
+/* __gmp_extract_double -- convert from double to array of mp_limb_t.
+
+Copyright 1996, 1999-2002, 2006, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifdef XDEBUG
+#undef _GMP_IEEE_FLOATS
+#endif
+
+#ifndef _GMP_IEEE_FLOATS
+#define _GMP_IEEE_FLOATS 0
+#endif
+
+/* Extract a non-negative double in d.  */
+
+int
+__gmp_extract_double (mp_ptr rp, double d)
+{
+  long exp;
+  unsigned sc;
+#ifdef _LONG_LONG_LIMB
+#define BITS_PER_PART 64	/* somewhat bogus */
+  unsigned long long int manl;
+#else
+#define BITS_PER_PART GMP_LIMB_BITS
+  unsigned long int manh, manl;
+#endif
+
+  /* BUGS
+
+     1. Should handle Inf and NaN in IEEE specific code.
+     2. Handle Inf and NaN also in default code, to avoid hangs.
+     3. Generalize to handle all GMP_LIMB_BITS >= 32.
+     4. This lits is incomplete and misspelled.
+   */
+
+  ASSERT (d >= 0.0);
+
+  if (d == 0.0)
+    {
+      MPN_ZERO (rp, LIMBS_PER_DOUBLE);
+      return 0;
+    }
+
+#if _GMP_IEEE_FLOATS
+  {
+#if defined (__alpha) && __GNUC__ == 2 && __GNUC_MINOR__ == 8
+    /* Work around alpha-specific bug in GCC 2.8.x.  */
+    volatile
+#endif
+    union ieee_double_extract x;
+    x.d = d;
+    exp = x.s.exp;
+#if BITS_PER_PART == 64		/* generalize this to BITS_PER_PART > BITS_IN_MANTISSA */
+    manl = (((mp_limb_t) 1 << 63)
+	    | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11));
+    if (exp == 0)
+      {
+	/* Denormalized number.  Don't try to be clever about this,
+	   since it is not an important case to make fast.  */
+	exp = 1;
+	do
+	  {
+	    manl = manl << 1;
+	    exp--;
+	  }
+	while ((manl & GMP_LIMB_HIGHBIT) == 0);
+      }
+#endif
+#if BITS_PER_PART == 32
+    manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21);
+    manl = x.s.manl << 11;
+    if (exp == 0)
+      {
+	/* Denormalized number.  Don't try to be clever about this,
+	   since it is not an important case to make fast.  */
+	exp = 1;
+	do
+	  {
+	    manh = (manh << 1) | (manl >> 31);
+	    manl = manl << 1;
+	    exp--;
+	  }
+	while ((manh & GMP_LIMB_HIGHBIT) == 0);
+      }
+#endif
+#if BITS_PER_PART != 32 && BITS_PER_PART != 64
+  You need to generalize the code above to handle this.
+#endif
+    exp -= 1022;		/* Remove IEEE bias.  */
+  }
+#else
+  {
+    /* Unknown (or known to be non-IEEE) double format.  */
+    exp = 0;
+    if (d >= 1.0)
+      {
+	ASSERT_ALWAYS (d * 0.5 != d);
+
+	while (d >= 32768.0)
+	  {
+	    d *= (1.0 / 65536.0);
+	    exp += 16;
+	  }
+	while (d >= 1.0)
+	  {
+	    d *= 0.5;
+	    exp += 1;
+	  }
+      }
+    else if (d < 0.5)
+      {
+	while (d < (1.0 / 65536.0))
+	  {
+	    d *=  65536.0;
+	    exp -= 16;
+	  }
+	while (d < 0.5)
+	  {
+	    d *= 2.0;
+	    exp -= 1;
+	  }
+      }
+
+    d *= (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
+#if BITS_PER_PART == 64
+    manl = d;
+#endif
+#if BITS_PER_PART == 32
+    manh = d;
+    manl = (d - manh) * (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
+#endif
+  }
+#endif /* IEEE */
+
+  sc = (unsigned) (exp + 64 * GMP_NUMB_BITS) % GMP_NUMB_BITS;
+
+  /* We add something here to get rounding right.  */
+  exp = (exp + 64 * GMP_NUMB_BITS) / GMP_NUMB_BITS - 64 * GMP_NUMB_BITS / GMP_NUMB_BITS + 1;
+
+#if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 2
+#if GMP_NAIL_BITS == 0
+  if (sc != 0)
+    {
+      rp[1] = manl >> (GMP_LIMB_BITS - sc);
+      rp[0] = manl << sc;
+    }
+  else
+    {
+      rp[1] = manl;
+      rp[0] = 0;
+      exp--;
+    }
+#else
+  if (sc > GMP_NAIL_BITS)
+    {
+      rp[1] = manl >> (GMP_LIMB_BITS - sc);
+      rp[0] = (manl << (sc - GMP_NAIL_BITS)) & GMP_NUMB_MASK;
+    }
+  else
+    {
+      if (sc == 0)
+	{
+	  rp[1] = manl >> GMP_NAIL_BITS;
+	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
+	  exp--;
+	}
+      else
+	{
+	  rp[1] = manl >> (GMP_LIMB_BITS - sc);
+	  rp[0] = (manl >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
+	}
+    }
+#endif
+#endif
+
+#if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 3
+  if (sc > GMP_NAIL_BITS)
+    {
+      rp[2] = manl >> (GMP_LIMB_BITS - sc);
+      rp[1] = (manl << sc - GMP_NAIL_BITS) & GMP_NUMB_MASK;
+      if (sc >= 2 * GMP_NAIL_BITS)
+	rp[0] = 0;
+      else
+	rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
+    }
+  else
+    {
+      if (sc == 0)
+	{
+	  rp[2] = manl >> GMP_NAIL_BITS;
+	  rp[1] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
+	  rp[0] = 0;
+	  exp--;
+	}
+      else
+	{
+	  rp[2] = manl >> (GMP_LIMB_BITS - sc);
+	  rp[1] = (manl >> GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
+	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
+	}
+    }
+#endif
+
+#if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE == 3
+#if GMP_NAIL_BITS == 0
+  if (sc != 0)
+    {
+      rp[2] = manh >> (GMP_LIMB_BITS - sc);
+      rp[1] = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
+      rp[0] = manl << sc;
+    }
+  else
+    {
+      rp[2] = manh;
+      rp[1] = manl;
+      rp[0] = 0;
+      exp--;
+    }
+#else
+  if (sc > GMP_NAIL_BITS)
+    {
+      rp[2] = (manh >> (GMP_LIMB_BITS - sc));
+      rp[1] = ((manh << (sc - GMP_NAIL_BITS)) |
+	       (manl >> (GMP_LIMB_BITS - sc + GMP_NAIL_BITS))) & GMP_NUMB_MASK;
+      if (sc >= 2 * GMP_NAIL_BITS)
+	rp[0] = (manl << sc - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
+      else
+	rp[0] = manl >> (2 * GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
+    }
+  else
+    {
+      if (sc == 0)
+	{
+	  rp[2] = manh >> GMP_NAIL_BITS;
+	  rp[1] = ((manh << GMP_NUMB_BITS - GMP_NAIL_BITS) | (manl >> 2 * GMP_NAIL_BITS)) & GMP_NUMB_MASK;
+	  rp[0] = (manl << GMP_NUMB_BITS - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
+	  exp--;
+	}
+      else
+	{
+	  rp[2] = (manh >> (GMP_LIMB_BITS - sc));
+	  rp[1] = (manh >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
+	  rp[0] = ((manh << (GMP_NUMB_BITS - GMP_NAIL_BITS + sc))
+		   | (manl >> (GMP_LIMB_BITS - (GMP_NUMB_BITS - GMP_NAIL_BITS + sc)))) & GMP_NUMB_MASK;
+	}
+    }
+#endif
+#endif
+
+#if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE > 3
+  if (sc == 0)
+    {
+      int i;
+
+      for (i = LIMBS_PER_DOUBLE - 1; i >= 0; i--)
+	{
+	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
+	  manh = ((manh << GMP_NUMB_BITS)
+		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
+	  manl = manl << GMP_NUMB_BITS;
+	}
+      exp--;
+    }
+  else
+    {
+      int i;
+
+      rp[LIMBS_PER_DOUBLE - 1] = (manh >> (GMP_LIMB_BITS - sc));
+      manh = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
+      manl = (manl << sc);
+      for (i = LIMBS_PER_DOUBLE - 2; i >= 0; i--)
+	{
+	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
+	  manh = ((manh << GMP_NUMB_BITS)
+		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
+	  manl = manl << GMP_NUMB_BITS;
+	}
+  }
+#endif
+
+  return exp;
+}
diff --git a/gen-bases.c b/gen-bases.c
new file mode 100644
index 0000000..5f5e7ed
--- /dev/null
+++ b/gen-bases.c
@@ -0,0 +1,265 @@
+/* Generate mp_bases data.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2002, 2004, 2011, 2012,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "bootstrap.c"
+
+
+int    chars_per_limb;
+int    big_base_ctz;
+mpz_t  big_base;
+int    normalization_steps;
+mpz_t  big_base_inverted;
+mpz_t  big_base_binverted;
+
+mpz_t  t;
+
+#define POW2_P(n)  (((n) & ((n) - 1)) == 0)
+
+unsigned int
+ulog2 (unsigned int x)
+{
+  unsigned int i;
+  for (i = 0;  x != 0;  i++)
+    x >>= 1;
+  return i;
+}
+
+void
+binvert (int numb_bits)
+{
+  mpz_t bbo;
+
+  mpz_init_set (bbo, big_base);
+  big_base_ctz = mpz_make_odd (bbo);
+  mpz_invert_2exp (big_base_binverted, bbo, numb_bits);
+}
+
+void
+generate (int limb_bits, int nail_bits, int base)
+{
+  int  numb_bits = limb_bits - nail_bits;
+
+  mpz_set_ui (t, 1L);
+  mpz_mul_2exp (t, t, numb_bits);
+  mpz_set_ui (big_base, (long) base);
+  chars_per_limb = 0;
+  while (mpz_cmp (big_base, t) <= 0)
+    {
+      mpz_mul_ui (big_base, big_base, (long) base);
+      chars_per_limb++;
+    }
+
+  mpz_ui_pow_ui (big_base, (long) base, (long) chars_per_limb);
+
+  normalization_steps = limb_bits - mpz_sizeinbase (big_base, 2);
+
+  mpz_set_ui (t, 1L);
+  mpz_mul_2exp (t, t, 2*limb_bits - normalization_steps);
+  mpz_tdiv_q (big_base_inverted, t, big_base);
+  mpz_clrbit (big_base_inverted, limb_bits);
+
+  binvert (numb_bits);
+}
+
+void
+header (int limb_bits, int nail_bits)
+{
+  int  numb_bits = limb_bits - nail_bits;
+
+  generate (limb_bits, nail_bits, 10);
+
+  printf ("/* This file generated by gen-bases.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("/* mp_bases[10] data, as literal values */\n");
+  printf ("#define MP_BASES_CHARS_PER_LIMB_10      %d\n", chars_per_limb);
+  printf ("#define MP_BASES_BIG_BASE_CTZ_10        %d\n", big_base_ctz);
+  printf ("#define MP_BASES_BIG_BASE_10            CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, big_base);
+  printf (")\n");
+  printf ("#define MP_BASES_BIG_BASE_INVERTED_10   CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, big_base_inverted);
+  printf (")\n");
+  printf ("#define MP_BASES_BIG_BASE_BINVERTED_10  CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, big_base_binverted);
+  printf (")\n");
+  printf ("#define MP_BASES_NORMALIZATION_STEPS_10 %d\n", normalization_steps);
+}
+
+
+#define EXTRA 16
+
+/* Compute log(2)/log(b) as a fixnum. */
+void
+mp_2logb (mpz_t r, int bi, int prec)
+{
+  mpz_t t, t2, two, b;
+  int i;
+
+  mpz_init (t);
+  mpz_setbit (t, prec + EXTRA);
+
+  mpz_init (t2);
+
+  mpz_init (two);
+  mpz_setbit (two, prec + EXTRA + 1);
+
+  mpz_set_ui (r, 0);
+
+  mpz_init_set_ui (b, bi);
+  mpz_mul_2exp (b, b, prec+EXTRA);
+
+  for (i = prec-1; i >= 0; i--)
+    {
+      mpz_mul_2exp (b, b, prec+EXTRA);
+      mpz_sqrt (b, b);
+
+      mpz_mul (t2, t, b);
+      mpz_tdiv_q_2exp (t2, t2, prec+EXTRA);
+
+      if (mpz_cmp (t2, two) < 0)	/* not too large? */
+	{
+	  mpz_setbit (r, i);		/* set next less significant bit */
+	  mpz_swap (t, t2);		/* new value acceptable */
+	}
+    }
+
+  mpz_clear (t);
+  mpz_clear (t2);
+  mpz_clear (two);
+  mpz_clear (b);
+}
+
+void
+table (int limb_bits, int nail_bits)
+{
+  int  numb_bits = limb_bits - nail_bits;
+  int  base;
+  mpz_t r, t, logb2, log2b;
+
+  mpz_init (r);
+  mpz_init (t);
+  mpz_init (logb2);
+  mpz_init (log2b);
+
+  printf ("/* This file generated by gen-bases.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#include \"gmp-impl.h\"\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  puts ("const struct bases mp_bases[257] =\n{");
+  puts ("  /*   0 */ { 0, 0, 0, 0, 0 },");
+  puts ("  /*   1 */ { 0, 0, 0, 0, 0 },");
+  for (base = 2; base <= 256; base++)
+    {
+      generate (limb_bits, nail_bits, base);
+      mp_2logb (r, base, limb_bits + 8);
+      mpz_tdiv_q_2exp (logb2, r, 8);
+      mpz_set_ui (t, 1);
+      mpz_mul_2exp (t, t, 2*limb_bits + 5);
+      mpz_sub_ui (t, t, 1);
+      mpz_add_ui (r, r, 1);
+      mpz_tdiv_q (log2b, t, r);
+
+      printf ("  /* %3u */ { ", base);
+      if (POW2_P (base))
+	{
+          mpz_set_ui (big_base, ulog2 (base) - 1);
+	  mpz_set_ui (big_base_inverted, 0);
+	}
+
+      printf ("%u,", chars_per_limb);
+      printf (" CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, logb2);
+      printf ("), CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, log2b);
+      printf ("), CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, big_base);
+      printf ("), CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, big_base_inverted);
+      printf (") },\n");
+    }
+
+  puts ("};");
+
+  mpz_clear (r);
+  mpz_clear (t);
+  mpz_clear (logb2);
+  mpz_clear (log2b);
+
+}
+
+int
+main (int argc, char **argv)
+{
+  int  limb_bits, nail_bits;
+
+  mpz_init (big_base);
+  mpz_init (big_base_inverted);
+  mpz_init (big_base_binverted);
+  mpz_init (t);
+
+  if (argc != 4)
+    {
+      fprintf (stderr, "Usage: gen-bases <header|table> <limbbits> <nailbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[2]);
+  nail_bits = atoi (argv[3]);
+
+  if (limb_bits <= 0
+      || nail_bits < 0
+      || nail_bits >= limb_bits)
+    {
+      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
+               limb_bits, nail_bits);
+      exit (1);
+    }
+
+  if (strcmp (argv[1], "header") == 0)
+    header (limb_bits, nail_bits);
+  else if (strcmp (argv[1], "table") == 0)
+    table (limb_bits, nail_bits);
+  else
+    {
+      fprintf (stderr, "Invalid header/table choice: %s\n", argv[1]);
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/gen-fac.c b/gen-fac.c
new file mode 100644
index 0000000..93ebf7b
--- /dev/null
+++ b/gen-fac.c
@@ -0,0 +1,285 @@
+/* Generate data for combinatorics: fac_ui, bin_uiui, ...
+
+Copyright 2002, 2011-2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bootstrap.c"
+
+int
+mpz_remove_twos (mpz_t x)
+{
+  mp_bitcnt_t r = mpz_scan1(x, 0);
+  mpz_tdiv_q_2exp (x, x, r);
+  return r;
+}
+
+/* returns 0 on success		*/
+int
+gen_consts (unsigned numb, unsigned limb)
+{
+  mpz_t x, mask, y, last;
+  unsigned long a, b;
+  unsigned long ofl, ofe;
+
+  printf ("/* This file is automatically generated by gen-fac.c */\n\n");
+  printf ("#if GMP_NUMB_BITS != %u\n", numb);
+  printf ("Error , error this data is for %u GMP_NUMB_BITS only\n", numb);
+  printf ("#endif\n");
+#if 0
+  printf ("#if GMP_LIMB_BITS != %u\n", limb);
+  printf ("Error , error this data is for %u GMP_LIMB_BITS only\n", limb);
+  printf ("#endif\n");
+#endif
+
+  printf
+    ("/* This table is 0!,1!,2!,3!,...,n! where n! has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define ONE_LIMB_FACTORIAL_TABLE CNST_LIMB(0x1),CNST_LIMB(0x1");
+  mpz_init_set_ui (x, 1);
+  mpz_init (last);
+  for (b = 2;; b++)
+    {
+      mpz_mul_ui (x, x, b);	/* so b!=a       */
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+
+  printf
+    ("\n/* This table is 0!,1!,2!/2,3!/2,...,n!/2^sn where n!/2^sn is an */\n");
+  printf
+    ("/* odd integer for each n, and n!/2^sn has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define ONE_LIMB_ODD_FACTORIAL_TABLE CNST_LIMB(0x1),CNST_LIMB(0x1),CNST_LIMB(0x1");
+  mpz_set_ui (x, 1);
+  for (b = 3;; b++)
+    {
+      for (a = b; (a & 1) == 0; a >>= 1);
+      mpz_swap (last, x);
+      mpz_mul_ui (x, last, a);
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+  printf
+    ("#define ODD_FACTORIAL_TABLE_MAX CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, last);
+  printf (")\n");
+
+  ofl = b - 1;
+  printf
+    ("#define ODD_FACTORIAL_TABLE_LIMIT (%lu)\n", ofl);
+  mpz_init (mask);
+  mpz_setbit (mask, numb);
+  mpz_sub_ui (mask, mask, 1);
+  printf
+    ("\n/* Previous table, continued, values modulo 2^GMP_NUMB_BITS */\n");
+  printf
+    ("#define ONE_LIMB_ODD_FACTORIAL_EXTTABLE CNST_LIMB(0x");
+  mpz_and (x, x, mask);
+  mpz_out_str (stdout, 16, x);
+  mpz_init (y);
+  mpz_bin_uiui (y, b, b/2);
+  b++;
+  for (;; b++)
+    {
+      for (a = b; (a & 1) == 0; a >>= 1);
+      if (a == b) {
+	mpz_divexact_ui (y, y, a/2+1);
+	mpz_mul_ui (y, y, a);
+      } else
+	mpz_mul_2exp (y, y, 1);
+      if (mpz_sizeinbase (y, 2) > numb)
+	break;
+      mpz_mul_ui (x, x, a);
+      mpz_and (x, x, mask);
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+  ofe = b - 1;
+  printf
+    ("#define ODD_FACTORIAL_EXTTABLE_LIMIT (%lu)\n", ofe);
+
+  printf
+    ("\n/* This table is 1!!,3!!,...,(2n+1)!! where (2n+1)!! has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE CNST_LIMB(0x1");
+  mpz_set_ui (x, 1);
+  for (b = 3;; b+=2)
+    {
+      mpz_swap (last, x);
+      mpz_mul_ui (x, last, b);
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+  printf
+    ("#define ODD_DOUBLEFACTORIAL_TABLE_MAX CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, last);
+  printf (")\n");
+
+  printf
+    ("#define ODD_DOUBLEFACTORIAL_TABLE_LIMIT (%lu)\n", b - 2);
+
+  printf
+    ("\n/* This table x_1, x_2,... contains values s.t. x_n^n has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define NTH_ROOT_NUMB_MASK_TABLE (GMP_NUMB_MASK");
+  for (b = 2;b <= 8; b++)
+    {
+      mpz_root (x, mask, b);
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+
+  mpz_add_ui (mask, mask, 1);
+  printf
+    ("\n/* This table contains inverses of odd factorials, modulo 2^GMP_NUMB_BITS */\n");
+  printf
+    ("\n/* It begins with (2!/2)^-1=1 */\n");
+  printf
+    ("#define ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE CNST_LIMB(0x1");
+  mpz_set_ui (x, 1);
+  for (b = 3;b <= ofe - 2; b++)
+    {
+      for (a = b; (a & 1) == 0; a >>= 1);
+      mpz_mul_ui (x, x, a);
+      mpz_invert (y, x, mask);
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, y);
+    }
+  printf (")\n");
+
+  ofe = (ofe / 16 + 1) * 16;
+
+  printf
+    ("\n/* This table contains 2n-popc(2n) for small n */\n");
+  printf
+    ("\n/* It begins with 2-1=1 (n=1) */\n");
+  printf
+    ("#define TABLE_2N_MINUS_POPC_2N 1");
+  for (b = 4; b <= ofe; b += 2)
+    {
+      mpz_set_ui (x, b);
+      printf (",%lu",b - mpz_popcount (x));
+    }
+  printf ("\n");
+  printf
+    ("#define TABLE_LIMIT_2N_MINUS_POPC_2N %lu\n", ofe + 1);
+
+
+  ofl = (ofl + 1) / 2;
+  printf
+    ("#define ODD_CENTRAL_BINOMIAL_OFFSET (%lu)\n", ofl);
+  printf
+    ("\n/* This table contains binomial(2k,k)/2^t */\n");
+  printf
+    ("\n/* It begins with ODD_CENTRAL_BINOMIAL_TABLE_MIN */\n");
+  printf
+    ("#define ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE ");
+  for (b = ofl;; b++)
+    {
+      mpz_bin_uiui (x, 2 * b, b);
+      mpz_remove_twos (x);
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      if (b != ofl)
+	printf ("),");
+      printf("CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+
+  ofe = b - 1;
+  printf
+    ("#define ODD_CENTRAL_BINOMIAL_TABLE_LIMIT (%lu)\n", ofe);
+
+  printf
+    ("\n/* This table contains the inverses of elements in the previous table. */\n");
+  printf
+    ("#define ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE CNST_LIMB(0x");
+  for (b = ofl; b <= ofe; b++)
+    {
+      mpz_bin_uiui (x, 2 * b, b);
+      mpz_remove_twos (x);
+      mpz_invert (x, x, mask);
+      mpz_out_str (stdout, 16, x);
+      if (b != ofe)
+	printf ("),CNST_LIMB(0x");
+    }
+  printf (")\n");
+
+  printf
+    ("\n/* This table contains the values t in the formula binomial(2k,k)/2^t */\n");
+  printf
+    ("#define CENTRAL_BINOMIAL_2FAC_TABLE ");
+  for (b = ofl; b <= ofe; b++)
+    {
+      mpz_bin_uiui (x, 2 * b, b);
+      printf ("%d", mpz_remove_twos (x));
+      if (b != ofe)
+	printf (",");
+    }
+  printf ("\n");
+
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int nail_bits, limb_bits, numb_bits;
+
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: gen-fac limbbits nailbits\n");
+      exit (1);
+    }
+  limb_bits = atoi (argv[1]);
+  nail_bits = atoi (argv[2]);
+  numb_bits = limb_bits - nail_bits;
+  if (limb_bits < 2 || nail_bits < 0 || numb_bits < 1)
+    {
+      fprintf (stderr, "Invalid limb/nail bits %d,%d\n", limb_bits,
+	       nail_bits);
+      exit (1);
+    }
+  gen_consts (numb_bits, limb_bits);
+  return 0;
+}
diff --git a/gen-fib.c b/gen-fib.c
new file mode 100644
index 0000000..647a6bb
--- /dev/null
+++ b/gen-fib.c
@@ -0,0 +1,156 @@
+/* Generate Fibonacci table data.
+
+Copyright 2001, 2002, 2004, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "bootstrap.c"
+
+mpz_t  *f;
+int    fnum, fib_limit, luc_limit;
+
+void
+generate (int numb_bits)
+{
+  mpz_t  limit, l;
+  int    falloc, i;
+
+  mpz_init2 (limit, numb_bits + 1);
+  mpz_setbit (limit, numb_bits);
+
+  /* fib(2n) > 2^n, so use 2n as a limit for the table size */
+  falloc = 2 * numb_bits;
+  f = (mpz_t*) xmalloc (falloc * sizeof (*f));
+
+  mpz_init_set_ui (f[0], 1L);  /* F[-1] */
+  mpz_init_set_ui (f[1], 0L);  /* F[0] */
+
+  mpz_init (l);
+
+  for (i = 2; ; i++)
+    {
+      assert (i < falloc);
+
+      /* F[i] = F[i-1] + F[i-2] */
+      mpz_init (f[i]);
+      mpz_add (f[i], f[i-1], f[i-2]);
+      if (mpz_cmp (f[i], limit) >= 0)
+        break;
+
+      fnum = i+1;
+      fib_limit = i-1;
+
+      /* L[i] = F[i]+2*F[i-1] */
+      mpz_add (l, f[i], f[i-1]);
+      mpz_add (l, l, f[i-1]);
+
+      if (mpz_cmp (l, limit) < 0)
+        luc_limit = i-1;
+    }
+
+  mpz_clear (limit);
+}
+
+
+void
+header (int numb_bits)
+{
+  printf ("/* This file generated by gen-fib.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("#define FIB_TABLE_LIMIT         %d\n", fib_limit);
+  printf ("#define FIB_TABLE_LUCNUM_LIMIT  %d\n", luc_limit);
+}
+
+void
+table (int numb_bits)
+{
+  int  i;
+
+  printf ("/* This file generated by gen-fib.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#include \"gmp.h\"\n");
+  printf ("#include \"gmp-impl.h\"\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("const mp_limb_t\n");
+  printf ("__gmp_fib_table[FIB_TABLE_LIMIT+2] = {\n");
+
+  for (i = 0; i < fnum; i++)
+    {
+      printf ("  CNST_LIMB (0x");
+      mpz_out_str (stdout, 16, f[i]);
+      printf ("),  /* %d */\n", i-1);
+    }
+  printf ("};\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+  int  limb_bits, nail_bits, numb_bits;
+
+  if (argc != 4)
+    {
+      fprintf (stderr, "Usage: gen-fib <header|table> <limbbits> <nailbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[2]);
+  nail_bits = atoi (argv[3]);
+
+  if (limb_bits <= 0
+      || nail_bits < 0
+      || nail_bits >= limb_bits)
+    {
+      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
+               limb_bits, nail_bits);
+      exit (1);
+    }
+  numb_bits = limb_bits - nail_bits;
+
+  generate (numb_bits);
+
+  if (strcmp (argv[1], "header") == 0)
+    header (numb_bits);
+  else if (strcmp (argv[1], "table") == 0)
+    table (numb_bits);
+  else
+    {
+      fprintf (stderr, "Invalid header/table choice: %s\n", argv[1]);
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/gen-jacobitab.c b/gen-jacobitab.c
new file mode 100644
index 0000000..537994b
--- /dev/null
+++ b/gen-jacobitab.c
@@ -0,0 +1,128 @@
+/* gen-jacobi.c
+
+   Contributed to the GNU project by Niels Möller.
+
+Copyright 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Generate the lookup table needed for fast left-to-right computation
+   of the Jacobi symbol. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const struct
+{
+  unsigned char a;
+  unsigned char b;
+} decode_table[13] = {
+  /*  0 */ { 0, 1 },
+  /*  1 */ { 0, 3 },
+  /*  2 */ { 1, 1 },
+  /*  3 */ { 1, 3 },
+  /*  4 */ { 2, 1 },
+  /*  5 */ { 2, 3 },
+  /*  6 */ { 3, 1 },
+  /*  7 */ { 3, 3 }, /* d = 1 */
+  /*  8 */ { 1, 0 },
+  /*  9 */ { 1, 2 },
+  /* 10 */ { 3, 0 },
+  /* 11 */ { 3, 2 },
+  /* 12 */ { 3, 3 }, /* d = 0 */
+
+};
+#define JACOBI_A(bits) (decode_table[(bits)>>1].a)
+#define JACOBI_B(bits) (decode_table[(bits)>>1].b)
+
+#define JACOBI_E(bits) ((bits) & 1)
+#define JACOBI_D(bits) (((bits)>>1) == 7) /* Gives 0 for don't care states. */
+
+static unsigned
+encode (unsigned a, unsigned b, unsigned d)
+{
+  unsigned i;
+
+  assert (d < 2);
+  assert (a < 4);
+  assert (b < 4);
+  assert ( (a | b ) & 1);
+
+  if (a == 3 && b == 3)
+    return d ? 7 : 12;
+
+  for (i = 0; i < 12; i++)
+    if (decode_table[i].a == a
+	&& decode_table[i].b == b)
+      return i;
+
+  abort ();
+}
+
+int
+main (int argc, char **argv)
+{
+  unsigned bits;
+
+  for (bits = 0; bits < 208; bits++)
+    {
+      unsigned e, a, b, d_old, d, q;
+
+      if (bits && !(bits & 0xf))
+	printf("\n");
+
+      q = bits & 3;
+      d = (bits >> 2) & 1;
+
+      e = JACOBI_E (bits >> 3);
+      a = JACOBI_A (bits >> 3);
+      b = JACOBI_B (bits >> 3);
+      d_old = JACOBI_D (bits >> 3);
+
+      if (d != d_old && a == 3 && b == 3)
+	e ^= 1;
+
+      if (d == 1)
+	{
+	  if (b == 2)
+	    e ^= (q & (a >> 1)) ^ (q >> 1);
+	  a = (a - q * b) & 3;
+	}
+      else
+	{
+	  if (a == 2)
+	    e ^= (q & (b >> 1)) ^ (q >> 1);
+	  b = (b - q * a) & 3;
+	}
+
+      printf("%2d,", (encode (a, b, d) << 1) | e);
+    }
+  printf("\n");
+
+  return 0;
+}
diff --git a/gen-psqr.c b/gen-psqr.c
new file mode 100644
index 0000000..a5054c6
--- /dev/null
+++ b/gen-psqr.c
@@ -0,0 +1,585 @@
+/* Generate perfect square testing data.
+
+Copyright 2002-2004, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bootstrap.c"
+
+
+/* The aim of this program is to choose either mpn_mod_34lsub1 or mpn_mod_1
+   (plus a PERFSQR_PP modulus), and generate tables indicating quadratic
+   residues and non-residues modulo small factors of that modulus.
+
+   For the usual 32 or 64 bit cases mpn_mod_34lsub1 gets used.  That
+   function exists specifically because 2^24-1 and 2^48-1 have nice sets of
+   prime factors.  For other limb sizes it's considered, but if it doesn't
+   have good factors then mpn_mod_1 will be used instead.
+
+   When mpn_mod_1 is used, the modulus PERFSQR_PP is created from a
+   selection of small primes, chosen to fill PERFSQR_MOD_BITS of a limb,
+   with that bit count chosen so (2*GMP_LIMB_BITS)*2^PERFSQR_MOD_BITS <=
+   GMP_LIMB_MAX, allowing PERFSQR_MOD_IDX in mpn/generic/perfsqr.c to do its
+   calculation within a single limb.
+
+   In either case primes can be combined to make divisors.  The table data
+   then effectively indicates remainders which are quadratic residues mod
+   all the primes.  This sort of combining reduces the number of steps
+   needed after mpn_mod_34lsub1 or mpn_mod_1, saving code size and time.
+   Nothing is gained or lost in terms of detections, the same total fraction
+   of non-residues will be identified.
+
+   Nothing particularly sophisticated is attempted for combining factors to
+   make divisors.  This is probably a kind of knapsack problem so it'd be
+   too hard to attempt anything completely general.  For the usual 32 and 64
+   bit limbs we get a good enough result just pairing the biggest and
+   smallest which fit together, repeatedly.
+
+   Another aim is to get powerful combinations, ie. divisors which identify
+   biggest fraction of non-residues, and have those run first.  Again for
+   the usual 32 and 64 bits it seems good enough just to pair for big
+   divisors then sort according to the resulting fraction of non-residues
+   identified.
+
+   Also in this program, a table sq_res_0x100 of residues modulo 256 is
+   generated.  This simply fills bits into limbs of the appropriate
+   build-time GMP_LIMB_BITS each.
+
+*/
+
+
+/* Normally we aren't using const in gen*.c programs, so as not to have to
+   bother figuring out if it works, but using it with f_cmp_divisor and
+   f_cmp_fraction avoids warnings from the qsort calls. */
+
+/* Same tests as gmp.h. */
+#if  defined (__STDC__)                                 \
+  || defined (__cplusplus)                              \
+  || defined (_AIX)                                     \
+  || defined (__DECC)                                   \
+  || (defined (__mips) && defined (_SYSTYPE_SVR4))      \
+  || defined (_MSC_VER)                                 \
+  || defined (_WIN32)
+#define HAVE_CONST        1
+#endif
+
+#if ! HAVE_CONST
+#define const
+#endif
+
+
+mpz_t  *sq_res_0x100;          /* table of limbs */
+int    nsq_res_0x100;          /* elements in sq_res_0x100 array */
+int    sq_res_0x100_num;       /* squares in sq_res_0x100 */
+double sq_res_0x100_fraction;  /* sq_res_0x100_num / 256 */
+
+int     mod34_bits;        /* 3*GMP_NUMB_BITS/4 */
+int     mod_bits;          /* bits from PERFSQR_MOD_34 or MOD_PP */
+int     max_divisor;       /* all divisors <= max_divisor */
+int     max_divisor_bits;  /* ceil(log2(max_divisor)) */
+double  total_fraction;    /* of squares */
+mpz_t   pp;                /* product of primes, or 0 if mod_34lsub1 used */
+mpz_t   pp_norm;           /* pp shifted so NUMB high bit set */
+mpz_t   pp_inverted;       /* invert_limb style inverse */
+mpz_t   mod_mask;          /* 2^mod_bits-1 */
+char    mod34_excuse[128]; /* why mod_34lsub1 not used (if it's not) */
+
+/* raw list of divisors of 2^mod34_bits-1 or pp, just to show in a comment */
+struct rawfactor_t {
+  int     divisor;
+  int     multiplicity;
+};
+struct rawfactor_t  *rawfactor;
+int                 nrawfactor;
+
+/* factors of 2^mod34_bits-1 or pp and associated data, after combining etc */
+struct factor_t {
+  int     divisor;
+  mpz_t   inverse;   /* 1/divisor mod 2^mod_bits */
+  mpz_t   mask;      /* indicating squares mod divisor */
+  double  fraction;  /* squares/total */
+};
+struct factor_t  *factor;
+int              nfactor;       /* entries in use in factor array */
+int              factor_alloc;  /* entries allocated to factor array */
+
+
+int
+f_cmp_divisor (const void *parg, const void *qarg)
+{
+  const struct factor_t *p, *q;
+  p = (const struct factor_t *) parg;
+  q = (const struct factor_t *) qarg;
+  if (p->divisor > q->divisor)
+    return 1;
+  else if (p->divisor < q->divisor)
+    return -1;
+  else
+    return 0;
+}
+
+int
+f_cmp_fraction (const void *parg, const void *qarg)
+{
+  const struct factor_t *p, *q;
+  p = (const struct factor_t *) parg;
+  q = (const struct factor_t *) qarg;
+  if (p->fraction > q->fraction)
+    return 1;
+  else if (p->fraction < q->fraction)
+    return -1;
+  else
+    return 0;
+}
+
+/* Remove array[idx] by copying the remainder down, and adjust narray
+   accordingly.  */
+#define COLLAPSE_ELEMENT(array, idx, narray)                    \
+  do {                                                          \
+    memmove (&(array)[idx],					\
+	     &(array)[idx+1],					\
+	     ((narray)-((idx)+1)) * sizeof (array[0]));		\
+    (narray)--;                                                 \
+  } while (0)
+
+
+/* return n*2^p mod m */
+int
+mul_2exp_mod (int n, int p, int m)
+{
+  while (--p >= 0)
+    n = (2 * n) % m;
+  return n;
+}
+
+/* return -n mod m */
+int
+neg_mod (int n, int m)
+{
+  assert (n >= 0 && n < m);
+  return (n == 0 ? 0 : m-n);
+}
+
+/* Set "mask" to a value such that "mask & (1<<idx)" is non-zero if
+   "-(idx<<mod_bits)" can be a square modulo m.  */
+void
+square_mask (mpz_t mask, int m)
+{
+  int    p, i, r, idx;
+
+  p = mul_2exp_mod (1, mod_bits, m);
+  p = neg_mod (p, m);
+
+  mpz_set_ui (mask, 0L);
+  for (i = 0; i < m; i++)
+    {
+      r = (i * i) % m;
+      idx = (r * p) % m;
+      mpz_setbit (mask, (unsigned long) idx);
+    }
+}
+
+void
+generate_sq_res_0x100 (int limb_bits)
+{
+  int  i, res;
+
+  nsq_res_0x100 = (0x100 + limb_bits - 1) / limb_bits;
+  sq_res_0x100 = (mpz_t *) xmalloc (nsq_res_0x100 * sizeof (*sq_res_0x100));
+
+  for (i = 0; i < nsq_res_0x100; i++)
+    mpz_init_set_ui (sq_res_0x100[i], 0L);
+
+  for (i = 0; i < 0x100; i++)
+    {
+      res = (i * i) % 0x100;
+      mpz_setbit (sq_res_0x100[res / limb_bits],
+                  (unsigned long) (res % limb_bits));
+    }
+
+  sq_res_0x100_num = 0;
+  for (i = 0; i < nsq_res_0x100; i++)
+    sq_res_0x100_num += mpz_popcount (sq_res_0x100[i]);
+  sq_res_0x100_fraction = (double) sq_res_0x100_num / 256.0;
+}
+
+void
+generate_mod (int limb_bits, int nail_bits)
+{
+  int    numb_bits = limb_bits - nail_bits;
+  int    i, divisor;
+
+  mpz_init_set_ui (pp, 0L);
+  mpz_init_set_ui (pp_norm, 0L);
+  mpz_init_set_ui (pp_inverted, 0L);
+
+  /* no more than limb_bits many factors in a one limb modulus (and of
+     course in reality nothing like that many) */
+  factor_alloc = limb_bits;
+  factor = (struct factor_t *) xmalloc (factor_alloc * sizeof (*factor));
+  rawfactor = (struct rawfactor_t *) xmalloc (factor_alloc * sizeof (*rawfactor));
+
+  if (numb_bits % 4 != 0)
+    {
+      strcpy (mod34_excuse, "GMP_NUMB_BITS % 4 != 0");
+      goto use_pp;
+    }
+
+  max_divisor = 2*limb_bits;
+  max_divisor_bits = log2_ceil (max_divisor);
+
+  if (numb_bits / 4 < max_divisor_bits)
+    {
+      /* Wind back to one limb worth of max_divisor, if that will let us use
+         mpn_mod_34lsub1.  */
+      max_divisor = limb_bits;
+      max_divisor_bits = log2_ceil (max_divisor);
+
+      if (numb_bits / 4 < max_divisor_bits)
+        {
+          strcpy (mod34_excuse, "GMP_NUMB_BITS / 4 too small");
+          goto use_pp;
+        }
+    }
+
+  {
+    /* Can use mpn_mod_34lsub1, find small factors of 2^mod34_bits-1. */
+    mpz_t  m, q, r;
+    int    multiplicity;
+
+    mod34_bits = (numb_bits / 4) * 3;
+
+    /* mpn_mod_34lsub1 returns a full limb value, PERFSQR_MOD_34 folds it at
+       the mod34_bits mark, adding the two halves for a remainder of at most
+       mod34_bits+1 many bits */
+    mod_bits = mod34_bits + 1;
+
+    mpz_init_set_ui (m, 1L);
+    mpz_mul_2exp (m, m, mod34_bits);
+    mpz_sub_ui (m, m, 1L);
+
+    mpz_init (q);
+    mpz_init (r);
+
+    for (i = 3; i <= max_divisor; i+=2)
+      {
+        if (! isprime (i))
+          continue;
+
+        mpz_tdiv_qr_ui (q, r, m, (unsigned long) i);
+        if (mpz_sgn (r) != 0)
+          continue;
+
+        /* if a repeated prime is found it's used as an i^n in one factor */
+        divisor = 1;
+        multiplicity = 0;
+        do
+          {
+            if (divisor > max_divisor / i)
+              break;
+            multiplicity++;
+            mpz_set (m, q);
+            mpz_tdiv_qr_ui (q, r, m, (unsigned long) i);
+          }
+        while (mpz_sgn (r) == 0);
+
+        assert (nrawfactor < factor_alloc);
+        rawfactor[nrawfactor].divisor = i;
+        rawfactor[nrawfactor].multiplicity = multiplicity;
+        nrawfactor++;
+      }
+
+    mpz_clear (m);
+    mpz_clear (q);
+    mpz_clear (r);
+  }
+
+  if (nrawfactor <= 2)
+    {
+      mpz_t  new_pp;
+
+      sprintf (mod34_excuse, "only %d small factor%s",
+               nrawfactor, nrawfactor == 1 ? "" : "s");
+
+    use_pp:
+      /* reset to two limbs of max_divisor, in case the mpn_mod_34lsub1 code
+         tried with just one */
+      max_divisor = 2*limb_bits;
+      max_divisor_bits = log2_ceil (max_divisor);
+
+      mpz_init (new_pp);
+      nrawfactor = 0;
+      mod_bits = MIN (numb_bits, limb_bits - max_divisor_bits);
+
+      /* one copy of each small prime */
+      mpz_set_ui (pp, 1L);
+      for (i = 3; i <= max_divisor; i+=2)
+        {
+          if (! isprime (i))
+            continue;
+
+          mpz_mul_ui (new_pp, pp, (unsigned long) i);
+          if (mpz_sizeinbase (new_pp, 2) > mod_bits)
+            break;
+          mpz_set (pp, new_pp);
+
+          assert (nrawfactor < factor_alloc);
+          rawfactor[nrawfactor].divisor = i;
+          rawfactor[nrawfactor].multiplicity = 1;
+          nrawfactor++;
+        }
+
+      /* Plus an extra copy of one or more of the primes selected, if that
+         still fits in max_divisor and the total in mod_bits.  Usually only
+         3 or 5 will be candidates */
+      for (i = nrawfactor-1; i >= 0; i--)
+        {
+          if (rawfactor[i].divisor > max_divisor / rawfactor[i].divisor)
+            continue;
+          mpz_mul_ui (new_pp, pp, (unsigned long) rawfactor[i].divisor);
+          if (mpz_sizeinbase (new_pp, 2) > mod_bits)
+            continue;
+          mpz_set (pp, new_pp);
+
+          rawfactor[i].multiplicity++;
+        }
+
+      mod_bits = mpz_sizeinbase (pp, 2);
+
+      mpz_set (pp_norm, pp);
+      while (mpz_sizeinbase (pp_norm, 2) < numb_bits)
+        mpz_add (pp_norm, pp_norm, pp_norm);
+
+      mpz_preinv_invert (pp_inverted, pp_norm, numb_bits);
+
+      mpz_clear (new_pp);
+    }
+
+  /* start the factor array */
+  for (i = 0; i < nrawfactor; i++)
+    {
+      int  j;
+      assert (nfactor < factor_alloc);
+      factor[nfactor].divisor = 1;
+      for (j = 0; j < rawfactor[i].multiplicity; j++)
+        factor[nfactor].divisor *= rawfactor[i].divisor;
+      nfactor++;
+    }
+
+ combine:
+  /* Combine entries in the factor array.  Combine the smallest entry with
+     the biggest one that will fit with it (ie. under max_divisor), then
+     repeat that with the new smallest entry. */
+  qsort (factor, nfactor, sizeof (factor[0]), f_cmp_divisor);
+  for (i = nfactor-1; i >= 1; i--)
+    {
+      if (factor[i].divisor <= max_divisor / factor[0].divisor)
+        {
+          factor[0].divisor *= factor[i].divisor;
+          COLLAPSE_ELEMENT (factor, i, nfactor);
+          goto combine;
+        }
+    }
+
+  total_fraction = 1.0;
+  for (i = 0; i < nfactor; i++)
+    {
+      mpz_init (factor[i].inverse);
+      mpz_invert_ui_2exp (factor[i].inverse,
+                          (unsigned long) factor[i].divisor,
+                          (unsigned long) mod_bits);
+
+      mpz_init (factor[i].mask);
+      square_mask (factor[i].mask, factor[i].divisor);
+
+      /* fraction of possible squares */
+      factor[i].fraction = (double) mpz_popcount (factor[i].mask)
+        / factor[i].divisor;
+
+      /* total fraction of possible squares */
+      total_fraction *= factor[i].fraction;
+    }
+
+  /* best tests first (ie. smallest fraction) */
+  qsort (factor, nfactor, sizeof (factor[0]), f_cmp_fraction);
+}
+
+void
+print (int limb_bits, int nail_bits)
+{
+  int    i;
+  mpz_t  mhi, mlo;
+
+  printf ("/* This file generated by gen-psqr.c - DO NOT EDIT. */\n");
+  printf ("\n");
+
+  printf ("#if GMP_LIMB_BITS != %d || GMP_NAIL_BITS != %d\n",
+          limb_bits, nail_bits);
+  printf ("Error, error, this data is for %d bit limb and %d bit nail\n",
+          limb_bits, nail_bits);
+  printf ("#endif\n");
+  printf ("\n");
+
+  printf ("/* Non-zero bit indicates a quadratic residue mod 0x100.\n");
+  printf ("   This test identifies %.2f%% as non-squares (%d/256). */\n",
+          (1.0 - sq_res_0x100_fraction) * 100.0,
+          0x100 - sq_res_0x100_num);
+  printf ("static const mp_limb_t\n");
+  printf ("sq_res_0x100[%d] = {\n", nsq_res_0x100);
+  for (i = 0; i < nsq_res_0x100; i++)
+    {
+      printf ("  CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, sq_res_0x100[i]);
+      printf ("),\n");
+    }
+  printf ("};\n");
+  printf ("\n");
+
+  if (mpz_sgn (pp) != 0)
+    {
+      printf ("/* mpn_mod_34lsub1 not used due to %s */\n", mod34_excuse);
+      printf ("/* PERFSQR_PP = ");
+    }
+  else
+    printf ("/* 2^%d-1 = ", mod34_bits);
+  for (i = 0; i < nrawfactor; i++)
+    {
+      if (i != 0)
+        printf (" * ");
+      printf ("%d", rawfactor[i].divisor);
+      if (rawfactor[i].multiplicity != 1)
+        printf ("^%d", rawfactor[i].multiplicity);
+    }
+  printf (" %s*/\n", mpz_sgn (pp) == 0 ? "... " : "");
+
+  printf ("#define PERFSQR_MOD_BITS  %d\n", mod_bits);
+  if (mpz_sgn (pp) != 0)
+    {
+      printf ("#define PERFSQR_PP            CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, pp);
+      printf (")\n");
+      printf ("#define PERFSQR_PP_NORM       CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, pp_norm);
+      printf (")\n");
+      printf ("#define PERFSQR_PP_INVERTED   CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, pp_inverted);
+      printf (")\n");
+    }
+  printf ("\n");
+
+  mpz_init (mhi);
+  mpz_init (mlo);
+
+  printf ("/* This test identifies %.2f%% as non-squares. */\n",
+          (1.0 - total_fraction) * 100.0);
+  printf ("#define PERFSQR_MOD_TEST(up, usize) \\\n");
+  printf ("  do {                              \\\n");
+  printf ("    mp_limb_t  r;                   \\\n");
+  if (mpz_sgn (pp) != 0)
+    printf ("    PERFSQR_MOD_PP (r, up, usize);  \\\n");
+  else
+    printf ("    PERFSQR_MOD_34 (r, up, usize);  \\\n");
+
+  for (i = 0; i < nfactor; i++)
+    {
+      printf ("                                    \\\n");
+      printf ("    /* %5.2f%% */                    \\\n",
+              (1.0 - factor[i].fraction) * 100.0);
+
+      printf ("    PERFSQR_MOD_%d (r, CNST_LIMB(%2d), CNST_LIMB(0x",
+              factor[i].divisor <= limb_bits ? 1 : 2,
+              factor[i].divisor);
+      mpz_out_str (stdout, 16, factor[i].inverse);
+      printf ("), \\\n");
+      printf ("                   CNST_LIMB(0x");
+
+      if ( factor[i].divisor <= limb_bits)
+        {
+          mpz_out_str (stdout, 16, factor[i].mask);
+        }
+      else
+        {
+          mpz_tdiv_r_2exp (mlo, factor[i].mask, (unsigned long) limb_bits);
+          mpz_tdiv_q_2exp (mhi, factor[i].mask, (unsigned long) limb_bits);
+          mpz_out_str (stdout, 16, mhi);
+          printf ("), CNST_LIMB(0x");
+          mpz_out_str (stdout, 16, mlo);
+        }
+      printf (")); \\\n");
+    }
+
+  printf ("  } while (0)\n");
+  printf ("\n");
+
+  printf ("/* Grand total sq_res_0x100 and PERFSQR_MOD_TEST, %.2f%% non-squares. */\n",
+          (1.0 - (total_fraction * 44.0/256.0)) * 100.0);
+  printf ("\n");
+
+  printf ("/* helper for tests/mpz/t-perfsqr.c */\n");
+  printf ("#define PERFSQR_DIVISORS  { 256,");
+  for (i = 0; i < nfactor; i++)
+      printf (" %d,", factor[i].divisor);
+  printf (" }\n");
+
+
+  mpz_clear (mhi);
+  mpz_clear (mlo);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int  limb_bits, nail_bits;
+
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: gen-psqr <limbbits> <nailbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[1]);
+  nail_bits = atoi (argv[2]);
+
+  if (limb_bits <= 0
+      || nail_bits < 0
+      || nail_bits >= limb_bits)
+    {
+      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
+               limb_bits, nail_bits);
+      exit (1);
+    }
+
+  generate_sq_res_0x100 (limb_bits);
+  generate_mod (limb_bits, nail_bits);
+
+  print (limb_bits, nail_bits);
+
+  return 0;
+}
diff --git a/gen-sieve.c b/gen-sieve.c
new file mode 100644
index 0000000..7133918
--- /dev/null
+++ b/gen-sieve.c
@@ -0,0 +1,194 @@
+/* Generate primesieve data.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2021, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "bootstrap.c"
+
+static int
+bit_to_n (int bit) { return (bit*3+4)|1; }
+
+int
+generate (int limb_bits, int limit)
+{
+  mpz_t  limb;
+  int i, lb, pc, c, totpc, maxprime;
+
+  mpz_init (limb);
+
+  printf ("/* This file generated by gen-sieve.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#if GMP_LIMB_BITS != %d\n", limb_bits);
+  printf ("Error, error, this data is for %d bits\n", limb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("#define PRIMESIEVE_INIT_TABLE ");
+
+  maxprime = 3;
+  lb = pc = c = totpc = 0;
+  for (i = 0; i < limit; i++)
+    {
+      if (! isprime (bit_to_n (i)))
+	mpz_setbit (limb, lb);
+      else
+	maxprime = bit_to_n (i), ++pc;
+      ++lb;
+      if (lb == limb_bits)
+	{
+	  ++c;
+	  printf ("\\\n\tCNST_LIMB (0x");
+	  mpz_out_str (stdout, -16, limb);
+	  printf ("),\t/* %d - %d (%d primes) */\t", bit_to_n (i + 1 - limb_bits),
+		  bit_to_n (i + 1) - 1, pc);
+	  totpc += pc;
+	  lb = pc = 0;
+	  mpz_set_ui (limb, 0);
+	}
+    }
+
+  if ((mpz_sgn (limb) | lb | pc) != 0)
+    {
+      printf ("\ngen-sieve: Internal error, during generate (%d, %d).\n", limb_bits,  limit);
+      abort();
+    }
+
+  mpz_clear (limb);
+
+  printf ("\n");
+  printf ("#define PRIMESIEVE_NUMBEROF_TABLE %d\n", c);
+
+  printf ("/* #define PRIMESIEVE_PRIMES_IN_TABLE %d */\n", totpc);
+  printf ("#define PRIMESIEVE_HIGHEST_PRIME %d\n", maxprime);
+  printf ("/* #define PRIMESIEVE_FIRST_UNCHECKED %d */\n", bit_to_n (limit));
+
+  return c;
+}
+
+void
+setmask (mpz_t mask, int a, int b)
+{
+  mpz_set_ui (mask, 0);
+  for (unsigned i = 0; i < 2 * a * b; ++i)
+    if ((bit_to_n (i) % a == 0) || (bit_to_n (i) % b == 0))
+      mpz_setbit (mask, i);
+}
+
+void
+gen_sieve_masks (int limb_bits) {
+  mpz_t  mask, limb;
+
+  mpz_init (mask);
+  mpz_init (limb);
+
+  printf ("\n");
+  if (limb_bits > 60 && limb_bits < 91)
+    {
+      setmask (mask, 5, 11);
+
+      mpz_tdiv_r_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_MASK1 CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+      mpz_tdiv_q_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_MASKT CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+
+      setmask (mask, 7, 13);
+
+      mpz_tdiv_r_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_2MSK1 CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+      mpz_tdiv_q_2exp (mask, mask, limb_bits);
+      mpz_tdiv_r_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_2MSK2 CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+      mpz_tdiv_q_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_2MSKT CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+    }
+  else if (limb_bits > 23 && limb_bits < 36)
+    {
+      setmask (mask, 5, 7);
+
+      mpz_tdiv_r_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_MASK1 CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+      mpz_tdiv_q_2exp (mask, mask, limb_bits);
+      mpz_tdiv_r_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_MASK2 CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+      mpz_tdiv_q_2exp (limb, mask, limb_bits);
+      printf ("#define SIEVE_MASKT CNST_LIMB(0x");
+      mpz_out_str (stdout, -16, limb);
+      printf (")\n");
+    }
+  printf ("\n");
+
+  mpz_clear (limb);
+  mpz_clear (mask);
+}
+
+/* 5*2 = 10
+   7*2 = 14
+   5*7*2 = 70 (2*35, 3*24, 4*18, 5*14...)
+   5*11*2 = 110 (2*55, 3*37, 4*28, 5*22...)
+   5*13*2 = 130 (2*65, 3*44, 4*33, 5*26...)
+   7*11*2 = 154 (2*77, 3*52, 4*39, 5*31...)
+   7*13*2 = 182 (2*91, 3*61, 4*46, 5*37...)
+*/
+
+int
+main (int argc, char *argv[])
+{
+  int  limb_bits, limit;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage: gen-sieve <limbbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[1]);
+
+  limit = 64 * 28; /* bits in the presieved sieve */
+  if (limit % limb_bits != 0)
+    limit += limb_bits - limit % limb_bits;
+  generate (limb_bits, limit);
+  gen_sieve_masks (limb_bits);
+
+  return 0;
+}
diff --git a/gen-trialdivtab.c b/gen-trialdivtab.c
new file mode 100644
index 0000000..218c322
--- /dev/null
+++ b/gen-trialdivtab.c
@@ -0,0 +1,301 @@
+/* gen-trialdivtab.c
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 2009, 2012, 2013, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  Generate tables for fast, division-free trial division for GMP.
+
+  There is one main table, ptab.  It contains primes, multiplied together, and
+  several types of pre-computed inverses.  It refers to tables of the type
+  dtab, via the last two indices.  That table contains the individual primes in
+  the range, except that the primes are not actually included in the table (see
+  the P macro; it sneakingly excludes the primes themselves).  Instead, the
+  dtab tables contains tuples for each prime (modular-inverse, limit) used for
+  divisibility checks.
+
+  This interface is not intended for division of very many primes, since then
+  other algorithms apply.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bootstrap.c"
+
+int sumspills (mpz_t, mpz_t *, int);
+void mpn_mod_1s_4p_cps (mpz_t [7], mpz_t);
+
+int limb_bits;
+
+mpz_t B;
+
+int
+main (int argc, char *argv[])
+{
+  int t, p;
+  mpz_t ppp, acc, inv, gmp_numb_max, tmp, Bhalf;
+  mpz_t pre[7];
+  int i;
+  int start_p, end_p, interval_start, interval_end, omitted_p;
+  const char *endtok;
+  int stop;
+  int np, start_idx;
+
+  if (argc < 2)
+    {
+      fprintf (stderr, "usage: %s bits endprime\n", argv[0]);
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[1]);
+
+  end_p = 1290;			/* default end prime */
+  if (argc == 3)
+    end_p = atoi (argv[2]);
+
+  printf ("#if GMP_LIMB_BITS != %d\n", limb_bits);
+  printf ("#error This table is for GMP_LIMB_BITS = %d\n", limb_bits);
+  printf ("#endif\n\n");
+
+  printf ("#if GMP_NAIL_BITS != 0\n");
+  printf ("#error This table does not support nails\n");
+  printf ("#endif\n\n");
+
+  for (i = 0; i < 7; i++)
+    mpz_init (pre[i]);
+
+  mpz_init (B);
+  mpz_setbit (B, limb_bits);
+  mpz_init_set (gmp_numb_max, B);
+  mpz_sub_ui (gmp_numb_max, gmp_numb_max, 1);
+
+  mpz_init (tmp);
+  mpz_init (inv);
+
+  mpz_init (Bhalf);
+  mpz_setbit (Bhalf, limb_bits - 1);
+
+  start_p = 3;
+
+  mpz_init_set_ui (ppp, 1);
+  mpz_init (acc);
+  interval_start = start_p;
+  omitted_p = 3;
+  interval_end = 0;
+
+/*  printf ("static struct gmp_primes_dtab gmp_primes_dtab[] = {\n"); */
+
+  printf ("#ifdef WANT_dtab\n");
+
+  for (t = start_p; t <= end_p; t += 2)
+    {
+      if (! isprime (t))
+	continue;
+
+      mpz_mul_ui (acc, ppp, t);
+      stop = mpz_cmp (acc, Bhalf) >= 0;
+      if (!stop)
+	{
+	  mpn_mod_1s_4p_cps (pre, acc);
+	  stop = sumspills (acc, pre + 2, 5);
+	}
+
+      if (stop)
+	{
+	  for (p = interval_start; p <= interval_end; p += 2)
+	    {
+	      if (! isprime (p))
+		continue;
+
+	      printf ("  P(%d,", (int) p);
+	      mpz_invert_ui_2exp (inv, p, limb_bits);
+	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, inv);  printf ("),");
+
+	      mpz_tdiv_q_ui (tmp, gmp_numb_max, p);
+	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, tmp);
+	      printf (")),\n");
+	    }
+	  mpz_set_ui (ppp, t);
+	  interval_start = t;
+	  omitted_p = t;
+	}
+      else
+	{
+	  mpz_set (ppp, acc);
+	}
+      interval_end = t;
+    }
+  printf ("#define SMALLEST_OMITTED_PRIME %d\n", (int) omitted_p);
+  printf ("#endif\n");
+
+  printf ("#ifdef WANT_ptab\n");
+
+/*  printf ("static struct gmp_primes_ptab gmp_primes_ptab[] = {\n"); */
+
+  endtok = "";
+
+  mpz_set_ui (ppp, 1);
+  interval_start = start_p;
+  interval_end = 0;
+  np = 0;
+  start_idx = 0;
+  for (t = start_p; t <= end_p; t += 2)
+    {
+      if (! isprime (t))
+	continue;
+
+      mpz_mul_ui (acc, ppp, t);
+
+      stop = mpz_cmp (acc, Bhalf) >= 0;
+      if (!stop)
+	{
+	  mpn_mod_1s_4p_cps (pre, acc);
+	  stop = sumspills (acc, pre + 2, 5);
+	}
+
+      if (stop)
+	{
+	  mpn_mod_1s_4p_cps (pre, ppp);
+	  printf ("%s", endtok);
+	  printf ("  {CNST_LIMB(0x");  mpz_out_str (stdout, 16, ppp);
+	  printf ("),{CNST_LIMB(0x");  mpz_out_str (stdout, 16, pre[0]);
+	  printf ("),%d", (int) PTR(pre[1])[0]);
+	  for (i = 0; i < 5; i++)
+	    {
+	      printf (",");
+	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, pre[2 + i]);
+	      printf (")");
+	    }
+	  printf ("},");
+	  printf ("%d,", start_idx);
+	  printf ("%d}", np - start_idx);
+
+	  endtok = ",\n";
+	  mpz_set_ui (ppp, t);
+	  interval_start = t;
+	  start_idx = np;
+	}
+      else
+	{
+	  mpz_set (ppp, acc);
+	}
+      interval_end = t;
+      np++;
+    }
+
+  printf ("\n");
+  printf ("#endif\n");
+
+  return 0;
+}
+
+unsigned long
+mpz_log2 (mpz_t x)
+{
+  return mpz_sgn (x) ? mpz_sizeinbase (x, 2) : 0;
+}
+
+void
+mpn_mod_1s_4p_cps (mpz_t cps[7], mpz_t bparm)
+{
+  mpz_t b, bi;
+  mpz_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  mpz_t t;
+  int cnt;
+
+  mpz_init_set (b, bparm);
+
+  cnt = limb_bits - mpz_log2 (b);
+
+  mpz_init (bi);
+  mpz_init (t);
+  mpz_init (B1modb);
+  mpz_init (B2modb);
+  mpz_init (B3modb);
+  mpz_init (B4modb);
+  mpz_init (B5modb);
+
+  mpz_set_ui (t, 1);
+  mpz_mul_2exp (t, t, limb_bits - cnt);
+  mpz_sub (t, t, b);
+  mpz_mul_2exp (t, t, limb_bits);
+  mpz_tdiv_q (bi, t, b);		/* bi = B^2/b, except msb */
+
+  mpz_set_ui (t, 1);
+  mpz_mul_2exp (t, t, limb_bits);	/* t = B */
+  mpz_tdiv_r (B1modb, t, b);
+
+  mpz_mul_2exp (t, B1modb, limb_bits);
+  mpz_tdiv_r (B2modb, t, b);
+
+  mpz_mul_2exp (t, B2modb, limb_bits);
+  mpz_tdiv_r (B3modb, t, b);
+
+  mpz_mul_2exp (t, B3modb, limb_bits);
+  mpz_tdiv_r (B4modb, t, b);
+
+  mpz_mul_2exp (t, B4modb, limb_bits);
+  mpz_tdiv_r (B5modb, t, b);
+
+  mpz_set (cps[0], bi);
+  mpz_set_ui (cps[1], cnt);
+  mpz_tdiv_q_2exp (cps[2], B1modb, 0);
+  mpz_tdiv_q_2exp (cps[3], B2modb, 0);
+  mpz_tdiv_q_2exp (cps[4], B3modb, 0);
+  mpz_tdiv_q_2exp (cps[5], B4modb, 0);
+  mpz_tdiv_q_2exp (cps[6], B5modb, 0);
+
+  mpz_clear (b);
+  mpz_clear (bi);
+  mpz_clear (t);
+  mpz_clear (B1modb);
+  mpz_clear (B2modb);
+  mpz_clear (B3modb);
+  mpz_clear (B4modb);
+  mpz_clear (B5modb);
+}
+
+int
+sumspills (mpz_t ppp, mpz_t *a, int n)
+{
+  mpz_t s;
+  int i, ret;
+
+  mpz_init_set (s, a[0]);
+
+  for (i = 1; i < n; i++)
+    {
+      mpz_add (s, s, a[i]);
+    }
+  ret = mpz_cmp (s, B) >= 0;
+  mpz_clear (s);
+
+  return ret;
+}
diff --git a/gmp-h.in b/gmp-h.in
new file mode 100644
index 0000000..8598e97
--- /dev/null
+++ b/gmp-h.in
@@ -0,0 +1,2344 @@
+/* Definitions for GNU multiple precision functions.   -*- mode: c -*-
+
+Copyright 1991, 1993-1997, 1999-2016, 2020, 2021 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_H__
+
+#if defined (__cplusplus)
+#include <iosfwd>   /* for std::istream, std::ostream, std::string */
+#include <cstdio>
+#endif
+
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#define __GMP_HAVE_HOST_CPU_FAMILY_power   @HAVE_HOST_CPU_FAMILY_power@
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc @HAVE_HOST_CPU_FAMILY_powerpc@
+#define GMP_LIMB_BITS                      @GMP_LIMB_BITS@
+#define GMP_NAIL_BITS                      @GMP_NAIL_BITS@
+#endif
+#define GMP_NUMB_BITS     (GMP_LIMB_BITS - GMP_NAIL_BITS)
+#define GMP_NUMB_MASK     ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
+#define GMP_NUMB_MAX      GMP_NUMB_MASK
+#define GMP_NAIL_MASK     (~ GMP_NUMB_MASK)
+
+
+#ifndef __GNU_MP__
+#define __GNU_MP__ 6
+
+#include <stddef.h>    /* for size_t */
+#include <limits.h>
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+@DEFN_LONG_LONG_LIMB@
+#define __GMP_LIBGMP_DLL  @LIBGMP_DLL@
+#endif
+
+
+/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in
+   all other circumstances.
+
+   When compiling objects for libgmp, __GMP_DECLSPEC is an export directive,
+   or when compiling for an application it's an import directive.  The two
+   cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles
+   (and not defined from an application).
+
+   __GMP_DECLSPEC_XX is similarly used for libgmpxx.  __GMP_WITHIN_GMPXX
+   indicates when building libgmpxx, and in that case libgmpxx functions are
+   exports, but libgmp functions which might get called are imports.
+
+   Libtool DLL_EXPORT define is not used.
+
+   There's no attempt to support GMP built both static and DLL.  Doing so
+   would mean applications would have to tell us which of the two is going
+   to be used when linking, and that seems very tedious and error prone if
+   using GMP by hand, and equally tedious from a package since autoconf and
+   automake don't give much help.
+
+   __GMP_DECLSPEC is required on all documented global functions and
+   variables, the various internals in gmp-impl.h etc can be left unadorned.
+   But internals used by the test programs or speed measuring programs
+   should have __GMP_DECLSPEC, and certainly constants or variables must
+   have it or the wrong address will be resolved.
+
+   In gcc __declspec can go at either the start or end of a prototype.
+
+   In Microsoft C __declspec must go at the start, or after the type like
+   void __declspec(...) *foo()".  There's no __dllexport or anything to
+   guard against someone foolish #defining dllexport.  _export used to be
+   available, but no longer.
+
+   In Borland C _export still exists, but needs to go after the type, like
+   "void _export foo();".  Would have to change the __GMP_DECLSPEC syntax to
+   make use of that.  Probably more trouble than it's worth.  */
+
+#if defined (__GNUC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(__dllexport__)
+#define __GMP_DECLSPEC_IMPORT  __declspec(__dllimport__)
+#endif
+#if defined (_MSC_VER) || defined (__BORLANDC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(dllexport)
+#define __GMP_DECLSPEC_IMPORT  __declspec(dllimport)
+#endif
+#ifdef __WATCOMC__
+#define __GMP_DECLSPEC_EXPORT  __export
+#define __GMP_DECLSPEC_IMPORT  __import
+#endif
+#ifdef __IBMC__
+#define __GMP_DECLSPEC_EXPORT  _Export
+#define __GMP_DECLSPEC_IMPORT  _Import
+#endif
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMP
+/* compiling to go into a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into an application which will link to a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC
+#endif
+
+
+#ifdef __GMP_SHORT_LIMB
+typedef unsigned int		mp_limb_t;
+typedef int			mp_limb_signed_t;
+#else
+#ifdef _LONG_LONG_LIMB
+typedef unsigned long long int	mp_limb_t;
+typedef long long int		mp_limb_signed_t;
+#else
+typedef unsigned long int	mp_limb_t;
+typedef long int		mp_limb_signed_t;
+#endif
+#endif
+typedef unsigned long int	mp_bitcnt_t;
+
+/* For reference, note that the name __mpz_struct gets into C++ mangled
+   function names, which means although the "__" suggests an internal, we
+   must leave this name for binary compatibility.  */
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+#endif /* __GNU_MP__ */
+
+
+typedef __mpz_struct MP_INT;    /* gmp 1 source compatibility */
+typedef __mpz_struct mpz_t[1];
+
+typedef mp_limb_t *		mp_ptr;
+typedef const mp_limb_t *	mp_srcptr;
+#if defined (_CRAY) && ! defined (_CRAYMPP)
+/* plain `int' is much faster (48 bits) */
+#define __GMP_MP_SIZE_T_INT     1
+typedef int			mp_size_t;
+typedef int			mp_exp_t;
+#else
+#define __GMP_MP_SIZE_T_INT     0
+typedef long int		mp_size_t;
+typedef long int		mp_exp_t;
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct MP_RAT;    /* gmp 1 source compatibility */
+typedef __mpq_struct mpq_t[1];
+
+typedef struct
+{
+  int _mp_prec;			/* Max precision, in number of `mp_limb_t's.
+				   Set by mpf_init and modified by
+				   mpf_set_prec.  The area pointed to by the
+				   _mp_d field contains `prec' + 1 limbs.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_exp_t _mp_exp;		/* Exponent, in the base of `mp_limb_t'.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpf_struct;
+
+/* typedef __mpf_struct MP_FLOAT; */
+typedef __mpf_struct mpf_t[1];
+
+/* Available random number generation algorithms.  */
+typedef enum
+{
+  GMP_RAND_ALG_DEFAULT = 0,
+  GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential.  */
+} gmp_randalg_t;
+
+/* Random state struct.  */
+typedef struct
+{
+  mpz_t _mp_seed;	  /* _mp_d member points to state of the generator. */
+  gmp_randalg_t _mp_alg;  /* Currently unused. */
+  union {
+    void *_mp_lc;         /* Pointer to function pointers structure.  */
+  } _mp_algdata;
+} __gmp_randstate_struct;
+typedef __gmp_randstate_struct gmp_randstate_t[1];
+
+/* Types for function declarations in gmp files.  */
+/* ??? Should not pollute user name space with these ??? */
+typedef const __mpz_struct *mpz_srcptr;
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpf_struct *mpf_srcptr;
+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
+#ifdef __GMP_WITHIN_GMPXX
+/* compiling to go into a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into a application which will link to a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC_XX
+#endif
+
+
+#ifndef __MPN
+#define __MPN(x) __gmpn_##x
+#endif
+
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */			\
+  || defined (_STDIO)                 /* HPE NonStop */         \
+  || defined (__DEFINED_FILE)         /* musl */
+#define _GMP_H_HAVE_FILE 1
+#endif
+
+/* In ISO C, if a prototype involving "struct obstack *" is given without
+   that structure defined, then the struct is scoped down to just the
+   prototype, causing a conflict if it's subsequently defined for real.  So
+   only give prototypes if we've got obstack.h.  */
+#if defined (_OBSTACK_H)   /* glibc <obstack.h> */
+#define _GMP_H_HAVE_OBSTACK 1
+#endif
+
+/* The prototypes for gmp_vprintf etc are provided only if va_list is defined,
+   via an application having included <stdarg.h>.  Usually va_list is a typedef
+   so can't be tested directly, but C99 specifies that va_start is a macro.
+
+   <stdio.h> will define some sort of va_list for vprintf and vfprintf, but
+   let's not bother trying to use that since it's not standard and since
+   application uses for gmp_vprintf etc will almost certainly require the
+   whole <stdarg.h> anyway.  */
+
+#ifdef va_start
+#define _GMP_H_HAVE_VA_LIST 1
+#endif
+
+/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+#define __GMP_GNUC_PREREQ(maj, min) \
+  ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GMP_GNUC_PREREQ(maj, min)  0
+#endif
+
+/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes".  Basically
+   it means a function does nothing but examine its arguments and memory
+   (global or via arguments) to generate a return value, but changes nothing
+   and has no side-effects.  __GMP_NO_ATTRIBUTE_CONST_PURE lets
+   tune/common.c etc turn this off when trying to write timing loops.  */
+#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define __GMP_ATTRIBUTE_PURE   __attribute__ ((__pure__))
+#else
+#define __GMP_ATTRIBUTE_PURE
+#endif
+
+
+/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean
+   to "g++ -Wold-style-cast".
+
+   Casts in "extern inline" code within an extern "C" block don't induce
+   these warnings, so __GMP_CAST only needs to be used on documented
+   macros.  */
+
+#ifdef __cplusplus
+#define __GMP_CAST(type, expr)  (static_cast<type> (expr))
+#else
+#define __GMP_CAST(type, expr)  ((type) (expr))
+#endif
+
+
+/* An empty "throw ()" means the function doesn't throw any C++ exceptions,
+   this can save some stack frame info in applications.
+
+   Currently it's given only on functions which never divide-by-zero etc,
+   don't allocate memory, and are expected to never need to allocate memory.
+   This leaves open the possibility of a C++ throw from a future GMP
+   exceptions scheme.
+
+   mpz_set_ui etc are omitted to leave open the lazy allocation scheme
+   described in doc/tasks.html.  mpz_get_d etc are omitted to leave open
+   exceptions for float overflows.
+
+   Note that __GMP_NOTHROW must be given on any inlines the same as on their
+   prototypes (for g++ at least, where they're used together).  Note also
+   that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like
+   __GMP_ATTRIBUTE_PURE.  */
+
+#if defined (__cplusplus)
+#if __cplusplus >= 201103L
+#define __GMP_NOTHROW  noexcept
+#else
+#define __GMP_NOTHROW  throw ()
+#endif
+#else
+#define __GMP_NOTHROW
+#endif
+
+
+/* PORTME: What other compilers have a useful "extern inline"?  "static
+   inline" would be an acceptable substitute if the compiler (or linker)
+   discards unused statics.  */
+
+ /* gcc has __inline__ in all modes, including strict ansi.  Give a prototype
+    for an inline too, so as to correctly specify "dllimport" on windows, in
+    case the function is called rather than inlined.
+    GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+    inline semantics, unless -fgnu89-inline is used.  */
+#ifdef __GNUC__
+#if (defined __GNUC_STDC_INLINE__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 2) \
+  || (defined __GNUC_GNU_INLINE__ && defined __cplusplus)
+#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__))
+#else
+#define __GMP_EXTERN_INLINE      extern __inline__
+#endif
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1
+   strict ANSI mode.  Inlining is done even when not optimizing (ie. -O0
+   mode, which is the default), but an unnecessary local copy of foo is
+   emitted unless -O is used.  "extern __inline" is accepted, but the
+   "extern" appears to be ignored, ie. it becomes a plain global function
+   but which is inlined within its file.  Don't know if all old versions of
+   DEC C supported __inline, but as a start let's do the right thing for
+   current versions.  */
+#ifdef __DECC
+#define __GMP_EXTERN_INLINE  static __inline
+#endif
+
+/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict
+   ANSI mode (__STDC__ is 1 in that mode).  Inlining only actually takes
+   place under -O.  Without -O "foo" seems to be emitted whether it's used
+   or not, which is wasteful.  "extern inline foo()" isn't useful, the
+   "extern" is apparently ignored, so foo is inlined if possible but also
+   emitted as a global, which causes multiple definition errors when
+   building a shared libgmp.  */
+#ifdef __SCO_VERSION__
+#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+#endif
+
+/* Microsoft's C compiler accepts __inline */
+#ifdef _MSC_VER
+#define __GMP_EXTERN_INLINE  __inline
+#endif
+
+/* Recent enough Sun C compilers want "inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x560 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Somewhat older Sun C compilers want "static inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x540 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+
+
+/* C++ always has "inline" and since it's a normal feature the linker should
+   discard duplicate non-inlined copies, or if it doesn't then that's a
+   problem for everyone, not just GMP.  */
+#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Don't do any inlining within a configure run, since if the compiler ends
+   up emitting copies of the code into the object file it can end up
+   demanding the various support routines (like mpn_popcount) for linking,
+   making the "alloca" test and perhaps others fail.  And on hppa ia64 a
+   pre-release gcc 3.2 was seen not respecting the "extern" in "extern
+   __inline__", triggering this problem too.  */
+#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE
+#undef __GMP_EXTERN_INLINE
+#endif
+
+/* By default, don't give a prototype when there's going to be an inline
+   version.  Note in particular that Cray C++ objects to the combination of
+   prototype and inline.  */
+#ifdef __GMP_EXTERN_INLINE
+#ifndef __GMP_INLINE_PROTOTYPES
+#define __GMP_INLINE_PROTOTYPES  0
+#endif
+#else
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+
+#define __GMP_ABS(x)   ((x) >= 0 ? (x) : -(x))
+#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+
+/* __builtin_expect is in gcc 3.0, and not in 2.95. */
+#if __GMP_GNUC_PREREQ (3,0)
+#define __GMP_LIKELY(cond)    __builtin_expect ((cond) != 0, 1)
+#define __GMP_UNLIKELY(cond)  __builtin_expect ((cond) != 0, 0)
+#else
+#define __GMP_LIKELY(cond)    (cond)
+#define __GMP_UNLIKELY(cond)  (cond)
+#endif
+
+#ifdef _CRAY
+#define __GMP_CRAY_Pragma(str)  _Pragma (str)
+#else
+#define __GMP_CRAY_Pragma(str)
+#endif
+
+
+/* Allow direct user access to numerator and denominator of an mpq_t object.  */
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+
+#if defined (__cplusplus)
+extern "C" {
+using std::FILE;
+#endif
+
+#define mp_set_memory_functions __gmp_set_memory_functions
+__GMP_DECLSPEC void mp_set_memory_functions (void *(*) (size_t),
+				      void *(*) (void *, size_t, size_t),
+				      void (*) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_get_memory_functions __gmp_get_memory_functions
+__GMP_DECLSPEC void mp_get_memory_functions (void *(**) (size_t),
+				      void *(**) (void *, size_t, size_t),
+				      void (**) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_bits_per_limb __gmp_bits_per_limb
+__GMP_DECLSPEC extern const int mp_bits_per_limb;
+
+#define gmp_errno __gmp_errno
+__GMP_DECLSPEC extern int gmp_errno;
+
+#define gmp_version __gmp_version
+__GMP_DECLSPEC extern const char * const gmp_version;
+
+
+/**************** Random number routines.  ****************/
+
+/* obsolete */
+#define gmp_randinit __gmp_randinit
+__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_ptr);
+
+#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp
+__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_ptr, mp_bitcnt_t);
+
+#define gmp_randinit_mt __gmp_randinit_mt
+__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_ptr);
+
+#define gmp_randinit_set __gmp_randinit_set
+__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_ptr, gmp_randstate_srcptr);
+
+#define gmp_randseed __gmp_randseed
+__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_ptr, unsigned long int);
+
+#define gmp_randclear __gmp_randclear
+__GMP_DECLSPEC void gmp_randclear (gmp_randstate_ptr);
+
+#define gmp_urandomb_ui __gmp_urandomb_ui
+__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_ptr, unsigned long);
+
+
+/**************** Formatted output routines.  ****************/
+
+#define gmp_asprintf __gmp_asprintf
+__GMP_DECLSPEC int gmp_asprintf (char **, const char *, ...);
+
+#define gmp_fprintf __gmp_fprintf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fprintf (FILE *, const char *, ...);
+#endif
+
+#define gmp_obstack_printf __gmp_obstack_printf
+#if defined (_GMP_H_HAVE_OBSTACK)
+__GMP_DECLSPEC int gmp_obstack_printf (struct obstack *, const char *, ...);
+#endif
+
+#define gmp_obstack_vprintf __gmp_obstack_vprintf
+#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_obstack_vprintf (struct obstack *, const char *, va_list);
+#endif
+
+#define gmp_printf __gmp_printf
+__GMP_DECLSPEC int gmp_printf (const char *, ...);
+
+#define gmp_snprintf __gmp_snprintf
+__GMP_DECLSPEC int gmp_snprintf (char *, size_t, const char *, ...);
+
+#define gmp_sprintf __gmp_sprintf
+__GMP_DECLSPEC int gmp_sprintf (char *, const char *, ...);
+
+#define gmp_vasprintf __gmp_vasprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vasprintf (char **, const char *, va_list);
+#endif
+
+#define gmp_vfprintf __gmp_vfprintf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfprintf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vprintf __gmp_vprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vprintf (const char *, va_list);
+#endif
+
+#define gmp_vsnprintf __gmp_vsnprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsnprintf (char *, size_t, const char *, va_list);
+#endif
+
+#define gmp_vsprintf __gmp_vsprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsprintf (char *, const char *, va_list);
+#endif
+
+
+/**************** Formatted input routines.  ****************/
+
+#define gmp_fscanf __gmp_fscanf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fscanf (FILE *, const char *, ...);
+#endif
+
+#define gmp_scanf __gmp_scanf
+__GMP_DECLSPEC int gmp_scanf (const char *, ...);
+
+#define gmp_sscanf __gmp_sscanf
+__GMP_DECLSPEC int gmp_sscanf (const char *, const char *, ...);
+
+#define gmp_vfscanf __gmp_vfscanf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfscanf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vscanf __gmp_vscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vscanf (const char *, va_list);
+#endif
+
+#define gmp_vsscanf __gmp_vsscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsscanf (const char *, const char *, va_list);
+#endif
+
+
+/**************** Integer (i.e. Z) routines.  ****************/
+
+#define _mpz_realloc __gmpz_realloc
+#define mpz_realloc __gmpz_realloc
+__GMP_DECLSPEC void *_mpz_realloc (mpz_ptr, mp_size_t);
+
+#define mpz_abs __gmpz_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs)
+__GMP_DECLSPEC void mpz_abs (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_add __gmpz_add
+__GMP_DECLSPEC void mpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_add_ui __gmpz_add_ui
+__GMP_DECLSPEC void mpz_add_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_addmul __gmpz_addmul
+__GMP_DECLSPEC void mpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_addmul_ui __gmpz_addmul_ui
+__GMP_DECLSPEC void mpz_addmul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_and __gmpz_and
+__GMP_DECLSPEC void mpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_array_init __gmpz_array_init
+__GMP_DECLSPEC void mpz_array_init (mpz_ptr, mp_size_t, mp_size_t);
+
+#define mpz_bin_ui __gmpz_bin_ui
+__GMP_DECLSPEC void mpz_bin_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_bin_uiui __gmpz_bin_uiui
+__GMP_DECLSPEC void mpz_bin_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_cdiv_q __gmpz_cdiv_q
+__GMP_DECLSPEC void mpz_cdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp
+__GMP_DECLSPEC void mpz_cdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_qr __gmpz_cdiv_qr
+__GMP_DECLSPEC void mpz_cdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_r __gmpz_cdiv_r
+__GMP_DECLSPEC void mpz_cdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp
+__GMP_DECLSPEC void mpz_cdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_ui __gmpz_cdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_clear __gmpz_clear
+__GMP_DECLSPEC void mpz_clear (mpz_ptr);
+
+#define mpz_clears __gmpz_clears
+__GMP_DECLSPEC void mpz_clears (mpz_ptr, ...);
+
+#define mpz_clrbit __gmpz_clrbit
+__GMP_DECLSPEC void mpz_clrbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_cmp __gmpz_cmp
+__GMP_DECLSPEC int mpz_cmp (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmp_d __gmpz_cmp_d
+__GMP_DECLSPEC int mpz_cmp_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_si __gmpz_cmp_si
+__GMP_DECLSPEC int _mpz_cmp_si (mpz_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_ui __gmpz_cmp_ui
+__GMP_DECLSPEC int _mpz_cmp_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs __gmpz_cmpabs
+__GMP_DECLSPEC int mpz_cmpabs (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_d __gmpz_cmpabs_d
+__GMP_DECLSPEC int mpz_cmpabs_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_ui __gmpz_cmpabs_ui
+__GMP_DECLSPEC int mpz_cmpabs_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_com __gmpz_com
+__GMP_DECLSPEC void mpz_com (mpz_ptr, mpz_srcptr);
+
+#define mpz_combit __gmpz_combit
+__GMP_DECLSPEC void mpz_combit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_congruent_p __gmpz_congruent_p
+__GMP_DECLSPEC int mpz_congruent_p (mpz_srcptr, mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p
+__GMP_DECLSPEC int mpz_congruent_2exp_p (mpz_srcptr, mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_ui_p __gmpz_congruent_ui_p
+__GMP_DECLSPEC int mpz_congruent_ui_p (mpz_srcptr, unsigned long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divexact __gmpz_divexact
+__GMP_DECLSPEC void mpz_divexact (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_divexact_ui __gmpz_divexact_ui
+__GMP_DECLSPEC void mpz_divexact_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_divisible_p __gmpz_divisible_p
+__GMP_DECLSPEC int mpz_divisible_p (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_ui_p __gmpz_divisible_ui_p
+__GMP_DECLSPEC int mpz_divisible_ui_p (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p
+__GMP_DECLSPEC int mpz_divisible_2exp_p (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_dump __gmpz_dump
+__GMP_DECLSPEC void mpz_dump (mpz_srcptr);
+
+#define mpz_export __gmpz_export
+__GMP_DECLSPEC void *mpz_export (void *, size_t *, int, size_t, int, size_t, mpz_srcptr);
+
+#define mpz_fac_ui __gmpz_fac_ui
+__GMP_DECLSPEC void mpz_fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_2fac_ui __gmpz_2fac_ui
+__GMP_DECLSPEC void mpz_2fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_mfac_uiui __gmpz_mfac_uiui
+__GMP_DECLSPEC void mpz_mfac_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_primorial_ui __gmpz_primorial_ui
+__GMP_DECLSPEC void mpz_primorial_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fdiv_q __gmpz_fdiv_q
+__GMP_DECLSPEC void mpz_fdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp
+__GMP_DECLSPEC void mpz_fdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_qr __gmpz_fdiv_qr
+__GMP_DECLSPEC void mpz_fdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_r __gmpz_fdiv_r
+__GMP_DECLSPEC void mpz_fdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp
+__GMP_DECLSPEC void mpz_fdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_ui __gmpz_fdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fib_ui __gmpz_fib_ui
+__GMP_DECLSPEC void mpz_fib_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fib2_ui __gmpz_fib2_ui
+__GMP_DECLSPEC void mpz_fib2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_fits_sint_p __gmpz_fits_sint_p
+__GMP_DECLSPEC int mpz_fits_sint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_slong_p __gmpz_fits_slong_p
+__GMP_DECLSPEC int mpz_fits_slong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_sshort_p __gmpz_fits_sshort_p
+__GMP_DECLSPEC int mpz_fits_sshort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_uint_p __gmpz_fits_uint_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_DECLSPEC int mpz_fits_uint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ulong_p __gmpz_fits_ulong_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_DECLSPEC int mpz_fits_ulong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ushort_p __gmpz_fits_ushort_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_DECLSPEC int mpz_fits_ushort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_gcd __gmpz_gcd
+__GMP_DECLSPEC void mpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_gcd_ui __gmpz_gcd_ui
+__GMP_DECLSPEC unsigned long int mpz_gcd_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_gcdext __gmpz_gcdext
+__GMP_DECLSPEC void mpz_gcdext (mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_get_d __gmpz_get_d
+__GMP_DECLSPEC double mpz_get_d (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_d_2exp __gmpz_get_d_2exp
+__GMP_DECLSPEC double mpz_get_d_2exp (signed long int *, mpz_srcptr);
+
+#define mpz_get_si __gmpz_get_si
+__GMP_DECLSPEC /* signed */ long int mpz_get_si (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_str __gmpz_get_str
+__GMP_DECLSPEC char *mpz_get_str (char *, int, mpz_srcptr);
+
+#define mpz_get_ui __gmpz_get_ui
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui)
+__GMP_DECLSPEC unsigned long int mpz_get_ui (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_getlimbn __gmpz_getlimbn
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_DECLSPEC mp_limb_t mpz_getlimbn (mpz_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_hamdist __gmpz_hamdist
+__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_import __gmpz_import
+__GMP_DECLSPEC void mpz_import (mpz_ptr, size_t, int, size_t, int, size_t, const void *);
+
+#define mpz_init __gmpz_init
+__GMP_DECLSPEC void mpz_init (mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_init2 __gmpz_init2
+__GMP_DECLSPEC void mpz_init2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_inits __gmpz_inits
+__GMP_DECLSPEC void mpz_inits (mpz_ptr, ...) __GMP_NOTHROW;
+
+#define mpz_init_set __gmpz_init_set
+__GMP_DECLSPEC void mpz_init_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_init_set_d __gmpz_init_set_d
+__GMP_DECLSPEC void mpz_init_set_d (mpz_ptr, double);
+
+#define mpz_init_set_si __gmpz_init_set_si
+__GMP_DECLSPEC void mpz_init_set_si (mpz_ptr, signed long int);
+
+#define mpz_init_set_str __gmpz_init_set_str
+__GMP_DECLSPEC int mpz_init_set_str (mpz_ptr, const char *, int);
+
+#define mpz_init_set_ui __gmpz_init_set_ui
+__GMP_DECLSPEC void mpz_init_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_inp_raw __gmpz_inp_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_raw (mpz_ptr, FILE *);
+#endif
+
+#define mpz_inp_str __gmpz_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_str (mpz_ptr, FILE *, int);
+#endif
+
+#define mpz_invert __gmpz_invert
+__GMP_DECLSPEC int mpz_invert (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_ior __gmpz_ior
+__GMP_DECLSPEC void mpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_jacobi __gmpz_jacobi
+__GMP_DECLSPEC int mpz_jacobi (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker mpz_jacobi  /* alias */
+
+#define mpz_kronecker_si __gmpz_kronecker_si
+__GMP_DECLSPEC int mpz_kronecker_si (mpz_srcptr, long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker_ui __gmpz_kronecker_ui
+__GMP_DECLSPEC int mpz_kronecker_ui (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_si_kronecker __gmpz_si_kronecker
+__GMP_DECLSPEC int mpz_si_kronecker (long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_kronecker __gmpz_ui_kronecker
+__GMP_DECLSPEC int mpz_ui_kronecker (unsigned long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_lcm __gmpz_lcm
+__GMP_DECLSPEC void mpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_lcm_ui __gmpz_lcm_ui
+__GMP_DECLSPEC void mpz_lcm_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_legendre mpz_jacobi  /* alias */
+
+#define mpz_lucnum_ui __gmpz_lucnum_ui
+__GMP_DECLSPEC void mpz_lucnum_ui (mpz_ptr, unsigned long int);
+
+#define mpz_lucnum2_ui __gmpz_lucnum2_ui
+__GMP_DECLSPEC void mpz_lucnum2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_millerrabin __gmpz_millerrabin
+__GMP_DECLSPEC int mpz_millerrabin (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_mod __gmpz_mod
+__GMP_DECLSPEC void mpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */
+
+#define mpz_mul __gmpz_mul
+__GMP_DECLSPEC void mpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mul_2exp __gmpz_mul_2exp
+__GMP_DECLSPEC void mpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_mul_si __gmpz_mul_si
+__GMP_DECLSPEC void mpz_mul_si (mpz_ptr, mpz_srcptr, long int);
+
+#define mpz_mul_ui __gmpz_mul_ui
+__GMP_DECLSPEC void mpz_mul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_neg __gmpz_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg)
+__GMP_DECLSPEC void mpz_neg (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_nextprime __gmpz_nextprime
+__GMP_DECLSPEC void mpz_nextprime (mpz_ptr, mpz_srcptr);
+
+#define mpz_prevprime __gmpz_prevprime
+__GMP_DECLSPEC int mpz_prevprime (mpz_ptr, mpz_srcptr);
+
+#define mpz_out_raw __gmpz_out_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_raw (FILE *, mpz_srcptr);
+#endif
+
+#define mpz_out_str __gmpz_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_str (FILE *, int, mpz_srcptr);
+#endif
+
+#define mpz_perfect_power_p __gmpz_perfect_power_p
+__GMP_DECLSPEC int mpz_perfect_power_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_perfect_square_p __gmpz_perfect_square_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_DECLSPEC int mpz_perfect_square_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_popcount __gmpz_popcount
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpz_popcount (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_pow_ui __gmpz_pow_ui
+__GMP_DECLSPEC void mpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_powm __gmpz_powm
+__GMP_DECLSPEC void mpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_sec __gmpz_powm_sec
+__GMP_DECLSPEC void mpz_powm_sec (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_ui __gmpz_powm_ui
+__GMP_DECLSPEC void mpz_powm_ui (mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr);
+
+#define mpz_probab_prime_p __gmpz_probab_prime_p
+__GMP_DECLSPEC int mpz_probab_prime_p (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_random __gmpz_random
+__GMP_DECLSPEC void mpz_random (mpz_ptr, mp_size_t);
+
+#define mpz_random2 __gmpz_random2
+__GMP_DECLSPEC void mpz_random2 (mpz_ptr, mp_size_t);
+
+#define mpz_realloc2 __gmpz_realloc2
+__GMP_DECLSPEC void mpz_realloc2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_remove __gmpz_remove
+__GMP_DECLSPEC mp_bitcnt_t mpz_remove (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_root __gmpz_root
+__GMP_DECLSPEC int mpz_root (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rootrem __gmpz_rootrem
+__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_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;
+
+#define mpz_scan1 __gmpz_scan1
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_set __gmpz_set
+__GMP_DECLSPEC void mpz_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_set_d __gmpz_set_d
+__GMP_DECLSPEC void mpz_set_d (mpz_ptr, double);
+
+#define mpz_set_f __gmpz_set_f
+__GMP_DECLSPEC void mpz_set_f (mpz_ptr, mpf_srcptr);
+
+#define mpz_set_q __gmpz_set_q
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q)
+__GMP_DECLSPEC void mpz_set_q (mpz_ptr, mpq_srcptr);
+#endif
+
+#define mpz_set_si __gmpz_set_si
+__GMP_DECLSPEC void mpz_set_si (mpz_ptr, signed long int);
+
+#define mpz_set_str __gmpz_set_str
+__GMP_DECLSPEC int mpz_set_str (mpz_ptr, const char *, int);
+
+#define mpz_set_ui __gmpz_set_ui
+__GMP_DECLSPEC void mpz_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_setbit __gmpz_setbit
+__GMP_DECLSPEC void mpz_setbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_size __gmpz_size
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size)
+__GMP_DECLSPEC size_t mpz_size (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_sizeinbase __gmpz_sizeinbase
+__GMP_DECLSPEC size_t mpz_sizeinbase (mpz_srcptr, int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_sqrt __gmpz_sqrt
+__GMP_DECLSPEC void mpz_sqrt (mpz_ptr, mpz_srcptr);
+
+#define mpz_sqrtrem __gmpz_sqrtrem
+__GMP_DECLSPEC void mpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
+
+#define mpz_sub __gmpz_sub
+__GMP_DECLSPEC void mpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_sub_ui __gmpz_sub_ui
+__GMP_DECLSPEC void mpz_sub_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_ui_sub __gmpz_ui_sub
+__GMP_DECLSPEC void mpz_ui_sub (mpz_ptr, unsigned long int, mpz_srcptr);
+
+#define mpz_submul __gmpz_submul
+__GMP_DECLSPEC void mpz_submul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_submul_ui __gmpz_submul_ui
+__GMP_DECLSPEC void mpz_submul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_swap __gmpz_swap
+__GMP_DECLSPEC void mpz_swap (mpz_ptr, mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_tdiv_ui __gmpz_tdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_tdiv_q __gmpz_tdiv_q
+__GMP_DECLSPEC void mpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp
+__GMP_DECLSPEC void mpz_tdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_qr __gmpz_tdiv_qr
+__GMP_DECLSPEC void mpz_tdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_r __gmpz_tdiv_r
+__GMP_DECLSPEC void mpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp
+__GMP_DECLSPEC void mpz_tdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tstbit __gmpz_tstbit
+__GMP_DECLSPEC int mpz_tstbit (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_pow_ui __gmpz_ui_pow_ui
+__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_ptr, mp_bitcnt_t);
+
+#define mpz_urandomm __gmpz_urandomm
+__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_ptr, mpz_srcptr);
+
+#define mpz_xor __gmpz_xor
+#define mpz_eor __gmpz_xor
+__GMP_DECLSPEC void mpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_limbs_read __gmpz_limbs_read
+__GMP_DECLSPEC mp_srcptr mpz_limbs_read (mpz_srcptr);
+
+#define mpz_limbs_write __gmpz_limbs_write
+__GMP_DECLSPEC mp_ptr mpz_limbs_write (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_modify __gmpz_limbs_modify
+__GMP_DECLSPEC mp_ptr mpz_limbs_modify (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_finish __gmpz_limbs_finish
+__GMP_DECLSPEC void mpz_limbs_finish (mpz_ptr, mp_size_t);
+
+#define mpz_roinit_n __gmpz_roinit_n
+__GMP_DECLSPEC mpz_srcptr mpz_roinit_n (mpz_ptr, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+/**************** Rational (i.e. Q) routines.  ****************/
+
+#define mpq_abs __gmpq_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs)
+__GMP_DECLSPEC void mpq_abs (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_add __gmpq_add
+__GMP_DECLSPEC void mpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_canonicalize __gmpq_canonicalize
+__GMP_DECLSPEC void mpq_canonicalize (mpq_ptr);
+
+#define mpq_clear __gmpq_clear
+__GMP_DECLSPEC void mpq_clear (mpq_ptr);
+
+#define mpq_clears __gmpq_clears
+__GMP_DECLSPEC void mpq_clears (mpq_ptr, ...);
+
+#define mpq_cmp __gmpq_cmp
+__GMP_DECLSPEC int mpq_cmp (mpq_srcptr, mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_si __gmpq_cmp_si
+__GMP_DECLSPEC int _mpq_cmp_si (mpq_srcptr, long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_ui __gmpq_cmp_ui
+__GMP_DECLSPEC int _mpq_cmp_ui (mpq_srcptr, unsigned long int, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_cmp_z __gmpq_cmp_z
+__GMP_DECLSPEC int mpq_cmp_z (mpq_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_div __gmpq_div
+__GMP_DECLSPEC void mpq_div (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_div_2exp __gmpq_div_2exp
+__GMP_DECLSPEC void mpq_div_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_equal __gmpq_equal
+__GMP_DECLSPEC int mpq_equal (mpq_srcptr, mpq_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_num __gmpq_get_num
+__GMP_DECLSPEC void mpq_get_num (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_den __gmpq_get_den
+__GMP_DECLSPEC void mpq_get_den (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_d __gmpq_get_d
+__GMP_DECLSPEC double mpq_get_d (mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_str __gmpq_get_str
+__GMP_DECLSPEC char *mpq_get_str (char *, int, mpq_srcptr);
+
+#define mpq_init __gmpq_init
+__GMP_DECLSPEC void mpq_init (mpq_ptr);
+
+#define mpq_inits __gmpq_inits
+__GMP_DECLSPEC void mpq_inits (mpq_ptr, ...);
+
+#define mpq_inp_str __gmpq_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_inp_str (mpq_ptr, FILE *, int);
+#endif
+
+#define mpq_inv __gmpq_inv
+__GMP_DECLSPEC void mpq_inv (mpq_ptr, mpq_srcptr);
+
+#define mpq_mul __gmpq_mul
+__GMP_DECLSPEC void mpq_mul (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_mul_2exp __gmpq_mul_2exp
+__GMP_DECLSPEC void mpq_mul_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_neg __gmpq_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg)
+__GMP_DECLSPEC void mpq_neg (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_out_str __gmpq_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_out_str (FILE *, int, mpq_srcptr);
+#endif
+
+#define mpq_set __gmpq_set
+__GMP_DECLSPEC void mpq_set (mpq_ptr, mpq_srcptr);
+
+#define mpq_set_d __gmpq_set_d
+__GMP_DECLSPEC void mpq_set_d (mpq_ptr, double);
+
+#define mpq_set_den __gmpq_set_den
+__GMP_DECLSPEC void mpq_set_den (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_f __gmpq_set_f
+__GMP_DECLSPEC void mpq_set_f (mpq_ptr, mpf_srcptr);
+
+#define mpq_set_num __gmpq_set_num
+__GMP_DECLSPEC void mpq_set_num (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_si __gmpq_set_si
+__GMP_DECLSPEC void mpq_set_si (mpq_ptr, signed long int, unsigned long int);
+
+#define mpq_set_str __gmpq_set_str
+__GMP_DECLSPEC int mpq_set_str (mpq_ptr, const char *, int);
+
+#define mpq_set_ui __gmpq_set_ui
+__GMP_DECLSPEC void mpq_set_ui (mpq_ptr, unsigned long int, unsigned long int);
+
+#define mpq_set_z __gmpq_set_z
+__GMP_DECLSPEC void mpq_set_z (mpq_ptr, mpz_srcptr);
+
+#define mpq_sub __gmpq_sub
+__GMP_DECLSPEC void mpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_swap __gmpq_swap
+__GMP_DECLSPEC void mpq_swap (mpq_ptr, mpq_ptr) __GMP_NOTHROW;
+
+
+/**************** Float (i.e. F) routines.  ****************/
+
+#define mpf_abs __gmpf_abs
+__GMP_DECLSPEC void mpf_abs (mpf_ptr, mpf_srcptr);
+
+#define mpf_add __gmpf_add
+__GMP_DECLSPEC void mpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_add_ui __gmpf_add_ui
+__GMP_DECLSPEC void mpf_add_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+#define mpf_ceil __gmpf_ceil
+__GMP_DECLSPEC void mpf_ceil (mpf_ptr, mpf_srcptr);
+
+#define mpf_clear __gmpf_clear
+__GMP_DECLSPEC void mpf_clear (mpf_ptr);
+
+#define mpf_clears __gmpf_clears
+__GMP_DECLSPEC void mpf_clears (mpf_ptr, ...);
+
+#define mpf_cmp __gmpf_cmp
+__GMP_DECLSPEC int mpf_cmp (mpf_srcptr, mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_z __gmpf_cmp_z
+__GMP_DECLSPEC int mpf_cmp_z (mpf_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_d __gmpf_cmp_d
+__GMP_DECLSPEC int mpf_cmp_d (mpf_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_si __gmpf_cmp_si
+__GMP_DECLSPEC int mpf_cmp_si (mpf_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_ui __gmpf_cmp_ui
+__GMP_DECLSPEC int mpf_cmp_ui (mpf_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_div __gmpf_div
+__GMP_DECLSPEC void mpf_div (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_div_2exp __gmpf_div_2exp
+__GMP_DECLSPEC void mpf_div_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_div_ui __gmpf_div_ui
+__GMP_DECLSPEC void mpf_div_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_dump __gmpf_dump
+__GMP_DECLSPEC void mpf_dump (mpf_srcptr);
+
+#define mpf_eq __gmpf_eq
+__GMP_DECLSPEC int mpf_eq (mpf_srcptr, mpf_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sint_p __gmpf_fits_sint_p
+__GMP_DECLSPEC int mpf_fits_sint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_slong_p __gmpf_fits_slong_p
+__GMP_DECLSPEC int mpf_fits_slong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sshort_p __gmpf_fits_sshort_p
+__GMP_DECLSPEC int mpf_fits_sshort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_uint_p __gmpf_fits_uint_p
+__GMP_DECLSPEC int mpf_fits_uint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ulong_p __gmpf_fits_ulong_p
+__GMP_DECLSPEC int mpf_fits_ulong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ushort_p __gmpf_fits_ushort_p
+__GMP_DECLSPEC int mpf_fits_ushort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_floor __gmpf_floor
+__GMP_DECLSPEC void mpf_floor (mpf_ptr, mpf_srcptr);
+
+#define mpf_get_d __gmpf_get_d
+__GMP_DECLSPEC double mpf_get_d (mpf_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_d_2exp __gmpf_get_d_2exp
+__GMP_DECLSPEC double mpf_get_d_2exp (signed long int *, mpf_srcptr);
+
+#define mpf_get_default_prec __gmpf_get_default_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec (void) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_prec __gmpf_get_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_si __gmpf_get_si
+__GMP_DECLSPEC long mpf_get_si (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_str __gmpf_get_str
+__GMP_DECLSPEC char *mpf_get_str (char *, mp_exp_t *, int, size_t, mpf_srcptr);
+
+#define mpf_get_ui __gmpf_get_ui
+__GMP_DECLSPEC unsigned long mpf_get_ui (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_init __gmpf_init
+__GMP_DECLSPEC void mpf_init (mpf_ptr);
+
+#define mpf_init2 __gmpf_init2
+__GMP_DECLSPEC void mpf_init2 (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_inits __gmpf_inits
+__GMP_DECLSPEC void mpf_inits (mpf_ptr, ...);
+
+#define mpf_init_set __gmpf_init_set
+__GMP_DECLSPEC void mpf_init_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_init_set_d __gmpf_init_set_d
+__GMP_DECLSPEC void mpf_init_set_d (mpf_ptr, double);
+
+#define mpf_init_set_si __gmpf_init_set_si
+__GMP_DECLSPEC void mpf_init_set_si (mpf_ptr, signed long int);
+
+#define mpf_init_set_str __gmpf_init_set_str
+__GMP_DECLSPEC int mpf_init_set_str (mpf_ptr, const char *, int);
+
+#define mpf_init_set_ui __gmpf_init_set_ui
+__GMP_DECLSPEC void mpf_init_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_inp_str __gmpf_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_inp_str (mpf_ptr, FILE *, int);
+#endif
+
+#define mpf_integer_p __gmpf_integer_p
+__GMP_DECLSPEC int mpf_integer_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_mul __gmpf_mul
+__GMP_DECLSPEC void mpf_mul (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_mul_2exp __gmpf_mul_2exp
+__GMP_DECLSPEC void mpf_mul_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_mul_ui __gmpf_mul_ui
+__GMP_DECLSPEC void mpf_mul_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_neg __gmpf_neg
+__GMP_DECLSPEC void mpf_neg (mpf_ptr, mpf_srcptr);
+
+#define mpf_out_str __gmpf_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_out_str (FILE *, int, size_t, mpf_srcptr);
+#endif
+
+#define mpf_pow_ui __gmpf_pow_ui
+__GMP_DECLSPEC void mpf_pow_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_random2 __gmpf_random2
+__GMP_DECLSPEC void mpf_random2 (mpf_ptr, mp_size_t, mp_exp_t);
+
+#define mpf_reldiff __gmpf_reldiff
+__GMP_DECLSPEC void mpf_reldiff (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_set __gmpf_set
+__GMP_DECLSPEC void mpf_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_set_d __gmpf_set_d
+__GMP_DECLSPEC void mpf_set_d (mpf_ptr, double);
+
+#define mpf_set_default_prec __gmpf_set_default_prec
+__GMP_DECLSPEC void mpf_set_default_prec (mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_prec __gmpf_set_prec
+__GMP_DECLSPEC void mpf_set_prec (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_set_prec_raw __gmpf_set_prec_raw
+__GMP_DECLSPEC void mpf_set_prec_raw (mpf_ptr, mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_q __gmpf_set_q
+__GMP_DECLSPEC void mpf_set_q (mpf_ptr, mpq_srcptr);
+
+#define mpf_set_si __gmpf_set_si
+__GMP_DECLSPEC void mpf_set_si (mpf_ptr, signed long int);
+
+#define mpf_set_str __gmpf_set_str
+__GMP_DECLSPEC int mpf_set_str (mpf_ptr, const char *, int);
+
+#define mpf_set_ui __gmpf_set_ui
+__GMP_DECLSPEC void mpf_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_set_z __gmpf_set_z
+__GMP_DECLSPEC void mpf_set_z (mpf_ptr, mpz_srcptr);
+
+#define mpf_size __gmpf_size
+__GMP_DECLSPEC size_t mpf_size (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_sqrt __gmpf_sqrt
+__GMP_DECLSPEC void mpf_sqrt (mpf_ptr, mpf_srcptr);
+
+#define mpf_sqrt_ui __gmpf_sqrt_ui
+__GMP_DECLSPEC void mpf_sqrt_ui (mpf_ptr, unsigned long int);
+
+#define mpf_sub __gmpf_sub
+__GMP_DECLSPEC void mpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_sub_ui __gmpf_sub_ui
+__GMP_DECLSPEC void mpf_sub_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_swap __gmpf_swap
+__GMP_DECLSPEC void mpf_swap (mpf_ptr, mpf_ptr) __GMP_NOTHROW;
+
+#define mpf_trunc __gmpf_trunc
+__GMP_DECLSPEC void mpf_trunc (mpf_ptr, mpf_srcptr);
+
+#define mpf_ui_div __gmpf_ui_div
+__GMP_DECLSPEC void mpf_ui_div (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_ui_sub __gmpf_ui_sub
+__GMP_DECLSPEC void mpf_ui_sub (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_urandomb __gmpf_urandomb
+__GMP_DECLSPEC void mpf_urandomb (mpf_ptr, gmp_randstate_ptr, mp_bitcnt_t);
+
+
+/************ Low level positive-integer (i.e. N) routines.  ************/
+
+/* This is ugly, but we need to make user calls reach the prefixed function. */
+
+#define mpn_add __MPN(add)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add)
+__GMP_DECLSPEC mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_add_1 __MPN(add_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_add_n __MPN(add_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_addmul_1 __MPN(addmul_1)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_cmp __MPN(cmp)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp)
+__GMP_DECLSPEC int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_zero_p __MPN(zero_p)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_zero_p)
+__GMP_DECLSPEC int mpn_zero_p (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_divexact_1 __MPN(divexact_1)
+__GMP_DECLSPEC void mpn_divexact_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divexact_by3(dst,src,size) \
+  mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0))
+
+#define mpn_divexact_by3c __MPN(divexact_by3c)
+__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divmod_1(qp,np,nsize,dlimb) \
+  mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb)
+
+#define mpn_divrem __MPN(divrem)
+__GMP_DECLSPEC mp_limb_t mpn_divrem (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_divrem_1 __MPN(divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divrem_2 __MPN(divrem_2)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+#define mpn_div_qr_1 __MPN(div_qr_1)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_1 (mp_ptr, mp_limb_t *, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_div_qr_2 __MPN(div_qr_2)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_gcd __MPN(gcd)
+__GMP_DECLSPEC mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_gcd_11 __MPN(gcd_11)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_11 (mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcd_1 __MPN(gcd_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcdext_1 __MPN(gcdext_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcdext_1 (mp_limb_signed_t *, mp_limb_signed_t *, mp_limb_t, mp_limb_t);
+
+#define mpn_gcdext __MPN(gcdext)
+__GMP_DECLSPEC mp_size_t mpn_gcdext (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_get_str __MPN(get_str)
+__GMP_DECLSPEC size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+#define mpn_hamdist __MPN(hamdist)
+__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_lshift __MPN(lshift)
+__GMP_DECLSPEC mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_mod_1 __MPN(mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul __MPN(mul)
+__GMP_DECLSPEC mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mul_1 __MPN(mul_1)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_mul_n __MPN(mul_n)
+__GMP_DECLSPEC void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr __MPN(sqr)
+__GMP_DECLSPEC void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_neg __MPN(neg)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_neg)
+__GMP_DECLSPEC mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_com __MPN(com)
+__GMP_DECLSPEC void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_perfect_square_p __MPN(perfect_square_p)
+__GMP_DECLSPEC int mpn_perfect_square_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_perfect_power_p __MPN(perfect_power_p)
+__GMP_DECLSPEC int mpn_perfect_power_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_popcount __MPN(popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_pow_1 __MPN(pow_1)
+__GMP_DECLSPEC mp_size_t mpn_pow_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+/* undocumented now, but retained here for upward compatibility */
+#define mpn_preinv_mod_1 __MPN(preinv_mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_random __MPN(random)
+__GMP_DECLSPEC void mpn_random (mp_ptr, mp_size_t);
+
+#define mpn_random2 __MPN(random2)
+__GMP_DECLSPEC void mpn_random2 (mp_ptr, mp_size_t);
+
+#define mpn_rshift __MPN(rshift)
+__GMP_DECLSPEC mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_scan0 __MPN(scan0)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_scan1 __MPN(scan1)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_set_str __MPN(set_str)
+__GMP_DECLSPEC mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+#define mpn_sizeinbase __MPN(sizeinbase)
+__GMP_DECLSPEC size_t mpn_sizeinbase (mp_srcptr, mp_size_t, int);
+
+#define mpn_sqrtrem __MPN(sqrtrem)
+__GMP_DECLSPEC mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sub __MPN(sub)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub)
+__GMP_DECLSPEC mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sub_1 __MPN(sub_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_sub_n __MPN(sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1 __MPN(submul_1)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_tdiv_qr __MPN(tdiv_qr)
+__GMP_DECLSPEC void mpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_and_n __MPN(and_n)
+__GMP_DECLSPEC void mpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_andn_n __MPN(andn_n)
+__GMP_DECLSPEC void mpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nand_n __MPN(nand_n)
+__GMP_DECLSPEC void mpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_ior_n __MPN(ior_n)
+__GMP_DECLSPEC void mpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_iorn_n __MPN(iorn_n)
+__GMP_DECLSPEC void mpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nior_n __MPN(nior_n)
+__GMP_DECLSPEC void mpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xor_n __MPN(xor_n)
+__GMP_DECLSPEC void mpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xnor_n __MPN(xnor_n)
+__GMP_DECLSPEC void mpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_zero __MPN(zero)
+__GMP_DECLSPEC void mpn_zero (mp_ptr, mp_size_t);
+
+#define mpn_cnd_add_n __MPN(cnd_add_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_cnd_sub_n __MPN(cnd_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sec_add_1 __MPN(sec_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_add_1_itch __MPN(sec_add_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_add_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sub_1 __MPN(sec_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_sub_1_itch __MPN(sec_sub_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sub_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_cnd_swap  __MPN(cnd_swap)
+__GMP_DECLSPEC void mpn_cnd_swap (mp_limb_t, volatile mp_limb_t *, volatile mp_limb_t *, mp_size_t);
+
+#define mpn_sec_mul __MPN(sec_mul)
+__GMP_DECLSPEC void mpn_sec_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_mul_itch __MPN(sec_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_mul_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sqr __MPN(sec_sqr)
+__GMP_DECLSPEC void mpn_sec_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_sqr_itch __MPN(sec_sqr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sqr_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_powm __MPN(sec_powm)
+__GMP_DECLSPEC void mpn_sec_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_bitcnt_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_powm_itch __MPN(sec_powm_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_powm_itch (mp_size_t, mp_bitcnt_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_tabselect __MPN(sec_tabselect)
+__GMP_DECLSPEC void mpn_sec_tabselect (volatile mp_limb_t *, volatile const mp_limb_t *, mp_size_t, mp_size_t, mp_size_t);
+
+#define mpn_sec_div_qr __MPN(sec_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_qr_itch __MPN(sec_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_qr_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#define mpn_sec_div_r __MPN(sec_div_r)
+__GMP_DECLSPEC void mpn_sec_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_r_itch __MPN(sec_div_r_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_r_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_invert __MPN(sec_invert)
+__GMP_DECLSPEC int mpn_sec_invert (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_bitcnt_t, mp_ptr);
+#define mpn_sec_invert_itch __MPN(sec_invert_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_invert_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+/**************** mpz inlines ****************/
+
+/* The following are provided as inlines where possible, but always exist as
+   library functions too, for binary compatibility.
+
+   Within gmp itself this inlining generally isn't relied on, since it
+   doesn't get done for all compilers, whereas if something is worth
+   inlining then it's worth arranging always.
+
+   There are two styles of inlining here.  When the same bit of code is
+   wanted for the inline as for the library version, then __GMP_FORCE_foo
+   arranges for that code to be emitted and the __GMP_EXTERN_INLINE
+   directive suppressed, eg. mpz_fits_uint_p.  When a different bit of code
+   is wanted for the inline than for the library version, then
+   __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs.  */
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs)
+__GMP_EXTERN_INLINE void
+mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size);
+}
+#endif
+
+#if GMP_NAIL_BITS == 0
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval));
+#else
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)	\
+	  || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS)));
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p)
+#if ! defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, UINT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, ULONG_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, USHRT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui)
+#if ! defined (__GMP_FORCE_mpz_get_ui)
+__GMP_EXTERN_INLINE
+#endif
+unsigned long
+mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  mp_ptr __gmp_p = __gmp_z->_mp_d;
+  mp_size_t __gmp_n = __gmp_z->_mp_size;
+  mp_limb_t __gmp_l = __gmp_p[0];
+  /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings
+     about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland
+     C++ 6.0 warnings about condition always true for something like
+     "ULONG_MAX < GMP_NUMB_MASK".  */
+#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB)
+  /* limb==long and no nails, or limb==longlong, one limb is enough */
+  return (__gmp_n != 0 ? __gmp_l : 0);
+#else
+  /* limb==long and nails, need two limbs when available */
+  __gmp_n = __GMP_ABS (__gmp_n);
+  if (__gmp_n <= 1)
+    return (__gmp_n != 0 ? __gmp_l : 0);
+  else
+    return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS);
+#endif
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn)
+#if ! defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_result = 0;
+  if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size)))
+    __gmp_result = __gmp_z->_mp_d[__gmp_n];
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg)
+__GMP_EXTERN_INLINE void
+mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = - __gmp_w->_mp_size;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p)
+#if ! defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_perfect_square_p (mpz_srcptr __gmp_a)
+{
+  mp_size_t __gmp_asize;
+  int       __gmp_result;
+
+  __gmp_asize = __gmp_a->_mp_size;
+  __gmp_result = (__gmp_asize >= 0);  /* zero is a square, negatives are not */
+  if (__GMP_LIKELY (__gmp_asize > 0))
+    __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount)
+#if ! defined (__GMP_FORCE_mpz_popcount)
+__GMP_EXTERN_INLINE
+#endif
+mp_bitcnt_t
+mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW
+{
+  mp_size_t      __gmp_usize;
+  mp_bitcnt_t    __gmp_result;
+
+  __gmp_usize = __gmp_u->_mp_size;
+  __gmp_result = (__gmp_usize < 0 ? ~ __GMP_CAST (mp_bitcnt_t, 0) : __GMP_CAST (mp_bitcnt_t, 0));
+  if (__GMP_LIKELY (__gmp_usize > 0))
+    __gmp_result =  mpn_popcount (__gmp_u->_mp_d, __gmp_usize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q)
+#if ! defined (__GMP_FORCE_mpz_set_q)
+__GMP_EXTERN_INLINE
+#endif
+void
+mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u));
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size)
+#if ! defined (__GMP_FORCE_mpz_size)
+__GMP_EXTERN_INLINE
+#endif
+size_t
+mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  return __GMP_ABS (__gmp_z->_mp_size);
+}
+#endif
+
+
+/**************** mpq inlines ****************/
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs)
+__GMP_EXTERN_INLINE void
+mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg)
+__GMP_EXTERN_INLINE void
+mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size;
+}
+#endif
+
+
+/**************** mpn inlines ****************/
+
+/* The comments with __GMPN_ADD_1 below apply here too.
+
+   The test for FUNCTION returning 0 should predict well.  If it's assumed
+   {yp,ysize} will usually have a random number of bits then the high limb
+   won't be full and a carry out will occur a good deal less than 50% of the
+   time.
+
+   ysize==0 isn't a documented feature, but is used internally in a few
+   places.
+
+   Producing cout last stops it using up a register during the main part of
+   the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))"
+   doesn't seem able to move the true and false legs of the conditional up
+   to the two places cout is generated.  */
+
+#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST)     \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x;                                                 \
+                                                                        \
+    /* ASSERT ((ysize) >= 0); */                                        \
+    /* ASSERT ((xsize) >= (ysize)); */                                  \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */      \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */      \
+                                                                        \
+    __gmp_i = (ysize);                                                  \
+    if (__gmp_i != 0)                                                   \
+      {                                                                 \
+        if (FUNCTION (wp, xp, yp, __gmp_i))                             \
+          {                                                             \
+            do                                                          \
+              {                                                         \
+                if (__gmp_i >= (xsize))                                 \
+                  {                                                     \
+                    (cout) = 1;                                         \
+                    goto __gmp_done;                                    \
+                  }                                                     \
+                __gmp_x = (xp)[__gmp_i];                                \
+              }                                                         \
+            while (TEST);                                               \
+          }                                                             \
+      }                                                                 \
+    if ((wp) != (xp))                                                   \
+      __GMPN_COPY_REST (wp, xp, xsize, __gmp_i);                        \
+    (cout) = 0;                                                         \
+  __gmp_done:                                                           \
+    ;                                                                   \
+  } while (0)
+
+#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0))
+#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0))
+
+
+/* The use of __gmp_i indexing is designed to ensure a compile time src==dst
+   remains nice and clear to the compiler, so that __GMPN_COPY_REST can
+   disappear, and the load/add/store gets a chance to become a
+   read-modify-write on CISC CPUs.
+
+   Alternatives:
+
+   Using a pair of pointers instead of indexing would be possible, but gcc
+   isn't able to recognise compile-time src==dst in that case, even when the
+   pointers are incremented more or less together.  Other compilers would
+   very likely have similar difficulty.
+
+   gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or
+   similar to detect a compile-time src==dst.  This works nicely on gcc
+   2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems
+   to be always false, for a pointer p.  But the current code form seems
+   good enough for src==dst anyway.
+
+   gcc on x86 as usual doesn't give particularly good flags handling for the
+   carry/borrow detection.  It's tempting to want some multi instruction asm
+   blocks to help it, and this was tried, but in truth there's only a few
+   instructions to save and any gain is all too easily lost by register
+   juggling setting up for the asm.  */
+
+#if GMP_NAIL_BITS == 0
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;                                \
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);                                   \
+    (dst)[0] = __gmp_r;						\
+    if (CB (__gmp_r, __gmp_x, (v)))                             \
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)                       \
+	  {							\
+	    __gmp_x = (src)[__gmp_i];                           \
+	    __gmp_r = __gmp_x OP 1;                             \
+	    (dst)[__gmp_i] = __gmp_r;                           \
+	    ++__gmp_i;						\
+	    if (!CB (__gmp_r, __gmp_x, 1))                      \
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);      \
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;				\
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);					\
+    (dst)[0] = __gmp_r & GMP_NUMB_MASK;				\
+    if (__gmp_r >> GMP_NUMB_BITS != 0)				\
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)			\
+	  {							\
+	    __gmp_x = (src)[__gmp_i];				\
+	    __gmp_r = __gmp_x OP 1;				\
+	    (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK;		\
+	    ++__gmp_i;						\
+	    if (__gmp_r >> GMP_NUMB_BITS == 0)			\
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);	\
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#define __GMPN_ADDCB(r,x,y) ((r) < (y))
+#define __GMPN_SUBCB(r,x,y) ((x) < (y))
+
+#define __GMPN_ADD_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB)
+#define __GMPN_SUB_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB)
+
+
+/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or
+   negative.  size==0 is allowed.  On random data usually only one limb will
+   need to be examined to get a result, so it's worth having it inline.  */
+#define __GMPN_CMP(result, xp, yp, size)                                \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x, __gmp_y;                                        \
+                                                                        \
+    /* ASSERT ((size) >= 0); */                                         \
+                                                                        \
+    (result) = 0;                                                       \
+    __gmp_i = (size);                                                   \
+    while (--__gmp_i >= 0)                                              \
+      {                                                                 \
+        __gmp_x = (xp)[__gmp_i];                                        \
+        __gmp_y = (yp)[__gmp_i];                                        \
+        if (__gmp_x != __gmp_y)                                         \
+          {                                                             \
+            /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */   \
+            (result) = (__gmp_x > __gmp_y ? 1 : -1);                    \
+            break;                                                      \
+          }                                                             \
+      }                                                                 \
+  } while (0)
+
+
+#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \
+  } while (0)
+#endif
+
+/* Copy {src,size} to {dst,size}, starting at "start".  This is designed to
+   keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1,
+   __GMPN_ADD, etc.  */
+#if ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    mp_size_t __gmp_j;                                          \
+    /* ASSERT ((size) >= 0); */                                 \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */     \
+    __GMP_CRAY_Pragma ("_CRI ivdep");                           \
+    for (__gmp_j = (start); __gmp_j < (size); __gmp_j++)        \
+      (dst)[__gmp_j] = (src)[__gmp_j];                          \
+  } while (0)
+#endif
+
+/* Enhancement: Use some of the smarter code from gmp-impl.h.  Maybe use
+   mpn_copyi if there's a native version, and if we don't mind demanding
+   binary compatibility for it (on targets which use it).  */
+
+#if ! defined (__GMPN_COPY)
+#define __GMPN_COPY(dst, src, size)   __GMPN_COPY_REST (dst, src, size, 0)
+#endif
+
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add)
+#if ! defined (__GMP_FORCE_mpn_add)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1)
+#if ! defined (__GMP_FORCE_mpn_add_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp)
+#if ! defined (__GMP_FORCE_mpn_cmp)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW
+{
+  int __gmp_result;
+  __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_zero_p)
+#if ! defined (__GMP_FORCE_mpn_zero_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_zero_p (mp_srcptr __gmp_p, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  /* if (__GMP_LIKELY (__gmp_n > 0)) */
+    do {
+      if (__gmp_p[--__gmp_n] != 0)
+	return 0;
+    } while (__gmp_n != 0);
+  return 1;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub)
+#if ! defined (__GMP_FORCE_mpn_sub)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1)
+#if ! defined (__GMP_FORCE_mpn_sub_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_neg)
+#if ! defined (__GMP_FORCE_mpn_neg)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_neg (mp_ptr __gmp_rp, mp_srcptr __gmp_up, mp_size_t __gmp_n)
+{
+  while (*__gmp_up == 0) /* Low zero limbs are unchanged by negation. */
+    {
+      *__gmp_rp = 0;
+      if (!--__gmp_n) /* All zero */
+	return 0;
+      ++__gmp_up; ++__gmp_rp;
+    }
+
+  *__gmp_rp = (- *__gmp_up) & GMP_NUMB_MASK;
+
+  if (--__gmp_n) /* Higher limbs get complemented. */
+    mpn_com (++__gmp_rp, ++__gmp_up, __gmp_n);
+
+  return 1;
+}
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Allow faster testing for negative, zero, and positive.  */
+#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0)
+#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0)
+#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0)
+
+/* When using GCC, optimize certain common comparisons.  */
+#if defined (__GNUC__) && __GNUC__ >= 2
+#define mpz_cmp_ui(Z,UI) \
+  (__builtin_constant_p (UI) && (UI) == 0				\
+   ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI))
+#define mpz_cmp_si(Z,SI)						\
+  (__builtin_constant_p ((SI) >= 0) && (SI) >= 0			\
+   ? mpz_cmp_ui (Z, __GMP_CAST (unsigned long, SI))			\
+   : _mpz_cmp_si (Z,SI))
+#define mpq_cmp_ui(Q,NUI,DUI)					\
+  (__builtin_constant_p (NUI) && (NUI) == 0 ? mpq_sgn (Q)	\
+   : __builtin_constant_p ((NUI) == (DUI)) && (NUI) == (DUI)	\
+   ? mpz_cmp (mpq_numref (Q), mpq_denref (Q))			\
+   : _mpq_cmp_ui (Q,NUI,DUI))
+#define mpq_cmp_si(q,n,d)				\
+  (__builtin_constant_p ((n) >= 0) && (n) >= 0		\
+   ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d)	\
+   : _mpq_cmp_si (q, n, d))
+#else
+#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI)
+#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI)
+#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI)
+#define mpq_cmp_si(q,n,d)  _mpq_cmp_si(q,n,d)
+#endif
+
+
+/* Using "&" rather than "&&" means these can come out branch-free.  Every
+   mpz_t has at least one limb allocated, so fetching the low limb is always
+   allowed.  */
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0]))
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+
+/**************** C++ routines ****************/
+
+#ifdef __cplusplus
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr);
+#endif
+
+
+/* Source-level compatibility with GMP 2 and earlier. */
+#define mpn_divmod(qp,np,nsize,dp,dsize) \
+  mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize)
+
+/* Source-level compatibility with GMP 1.  */
+#define mpz_mdiv	mpz_fdiv_q
+#define mpz_mdivmod	mpz_fdiv_qr
+#define mpz_mmod	mpz_fdiv_r
+#define mpz_mdiv_ui	mpz_fdiv_q_ui
+#define mpz_mdivmod_ui(q,r,n,d) \
+  (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d))
+#define mpz_mmod_ui(r,n,d) \
+  (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d))
+
+/* Useful synonyms, but not quite compatible with GMP 1.  */
+#define mpz_div		mpz_fdiv_q
+#define mpz_divmod	mpz_fdiv_qr
+#define mpz_div_ui	mpz_fdiv_q_ui
+#define mpz_divmod_ui	mpz_fdiv_qr_ui
+#define mpz_div_2exp	mpz_fdiv_q_2exp
+#define mpz_mod_2exp	mpz_fdiv_r_2exp
+
+enum
+{
+  GMP_ERROR_NONE = 0,
+  GMP_ERROR_UNSUPPORTED_ARGUMENT = 1,
+  GMP_ERROR_DIVISION_BY_ZERO = 2,
+  GMP_ERROR_SQRT_OF_NEGATIVE = 4,
+  GMP_ERROR_INVALID_ARGUMENT = 8,
+  GMP_ERROR_MPZ_OVERFLOW = 16
+};
+
+/* Define CC and CFLAGS which were used to build this version of GMP */
+#define __GMP_CC "@CC@"
+#define __GMP_CFLAGS "@CFLAGS@"
+
+/* Major version number is the value of __GNU_MP__ too, above. */
+#define __GNU_MP_VERSION            6
+#define __GNU_MP_VERSION_MINOR      3
+#define __GNU_MP_VERSION_PATCHLEVEL 0
+#define __GNU_MP_RELEASE (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL)
+
+#define __GMP_H__
+#endif /* __GMP_H__ */
diff --git a/gmp-impl.h b/gmp-impl.h
new file mode 100644
index 0000000..2615af7
--- /dev/null
+++ b/gmp-impl.h
@@ -0,0 +1,5346 @@
+/* Include file for internal GNU MP types and definitions.
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
+
+Copyright 1991-2018, 2021, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* __GMP_DECLSPEC must be given on any global data that will be accessed
+   from outside libgmp, meaning from the test or development programs, or
+   from libgmpxx.  Failing to do this will result in an incorrect address
+   being used for the accesses.  On functions __GMP_DECLSPEC makes calls
+   from outside libgmp more efficient, but they'll still work fine without
+   it.  */
+
+
+#ifndef __GMP_IMPL_H__
+#define __GMP_IMPL_H__
+
+#if defined _CRAY
+#include <intrinsics.h>  /* for _popcnt */
+#endif
+
+/* For INT_MAX, etc. We used to avoid it because of a bug (on solaris,
+   gcc 2.95 under -mcpu=ultrasparc in ABI=32 ends up getting wrong
+   values (the ABI=64 values)), but it should be safe now.
+
+   On Cray vector systems, however, we need the system limits.h since sizes
+   of signed and unsigned types can differ there, depending on compiler
+   options (eg. -hnofastmd), making our SHRT_MAX etc expressions fail.  For
+   reference, int can be 46 or 64 bits, whereas uint is always 64 bits; and
+   short can be 24, 32, 46 or 64 bits, and different for ushort.  */
+
+#include <limits.h>
+
+/* For fat.h and other fat binary stuff.
+   No need for __GMP_ATTRIBUTE_PURE or __GMP_NOTHROW, since functions
+   declared this way are only used to set function pointers in __gmpn_cpuvec,
+   they're not called directly.  */
+#define DECL_add_n(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_addlsh1_n(name) \
+  DECL_add_n (name)
+#define DECL_addlsh2_n(name) \
+  DECL_add_n (name)
+#define DECL_addmul_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_addmul_2(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr)
+#define DECL_bdiv_dbm1c(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)
+#define DECL_cnd_add_n(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_cnd_sub_n(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_com(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t)
+#define DECL_copyd(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t)
+#define DECL_copyi(name) \
+  DECL_copyd (name)
+#define DECL_divexact_1(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_divexact_by3c(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_divrem_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_gcd_11(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_limb_t, mp_limb_t)
+#define DECL_lshift(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, unsigned)
+#define DECL_lshiftc(name) \
+  DECL_lshift (name)
+#define DECL_mod_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_mod_1_1p(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [])
+#define DECL_mod_1_1p_cps(name) \
+  __GMP_DECLSPEC void name (mp_limb_t cps[], mp_limb_t b)
+#define DECL_mod_1s_2p(name) \
+  DECL_mod_1_1p (name)
+#define DECL_mod_1s_2p_cps(name) \
+  DECL_mod_1_1p_cps (name)
+#define DECL_mod_1s_4p(name) \
+  DECL_mod_1_1p (name)
+#define DECL_mod_1s_4p_cps(name) \
+  DECL_mod_1_1p_cps (name)
+#define DECL_mod_34lsub1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t)
+#define DECL_modexact_1c_odd(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)
+#define DECL_mul_1(name) \
+  DECL_addmul_1 (name)
+#define DECL_mul_basecase(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)
+#define DECL_mullo_basecase(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_preinv_divrem_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int)
+#define DECL_preinv_mod_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)
+#define DECL_redc_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_redc_2(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr)
+#define DECL_rshift(name) \
+  DECL_lshift (name)
+#define DECL_sqr_basecase(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t)
+#define DECL_sub_n(name) \
+  DECL_add_n (name)
+#define DECL_sublsh1_n(name) \
+  DECL_add_n (name)
+#define DECL_submul_1(name) \
+  DECL_addmul_1 (name)
+
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#include "config.h"
+#include "gmp.h"
+#include "gmp-mparam.h"
+#include "fib_table.h"
+#include "fac_table.h"
+#include "sieve_table.h"
+#include "mp_bases.h"
+#if WANT_FAT_BINARY
+#include "fat.h"
+#endif
+#endif
+
+#if HAVE_INTTYPES_H      /* for uint_least32_t */
+# include <inttypes.h>
+#endif
+/* On some platforms inttypes.h exists but is incomplete
+   and we still need stdint.h. */
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifdef __cplusplus
+#include <cstring>  /* for strlen */
+#include <string>   /* for std::string */
+#endif
+
+
+#ifndef WANT_TMP_DEBUG  /* for TMP_ALLOC_LIMBS_2 and others */
+#define WANT_TMP_DEBUG 0
+#endif
+
+/* The following tries to get a good version of alloca.  The tests are
+   adapted from autoconf AC_FUNC_ALLOCA, with a couple of additions.
+   Whether this succeeds is tested by GMP_FUNC_ALLOCA and HAVE_ALLOCA will
+   be setup appropriately.
+
+   ifndef alloca - a cpp define might already exist.
+       glibc <stdlib.h> includes <alloca.h> which uses GCC __builtin_alloca.
+       HP cc +Olibcalls adds a #define of alloca to __builtin_alloca.
+
+   GCC __builtin_alloca - preferred whenever available.
+
+   _AIX pragma - IBM compilers need a #pragma in "each module that needs to
+       use alloca".  Pragma indented to protect pre-ANSI cpp's.  _IBMR2 was
+       used in past versions of GMP, retained still in case it matters.
+
+       The autoconf manual says this pragma needs to be at the start of a C
+       file, apart from comments and preprocessor directives.  Is that true?
+       xlc on aix 4.xxx doesn't seem to mind it being after prototypes etc
+       from gmp.h.
+*/
+
+#ifndef alloca
+# ifdef __GNUC__
+#  define alloca __builtin_alloca
+# else
+#  ifdef __DECC
+#   define alloca(x) __ALLOCA(x)
+#  else
+#   ifdef _MSC_VER
+#    include <malloc.h>
+#    define alloca _alloca
+#   else
+#    if HAVE_ALLOCA_H
+#     include <alloca.h>
+#    else
+#     if defined (_AIX) || defined (_IBMR2)
+ #pragma alloca
+#     else
+       char *alloca ();
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+
+/* if not provided by gmp-mparam.h */
+#ifndef GMP_LIMB_BYTES
+#define GMP_LIMB_BYTES  SIZEOF_MP_LIMB_T
+#endif
+#ifndef GMP_LIMB_BITS
+#define GMP_LIMB_BITS  (8 * SIZEOF_MP_LIMB_T)
+#endif
+
+#define BITS_PER_ULONG  (8 * SIZEOF_UNSIGNED_LONG)
+
+
+/* gmp_uint_least32_t is an unsigned integer type with at least 32 bits. */
+#if HAVE_UINT_LEAST32_T
+typedef uint_least32_t      gmp_uint_least32_t;
+#else
+#if SIZEOF_UNSIGNED_SHORT >= 4
+typedef unsigned short      gmp_uint_least32_t;
+#else
+#if SIZEOF_UNSIGNED >= 4
+typedef unsigned            gmp_uint_least32_t;
+#else
+typedef unsigned long       gmp_uint_least32_t;
+#endif
+#endif
+#endif
+
+
+/* gmp_intptr_t, for pointer to integer casts */
+#if HAVE_INTPTR_T
+typedef intptr_t            gmp_intptr_t;
+#else /* fallback */
+typedef size_t              gmp_intptr_t;
+#endif
+
+
+/* pre-inverse types for truncating division and modulo */
+typedef struct {mp_limb_t inv32;} gmp_pi1_t;
+typedef struct {mp_limb_t inv21, inv32, inv53;} gmp_pi2_t;
+
+
+/* "const" basically means a function does nothing but examine its arguments
+   and give a return value, it doesn't read or write any memory (neither
+   global nor pointed to by arguments), and has no other side-effects.  This
+   is more restrictive than "pure".  See info node "(gcc)Function
+   Attributes".  __GMP_NO_ATTRIBUTE_CONST_PURE lets tune/common.c etc turn
+   this off when trying to write timing loops.  */
+#if HAVE_ATTRIBUTE_CONST && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define ATTRIBUTE_CONST  __attribute__ ((const))
+#else
+#define ATTRIBUTE_CONST
+#endif
+
+#if HAVE_ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN  __attribute__ ((noreturn))
+#else
+#define ATTRIBUTE_NORETURN
+#endif
+
+/* "malloc" means a function behaves like malloc in that the pointer it
+   returns doesn't alias anything.  */
+#if HAVE_ATTRIBUTE_MALLOC
+#define ATTRIBUTE_MALLOC  __attribute__ ((malloc))
+#else
+#define ATTRIBUTE_MALLOC
+#endif
+
+
+#if ! HAVE_STRCHR
+#define strchr(s,c)  index(s,c)
+#endif
+
+#if ! HAVE_MEMSET
+#define memset(p, c, n)			\
+  do {					\
+    ASSERT ((n) >= 0);			\
+    char *__memset__p = (p);		\
+    int	 __i;				\
+    for (__i = 0; __i < (n); __i++)	\
+      __memset__p[__i] = (c);		\
+  } while (0)
+#endif
+
+/* va_copy is standard in C99, and gcc provides __va_copy when in strict C89
+   mode.  Falling back to a memcpy will give maximum portability, since it
+   works no matter whether va_list is a pointer, struct or array.  */
+#if ! defined (va_copy) && defined (__va_copy)
+#define va_copy(dst,src)  __va_copy(dst,src)
+#endif
+#if ! defined (va_copy)
+#define va_copy(dst,src) \
+  do { memcpy (&(dst), &(src), sizeof (va_list)); } while (0)
+#endif
+
+
+/* HAVE_HOST_CPU_alpha_CIX is 1 on an alpha with the CIX instructions
+   (ie. ctlz, ctpop, cttz).  */
+#if HAVE_HOST_CPU_alphaev67 || HAVE_HOST_CPU_alphaev68  \
+  || HAVE_HOST_CPU_alphaev7
+#define HAVE_HOST_CPU_alpha_CIX 1
+#endif
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* Usage: TMP_DECL;
+	  TMP_MARK;
+	  ptr = TMP_ALLOC (bytes);
+	  TMP_FREE;
+
+   Small allocations should use TMP_SALLOC, big allocations should use
+   TMP_BALLOC.  Allocations that might be small or big should use TMP_ALLOC.
+
+   Functions that use just TMP_SALLOC should use TMP_SDECL, TMP_SMARK, and
+   TMP_SFREE.
+
+   TMP_DECL just declares a variable, but might be empty and so must be last
+   in a list of variables.  TMP_MARK must be done before any TMP_ALLOC.
+   TMP_ALLOC(0) is not allowed.  TMP_FREE doesn't need to be done if a
+   TMP_MARK was made, but then no TMP_ALLOCs.  */
+
+/* The alignment in bytes, used for TMP_ALLOCed blocks, when alloca or
+   __gmp_allocate_func doesn't already determine it.  */
+union tmp_align_t {
+  mp_limb_t  l;
+  double     d;
+  char       *p;
+};
+#define __TMP_ALIGN  sizeof (union tmp_align_t)
+
+/* Return "a" rounded upwards to a multiple of "m", if it isn't already.
+   "a" must be an unsigned type.
+   This is designed for use with a compile-time constant "m".
+   The POW2 case is expected to be usual, and gcc 3.0 and up recognises
+   "(-(8*n))%8" or the like is always zero, which means the rounding up in
+   the WANT_TMP_NOTREENTRANT version of TMP_ALLOC below will be a noop.  */
+#define ROUND_UP_MULTIPLE(a,m)          \
+  (POW2_P(m) ? (a) + (-(a))%(m)         \
+   : (a)+(m)-1 - (((a)+(m)-1) % (m)))
+
+#if defined (WANT_TMP_ALLOCA) || defined (WANT_TMP_REENTRANT)
+struct tmp_reentrant_t {
+  struct tmp_reentrant_t  *next;
+  size_t		  size;	  /* bytes, including header */
+};
+__GMP_DECLSPEC void *__gmp_tmp_reentrant_alloc (struct tmp_reentrant_t **, size_t) ATTRIBUTE_MALLOC;
+__GMP_DECLSPEC void  __gmp_tmp_reentrant_free (struct tmp_reentrant_t *);
+#endif
+
+#if WANT_TMP_ALLOCA
+#define TMP_SDECL
+#define TMP_DECL		struct tmp_reentrant_t *__tmp_marker
+#define TMP_SMARK
+#define TMP_MARK		__tmp_marker = 0
+#define TMP_SALLOC(n)		alloca(n)
+#define TMP_BALLOC(n)		__gmp_tmp_reentrant_alloc (&__tmp_marker, n)
+/* The peculiar stack allocation limit here is chosen for efficient asm.  */
+#define TMP_ALLOC(n)							\
+  (LIKELY ((n) <= 0x7f00) ? TMP_SALLOC(n) : TMP_BALLOC(n))
+#define TMP_SFREE
+#define TMP_FREE							\
+  do {									\
+    if (UNLIKELY (__tmp_marker != 0))					\
+      __gmp_tmp_reentrant_free (__tmp_marker);				\
+  } while (0)
+#endif
+
+#if WANT_TMP_REENTRANT
+#define TMP_SDECL		TMP_DECL
+#define TMP_DECL		struct tmp_reentrant_t *__tmp_marker
+#define TMP_SMARK		TMP_MARK
+#define TMP_MARK		__tmp_marker = 0
+#define TMP_SALLOC(n)		TMP_ALLOC(n)
+#define TMP_BALLOC(n)		TMP_ALLOC(n)
+#define TMP_ALLOC(n)		__gmp_tmp_reentrant_alloc (&__tmp_marker, n)
+#define TMP_SFREE		TMP_FREE
+#define TMP_FREE		__gmp_tmp_reentrant_free (__tmp_marker)
+#endif
+
+#if WANT_TMP_NOTREENTRANT
+struct tmp_marker
+{
+  struct tmp_stack *which_chunk;
+  void *alloc_point;
+};
+__GMP_DECLSPEC void *__gmp_tmp_alloc (unsigned long) ATTRIBUTE_MALLOC;
+__GMP_DECLSPEC void __gmp_tmp_mark (struct tmp_marker *);
+__GMP_DECLSPEC void __gmp_tmp_free (struct tmp_marker *);
+#define TMP_SDECL		TMP_DECL
+#define TMP_DECL		struct tmp_marker __tmp_marker
+#define TMP_SMARK		TMP_MARK
+#define TMP_MARK		__gmp_tmp_mark (&__tmp_marker)
+#define TMP_SALLOC(n)		TMP_ALLOC(n)
+#define TMP_BALLOC(n)		TMP_ALLOC(n)
+#define TMP_ALLOC(n)							\
+  __gmp_tmp_alloc (ROUND_UP_MULTIPLE ((unsigned long) (n), __TMP_ALIGN))
+#define TMP_SFREE		TMP_FREE
+#define TMP_FREE		__gmp_tmp_free (&__tmp_marker)
+#endif
+
+#if WANT_TMP_DEBUG
+/* See tal-debug.c for some comments. */
+struct tmp_debug_t {
+  struct tmp_debug_entry_t  *list;
+  const char                *file;
+  int                       line;
+};
+struct tmp_debug_entry_t {
+  struct tmp_debug_entry_t  *next;
+  void                      *block;
+  size_t                    size;
+};
+__GMP_DECLSPEC void  __gmp_tmp_debug_mark (const char *, int, struct tmp_debug_t **,
+					   struct tmp_debug_t *,
+					   const char *, const char *);
+__GMP_DECLSPEC void *__gmp_tmp_debug_alloc (const char *, int, int,
+					    struct tmp_debug_t **, const char *,
+					    size_t) ATTRIBUTE_MALLOC;
+__GMP_DECLSPEC void  __gmp_tmp_debug_free (const char *, int, int,
+					   struct tmp_debug_t **,
+					   const char *, const char *);
+#define TMP_SDECL TMP_DECL_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_DECL TMP_DECL_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_SMARK TMP_MARK_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_MARK TMP_MARK_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_SFREE TMP_FREE_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_FREE TMP_FREE_NAME(__tmp_xmarker, "__tmp_marker")
+/* The marker variable is designed to provoke an uninitialized variable
+   warning from the compiler if TMP_FREE is used without a TMP_MARK.
+   __tmp_marker_inscope does the same for TMP_ALLOC.  Runtime tests pick
+   these things up too.  */
+#define TMP_DECL_NAME(marker, marker_name)				\
+  int marker;								\
+  int __tmp_marker_inscope;						\
+  const char *__tmp_marker_name = marker_name;				\
+  struct tmp_debug_t  __tmp_marker_struct;				\
+  /* don't demand NULL, just cast a zero */				\
+  struct tmp_debug_t  *__tmp_marker = (struct tmp_debug_t *) 0
+#define TMP_MARK_NAME(marker, marker_name)				\
+  do {									\
+    marker = 1;								\
+    __tmp_marker_inscope = 1;						\
+    __gmp_tmp_debug_mark  (ASSERT_FILE, ASSERT_LINE,			\
+			   &__tmp_marker, &__tmp_marker_struct,		\
+			   __tmp_marker_name, marker_name);		\
+  } while (0)
+#define TMP_SALLOC(n)		TMP_ALLOC(n)
+#define TMP_BALLOC(n)		TMP_ALLOC(n)
+#define TMP_ALLOC(size)							\
+  __gmp_tmp_debug_alloc (ASSERT_FILE, ASSERT_LINE,			\
+			 __tmp_marker_inscope,				\
+			 &__tmp_marker, __tmp_marker_name, size)
+#define TMP_FREE_NAME(marker, marker_name)				\
+  do {									\
+    __gmp_tmp_debug_free  (ASSERT_FILE, ASSERT_LINE,			\
+			   marker, &__tmp_marker,			\
+			   __tmp_marker_name, marker_name);		\
+  } while (0)
+#endif /* WANT_TMP_DEBUG */
+
+
+/* Allocating various types. */
+#define TMP_ALLOC_TYPE(n,type)  ((type *) TMP_ALLOC ((n) * sizeof (type)))
+#define TMP_SALLOC_TYPE(n,type) ((type *) TMP_SALLOC ((n) * sizeof (type)))
+#define TMP_BALLOC_TYPE(n,type) ((type *) TMP_BALLOC ((n) * sizeof (type)))
+#define TMP_ALLOC_LIMBS(n)      TMP_ALLOC_TYPE(n,mp_limb_t)
+#define TMP_SALLOC_LIMBS(n)     TMP_SALLOC_TYPE(n,mp_limb_t)
+#define TMP_BALLOC_LIMBS(n)     TMP_BALLOC_TYPE(n,mp_limb_t)
+#define TMP_ALLOC_MP_PTRS(n)    TMP_ALLOC_TYPE(n,mp_ptr)
+#define TMP_SALLOC_MP_PTRS(n)   TMP_SALLOC_TYPE(n,mp_ptr)
+#define TMP_BALLOC_MP_PTRS(n)   TMP_BALLOC_TYPE(n,mp_ptr)
+
+/* It's more efficient to allocate one block than many.  This is certainly
+   true of the malloc methods, but it can even be true of alloca if that
+   involves copying a chunk of stack (various RISCs), or a call to a stack
+   bounds check (mingw).  In any case, when debugging keep separate blocks
+   so a redzoning malloc debugger can protect each individually.  */
+#define TMP_ALLOC_LIMBS_2(xp,xsize, yp,ysize)				\
+  do {									\
+    if (WANT_TMP_DEBUG)							\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS (xsize);					\
+	(yp) = TMP_ALLOC_LIMBS (ysize);					\
+      }									\
+    else								\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS ((xsize) + (ysize));			\
+	(yp) = (xp) + (xsize);						\
+      }									\
+  } while (0)
+#define TMP_ALLOC_LIMBS_3(xp,xsize, yp,ysize, zp,zsize)			\
+  do {									\
+    if (WANT_TMP_DEBUG)							\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS (xsize);					\
+	(yp) = TMP_ALLOC_LIMBS (ysize);					\
+	(zp) = TMP_ALLOC_LIMBS (zsize);					\
+      }									\
+    else								\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS ((xsize) + (ysize) + (zsize));		\
+	(yp) = (xp) + (xsize);						\
+	(zp) = (yp) + (ysize);						\
+      }									\
+  } while (0)
+
+/* From gmp.h, nicer names for internal use. */
+#define CRAY_Pragma(str)               __GMP_CRAY_Pragma(str)
+#define MPN_CMP(result, xp, yp, size)  __GMPN_CMP(result, xp, yp, size)
+#define LIKELY(cond)                   __GMP_LIKELY(cond)
+#define UNLIKELY(cond)                 __GMP_UNLIKELY(cond)
+
+#define ABS(x) ((x) >= 0 ? (x) : -(x))
+#define NEG_CAST(T,x) (- (__GMP_CAST (T, (x) + 1) - 1))
+#define ABS_CAST(T,x) ((x) >= 0 ? __GMP_CAST (T, x) : NEG_CAST (T,x))
+#undef MIN
+#define MIN(l,o) ((l) < (o) ? (l) : (o))
+#undef MAX
+#define MAX(h,i) ((h) > (i) ? (h) : (i))
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+/* Field access macros.  */
+#define SIZ(x) ((x)->_mp_size)
+#define ABSIZ(x) ABS (SIZ (x))
+#define PTR(x) ((x)->_mp_d)
+#define EXP(x) ((x)->_mp_exp)
+#define PREC(x) ((x)->_mp_prec)
+#define ALLOC(x) ((x)->_mp_alloc)
+#define NUM(x) mpq_numref(x)
+#define DEN(x) mpq_denref(x)
+
+/* n-1 inverts any low zeros and the lowest one bit.  If n&(n-1) leaves zero
+   then that lowest one bit must have been the only bit set.  n==0 will
+   return true though, so avoid that.  */
+#define POW2_P(n)  (((n) & ((n) - 1)) == 0)
+
+/* This is intended for constant THRESHOLDs only, where the compiler
+   can completely fold the result.  */
+#define LOG2C(n) \
+ (((n) >=    0x1) + ((n) >=    0x2) + ((n) >=    0x4) + ((n) >=    0x8) + \
+  ((n) >=   0x10) + ((n) >=   0x20) + ((n) >=   0x40) + ((n) >=   0x80) + \
+  ((n) >=  0x100) + ((n) >=  0x200) + ((n) >=  0x400) + ((n) >=  0x800) + \
+  ((n) >= 0x1000) + ((n) >= 0x2000) + ((n) >= 0x4000) + ((n) >= 0x8000))
+
+#define MP_LIMB_T_MAX      (~ (mp_limb_t) 0)
+
+/* Must cast ULONG_MAX etc to unsigned long etc, since they might not be
+   unsigned on a K&R compiler.  In particular the HP-UX 10 bundled K&R cc
+   treats the plain decimal values in <limits.h> as signed.  */
+#define ULONG_HIGHBIT      (ULONG_MAX ^ ((unsigned long) ULONG_MAX >> 1))
+#define UINT_HIGHBIT       (UINT_MAX ^ ((unsigned) UINT_MAX >> 1))
+#define USHRT_HIGHBIT      (USHRT_MAX ^ ((unsigned short) USHRT_MAX >> 1))
+#define GMP_LIMB_HIGHBIT  (MP_LIMB_T_MAX ^ (MP_LIMB_T_MAX >> 1))
+
+#if __GMP_MP_SIZE_T_INT
+#define MP_SIZE_T_MAX      INT_MAX
+#define MP_SIZE_T_MIN      INT_MIN
+#else
+#define MP_SIZE_T_MAX      LONG_MAX
+#define MP_SIZE_T_MIN      LONG_MIN
+#endif
+
+/* mp_exp_t is the same as mp_size_t */
+#define MP_EXP_T_MAX   MP_SIZE_T_MAX
+#define MP_EXP_T_MIN   MP_SIZE_T_MIN
+
+#define LONG_HIGHBIT       LONG_MIN
+#define INT_HIGHBIT        INT_MIN
+#define SHRT_HIGHBIT       SHRT_MIN
+
+
+#define GMP_NUMB_HIGHBIT  (CNST_LIMB(1) << (GMP_NUMB_BITS-1))
+
+#if GMP_NAIL_BITS == 0
+#define GMP_NAIL_LOWBIT   CNST_LIMB(0)
+#else
+#define GMP_NAIL_LOWBIT   (CNST_LIMB(1) << GMP_NUMB_BITS)
+#endif
+
+#if GMP_NAIL_BITS != 0
+/* Set various *_THRESHOLD values to be used for nails.  Thus we avoid using
+   code that has not yet been qualified.  */
+
+#undef  DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD              50
+
+#undef DIVREM_1_NORM_THRESHOLD
+#undef DIVREM_1_UNNORM_THRESHOLD
+#undef MOD_1_NORM_THRESHOLD
+#undef MOD_1_UNNORM_THRESHOLD
+#undef USE_PREINV_DIVREM_1
+#undef DIVREM_2_THRESHOLD
+#undef DIVEXACT_1_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD           MP_SIZE_T_MAX  /* no preinv */
+#define DIVREM_1_UNNORM_THRESHOLD         MP_SIZE_T_MAX  /* no preinv */
+#define MOD_1_NORM_THRESHOLD              MP_SIZE_T_MAX  /* no preinv */
+#define MOD_1_UNNORM_THRESHOLD            MP_SIZE_T_MAX  /* no preinv */
+#define USE_PREINV_DIVREM_1               0  /* no preinv */
+#define DIVREM_2_THRESHOLD                MP_SIZE_T_MAX  /* no preinv */
+
+/* mpn/generic/mul_fft.c is not nails-capable. */
+#undef  MUL_FFT_THRESHOLD
+#undef  SQR_FFT_THRESHOLD
+#define MUL_FFT_THRESHOLD                MP_SIZE_T_MAX
+#define SQR_FFT_THRESHOLD                MP_SIZE_T_MAX
+#endif
+
+/* Swap macros. */
+
+#define MP_LIMB_T_SWAP(x, y)						\
+  do {									\
+    mp_limb_t __mp_limb_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_limb_t_swap__tmp;					\
+  } while (0)
+#define MP_SIZE_T_SWAP(x, y)						\
+  do {									\
+    mp_size_t __mp_size_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_size_t_swap__tmp;					\
+  } while (0)
+
+#define MP_PTR_SWAP(x, y)						\
+  do {									\
+    mp_ptr __mp_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mp_ptr_swap__tmp;						\
+  } while (0)
+#define MP_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mp_srcptr __mp_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_srcptr_swap__tmp;					\
+  } while (0)
+
+#define MPN_PTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_PTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+#define MPN_SRCPTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_SRCPTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+
+#define MPZ_PTR_SWAP(x, y)						\
+  do {									\
+    mpz_ptr __mpz_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mpz_ptr_swap__tmp;						\
+  } while (0)
+#define MPZ_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mpz_srcptr __mpz_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mpz_srcptr_swap__tmp;					\
+  } while (0)
+
+#define MPQ_PTR_SWAP(x, y)						\
+  do {                                                                  \
+    mpq_ptr __mpq_ptr_swap__tmp = (x);					\
+    (x) = (y);                                                          \
+    (y) = __mpq_ptr_swap__tmp;						\
+  } while (0)
+#define MPQ_SRCPTR_SWAP(x, y)                                           \
+  do {                                                                  \
+    mpq_srcptr __mpq_srcptr_swap__tmp = (x);                            \
+    (x) = (y);                                                          \
+    (y) = __mpq_srcptr_swap__tmp;                                       \
+  } while (0)
+
+
+/* Enhancement: __gmp_allocate_func could have "__attribute__ ((malloc))",
+   but current gcc (3.0) doesn't seem to support that.  */
+__GMP_DECLSPEC extern void * (*__gmp_allocate_func) (size_t);
+__GMP_DECLSPEC extern void * (*__gmp_reallocate_func) (void *, size_t, size_t);
+__GMP_DECLSPEC extern void   (*__gmp_free_func) (void *, size_t);
+
+__GMP_DECLSPEC void *__gmp_default_allocate (size_t);
+__GMP_DECLSPEC void *__gmp_default_reallocate (void *, size_t, size_t);
+__GMP_DECLSPEC void __gmp_default_free (void *, size_t);
+
+#define __GMP_ALLOCATE_FUNC_TYPE(n,type) \
+  ((type *) (*__gmp_allocate_func) ((n) * sizeof (type)))
+#define __GMP_ALLOCATE_FUNC_LIMBS(n)   __GMP_ALLOCATE_FUNC_TYPE (n, mp_limb_t)
+
+#define __GMP_REALLOCATE_FUNC_TYPE(p, old_size, new_size, type)		\
+  ((type *) (*__gmp_reallocate_func)					\
+   (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
+#define __GMP_REALLOCATE_FUNC_LIMBS(p, old_size, new_size)		\
+  __GMP_REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
+
+#define __GMP_FREE_FUNC_TYPE(p,n,type) (*__gmp_free_func) (p, (n) * sizeof (type))
+#define __GMP_FREE_FUNC_LIMBS(p,n)     __GMP_FREE_FUNC_TYPE (p, n, mp_limb_t)
+
+#define __GMP_REALLOCATE_FUNC_MAYBE(ptr, oldsize, newsize)		\
+  do {									\
+    if ((oldsize) != (newsize))						\
+      (ptr) = (*__gmp_reallocate_func) (ptr, oldsize, newsize);		\
+  } while (0)
+
+#define __GMP_REALLOCATE_FUNC_MAYBE_TYPE(ptr, oldsize, newsize, type)	\
+  do {									\
+    if ((oldsize) != (newsize))						\
+      (ptr) = (type *) (*__gmp_reallocate_func)				\
+	(ptr, (oldsize) * sizeof (type), (newsize) * sizeof (type));	\
+  } while (0)
+
+
+/* Dummy for non-gcc, code involving it will go dead. */
+#if ! defined (__GNUC__) || __GNUC__ < 2
+#define __builtin_constant_p(x)   0
+#endif
+
+
+/* In gcc 2.96 and up on i386, tail calls are optimized to jumps if the
+   stack usage is compatible.  __attribute__ ((regparm (N))) helps by
+   putting leading parameters in registers, avoiding extra stack.
+
+   regparm cannot be used with calls going through the PLT, because the
+   binding code there may clobber the registers (%eax, %edx, %ecx) used for
+   the regparm parameters.  Calls to local (ie. static) functions could
+   still use this, if we cared to differentiate locals and globals.
+
+   On athlon-unknown-freebsd4.9 with gcc 3.3.3, regparm cannot be used with
+   -p or -pg profiling, since that version of gcc doesn't realize the
+   .mcount calls will clobber the parameter registers.  Other systems are
+   ok, like debian with glibc 2.3.2 (mcount doesn't clobber), but we don't
+   bother to try to detect this.  regparm is only an optimization so we just
+   disable it when profiling (profiling being a slowdown anyway).  */
+
+#if HAVE_HOST_CPU_FAMILY_x86 && __GMP_GNUC_PREREQ (2,96) && ! defined (PIC) \
+  && ! WANT_PROFILING_PROF && ! WANT_PROFILING_GPROF
+#define USE_LEADING_REGPARM 1
+#else
+#define USE_LEADING_REGPARM 0
+#endif
+
+/* Macros for altering parameter order according to regparm usage. */
+#if USE_LEADING_REGPARM
+#define REGPARM_2_1(a,b,x)    x,a,b
+#define REGPARM_3_1(a,b,c,x)  x,a,b,c
+#define REGPARM_ATTR(n) __attribute__ ((regparm (n)))
+#else
+#define REGPARM_2_1(a,b,x)    a,b,x
+#define REGPARM_3_1(a,b,c,x)  a,b,c,x
+#define REGPARM_ATTR(n)
+#endif
+
+
+/* ASM_L gives a local label for a gcc asm block, for use when temporary
+   local labels like "1:" might not be available, which is the case for
+   instance on the x86s (the SCO assembler doesn't support them).
+
+   The label generated is made unique by including "%=" which is a unique
+   number for each insn.  This ensures the same name can be used in multiple
+   asm blocks, perhaps via a macro.  Since jumps between asm blocks are not
+   allowed there's no need for a label to be usable outside a single
+   block.  */
+
+#define ASM_L(name)  LSYM_PREFIX "asm_%=_" #name
+
+
+#if defined (__GNUC__) && HAVE_HOST_CPU_FAMILY_x86
+#if 0
+/* FIXME: Check that these actually improve things.
+   FIXME: Need a cld after each std.
+   FIXME: Can't have inputs in clobbered registers, must describe them as
+   dummy outputs, and add volatile. */
+#define MPN_COPY_INCR(DST, SRC, N)					\
+  __asm__ ("cld\n\trep\n\tmovsl" : :					\
+	   "D" (DST), "S" (SRC), "c" (N) :				\
+	   "cx", "di", "si", "memory")
+#define MPN_COPY_DECR(DST, SRC, N)					\
+  __asm__ ("std\n\trep\n\tmovsl" : :					\
+	   "D" ((DST) + (N) - 1), "S" ((SRC) + (N) - 1), "c" (N) :	\
+	   "cx", "di", "si", "memory")
+#endif
+#endif
+
+
+__GMP_DECLSPEC void __gmpz_aorsmul_1 (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_limb_t, mp_size_t)) REGPARM_ATTR(1);
+#define mpz_aorsmul_1(w,u,v,sub)  __gmpz_aorsmul_1 (REGPARM_3_1 (w, u, v, sub))
+
+#define mpz_n_pow_ui __gmpz_n_pow_ui
+__GMP_DECLSPEC void    mpz_n_pow_ui (mpz_ptr, mp_srcptr, mp_size_t, unsigned long);
+
+
+#define mpn_addmul_1c __MPN(addmul_1c)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#ifndef mpn_addmul_2  /* if not done with cpuvec in a fat binary */
+#define mpn_addmul_2 __MPN(addmul_2)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+#endif
+
+#define mpn_addmul_3 __MPN(addmul_3)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_4 __MPN(addmul_4)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_5 __MPN(addmul_5)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_6 __MPN(addmul_6)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_7 __MPN(addmul_7)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_7 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_8 __MPN(addmul_8)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_8 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+/* Alternative entry point in mpn_addmul_2 for the benefit of mpn_sqr_basecase.  */
+#define mpn_addmul_2s __MPN(addmul_2s)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_2s (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+/* Override mpn_addlsh1_n, mpn_addlsh2_n, mpn_sublsh1_n, etc with mpn_addlsh_n,
+   etc when !HAVE_NATIVE the former but HAVE_NATIVE_ the latter.  Similarly,
+   override foo_ip1 functions with foo.  We then lie and say these macros
+   represent native functions, but leave a trace by using the value 2 rather
+   than 1.  */
+
+#if HAVE_NATIVE_mpn_addlsh_n && ! HAVE_NATIVE_mpn_addlsh1_n
+#define mpn_addlsh1_n(a,b,c,d)          mpn_addlsh_n(a,b,c,d,1)
+#define HAVE_NATIVE_mpn_addlsh1_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_nc && ! HAVE_NATIVE_mpn_addlsh1_nc
+#define mpn_addlsh1_nc(a,b,c,d,x)       mpn_addlsh_nc(a,b,c,d,1,x)
+#define HAVE_NATIVE_mpn_addlsh1_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_n && ! HAVE_NATIVE_mpn_addlsh1_n_ip1
+#define mpn_addlsh1_n_ip1(a,b,n)        mpn_addlsh1_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_addlsh1_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_nc && ! HAVE_NATIVE_mpn_addlsh1_nc_ip1
+#define mpn_addlsh1_nc_ip1(a,b,n,c)     mpn_addlsh1_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_addlsh1_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_n && ! HAVE_NATIVE_mpn_addlsh2_n
+#define mpn_addlsh2_n(a,b,c,d)          mpn_addlsh_n(a,b,c,d,2)
+#define HAVE_NATIVE_mpn_addlsh2_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_nc && ! HAVE_NATIVE_mpn_addlsh2_nc
+#define mpn_addlsh2_nc(a,b,c,d,x)       mpn_addlsh_nc(a,b,c,d,2,x)
+#define HAVE_NATIVE_mpn_addlsh2_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh2_n && ! HAVE_NATIVE_mpn_addlsh2_n_ip1
+#define mpn_addlsh2_n_ip1(a,b,n)        mpn_addlsh2_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_addlsh2_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh2_nc && ! HAVE_NATIVE_mpn_addlsh2_nc_ip1
+#define mpn_addlsh2_nc_ip1(a,b,n,c)     mpn_addlsh2_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_addlsh2_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_n && ! HAVE_NATIVE_mpn_sublsh1_n
+#define mpn_sublsh1_n(a,b,c,d)          mpn_sublsh_n(a,b,c,d,1)
+#define HAVE_NATIVE_mpn_sublsh1_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_nc && ! HAVE_NATIVE_mpn_sublsh1_nc
+#define mpn_sublsh1_nc(a,b,c,d,x)       mpn_sublsh_nc(a,b,c,d,1,x)
+#define HAVE_NATIVE_mpn_sublsh1_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh1_n && ! HAVE_NATIVE_mpn_sublsh1_n_ip1
+#define mpn_sublsh1_n_ip1(a,b,n)        mpn_sublsh1_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_sublsh1_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh1_nc && ! HAVE_NATIVE_mpn_sublsh1_nc_ip1
+#define mpn_sublsh1_nc_ip1(a,b,n,c)     mpn_sublsh1_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_sublsh1_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_n && ! HAVE_NATIVE_mpn_sublsh2_n
+#define mpn_sublsh2_n(a,b,c,d)          mpn_sublsh_n(a,b,c,d,2)
+#define HAVE_NATIVE_mpn_sublsh2_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_nc && ! HAVE_NATIVE_mpn_sublsh2_nc
+#define mpn_sublsh2_nc(a,b,c,d,x)       mpn_sublsh_nc(a,b,c,d,2,x)
+#define HAVE_NATIVE_mpn_sublsh2_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh2_n && ! HAVE_NATIVE_mpn_sublsh2_n_ip1
+#define mpn_sublsh2_n_ip1(a,b,n)        mpn_sublsh2_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_sublsh2_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh2_nc && ! HAVE_NATIVE_mpn_sublsh2_nc_ip1
+#define mpn_sublsh2_nc_ip1(a,b,n,c)     mpn_sublsh2_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_sublsh2_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_n && ! HAVE_NATIVE_mpn_rsblsh1_n
+#define mpn_rsblsh1_n(a,b,c,d)          mpn_rsblsh_n(a,b,c,d,1)
+#define HAVE_NATIVE_mpn_rsblsh1_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_nc && ! HAVE_NATIVE_mpn_rsblsh1_nc
+#define mpn_rsblsh1_nc(a,b,c,d,x)       mpn_rsblsh_nc(a,b,c,d,1,x)
+#define HAVE_NATIVE_mpn_rsblsh1_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh1_n && ! HAVE_NATIVE_mpn_rsblsh1_n_ip1
+#define mpn_rsblsh1_n_ip1(a,b,n)        mpn_rsblsh1_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_rsblsh1_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh1_nc && ! HAVE_NATIVE_mpn_rsblsh1_nc_ip1
+#define mpn_rsblsh1_nc_ip1(a,b,n,c)     mpn_rsblsh1_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_rsblsh1_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_n && ! HAVE_NATIVE_mpn_rsblsh2_n
+#define mpn_rsblsh2_n(a,b,c,d)          mpn_rsblsh_n(a,b,c,d,2)
+#define HAVE_NATIVE_mpn_rsblsh2_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_nc && ! HAVE_NATIVE_mpn_rsblsh2_nc
+#define mpn_rsblsh2_nc(a,b,c,d,x)       mpn_rsblsh_nc(a,b,c,d,2,x)
+#define HAVE_NATIVE_mpn_rsblsh2_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh2_n && ! HAVE_NATIVE_mpn_rsblsh2_n_ip1
+#define mpn_rsblsh2_n_ip1(a,b,n)        mpn_rsblsh2_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_rsblsh2_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh2_nc && ! HAVE_NATIVE_mpn_rsblsh2_nc_ip1
+#define mpn_rsblsh2_nc_ip1(a,b,n,c)     mpn_rsblsh2_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_rsblsh2_nc_ip1  2
+#endif
+
+
+#ifndef mpn_addlsh1_n
+#define mpn_addlsh1_n __MPN(addlsh1_n)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh1_nc
+#define mpn_addlsh1_nc __MPN(addlsh1_nc)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_addlsh1_n_ip1
+#define mpn_addlsh1_n_ip1 __MPN(addlsh1_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh1_nc_ip1
+#define mpn_addlsh1_nc_ip1 __MPN(addlsh1_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_addlsh2_n
+#define mpn_addlsh2_n __MPN(addlsh2_n)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh2_nc
+#define mpn_addlsh2_nc __MPN(addlsh2_nc)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_addlsh2_n_ip1
+#define mpn_addlsh2_n_ip1 __MPN(addlsh2_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh2_nc_ip1
+#define mpn_addlsh2_nc_ip1 __MPN(addlsh2_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_addlsh_n
+#define mpn_addlsh_n __MPN(addlsh_n)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_addlsh_nc
+#define mpn_addlsh_nc __MPN(addlsh_nc)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+#ifndef mpn_addlsh_n_ip1
+#define mpn_addlsh_n_ip1 __MPN(addlsh_n_ip1)
+  __GMP_DECLSPEC mp_limb_t mpn_addlsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_addlsh_nc_ip1
+#define mpn_addlsh_nc_ip1 __MPN(addlsh_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+
+#ifndef mpn_sublsh1_n
+#define mpn_sublsh1_n __MPN(sublsh1_n)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh1_nc
+#define mpn_sublsh1_nc __MPN(sublsh1_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_sublsh1_n_ip1
+#define mpn_sublsh1_n_ip1 __MPN(sublsh1_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh1_nc_ip1
+#define mpn_sublsh1_nc_ip1 __MPN(sublsh1_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_sublsh2_n
+#define mpn_sublsh2_n __MPN(sublsh2_n)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh2_nc
+#define mpn_sublsh2_nc __MPN(sublsh2_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_sublsh2_n_ip1
+#define mpn_sublsh2_n_ip1 __MPN(sublsh2_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh2_nc_ip1
+#define mpn_sublsh2_nc_ip1 __MPN(sublsh2_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_sublsh_n
+#define mpn_sublsh_n __MPN(sublsh_n)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_sublsh_nc
+#define mpn_sublsh_nc __MPN(sublsh_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+#ifndef mpn_sublsh_n_ip1
+#define mpn_sublsh_n_ip1 __MPN(sublsh_n_ip1)
+  __GMP_DECLSPEC mp_limb_t mpn_sublsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_sublsh_nc_ip1
+#define mpn_sublsh_nc_ip1 __MPN(sublsh_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+
+#define mpn_rsblsh1_n __MPN(rsblsh1_n)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsblsh1_nc __MPN(rsblsh1_nc)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_rsblsh2_n __MPN(rsblsh2_n)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsblsh2_nc __MPN(rsblsh2_nc)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_rsblsh_n __MPN(rsblsh_n)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+#define mpn_rsblsh_nc __MPN(rsblsh_nc)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+
+#define mpn_rsh1add_n __MPN(rsh1add_n)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsh1add_nc __MPN(rsh1add_nc)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1add_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_rsh1sub_n __MPN(rsh1sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsh1sub_nc __MPN(rsh1sub_nc)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1sub_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#ifndef mpn_lshiftc  /* if not done with cpuvec in a fat binary */
+#define mpn_lshiftc __MPN(lshiftc)
+__GMP_DECLSPEC mp_limb_t mpn_lshiftc (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+
+#define mpn_add_err1_n  __MPN(add_err1_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_add_err2_n  __MPN(add_err2_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_add_err3_n  __MPN(add_err3_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_sub_err1_n  __MPN(sub_err1_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_sub_err2_n  __MPN(sub_err2_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_sub_err3_n  __MPN(sub_err3_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_add_n_sub_n __MPN(add_n_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n_sub_n (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_add_n_sub_nc __MPN(add_n_sub_nc)
+__GMP_DECLSPEC mp_limb_t mpn_add_n_sub_nc (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_addaddmul_1msb0 __MPN(addaddmul_1msb0)
+__GMP_DECLSPEC mp_limb_t mpn_addaddmul_1msb0 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#define mpn_divrem_1c __MPN(divrem_1c)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1c (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#define mpn_dump __MPN(dump)
+__GMP_DECLSPEC void mpn_dump (mp_srcptr, mp_size_t);
+
+#define mpn_fib2_ui __MPN(fib2_ui)
+__GMP_DECLSPEC mp_size_t mpn_fib2_ui (mp_ptr, mp_ptr, unsigned long);
+
+#define mpn_fib2m __MPN(fib2m)
+__GMP_DECLSPEC int mpn_fib2m (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_strongfibo __MPN(strongfibo)
+__GMP_DECLSPEC int mpn_strongfibo (mp_srcptr, mp_size_t, mp_ptr);
+
+/* Remap names of internal mpn functions.  */
+#define __clz_tab               __MPN(clz_tab)
+#define mpn_udiv_w_sdiv		__MPN(udiv_w_sdiv)
+
+#define mpn_jacobi_base __MPN(jacobi_base)
+__GMP_DECLSPEC int mpn_jacobi_base (mp_limb_t, mp_limb_t, int) ATTRIBUTE_CONST;
+
+#define mpn_jacobi_2 __MPN(jacobi_2)
+__GMP_DECLSPEC int mpn_jacobi_2 (mp_srcptr, mp_srcptr, unsigned);
+
+#define mpn_jacobi_n __MPN(jacobi_n)
+__GMP_DECLSPEC int mpn_jacobi_n (mp_ptr, mp_ptr, mp_size_t, unsigned);
+
+#define mpn_mod_1c __MPN(mod_1c)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1c (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul_1c __MPN(mul_1c)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#define mpn_mul_2 __MPN(mul_2)
+__GMP_DECLSPEC mp_limb_t mpn_mul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_3 __MPN(mul_3)
+__GMP_DECLSPEC mp_limb_t mpn_mul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_4 __MPN(mul_4)
+__GMP_DECLSPEC mp_limb_t mpn_mul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_5 __MPN(mul_5)
+__GMP_DECLSPEC mp_limb_t mpn_mul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_6 __MPN(mul_6)
+__GMP_DECLSPEC mp_limb_t mpn_mul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#ifndef mpn_mul_basecase  /* if not done with cpuvec in a fat binary */
+#define mpn_mul_basecase __MPN(mul_basecase)
+__GMP_DECLSPEC void mpn_mul_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_mullo_n __MPN(mullo_n)
+__GMP_DECLSPEC void mpn_mullo_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#ifndef mpn_mullo_basecase  /* if not done with cpuvec in a fat binary */
+#define mpn_mullo_basecase __MPN(mullo_basecase)
+__GMP_DECLSPEC void mpn_mullo_basecase (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+
+#ifndef mpn_sqr_basecase  /* if not done with cpuvec in a fat binary */
+#define mpn_sqr_basecase __MPN(sqr_basecase)
+__GMP_DECLSPEC void mpn_sqr_basecase (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sqrlo __MPN(sqrlo)
+__GMP_DECLSPEC void mpn_sqrlo (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqrlo_basecase __MPN(sqrlo_basecase)
+__GMP_DECLSPEC void mpn_sqrlo_basecase (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_mulmid_basecase __MPN(mulmid_basecase)
+__GMP_DECLSPEC void mpn_mulmid_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mulmid_n __MPN(mulmid_n)
+__GMP_DECLSPEC void mpn_mulmid_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_mulmid __MPN(mulmid)
+__GMP_DECLSPEC void mpn_mulmid (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1c __MPN(submul_1c)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#ifndef mpn_redc_1  /* if not done with cpuvec in a fat binary */
+#define mpn_redc_1 __MPN(redc_1)
+__GMP_DECLSPEC mp_limb_t mpn_redc_1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_redc_2  /* if not done with cpuvec in a fat binary */
+#define mpn_redc_2 __MPN(redc_2)
+__GMP_DECLSPEC mp_limb_t mpn_redc_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+#endif
+
+#define mpn_redc_n __MPN(redc_n)
+__GMP_DECLSPEC void mpn_redc_n (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+
+#ifndef mpn_mod_1_1p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1_1p_cps __MPN(mod_1_1p_cps)
+__GMP_DECLSPEC void mpn_mod_1_1p_cps (mp_limb_t [4], mp_limb_t);
+#endif
+#ifndef mpn_mod_1_1p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1_1p __MPN(mod_1_1p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1_1p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [4]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#ifndef mpn_mod_1s_2p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_2p_cps __MPN(mod_1s_2p_cps)
+__GMP_DECLSPEC void mpn_mod_1s_2p_cps (mp_limb_t [5], mp_limb_t);
+#endif
+#ifndef mpn_mod_1s_2p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_2p __MPN(mod_1s_2p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1s_2p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [5]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#ifndef mpn_mod_1s_3p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_3p_cps __MPN(mod_1s_3p_cps)
+__GMP_DECLSPEC void mpn_mod_1s_3p_cps (mp_limb_t [6], mp_limb_t);
+#endif
+#ifndef mpn_mod_1s_3p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_3p __MPN(mod_1s_3p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1s_3p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [6]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#ifndef mpn_mod_1s_4p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_4p_cps __MPN(mod_1s_4p_cps)
+__GMP_DECLSPEC void mpn_mod_1s_4p_cps (mp_limb_t [7], mp_limb_t);
+#endif
+#ifndef mpn_mod_1s_4p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_4p __MPN(mod_1s_4p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1s_4p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [7]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_bc_mulmod_bnm1 __MPN(bc_mulmod_bnm1)
+__GMP_DECLSPEC void mpn_bc_mulmod_bnm1 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_mulmod_bnm1 __MPN(mulmod_bnm1)
+__GMP_DECLSPEC void mpn_mulmod_bnm1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_mulmod_bnm1_next_size __MPN(mulmod_bnm1_next_size)
+__GMP_DECLSPEC mp_size_t mpn_mulmod_bnm1_next_size (mp_size_t) ATTRIBUTE_CONST;
+static inline mp_size_t
+mpn_mulmod_bnm1_itch (mp_size_t rn, mp_size_t an, mp_size_t bn) {
+  mp_size_t n, itch;
+  n = rn >> 1;
+  itch = rn + 4 +
+    (an > n ? (bn > n ? rn : n) : 0);
+  return itch;
+}
+
+#ifndef MOD_BKNP1_USE11
+#define MOD_BKNP1_USE11 ((GMP_NUMB_BITS % 8 != 0) && (GMP_NUMB_BITS % 2 == 0))
+#endif
+#ifndef MOD_BKNP1_ONLY3
+#define MOD_BKNP1_ONLY3 0
+#endif
+#define mpn_mulmod_bknp1 __MPN(mulmod_bknp1)
+__GMP_DECLSPEC void mpn_mulmod_bknp1 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned, mp_ptr);
+static inline mp_size_t
+mpn_mulmod_bknp1_itch (mp_size_t rn) {
+  return rn << 2;
+}
+#if MOD_BKNP1_ONLY3
+#define MPN_MULMOD_BKNP1_USABLE(rn, k, mn)				\
+  ((GMP_NUMB_BITS % 8 == 0) && ((mn) >= 18) && ((rn) > 16) &&		\
+   (((rn) % ((k) = 3) == 0)))
+#else
+#define MPN_MULMOD_BKNP1_USABLE(rn, k, mn)				\
+  (((GMP_NUMB_BITS % 8 == 0) && ((mn) >= 18) && ((rn) > 16) &&		\
+    (((rn) % ((k) = 3) == 0) ||						\
+     (((GMP_NUMB_BITS % 16 != 0) || (((mn) >= 35) && ((rn) >= 32))) &&	\
+      (((GMP_NUMB_BITS % 16 == 0) && ((rn) % ((k) = 5) == 0)) ||	\
+       (((mn) >= 49) &&							\
+	(((rn) % ((k) = 7) == 0) ||					\
+	 ((GMP_NUMB_BITS % 16 == 0) && ((mn) >= 104) && ((rn) >= 64) &&	\
+	  ((MOD_BKNP1_USE11 && ((rn) % ((k) = 11) == 0)) ||		\
+	   ((rn) % ((k) = 13) == 0) ||					\
+	   ((GMP_NUMB_BITS % 32 == 0) && ((mn) >= 136) && ((rn) >= 128) && \
+	    ((rn) % ((k) = 17) == 0)					\
+	    ))))))))) ||						\
+  ((GMP_NUMB_BITS % 16 != 0) && MOD_BKNP1_USE11 &&			\
+   ((mn) >= 104) && ((rn) >= 64) && ((rn) % ((k) = 11) == 0)) )
+#endif
+
+#define mpn_sqrmod_bknp1 __MPN(sqrmod_bknp1)
+__GMP_DECLSPEC void mpn_sqrmod_bknp1 (mp_ptr, mp_srcptr, mp_size_t, unsigned, mp_ptr);
+static inline mp_size_t
+mpn_sqrmod_bknp1_itch (mp_size_t rn) {
+  return rn * 3;
+}
+#if MOD_BKNP1_ONLY3
+#define MPN_SQRMOD_BKNP1_USABLE(rn, k, mn)				\
+  MPN_MULMOD_BKNP1_USABLE(rn, k, mn)
+#else
+#define MPN_SQRMOD_BKNP1_USABLE(rn, k, mn)				\
+  (((GMP_NUMB_BITS % 8 == 0) && ((mn) >= 27) && ((rn) > 24) &&		\
+    (((rn) % ((k) = 3) == 0) ||						\
+     (((GMP_NUMB_BITS % 16 != 0) || (((mn) >= 55) && ((rn) > 50))) &&	\
+      (((GMP_NUMB_BITS % 16 == 0) && ((rn) % ((k) = 5) == 0)) ||	\
+       (((mn) >= 56) &&							\
+	(((rn) % ((k) = 7) == 0) ||					\
+	 ((GMP_NUMB_BITS % 16 == 0) && ((mn) >= 143) && ((rn) >= 128) && \
+	  ((MOD_BKNP1_USE11 && ((rn) % ((k) = 11) == 0)) ||		\
+	   ((rn) % ((k) = 13) == 0) ||					\
+	   ((GMP_NUMB_BITS % 32 == 0) && ((mn) >= 272) && ((rn) >= 256) && \
+	    ((rn) % ((k) = 17) == 0)					\
+	    ))))))))) ||						\
+   ((GMP_NUMB_BITS % 16 != 0) && MOD_BKNP1_USE11 &&			\
+    ((mn) >= 143) && ((rn) >= 128) && ((rn) % ((k) = 11) == 0)) )
+#endif
+
+
+#define mpn_sqrmod_bnm1 __MPN(sqrmod_bnm1)
+__GMP_DECLSPEC void mpn_sqrmod_bnm1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sqrmod_bnm1_next_size __MPN(sqrmod_bnm1_next_size)
+__GMP_DECLSPEC mp_size_t mpn_sqrmod_bnm1_next_size (mp_size_t) ATTRIBUTE_CONST;
+static inline mp_size_t
+mpn_sqrmod_bnm1_itch (mp_size_t rn, mp_size_t an) {
+  mp_size_t n, itch;
+  n = rn >> 1;
+  itch = rn + 3 +
+    (an > n ? an : 0);
+  return itch;
+}
+
+/* Pseudo-random number generator function pointers structure.  */
+typedef struct {
+  void (*randseed_fn) (gmp_randstate_ptr, mpz_srcptr);
+  void (*randget_fn) (gmp_randstate_ptr, mp_ptr, unsigned long int);
+  void (*randclear_fn) (gmp_randstate_ptr);
+  void (*randiset_fn) (gmp_randstate_ptr, gmp_randstate_srcptr);
+} gmp_randfnptr_t;
+
+/* Macro to obtain a void pointer to the function pointers structure.  */
+#define RNG_FNPTR(rstate) ((rstate)->_mp_algdata._mp_lc)
+
+/* Macro to obtain a pointer to the generator's state.
+   When used as a lvalue the rvalue needs to be cast to mp_ptr.  */
+#define RNG_STATE(rstate) ((rstate)->_mp_seed->_mp_d)
+
+/* Write a given number of random bits to rp.  */
+#define _gmp_rand(rp, state, bits)					\
+  do {									\
+    gmp_randstate_ptr  __rstate = (state);				\
+    (*((gmp_randfnptr_t *) RNG_FNPTR (__rstate))->randget_fn)		\
+      (__rstate, rp, bits);						\
+  } while (0)
+
+__GMP_DECLSPEC void __gmp_randinit_mt_noseed (gmp_randstate_ptr);
+
+
+/* __gmp_rands is the global state for the old-style random functions, and
+   is also used in the test programs (hence the __GMP_DECLSPEC).
+
+   There's no seeding here, so mpz_random etc will generate the same
+   sequence every time.  This is not unlike the C library random functions
+   if you don't seed them, so perhaps it's acceptable.  Digging up a seed
+   from /dev/random or the like would work on many systems, but might
+   encourage a false confidence, since it'd be pretty much impossible to do
+   something that would work reliably everywhere.  In any case the new style
+   functions are recommended to applications which care about randomness, so
+   the old functions aren't too important.  */
+
+__GMP_DECLSPEC extern char             __gmp_rands_initialized;
+__GMP_DECLSPEC extern gmp_randstate_t  __gmp_rands;
+
+#define RANDS								\
+  ((__gmp_rands_initialized ? 0						\
+    : (__gmp_rands_initialized = 1,					\
+       __gmp_randinit_mt_noseed (__gmp_rands), 0)),			\
+   __gmp_rands)
+
+/* this is used by the test programs, to free memory */
+#define RANDS_CLEAR()							\
+  do {									\
+    if (__gmp_rands_initialized)					\
+      {									\
+	__gmp_rands_initialized = 0;					\
+	gmp_randclear (__gmp_rands);					\
+      }									\
+  } while (0)
+
+
+/* For a threshold between algorithms A and B, size>=thresh is where B
+   should be used.  Special value MP_SIZE_T_MAX means only ever use A, or
+   value 0 means only ever use B.  The tests for these special values will
+   be compile-time constants, so the compiler should be able to eliminate
+   the code for the unwanted algorithm.  */
+
+#if ! defined (__GNUC__) || __GNUC__ < 2
+#define ABOVE_THRESHOLD(size,thresh)					\
+  ((thresh) == 0							\
+   || ((thresh) != MP_SIZE_T_MAX					\
+       && (size) >= (thresh)))
+#else
+#define ABOVE_THRESHOLD(size,thresh)					\
+  ((__builtin_constant_p (thresh) && (thresh) == 0)			\
+   || (!(__builtin_constant_p (thresh) && (thresh) == MP_SIZE_T_MAX)	\
+       && (size) >= (thresh)))
+#endif
+#define BELOW_THRESHOLD(size,thresh)  (! ABOVE_THRESHOLD (size, thresh))
+
+/* The minimal supported value for Toom22 depends also on Toom32 and
+   Toom42 implementations. */
+#define MPN_TOOM22_MUL_MINSIZE    6
+#define MPN_TOOM2_SQR_MINSIZE     4
+
+#define MPN_TOOM33_MUL_MINSIZE   17
+#define MPN_TOOM3_SQR_MINSIZE    17
+
+#define MPN_TOOM44_MUL_MINSIZE   30
+#define MPN_TOOM4_SQR_MINSIZE    30
+
+#define MPN_TOOM6H_MUL_MINSIZE   46
+#define MPN_TOOM6_SQR_MINSIZE    46
+
+#define MPN_TOOM8H_MUL_MINSIZE   86
+#define MPN_TOOM8_SQR_MINSIZE    86
+
+#define MPN_TOOM32_MUL_MINSIZE   10
+#define MPN_TOOM42_MUL_MINSIZE   10
+#define MPN_TOOM43_MUL_MINSIZE   25
+#define MPN_TOOM53_MUL_MINSIZE   17
+#define MPN_TOOM54_MUL_MINSIZE   31
+#define MPN_TOOM63_MUL_MINSIZE   49
+
+#define MPN_TOOM42_MULMID_MINSIZE    4
+
+#define   mpn_sqr_diagonal __MPN(sqr_diagonal)
+__GMP_DECLSPEC void      mpn_sqr_diagonal (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr_diag_addlsh1 __MPN(sqr_diag_addlsh1)
+__GMP_DECLSPEC void      mpn_sqr_diag_addlsh1 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define   mpn_toom_interpolate_5pts __MPN(toom_interpolate_5pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_5pts (mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_size_t, int, mp_limb_t);
+
+enum toom6_flags {toom6_all_pos = 0, toom6_vm1_neg = 1, toom6_vm2_neg = 2};
+#define   mpn_toom_interpolate_6pts __MPN(toom_interpolate_6pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_6pts (mp_ptr, mp_size_t, enum toom6_flags, mp_ptr, mp_ptr, mp_ptr, mp_size_t);
+
+enum toom7_flags { toom7_w1_neg = 1, toom7_w3_neg = 2 };
+#define   mpn_toom_interpolate_7pts __MPN(toom_interpolate_7pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_7pts (mp_ptr, mp_size_t, enum toom7_flags, mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+#define mpn_toom_interpolate_8pts __MPN(toom_interpolate_8pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_8pts (mp_ptr, mp_size_t, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+#define mpn_toom_interpolate_12pts __MPN(toom_interpolate_12pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_12pts (mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_size_t, int, mp_ptr);
+
+#define mpn_toom_interpolate_16pts __MPN(toom_interpolate_16pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_16pts (mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_size_t, int, mp_ptr);
+
+#define   mpn_toom_couple_handling __MPN(toom_couple_handling)
+__GMP_DECLSPEC void mpn_toom_couple_handling (mp_ptr, mp_size_t, mp_ptr, int, mp_size_t, int, int);
+
+#define   mpn_toom_eval_dgr3_pm1 __MPN(toom_eval_dgr3_pm1)
+__GMP_DECLSPEC int mpn_toom_eval_dgr3_pm1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_dgr3_pm2 __MPN(toom_eval_dgr3_pm2)
+__GMP_DECLSPEC int mpn_toom_eval_dgr3_pm2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_pm1 __MPN(toom_eval_pm1)
+__GMP_DECLSPEC int mpn_toom_eval_pm1 (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_pm2 __MPN(toom_eval_pm2)
+__GMP_DECLSPEC int mpn_toom_eval_pm2 (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_pm2exp __MPN(toom_eval_pm2exp)
+__GMP_DECLSPEC int mpn_toom_eval_pm2exp (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, unsigned, mp_ptr);
+
+#define   mpn_toom_eval_pm2rexp __MPN(toom_eval_pm2rexp)
+__GMP_DECLSPEC int mpn_toom_eval_pm2rexp (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, unsigned, mp_ptr);
+
+#define   mpn_toom22_mul __MPN(toom22_mul)
+__GMP_DECLSPEC void      mpn_toom22_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom32_mul __MPN(toom32_mul)
+__GMP_DECLSPEC void      mpn_toom32_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom42_mul __MPN(toom42_mul)
+__GMP_DECLSPEC void      mpn_toom42_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom52_mul __MPN(toom52_mul)
+__GMP_DECLSPEC void      mpn_toom52_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom62_mul __MPN(toom62_mul)
+__GMP_DECLSPEC void      mpn_toom62_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom2_sqr __MPN(toom2_sqr)
+__GMP_DECLSPEC void      mpn_toom2_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom33_mul __MPN(toom33_mul)
+__GMP_DECLSPEC void      mpn_toom33_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom43_mul __MPN(toom43_mul)
+__GMP_DECLSPEC void      mpn_toom43_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom53_mul __MPN(toom53_mul)
+__GMP_DECLSPEC void      mpn_toom53_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom54_mul __MPN(toom54_mul)
+__GMP_DECLSPEC void      mpn_toom54_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom63_mul __MPN(toom63_mul)
+__GMP_DECLSPEC void      mpn_toom63_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom3_sqr __MPN(toom3_sqr)
+__GMP_DECLSPEC void      mpn_toom3_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom44_mul __MPN(toom44_mul)
+__GMP_DECLSPEC void      mpn_toom44_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom4_sqr __MPN(toom4_sqr)
+__GMP_DECLSPEC void      mpn_toom4_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom6h_mul __MPN(toom6h_mul)
+__GMP_DECLSPEC void      mpn_toom6h_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom6_sqr __MPN(toom6_sqr)
+__GMP_DECLSPEC void      mpn_toom6_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom8h_mul __MPN(toom8h_mul)
+__GMP_DECLSPEC void      mpn_toom8h_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom8_sqr __MPN(toom8_sqr)
+__GMP_DECLSPEC void      mpn_toom8_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom42_mulmid __MPN(toom42_mulmid)
+__GMP_DECLSPEC void      mpn_toom42_mulmid (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_fft_best_k __MPN(fft_best_k)
+__GMP_DECLSPEC int       mpn_fft_best_k (mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_mul_fft __MPN(mul_fft)
+__GMP_DECLSPEC mp_limb_t mpn_mul_fft (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, int);
+
+#define   mpn_mul_fft_full __MPN(mul_fft_full)
+__GMP_DECLSPEC void      mpn_mul_fft_full (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define   mpn_nussbaumer_mul __MPN(nussbaumer_mul)
+__GMP_DECLSPEC void      mpn_nussbaumer_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define   mpn_fft_next_size __MPN(fft_next_size)
+__GMP_DECLSPEC mp_size_t mpn_fft_next_size (mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_div_qr_1n_pi1 __MPN(div_qr_1n_pi1)
+  __GMP_DECLSPEC mp_limb_t mpn_div_qr_1n_pi1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#define   mpn_div_qr_2n_pi1 __MPN(div_qr_2n_pi1)
+  __GMP_DECLSPEC mp_limb_t mpn_div_qr_2n_pi1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#define   mpn_div_qr_2u_pi1 __MPN(div_qr_2u_pi1)
+  __GMP_DECLSPEC mp_limb_t mpn_div_qr_2u_pi1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int, mp_limb_t);
+
+#define   mpn_sbpi1_div_qr __MPN(sbpi1_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_div_q __MPN(sbpi1_div_q)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_div_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_divappr_q __MPN(sbpi1_divappr_q)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_divappr_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_dcpi1_div_qr __MPN(dcpi1_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, gmp_pi1_t *);
+#define   mpn_dcpi1_div_qr_n __MPN(dcpi1_div_qr_n)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_div_qr_n (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, gmp_pi1_t *, mp_ptr);
+
+#define   mpn_dcpi1_div_q __MPN(dcpi1_div_q)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_div_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, gmp_pi1_t *);
+
+#define   mpn_dcpi1_divappr_q __MPN(dcpi1_divappr_q)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_divappr_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, gmp_pi1_t *);
+
+#define   mpn_mu_div_qr __MPN(mu_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_mu_div_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_div_qr_itch __MPN(mu_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_div_qr_itch (mp_size_t, mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_preinv_mu_div_qr __MPN(preinv_mu_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mu_div_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_preinv_mu_div_qr_itch __MPN(preinv_mu_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_preinv_mu_div_qr_itch (mp_size_t, mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_mu_divappr_q __MPN(mu_divappr_q)
+__GMP_DECLSPEC mp_limb_t mpn_mu_divappr_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_divappr_q_itch __MPN(mu_divappr_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_divappr_q_itch (mp_size_t, mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_mu_div_q __MPN(mu_div_q)
+__GMP_DECLSPEC mp_limb_t mpn_mu_div_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_div_q_itch __MPN(mu_div_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_div_q_itch (mp_size_t, mp_size_t, int) ATTRIBUTE_CONST;
+
+#define  mpn_div_q __MPN(div_q)
+__GMP_DECLSPEC void mpn_div_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_invert __MPN(invert)
+__GMP_DECLSPEC void      mpn_invert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_invert_itch(n)  mpn_invertappr_itch(n)
+
+#define   mpn_ni_invertappr __MPN(ni_invertappr)
+__GMP_DECLSPEC mp_limb_t mpn_ni_invertappr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_invertappr __MPN(invertappr)
+__GMP_DECLSPEC mp_limb_t mpn_invertappr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_invertappr_itch(n)  (2 * (n))
+
+#define   mpn_binvert __MPN(binvert)
+__GMP_DECLSPEC void      mpn_binvert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_binvert_itch __MPN(binvert_itch)
+__GMP_DECLSPEC mp_size_t mpn_binvert_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_bdiv_q_1 __MPN(bdiv_q_1)
+__GMP_DECLSPEC mp_limb_t mpn_bdiv_q_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_pi1_bdiv_q_1 __MPN(pi1_bdiv_q_1)
+__GMP_DECLSPEC mp_limb_t mpn_pi1_bdiv_q_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int);
+
+#define   mpn_sbpi1_bdiv_qr __MPN(sbpi1_bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_bdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_bdiv_q __MPN(sbpi1_bdiv_q)
+__GMP_DECLSPEC void      mpn_sbpi1_bdiv_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_bdiv_r __MPN(sbpi1_bdiv_r)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_bdiv_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_dcpi1_bdiv_qr __MPN(dcpi1_bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_bdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+#define   mpn_dcpi1_bdiv_qr_n_itch __MPN(dcpi1_bdiv_qr_n_itch)
+__GMP_DECLSPEC mp_size_t mpn_dcpi1_bdiv_qr_n_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_dcpi1_bdiv_qr_n __MPN(dcpi1_bdiv_qr_n)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_bdiv_qr_n (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define   mpn_dcpi1_bdiv_q __MPN(dcpi1_bdiv_q)
+__GMP_DECLSPEC void      mpn_dcpi1_bdiv_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_mu_bdiv_qr __MPN(mu_bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_mu_bdiv_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_bdiv_qr_itch __MPN(mu_bdiv_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_bdiv_qr_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_mu_bdiv_q __MPN(mu_bdiv_q)
+__GMP_DECLSPEC void      mpn_mu_bdiv_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_bdiv_q_itch __MPN(mu_bdiv_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_bdiv_q_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_bdiv_qr __MPN(bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_bdiv_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_bdiv_qr_itch __MPN(bdiv_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_bdiv_qr_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_bdiv_q __MPN(bdiv_q)
+__GMP_DECLSPEC void      mpn_bdiv_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_bdiv_q_itch __MPN(bdiv_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_bdiv_q_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_divexact __MPN(divexact)
+__GMP_DECLSPEC void      mpn_divexact (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#define   mpn_divexact_itch __MPN(divexact_itch)
+__GMP_DECLSPEC mp_size_t mpn_divexact_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#ifndef mpn_bdiv_dbm1c  /* if not done with cpuvec in a fat binary */
+#define   mpn_bdiv_dbm1c __MPN(bdiv_dbm1c)
+__GMP_DECLSPEC mp_limb_t mpn_bdiv_dbm1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+#endif
+
+#define   mpn_bdiv_dbm1(dst, src, size, divisor) \
+  mpn_bdiv_dbm1c (dst, src, size, divisor, __GMP_CAST (mp_limb_t, 0))
+
+#define   mpn_powm __MPN(powm)
+__GMP_DECLSPEC void      mpn_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_powlo __MPN(powlo)
+__GMP_DECLSPEC void      mpn_powlo (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define mpn_sec_pi1_div_qr __MPN(sec_pi1_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_pi1_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_pi1_div_r __MPN(sec_pi1_div_r)
+__GMP_DECLSPEC void mpn_sec_pi1_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+
+#ifndef DIVEXACT_BY3_METHOD
+#if GMP_NUMB_BITS % 2 == 0 && ! defined (HAVE_NATIVE_mpn_divexact_by3c)
+#define DIVEXACT_BY3_METHOD 0	/* default to using mpn_bdiv_dbm1c */
+#else
+#define DIVEXACT_BY3_METHOD 1
+#endif
+#endif
+
+#if DIVEXACT_BY3_METHOD == 0
+#undef mpn_divexact_by3
+#define mpn_divexact_by3(dst,src,size) \
+  (3 & mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 3)))
+/* override mpn_divexact_by3c defined in gmp.h */
+/*
+#undef mpn_divexact_by3c
+#define mpn_divexact_by3c(dst,src,size,cy) \
+  (3 & mpn_bdiv_dbm1c (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 3, GMP_NUMB_MASK / 3 * cy)))
+*/
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+#define mpn_divexact_by5(dst,src,size) \
+  (7 & 3 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 5)))
+#endif
+
+#if GMP_NUMB_BITS % 3 == 0
+#define mpn_divexact_by7(dst,src,size) \
+  (7 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 7)))
+#endif
+
+#if GMP_NUMB_BITS % 6 == 0
+#define mpn_divexact_by9(dst,src,size) \
+  (15 & 7 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 9)))
+#endif
+
+#if GMP_NUMB_BITS % 10 == 0
+#define mpn_divexact_by11(dst,src,size) \
+  (15 & 5 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 11)))
+#endif
+
+#if GMP_NUMB_BITS % 12 == 0
+#define mpn_divexact_by13(dst,src,size) \
+  (15 & 3 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 13)))
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+#define mpn_divexact_by15(dst,src,size) \
+  (15 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 15)))
+#endif
+
+#if GMP_NUMB_BITS % 8 == 0
+#define mpn_divexact_by17(dst,src,size) \
+  (31 & 15 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 17)))
+#endif
+
+#define mpz_divexact_gcd  __gmpz_divexact_gcd
+__GMP_DECLSPEC void    mpz_divexact_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_prodlimbs  __gmpz_prodlimbs
+__GMP_DECLSPEC mp_size_t mpz_prodlimbs (mpz_ptr, mp_ptr, mp_size_t);
+
+#define mpz_oddfac_1  __gmpz_oddfac_1
+__GMP_DECLSPEC void mpz_oddfac_1 (mpz_ptr, mp_limb_t, unsigned);
+
+#define mpz_stronglucas  __gmpz_stronglucas
+__GMP_DECLSPEC int mpz_stronglucas (mpz_srcptr, mpz_ptr, mpz_ptr);
+
+#define mpz_lucas_mod  __gmpz_lucas_mod
+__GMP_DECLSPEC int mpz_lucas_mod (mpz_ptr, mpz_ptr, long, mp_bitcnt_t, mpz_srcptr, mpz_ptr, mpz_ptr);
+
+#define mpz_inp_str_nowhite __gmpz_inp_str_nowhite
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t  mpz_inp_str_nowhite (mpz_ptr, FILE *, int, int, size_t);
+#endif
+
+#define mpn_divisible_p __MPN(divisible_p)
+__GMP_DECLSPEC int     mpn_divisible_p (mp_srcptr, mp_size_t, mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define   mpn_rootrem __MPN(rootrem)
+__GMP_DECLSPEC mp_size_t mpn_rootrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_broot __MPN(broot)
+__GMP_DECLSPEC void mpn_broot (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_broot_invm1 __MPN(broot_invm1)
+__GMP_DECLSPEC void mpn_broot_invm1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_brootinv __MPN(brootinv)
+__GMP_DECLSPEC void mpn_brootinv (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+#define mpn_bsqrt __MPN(bsqrt)
+__GMP_DECLSPEC void mpn_bsqrt (mp_ptr, mp_srcptr, mp_bitcnt_t, mp_ptr);
+
+#define mpn_bsqrtinv __MPN(bsqrtinv)
+__GMP_DECLSPEC int mpn_bsqrtinv (mp_ptr, mp_srcptr, mp_bitcnt_t, mp_ptr);
+
+#if defined (_CRAY)
+#define MPN_COPY_INCR(dst, src, n)					\
+  do {									\
+    int __i;		/* Faster on some Crays with plain int */	\
+    _Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < (n); __i++)					\
+      (dst)[__i] = (src)[__i];						\
+  } while (0)
+#endif
+
+/* used by test programs, hence __GMP_DECLSPEC */
+#ifndef mpn_copyi  /* if not done with cpuvec in a fat binary */
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#if ! defined (MPN_COPY_INCR) && HAVE_NATIVE_mpn_copyi
+#define MPN_COPY_INCR(dst, src, size)					\
+  do {									\
+    ASSERT ((size) >= 0);						\
+    ASSERT (MPN_SAME_OR_INCR_P (dst, src, size));			\
+    mpn_copyi (dst, src, size);						\
+  } while (0)
+#endif
+
+/* Copy N limbs from SRC to DST incrementing, N==0 allowed.  */
+#if ! defined (MPN_COPY_INCR)
+#define MPN_COPY_INCR(dst, src, n)					\
+  do {									\
+    ASSERT ((n) >= 0);							\
+    ASSERT (MPN_SAME_OR_INCR_P (dst, src, n));				\
+    if ((n) != 0)							\
+      {									\
+	mp_size_t __n = (n) - 1;					\
+	mp_ptr __dst = (dst);						\
+	mp_srcptr __src = (src);					\
+	mp_limb_t __x;							\
+	__x = *__src++;							\
+	if (__n != 0)							\
+	  {								\
+	    do								\
+	      {								\
+		*__dst++ = __x;						\
+		__x = *__src++;						\
+	      }								\
+	    while (--__n);						\
+	  }								\
+	*__dst++ = __x;							\
+      }									\
+  } while (0)
+#endif
+
+
+#if defined (_CRAY)
+#define MPN_COPY_DECR(dst, src, n)					\
+  do {									\
+    int __i;		/* Faster on some Crays with plain int */	\
+    _Pragma ("_CRI ivdep");						\
+    for (__i = (n) - 1; __i >= 0; __i--)				\
+      (dst)[__i] = (src)[__i];						\
+  } while (0)
+#endif
+
+/* used by test programs, hence __GMP_DECLSPEC */
+#ifndef mpn_copyd  /* if not done with cpuvec in a fat binary */
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#if ! defined (MPN_COPY_DECR) && HAVE_NATIVE_mpn_copyd
+#define MPN_COPY_DECR(dst, src, size)					\
+  do {									\
+    ASSERT ((size) >= 0);						\
+    ASSERT (MPN_SAME_OR_DECR_P (dst, src, size));			\
+    mpn_copyd (dst, src, size);						\
+  } while (0)
+#endif
+
+/* Copy N limbs from SRC to DST decrementing, N==0 allowed.  */
+#if ! defined (MPN_COPY_DECR)
+#define MPN_COPY_DECR(dst, src, n)					\
+  do {									\
+    ASSERT ((n) >= 0);							\
+    ASSERT (MPN_SAME_OR_DECR_P (dst, src, n));				\
+    if ((n) != 0)							\
+      {									\
+	mp_size_t __n = (n) - 1;					\
+	mp_ptr __dst = (dst) + __n;					\
+	mp_srcptr __src = (src) + __n;					\
+	mp_limb_t __x;							\
+	__x = *__src--;							\
+	if (__n != 0)							\
+	  {								\
+	    do								\
+	      {								\
+		*__dst-- = __x;						\
+		__x = *__src--;						\
+	      }								\
+	    while (--__n);						\
+	  }								\
+	*__dst-- = __x;							\
+      }									\
+  } while (0)
+#endif
+
+
+#ifndef MPN_COPY
+#define MPN_COPY(d,s,n)							\
+  do {									\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (d, s, n));				\
+    MPN_COPY_INCR (d, s, n);						\
+  } while (0)
+#endif
+
+
+/* Set {dst,size} to the limbs of {src,size} in reverse order. */
+#define MPN_REVERSE(dst, src, size)					\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_size_t  __size = (size);						\
+    mp_srcptr  __src = (src) + __size - 1;				\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    ASSERT (! MPN_OVERLAP_P (dst, size, src, size));			\
+    CRAY_Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < __size; __i++)					\
+      {									\
+	*__dst = *__src;						\
+	__dst++;							\
+	__src--;							\
+      }									\
+  } while (0)
+
+
+/* Zero n limbs at dst.
+
+   For power and powerpc we want an inline stu/bdnz loop for zeroing.  On
+   ppc630 for instance this is optimal since it can sustain only 1 store per
+   cycle.
+
+   gcc 2.95.x (for powerpc64 -maix64, or powerpc32) doesn't recognise the
+   "for" loop in the generic code below can become stu/bdnz.  The do/while
+   here helps it get to that.  The same caveat about plain -mpowerpc64 mode
+   applies here as to __GMPN_COPY_INCR in gmp.h.
+
+   xlc 3.1 already generates stu/bdnz from the generic C, and does so from
+   this loop too.
+
+   Enhancement: GLIBC does some trickery with dcbz to zero whole cache lines
+   at a time.  MPN_ZERO isn't all that important in GMP, so it might be more
+   trouble than it's worth to do the same, though perhaps a call to memset
+   would be good when on a GNU system.  */
+
+#if HAVE_HOST_CPU_FAMILY_power || HAVE_HOST_CPU_FAMILY_powerpc
+#define MPN_FILL(dst, n, f)						\
+  do {									\
+    mp_ptr __dst = (dst) - 1;						\
+    mp_size_t __n = (n);						\
+    ASSERT (__n > 0);							\
+    do									\
+      *++__dst = (f);							\
+    while (--__n);							\
+  } while (0)
+#endif
+
+#ifndef MPN_FILL
+#define MPN_FILL(dst, n, f)						\
+  do {									\
+    mp_ptr __dst = (dst);						\
+    mp_size_t __n = (n);						\
+    ASSERT (__n > 0);							\
+    do									\
+      *__dst++ = (f);							\
+    while (--__n);							\
+  } while (0)
+#endif
+
+#define MPN_ZERO(dst, n)						\
+  do {									\
+    ASSERT ((n) >= 0);							\
+    if ((n) != 0)							\
+      MPN_FILL (dst, n, CNST_LIMB (0));					\
+  } while (0)
+
+/* On the x86s repe/scasl doesn't seem useful, since it takes many cycles to
+   start up and would need to strip a lot of zeros before it'd be faster
+   than a simple cmpl loop.  Here are some times in cycles for
+   std/repe/scasl/cld and cld/repe/scasl (the latter would be for stripping
+   low zeros).
+
+		std   cld
+	   P5    18    16
+	   P6    46    38
+	   K6    36    13
+	   K7    21    20
+*/
+#ifndef MPN_NORMALIZE
+#define MPN_NORMALIZE(DST, NLIMBS) \
+  do {									\
+    while ((NLIMBS) > 0)						\
+      {									\
+	if ((DST)[(NLIMBS) - 1] != 0)					\
+	  break;							\
+	(NLIMBS)--;							\
+      }									\
+  } while (0)
+#endif
+#ifndef MPN_NORMALIZE_NOT_ZERO
+#define MPN_NORMALIZE_NOT_ZERO(DST, NLIMBS)				\
+  do {									\
+    while (1)								\
+      {									\
+	ASSERT ((NLIMBS) >= 1);						\
+	if ((DST)[(NLIMBS) - 1] != 0)					\
+	  break;							\
+	(NLIMBS)--;							\
+      }									\
+  } while (0)
+#endif
+
+/* Strip least significant zero limbs from {ptr,size} by incrementing ptr
+   and decrementing size.  low should be ptr[0], and will be the new ptr[0]
+   on returning.  The number in {ptr,size} must be non-zero, ie. size!=0 and
+   somewhere a non-zero limb.  */
+#define MPN_STRIP_LOW_ZEROS_NOT_ZERO(ptr, size, low)			\
+  do {									\
+    ASSERT ((size) >= 1);						\
+    ASSERT ((low) == (ptr)[0]);						\
+									\
+    while ((low) == 0)							\
+      {									\
+	(size)--;							\
+	ASSERT ((size) >= 1);						\
+	(ptr)++;							\
+	(low) = *(ptr);							\
+      }									\
+  } while (0)
+
+/* Initialize X of type mpz_t with space for NLIMBS limbs.  X should be a
+   temporary variable; it will be automatically cleared out at function
+   return.  We use __x here to make it possible to accept both mpz_ptr and
+   mpz_t arguments.  */
+#define MPZ_TMP_INIT(X, NLIMBS)						\
+  do {									\
+    mpz_ptr __x = (X);							\
+    ASSERT ((NLIMBS) >= 1);						\
+    __x->_mp_alloc = (NLIMBS);						\
+    __x->_mp_d = TMP_ALLOC_LIMBS (NLIMBS);				\
+  } while (0)
+
+#if WANT_ASSERT
+static inline void *
+_mpz_newalloc (mpz_ptr z, mp_size_t n)
+{
+  void * res = _mpz_realloc(z,n);
+  /* If we are checking the code, force a random change to limbs. */
+  ((mp_ptr) res)[0] = ~ ((mp_ptr) res)[ALLOC (z) - 1];
+  return res;
+}
+#else
+#define _mpz_newalloc _mpz_realloc
+#endif
+/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs.  */
+#define MPZ_REALLOC(z,n) (UNLIKELY ((n) > ALLOC(z))			\
+			  ? (mp_ptr) _mpz_realloc(z,n)			\
+			  : PTR(z))
+#define MPZ_NEWALLOC(z,n) (UNLIKELY ((n) > ALLOC(z))			\
+			   ? (mp_ptr) _mpz_newalloc(z,n)		\
+			   : PTR(z))
+
+#define MPZ_EQUAL_1_P(z)  (SIZ(z)==1 && PTR(z)[0] == 1)
+
+
+/* MPN_FIB2_SIZE(n) is the size in limbs required by mpn_fib2_ui for fp and
+   f1p.
+
+   From Knuth vol 1 section 1.2.8, F[n] = phi^n/sqrt(5) rounded to the
+   nearest integer, where phi=(1+sqrt(5))/2 is the golden ratio.  So the
+   number of bits required is n*log_2((1+sqrt(5))/2) = n*0.6942419.
+
+   The multiplier used is 23/32=0.71875 for efficient calculation on CPUs
+   without good floating point.  There's +2 for rounding up, and a further
+   +2 since at the last step x limbs are doubled into a 2x+1 limb region
+   whereas the actual F[2k] value might be only 2x-1 limbs.
+
+   Note that a division is done first, since on a 32-bit system it's at
+   least conceivable to go right up to n==ULONG_MAX.  (F[2^32-1] would be
+   about 380Mbytes, plus temporary workspace of about 1.2Gbytes here and
+   whatever a multiply of two 190Mbyte numbers takes.)
+
+   Enhancement: When GMP_NUMB_BITS is not a power of 2 the division could be
+   worked into the multiplier.  */
+
+#define MPN_FIB2_SIZE(n) \
+  ((mp_size_t) ((n) / 32 * 23 / GMP_NUMB_BITS) + 4)
+
+
+/* FIB_TABLE(n) returns the Fibonacci number F[n].  Must have n in the range
+   -1 <= n <= FIB_TABLE_LIMIT (that constant in fib_table.h).
+
+   FIB_TABLE_LUCNUM_LIMIT (in fib_table.h) is the largest n for which L[n] =
+   F[n] + 2*F[n-1] fits in a limb.  */
+
+__GMP_DECLSPEC extern const mp_limb_t __gmp_fib_table[];
+#define FIB_TABLE(n)  (__gmp_fib_table[(n)+1])
+
+extern const mp_limb_t __gmp_oddfac_table[];
+extern const mp_limb_t __gmp_odd2fac_table[];
+extern const unsigned char __gmp_fac2cnt_table[];
+extern const mp_limb_t __gmp_limbroots_table[];
+
+/* n^log <= GMP_NUMB_MAX, a limb can store log factors less than n */
+static inline unsigned
+log_n_max (mp_limb_t n)
+{
+  unsigned log;
+  for (log = 8; n > __gmp_limbroots_table[log - 1]; log--);
+  return log;
+}
+
+#define SIEVESIZE 512		/* FIXME: Allow gmp_init_primesieve to choose */
+typedef struct
+{
+  unsigned long d;		   /* current index in s[] */
+  unsigned long s0;		   /* number corresponding to s[0] */
+  unsigned long sqrt_s0;	   /* misnomer for sqrt(s[SIEVESIZE-1]) */
+  unsigned char s[SIEVESIZE + 1];  /* sieve table */
+} gmp_primesieve_t;
+
+#define gmp_init_primesieve __gmp_init_primesieve
+__GMP_DECLSPEC void gmp_init_primesieve (gmp_primesieve_t *);
+
+#define gmp_nextprime __gmp_nextprime
+__GMP_DECLSPEC unsigned long int gmp_nextprime (gmp_primesieve_t *);
+
+#define gmp_primesieve __gmp_primesieve
+__GMP_DECLSPEC mp_limb_t gmp_primesieve (mp_ptr, mp_limb_t);
+
+
+#ifndef MUL_TOOM22_THRESHOLD
+#define MUL_TOOM22_THRESHOLD             30
+#endif
+
+#ifndef MUL_TOOM33_THRESHOLD
+#define MUL_TOOM33_THRESHOLD            100
+#endif
+
+#ifndef MUL_TOOM44_THRESHOLD
+#define MUL_TOOM44_THRESHOLD            300
+#endif
+
+#ifndef MUL_TOOM6H_THRESHOLD
+#define MUL_TOOM6H_THRESHOLD            350
+#endif
+
+#ifndef SQR_TOOM6_THRESHOLD
+#define SQR_TOOM6_THRESHOLD MUL_TOOM6H_THRESHOLD
+#endif
+
+#ifndef MUL_TOOM8H_THRESHOLD
+#define MUL_TOOM8H_THRESHOLD            450
+#endif
+
+#ifndef SQR_TOOM8_THRESHOLD
+#define SQR_TOOM8_THRESHOLD MUL_TOOM8H_THRESHOLD
+#endif
+
+#ifndef MUL_TOOM32_TO_TOOM43_THRESHOLD
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD  100
+#endif
+
+#ifndef MUL_TOOM32_TO_TOOM53_THRESHOLD
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD  110
+#endif
+
+#ifndef MUL_TOOM42_TO_TOOM53_THRESHOLD
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD  100
+#endif
+
+#ifndef MUL_TOOM42_TO_TOOM63_THRESHOLD
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD  110
+#endif
+
+#ifndef MUL_TOOM43_TO_TOOM54_THRESHOLD
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD  150
+#endif
+
+/* MUL_TOOM22_THRESHOLD_LIMIT is the maximum for MUL_TOOM22_THRESHOLD.  In a
+   normal build MUL_TOOM22_THRESHOLD is a constant and we use that.  In a fat
+   binary or tune program build MUL_TOOM22_THRESHOLD is a variable and a
+   separate hard limit will have been defined.  Similarly for TOOM3.  */
+#ifndef MUL_TOOM22_THRESHOLD_LIMIT
+#define MUL_TOOM22_THRESHOLD_LIMIT  MUL_TOOM22_THRESHOLD
+#endif
+#ifndef MUL_TOOM33_THRESHOLD_LIMIT
+#define MUL_TOOM33_THRESHOLD_LIMIT  MUL_TOOM33_THRESHOLD
+#endif
+#ifndef MULLO_BASECASE_THRESHOLD_LIMIT
+#define MULLO_BASECASE_THRESHOLD_LIMIT  MULLO_BASECASE_THRESHOLD
+#endif
+#ifndef SQRLO_BASECASE_THRESHOLD_LIMIT
+#define SQRLO_BASECASE_THRESHOLD_LIMIT  SQRLO_BASECASE_THRESHOLD
+#endif
+#ifndef SQRLO_DC_THRESHOLD_LIMIT
+#define SQRLO_DC_THRESHOLD_LIMIT  SQRLO_DC_THRESHOLD
+#endif
+
+/* SQR_BASECASE_THRESHOLD is where mpn_sqr_basecase should take over from
+   mpn_mul_basecase.  Default is to use mpn_sqr_basecase from 0.  (Note that we
+   certainly always want it if there's a native assembler mpn_sqr_basecase.)
+
+   If it turns out that mpn_toom2_sqr becomes faster than mpn_mul_basecase
+   before mpn_sqr_basecase does, then SQR_BASECASE_THRESHOLD is the toom2
+   threshold and SQR_TOOM2_THRESHOLD is 0.  This oddity arises more or less
+   because SQR_TOOM2_THRESHOLD represents the size up to which mpn_sqr_basecase
+   should be used, and that may be never.  */
+
+#ifndef SQR_BASECASE_THRESHOLD
+#define SQR_BASECASE_THRESHOLD            0  /* never use mpn_mul_basecase */
+#endif
+
+#ifndef SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD              50
+#endif
+
+#ifndef SQR_TOOM3_THRESHOLD
+#define SQR_TOOM3_THRESHOLD             120
+#endif
+
+#ifndef SQR_TOOM4_THRESHOLD
+#define SQR_TOOM4_THRESHOLD             400
+#endif
+
+/* See comments above about MUL_TOOM33_THRESHOLD_LIMIT.  */
+#ifndef SQR_TOOM3_THRESHOLD_LIMIT
+#define SQR_TOOM3_THRESHOLD_LIMIT  SQR_TOOM3_THRESHOLD
+#endif
+
+#ifndef MULMID_TOOM42_THRESHOLD
+#define MULMID_TOOM42_THRESHOLD     MUL_TOOM22_THRESHOLD
+#endif
+
+#ifndef MULLO_BASECASE_THRESHOLD
+#define MULLO_BASECASE_THRESHOLD          0  /* never use mpn_mul_basecase */
+#endif
+
+#ifndef MULLO_DC_THRESHOLD
+#define MULLO_DC_THRESHOLD         (2*MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef MULLO_MUL_N_THRESHOLD
+#define MULLO_MUL_N_THRESHOLD      (2*MUL_FFT_THRESHOLD)
+#endif
+
+#ifndef SQRLO_BASECASE_THRESHOLD
+#define SQRLO_BASECASE_THRESHOLD          0  /* never use mpn_sqr_basecase */
+#endif
+
+#ifndef SQRLO_DC_THRESHOLD
+#define SQRLO_DC_THRESHOLD         (MULLO_DC_THRESHOLD)
+#endif
+
+#ifndef SQRLO_SQR_THRESHOLD
+#define SQRLO_SQR_THRESHOLD        (MULLO_MUL_N_THRESHOLD)
+#endif
+
+#ifndef DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD        (2*MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef DC_DIVAPPR_Q_THRESHOLD
+#define DC_DIVAPPR_Q_THRESHOLD          200
+#endif
+
+#ifndef DC_BDIV_QR_THRESHOLD
+#define DC_BDIV_QR_THRESHOLD       (2*MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef DC_BDIV_Q_THRESHOLD
+#define DC_BDIV_Q_THRESHOLD             180
+#endif
+
+#ifndef DIVEXACT_JEB_THRESHOLD
+#define DIVEXACT_JEB_THRESHOLD           25
+#endif
+
+#ifndef INV_MULMOD_BNM1_THRESHOLD
+#define INV_MULMOD_BNM1_THRESHOLD  (4*MULMOD_BNM1_THRESHOLD)
+#endif
+
+#ifndef INV_APPR_THRESHOLD
+#define INV_APPR_THRESHOLD         INV_NEWTON_THRESHOLD
+#endif
+
+#ifndef INV_NEWTON_THRESHOLD
+#define INV_NEWTON_THRESHOLD            200
+#endif
+
+#ifndef BINV_NEWTON_THRESHOLD
+#define BINV_NEWTON_THRESHOLD           300
+#endif
+
+#ifndef MU_DIVAPPR_Q_THRESHOLD
+#define MU_DIVAPPR_Q_THRESHOLD         2000
+#endif
+
+#ifndef MU_DIV_QR_THRESHOLD
+#define MU_DIV_QR_THRESHOLD            2000
+#endif
+
+#ifndef MUPI_DIV_QR_THRESHOLD
+#define MUPI_DIV_QR_THRESHOLD           200
+#endif
+
+#ifndef MU_BDIV_Q_THRESHOLD
+#define MU_BDIV_Q_THRESHOLD            2000
+#endif
+
+#ifndef MU_BDIV_QR_THRESHOLD
+#define MU_BDIV_QR_THRESHOLD           2000
+#endif
+
+#ifndef MULMOD_BNM1_THRESHOLD
+#define MULMOD_BNM1_THRESHOLD            16
+#endif
+
+#ifndef SQRMOD_BNM1_THRESHOLD
+#define SQRMOD_BNM1_THRESHOLD            16
+#endif
+
+#ifndef MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD
+#define MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD  (INV_MULMOD_BNM1_THRESHOLD/2)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+
+#ifndef REDC_1_TO_REDC_2_THRESHOLD
+#define REDC_1_TO_REDC_2_THRESHOLD       15
+#endif
+#ifndef REDC_2_TO_REDC_N_THRESHOLD
+#define REDC_2_TO_REDC_N_THRESHOLD      100
+#endif
+
+#else
+
+#ifndef REDC_1_TO_REDC_N_THRESHOLD
+#define REDC_1_TO_REDC_N_THRESHOLD      100
+#endif
+
+#endif /* HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2 */
+
+
+/* First k to use for an FFT modF multiply.  A modF FFT is an order
+   log(2^k)/log(2^(k-1)) algorithm, so k=3 is merely 1.5 like karatsuba,
+   whereas k=4 is 1.33 which is faster than toom3 at 1.485.    */
+#define FFT_FIRST_K  4
+
+/* Threshold at which FFT should be used to do a modF NxN -> N multiply. */
+#ifndef MUL_FFT_MODF_THRESHOLD
+#define MUL_FFT_MODF_THRESHOLD   (MUL_TOOM33_THRESHOLD * 3)
+#endif
+#ifndef SQR_FFT_MODF_THRESHOLD
+#define SQR_FFT_MODF_THRESHOLD   (SQR_TOOM3_THRESHOLD * 3)
+#endif
+
+/* Threshold at which FFT should be used to do an NxN -> 2N multiply.  This
+   will be a size where FFT is using k=7 or k=8, since an FFT-k used for an
+   NxN->2N multiply and not recursing into itself is an order
+   log(2^k)/log(2^(k-2)) algorithm, so it'll be at least k=7 at 1.39 which
+   is the first better than toom3.  */
+#ifndef MUL_FFT_THRESHOLD
+#define MUL_FFT_THRESHOLD   (MUL_FFT_MODF_THRESHOLD * 10)
+#endif
+#ifndef SQR_FFT_THRESHOLD
+#define SQR_FFT_THRESHOLD   (SQR_FFT_MODF_THRESHOLD * 10)
+#endif
+
+/* Table of thresholds for successive modF FFT "k"s.  The first entry is
+   where FFT_FIRST_K+1 should be used, the second FFT_FIRST_K+2,
+   etc.  See mpn_fft_best_k(). */
+#ifndef MUL_FFT_TABLE
+#define MUL_FFT_TABLE							\
+  { MUL_TOOM33_THRESHOLD * 4,   /* k=5 */				\
+    MUL_TOOM33_THRESHOLD * 8,   /* k=6 */				\
+    MUL_TOOM33_THRESHOLD * 16,  /* k=7 */				\
+    MUL_TOOM33_THRESHOLD * 32,  /* k=8 */				\
+    MUL_TOOM33_THRESHOLD * 96,  /* k=9 */				\
+    MUL_TOOM33_THRESHOLD * 288, /* k=10 */				\
+    0 }
+#endif
+#ifndef SQR_FFT_TABLE
+#define SQR_FFT_TABLE							\
+  { SQR_TOOM3_THRESHOLD * 4,   /* k=5 */				\
+    SQR_TOOM3_THRESHOLD * 8,   /* k=6 */				\
+    SQR_TOOM3_THRESHOLD * 16,  /* k=7 */				\
+    SQR_TOOM3_THRESHOLD * 32,  /* k=8 */				\
+    SQR_TOOM3_THRESHOLD * 96,  /* k=9 */				\
+    SQR_TOOM3_THRESHOLD * 288, /* k=10 */				\
+    0 }
+#endif
+
+struct fft_table_nk
+{
+  gmp_uint_least32_t n:27;
+  gmp_uint_least32_t k:5;
+};
+
+#ifndef FFT_TABLE_ATTRS
+#define FFT_TABLE_ATTRS   static const
+#endif
+
+#define MPN_FFT_TABLE_SIZE  16
+
+
+#ifndef DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD    (3 * MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef GET_STR_DC_THRESHOLD
+#define GET_STR_DC_THRESHOLD             18
+#endif
+
+#ifndef GET_STR_PRECOMPUTE_THRESHOLD
+#define GET_STR_PRECOMPUTE_THRESHOLD     35
+#endif
+
+#ifndef SET_STR_DC_THRESHOLD
+#define SET_STR_DC_THRESHOLD            750
+#endif
+
+#ifndef SET_STR_PRECOMPUTE_THRESHOLD
+#define SET_STR_PRECOMPUTE_THRESHOLD   2000
+#endif
+
+#ifndef FAC_ODD_THRESHOLD
+#define FAC_ODD_THRESHOLD    35
+#endif
+
+#ifndef FAC_DSC_THRESHOLD
+#define FAC_DSC_THRESHOLD   400
+#endif
+
+/* Return non-zero if xp,xsize and yp,ysize overlap.
+   If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
+   overlap.  If both these are false, there's an overlap. */
+#define MPN_OVERLAP_P(xp, xsize, yp, ysize)				\
+  ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))
+#define MEM_OVERLAP_P(xp, xsize, yp, ysize)				\
+  (   (char *) (xp) + (xsize) > (char *) (yp)				\
+   && (char *) (yp) + (ysize) > (char *) (xp))
+
+/* Return non-zero if xp,xsize and yp,ysize are either identical or not
+   overlapping.  Return zero if they're partially overlapping. */
+#define MPN_SAME_OR_SEPARATE_P(xp, yp, size)				\
+  MPN_SAME_OR_SEPARATE2_P(xp, size, yp, size)
+#define MPN_SAME_OR_SEPARATE2_P(xp, xsize, yp, ysize)			\
+  ((xp) == (yp) || ! MPN_OVERLAP_P (xp, xsize, yp, ysize))
+
+/* Return non-zero if dst,dsize and src,ssize are either identical or
+   overlapping in a way suitable for an incrementing/decrementing algorithm.
+   Return zero if they're partially overlapping in an unsuitable fashion. */
+#define MPN_SAME_OR_INCR2_P(dst, dsize, src, ssize)			\
+  ((dst) <= (src) || ! MPN_OVERLAP_P (dst, dsize, src, ssize))
+#define MPN_SAME_OR_INCR_P(dst, src, size)				\
+  MPN_SAME_OR_INCR2_P(dst, size, src, size)
+#define MPN_SAME_OR_DECR2_P(dst, dsize, src, ssize)			\
+  ((dst) >= (src) || ! MPN_OVERLAP_P (dst, dsize, src, ssize))
+#define MPN_SAME_OR_DECR_P(dst, src, size)				\
+  MPN_SAME_OR_DECR2_P(dst, size, src, size)
+
+
+/* ASSERT() is a private assertion checking scheme, similar to <assert.h>.
+   ASSERT() does the check only if WANT_ASSERT is selected, ASSERT_ALWAYS()
+   does it always.  Generally assertions are meant for development, but
+   might help when looking for a problem later too.  */
+
+#ifdef __LINE__
+#define ASSERT_LINE  __LINE__
+#else
+#define ASSERT_LINE  -1
+#endif
+
+#ifdef __FILE__
+#define ASSERT_FILE  __FILE__
+#else
+#define ASSERT_FILE  ""
+#endif
+
+__GMP_DECLSPEC void __gmp_assert_header (const char *, int);
+__GMP_DECLSPEC void __gmp_assert_fail (const char *, int, const char *) ATTRIBUTE_NORETURN;
+
+#define ASSERT_FAIL(expr)  __gmp_assert_fail (ASSERT_FILE, ASSERT_LINE, #expr)
+
+#define ASSERT_ALWAYS(expr)						\
+  do {									\
+    if (UNLIKELY (!(expr)))						\
+      ASSERT_FAIL (expr);						\
+  } while (0)
+
+#if WANT_ASSERT
+#define ASSERT(expr)   ASSERT_ALWAYS (expr)
+#else
+#define ASSERT(expr)   do {} while (0)
+#endif
+
+
+/* ASSERT_CARRY checks the expression is non-zero, and ASSERT_NOCARRY checks
+   that it's zero.  In both cases if assertion checking is disabled the
+   expression is still evaluated.  These macros are meant for use with
+   routines like mpn_add_n() where the return value represents a carry or
+   whatever that should or shouldn't occur in some context.  For example,
+   ASSERT_NOCARRY (mpn_add_n (rp, s1p, s2p, size)); */
+#if WANT_ASSERT
+#define ASSERT_CARRY(expr)     ASSERT_ALWAYS ((expr) != 0)
+#define ASSERT_NOCARRY(expr)   ASSERT_ALWAYS ((expr) == 0)
+#else
+#define ASSERT_CARRY(expr)     (expr)
+#define ASSERT_NOCARRY(expr)   (expr)
+#endif
+
+
+/* ASSERT_CODE includes code when assertion checking is wanted.  This is the
+   same as writing "#if WANT_ASSERT", but more compact.  */
+#if WANT_ASSERT
+#define ASSERT_CODE(expr)  expr
+#else
+#define ASSERT_CODE(expr)
+#endif
+
+
+/* Test that an mpq_t is in fully canonical form.  This can be used as
+   protection on routines like mpq_equal which give wrong results on
+   non-canonical inputs.  */
+#if WANT_ASSERT
+#define ASSERT_MPQ_CANONICAL(q)						\
+  do {									\
+    ASSERT (q->_mp_den._mp_size > 0);					\
+    if (q->_mp_num._mp_size == 0)					\
+      {									\
+	/* zero should be 0/1 */					\
+	ASSERT (mpz_cmp_ui (mpq_denref(q), 1L) == 0);			\
+      }									\
+    else								\
+      {									\
+	/* no common factors */						\
+	mpz_t  __g;							\
+	mpz_init (__g);							\
+	mpz_gcd (__g, mpq_numref(q), mpq_denref(q));			\
+	ASSERT (mpz_cmp_ui (__g, 1) == 0);				\
+	mpz_clear (__g);						\
+      }									\
+  } while (0)
+#else
+#define ASSERT_MPQ_CANONICAL(q)	 do {} while (0)
+#endif
+
+/* Check that the nail parts are zero. */
+#define ASSERT_ALWAYS_LIMB(limb)					\
+  do {									\
+    mp_limb_t  __nail = (limb) & GMP_NAIL_MASK;				\
+    ASSERT_ALWAYS (__nail == 0);					\
+  } while (0)
+#define ASSERT_ALWAYS_MPN(ptr, size)					\
+  do {									\
+    /* let whole loop go dead when no nails */				\
+    if (GMP_NAIL_BITS != 0)						\
+      {									\
+	mp_size_t  __i;							\
+	for (__i = 0; __i < (size); __i++)				\
+	  ASSERT_ALWAYS_LIMB ((ptr)[__i]);				\
+      }									\
+  } while (0)
+#if WANT_ASSERT
+#define ASSERT_LIMB(limb)       ASSERT_ALWAYS_LIMB (limb)
+#define ASSERT_MPN(ptr, size)   ASSERT_ALWAYS_MPN (ptr, size)
+#else
+#define ASSERT_LIMB(limb)       do {} while (0)
+#define ASSERT_MPN(ptr, size)   do {} while (0)
+#endif
+
+
+/* Assert that an mpn region {ptr,size} is zero, or non-zero.
+   size==0 is allowed, and in that case {ptr,size} considered to be zero.  */
+#if WANT_ASSERT
+#define ASSERT_MPN_ZERO_P(ptr,size)					\
+  do {									\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    for (__i = 0; __i < (size); __i++)					\
+      ASSERT ((ptr)[__i] == 0);						\
+  } while (0)
+#define ASSERT_MPN_NONZERO_P(ptr,size)					\
+  do {									\
+    mp_size_t  __i;							\
+    int	       __nonzero = 0;						\
+    ASSERT ((size) >= 0);						\
+    for (__i = 0; __i < (size); __i++)					\
+      if ((ptr)[__i] != 0)						\
+	{								\
+	  __nonzero = 1;						\
+	  break;							\
+	}								\
+    ASSERT (__nonzero);							\
+  } while (0)
+#else
+#define ASSERT_MPN_ZERO_P(ptr,size)     do {} while (0)
+#define ASSERT_MPN_NONZERO_P(ptr,size)  do {} while (0)
+#endif
+
+
+#if ! HAVE_NATIVE_mpn_com
+#undef mpn_com
+#define mpn_com(d,s,n)							\
+  do {									\
+    mp_ptr     __d = (d);						\
+    mp_srcptr  __s = (s);						\
+    mp_size_t  __n = (n);						\
+    ASSERT (__n >= 1);							\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (__d, __s, __n));			\
+    do									\
+      *__d++ = (~ *__s++) & GMP_NUMB_MASK;				\
+    while (--__n);							\
+  } while (0)
+#endif
+
+#define MPN_LOGOPS_N_INLINE(rp, up, vp, n, operation)			\
+  do {									\
+    mp_srcptr	__up = (up);						\
+    mp_srcptr	__vp = (vp);						\
+    mp_ptr	__rp = (rp);						\
+    mp_size_t	__n = (n);						\
+    mp_limb_t __a, __b;							\
+    ASSERT (__n > 0);							\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (__rp, __up, __n));			\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (__rp, __vp, __n));			\
+    __up += __n;							\
+    __vp += __n;							\
+    __rp += __n;							\
+    __n = -__n;								\
+    do {								\
+      __a = __up[__n];							\
+      __b = __vp[__n];							\
+      __rp[__n] = operation;						\
+    } while (++__n);							\
+  } while (0)
+
+
+#if ! HAVE_NATIVE_mpn_and_n
+#undef mpn_and_n
+#define mpn_and_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a & __b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_andn_n
+#undef mpn_andn_n
+#define mpn_andn_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a & ~__b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_nand_n
+#undef mpn_nand_n
+#define mpn_nand_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, ~(__a & __b) & GMP_NUMB_MASK)
+#endif
+
+#if ! HAVE_NATIVE_mpn_ior_n
+#undef mpn_ior_n
+#define mpn_ior_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a | __b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_iorn_n
+#undef mpn_iorn_n
+#define mpn_iorn_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, (__a | ~__b) & GMP_NUMB_MASK)
+#endif
+
+#if ! HAVE_NATIVE_mpn_nior_n
+#undef mpn_nior_n
+#define mpn_nior_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, ~(__a | __b) & GMP_NUMB_MASK)
+#endif
+
+#if ! HAVE_NATIVE_mpn_xor_n
+#undef mpn_xor_n
+#define mpn_xor_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a ^ __b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_xnor_n
+#undef mpn_xnor_n
+#define mpn_xnor_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, ~(__a ^ __b) & GMP_NUMB_MASK)
+#endif
+
+#define mpn_trialdiv __MPN(trialdiv)
+__GMP_DECLSPEC mp_limb_t mpn_trialdiv (mp_srcptr, mp_size_t, mp_size_t, int *);
+
+#define mpn_remove __MPN(remove)
+__GMP_DECLSPEC mp_bitcnt_t mpn_remove (mp_ptr, mp_size_t *, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_bitcnt_t);
+
+
+/* ADDC_LIMB sets w=x+y and cout to 0 or 1 for a carry from that addition. */
+#if GMP_NAIL_BITS == 0
+#define ADDC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __x = (x);						\
+    mp_limb_t  __y = (y);						\
+    mp_limb_t  __w = __x + __y;						\
+    (w) = __w;								\
+    (cout) = __w < __x;							\
+  } while (0)
+#else
+#define ADDC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __w;							\
+    ASSERT_LIMB (x);							\
+    ASSERT_LIMB (y);							\
+    __w = (x) + (y);							\
+    (w) = __w & GMP_NUMB_MASK;						\
+    (cout) = __w >> GMP_NUMB_BITS;					\
+  } while (0)
+#endif
+
+/* SUBC_LIMB sets w=x-y and cout to 0 or 1 for a borrow from that
+   subtract.  */
+#if GMP_NAIL_BITS == 0
+#define SUBC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __x = (x);						\
+    mp_limb_t  __y = (y);						\
+    mp_limb_t  __w = __x - __y;						\
+    (w) = __w;								\
+    (cout) = __w > __x;							\
+  } while (0)
+#else
+#define SUBC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __w = (x) - (y);						\
+    (w) = __w & GMP_NUMB_MASK;						\
+    (cout) = __w >> (GMP_LIMB_BITS-1);					\
+  } while (0)
+#endif
+
+
+/* MPN_INCR_U does {ptr,size} += n, MPN_DECR_U does {ptr,size} -= n, both
+   expecting no carry (or borrow) from that.
+
+   The size parameter is only for the benefit of assertion checking.  In a
+   normal build it's unused and the carry/borrow is just propagated as far
+   as it needs to go.
+
+   On random data, usually only one or two limbs of {ptr,size} get updated,
+   so there's no need for any sophisticated looping, just something compact
+   and sensible.
+
+   FIXME: Switch all code from mpn_{incr,decr}_u to MPN_{INCR,DECR}_U,
+   declaring their operand sizes, then remove the former.  This is purely
+   for the benefit of assertion checking.  */
+
+#if defined (__GNUC__) && GMP_NAIL_BITS == 0 && ! defined (NO_ASM)	\
+  && (defined(HAVE_HOST_CPU_FAMILY_x86) || defined(HAVE_HOST_CPU_FAMILY_x86_64)) \
+  && ! WANT_ASSERT
+/* Better flags handling than the generic C gives on i386, saving a few
+   bytes of code and maybe a cycle or two.  */
+
+#define MPN_IORD_U(ptr, incr, aors)					\
+  do {									\
+    mp_ptr  __ptr_dummy;						\
+    if (__builtin_constant_p (incr) && (incr) == 0)			\
+      {									\
+      }									\
+    else if (__builtin_constant_p (incr) && (incr) == 1)		\
+      {									\
+	__asm__ __volatile__						\
+	  ("\n" ASM_L(top) ":\n"					\
+	   "\t" aors "\t$1, (%0)\n"					\
+	   "\tlea\t%c2(%0), %0\n"					\
+	   "\tjc\t" ASM_L(top)						\
+	   : "=r" (__ptr_dummy)						\
+	   : "0"  (ptr), "n" (sizeof(mp_limb_t))			\
+	   : "memory");							\
+      }									\
+    else								\
+      {									\
+	__asm__ __volatile__						\
+	  (   aors  "\t%2, (%0)\n"					\
+	   "\tjnc\t" ASM_L(done) "\n"					\
+	   ASM_L(top) ":\n"						\
+	   "\t" aors "\t$1, %c3(%0)\n"					\
+	   "\tlea\t%c3(%0), %0\n"					\
+	   "\tjc\t" ASM_L(top) "\n"					\
+	   ASM_L(done) ":\n"						\
+	   : "=r" (__ptr_dummy)						\
+	   : "0"  (ptr),						\
+	     "re" ((mp_limb_t) (incr)), "n" (sizeof(mp_limb_t))		\
+	   : "memory");							\
+      }									\
+  } while (0)
+
+#if GMP_LIMB_BITS == 32
+#define MPN_INCR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "addl")
+#define MPN_DECR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "subl")
+#endif
+#if GMP_LIMB_BITS == 64
+#define MPN_INCR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "addq")
+#define MPN_DECR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "subq")
+#endif
+#define mpn_incr_u(ptr, incr)  MPN_INCR_U (ptr, 0, incr)
+#define mpn_decr_u(ptr, incr)  MPN_DECR_U (ptr, 0, incr)
+#endif
+
+#if GMP_NAIL_BITS == 0
+#ifndef mpn_incr_u
+#define mpn_incr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	while (++(*(__p++)) == 0)					\
+	  ;								\
+      }									\
+    else								\
+      {									\
+	__x = *__p + (incr);						\
+	*__p = __x;							\
+	if (__x < (incr))						\
+	  while (++(*(++__p)) == 0)					\
+	    ;								\
+      }									\
+  } while (0)
+#endif
+#ifndef mpn_decr_u
+#define mpn_decr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	while ((*(__p++))-- == 0)					\
+	  ;								\
+      }									\
+    else								\
+      {									\
+	__x = *__p;							\
+	*__p = __x - (incr);						\
+	if (__x < (incr))						\
+	  while ((*(++__p))-- == 0)					\
+	    ;								\
+      }									\
+  } while (0)
+#endif
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#ifndef mpn_incr_u
+#define mpn_incr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	do								\
+	  {								\
+	    __x = (*__p + 1) & GMP_NUMB_MASK;				\
+	    *__p++ = __x;						\
+	  }								\
+	while (__x == 0);						\
+      }									\
+    else								\
+      {									\
+	__x = (*__p + (incr));						\
+	*__p++ = __x & GMP_NUMB_MASK;					\
+	if (__x >> GMP_NUMB_BITS != 0)					\
+	  {								\
+	    do								\
+	      {								\
+		__x = (*__p + 1) & GMP_NUMB_MASK;			\
+		*__p++ = __x;						\
+	      }								\
+	    while (__x == 0);						\
+	  }								\
+      }									\
+  } while (0)
+#endif
+#ifndef mpn_decr_u
+#define mpn_decr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	do								\
+	  {								\
+	    __x = *__p;							\
+	    *__p++ = (__x - 1) & GMP_NUMB_MASK;				\
+	  }								\
+	while (__x == 0);						\
+      }									\
+    else								\
+      {									\
+	__x = *__p - (incr);						\
+	*__p++ = __x & GMP_NUMB_MASK;					\
+	if (__x >> GMP_NUMB_BITS != 0)					\
+	  {								\
+	    do								\
+	      {								\
+		__x = *__p;						\
+		*__p++ = (__x - 1) & GMP_NUMB_MASK;			\
+	      }								\
+	    while (__x == 0);						\
+	  }								\
+      }									\
+  } while (0)
+#endif
+#endif
+
+#ifndef MPN_INCR_U
+#if WANT_ASSERT
+#define MPN_INCR_U(ptr, size, n)					\
+  do {									\
+    ASSERT ((size) >= 1);						\
+    ASSERT_NOCARRY (mpn_add_1 (ptr, ptr, size, n));			\
+  } while (0)
+#else
+#define MPN_INCR_U(ptr, size, n)   mpn_incr_u (ptr, n)
+#endif
+#endif
+
+#ifndef MPN_DECR_U
+#if WANT_ASSERT
+#define MPN_DECR_U(ptr, size, n)					\
+  do {									\
+    ASSERT ((size) >= 1);						\
+    ASSERT_NOCARRY (mpn_sub_1 (ptr, ptr, size, n));			\
+  } while (0)
+#else
+#define MPN_DECR_U(ptr, size, n)   mpn_decr_u (ptr, n)
+#endif
+#endif
+
+
+/* Structure for conversion between internal binary format and strings.  */
+struct bases
+{
+  /* Number of digits in the conversion base that always fits in an mp_limb_t.
+     For example, for base 10 on a machine where an mp_limb_t has 32 bits this
+     is 9, since 10**9 is the largest number that fits into an mp_limb_t.  */
+  int chars_per_limb;
+
+  /* log(2)/log(conversion_base) */
+  mp_limb_t logb2;
+
+  /* log(conversion_base)/log(2) */
+  mp_limb_t log2b;
+
+  /* base**chars_per_limb, i.e. the biggest number that fits a word, built by
+     factors of base.  Exception: For 2, 4, 8, etc, big_base is log2(base),
+     i.e. the number of bits used to represent each digit in the base.  */
+  mp_limb_t big_base;
+
+  /* A GMP_LIMB_BITS bit approximation to 1/big_base, represented as a
+     fixed-point number.  Instead of dividing by big_base an application can
+     choose to multiply by big_base_inverted.  */
+  mp_limb_t big_base_inverted;
+};
+
+#define   mp_bases __MPN(bases)
+__GMP_DECLSPEC extern const struct bases mp_bases[257];
+
+
+/* Compute the number of digits in base for nbits bits, making sure the result
+   is never too small.  The two variants of the macro implement the same
+   function; the GT2 variant below works just for bases > 2.  */
+#define DIGITS_IN_BASE_FROM_BITS(res, nbits, b)				\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    size_t _nbits = (nbits);						\
+    umul_ppmm (_ph, _dummy, mp_bases[b].logb2, _nbits);			\
+    _ph += (_dummy + _nbits < _dummy);					\
+    res = _ph + 1;							\
+  } while (0)
+#define DIGITS_IN_BASEGT2_FROM_BITS(res, nbits, b)			\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    size_t _nbits = (nbits);						\
+    umul_ppmm (_ph, _dummy, mp_bases[b].logb2 + 1, _nbits);		\
+    res = _ph + 1;							\
+  } while (0)
+
+/* For power of 2 bases this is exact.  For other bases the result is either
+   exact or one too big.
+
+   To be exact always it'd be necessary to examine all the limbs of the
+   operand, since numbers like 100..000 and 99...999 generally differ only
+   in the lowest limb.  It'd be possible to examine just a couple of high
+   limbs to increase the probability of being exact, but that doesn't seem
+   worth bothering with.  */
+
+#define MPN_SIZEINBASE(result, ptr, size, base)				\
+  do {									\
+    int	   __lb_base, __cnt;						\
+    size_t __totbits;							\
+									\
+    ASSERT ((size) >= 0);						\
+    ASSERT ((base) >= 2);						\
+    ASSERT ((base) < numberof (mp_bases));				\
+									\
+    /* Special case for X == 0.  */					\
+    if ((size) == 0)							\
+      (result) = 1;							\
+    else								\
+      {									\
+	/* Calculate the total number of significant bits of X.  */	\
+	count_leading_zeros (__cnt, (ptr)[(size)-1]);			\
+	__totbits = (size_t) (size) * GMP_NUMB_BITS - (__cnt - GMP_NAIL_BITS);\
+									\
+	if (POW2_P (base))						\
+	  {								\
+	    __lb_base = mp_bases[base].big_base;			\
+	    (result) = (__totbits + __lb_base - 1) / __lb_base;		\
+	  }								\
+	else								\
+	  {								\
+	    DIGITS_IN_BASEGT2_FROM_BITS (result, __totbits, base);	\
+	  }								\
+      }									\
+  } while (0)
+
+#define MPN_SIZEINBASE_2EXP(result, ptr, size, base2exp)			\
+  do {										\
+    int          __cnt;								\
+    mp_bitcnt_t  __totbits;							\
+    ASSERT ((size) > 0);							\
+    ASSERT ((ptr)[(size)-1] != 0);						\
+    count_leading_zeros (__cnt, (ptr)[(size)-1]);				\
+    __totbits = (mp_bitcnt_t) (size) * GMP_NUMB_BITS - (__cnt - GMP_NAIL_BITS);	\
+    (result) = (__totbits + (base2exp)-1) / (base2exp);				\
+  } while (0)
+
+
+/* bit count to limb count, rounding up */
+#define BITS_TO_LIMBS(n)  (((n) + (GMP_NUMB_BITS - 1)) / GMP_NUMB_BITS)
+
+/* MPN_SET_UI sets an mpn (ptr, cnt) to given ui.  MPZ_FAKE_UI creates fake
+   mpz_t from ui.  The zp argument must have room for LIMBS_PER_ULONG limbs
+   in both cases (LIMBS_PER_ULONG is also defined here.) */
+#if BITS_PER_ULONG <= GMP_NUMB_BITS /* need one limb per ulong */
+
+#define LIMBS_PER_ULONG 1
+#define MPN_SET_UI(zp, zn, u)						\
+  (zp)[0] = (u);							\
+  (zn) = ((zp)[0] != 0);
+#define MPZ_FAKE_UI(z, zp, u)						\
+  (zp)[0] = (u);							\
+  PTR (z) = (zp);							\
+  SIZ (z) = ((zp)[0] != 0);						\
+  ASSERT_CODE (ALLOC (z) = 1);
+
+#else /* need two limbs per ulong */
+
+#define LIMBS_PER_ULONG 2
+#define MPN_SET_UI(zp, zn, u)						\
+  (zp)[0] = (u) & GMP_NUMB_MASK;					\
+  (zp)[1] = (u) >> GMP_NUMB_BITS;					\
+  (zn) = ((zp)[1] != 0 ? 2 : (zp)[0] != 0 ? 1 : 0);
+#define MPZ_FAKE_UI(z, zp, u)						\
+  (zp)[0] = (u) & GMP_NUMB_MASK;					\
+  (zp)[1] = (u) >> GMP_NUMB_BITS;					\
+  SIZ (z) = ((zp)[1] != 0 ? 2 : (zp)[0] != 0 ? 1 : 0);			\
+  PTR (z) = (zp);							\
+  ASSERT_CODE (ALLOC (z) = 2);
+
+#endif
+
+
+#if HAVE_HOST_CPU_FAMILY_x86
+#define TARGET_REGISTER_STARVED 1
+#else
+#define TARGET_REGISTER_STARVED 0
+#endif
+
+
+/* LIMB_HIGHBIT_TO_MASK(n) examines the high bit of a limb value and turns 1
+   or 0 there into a limb 0xFF..FF or 0 respectively.
+
+   On most CPUs this is just an arithmetic right shift by GMP_LIMB_BITS-1,
+   but C99 doesn't guarantee signed right shifts are arithmetic, so we have
+   a little compile-time test and a fallback to a "? :" form.  The latter is
+   necessary for instance on Cray vector systems.
+
+   Recent versions of gcc (eg. 3.3) will in fact optimize a "? :" like this
+   to an arithmetic right shift anyway, but it's good to get the desired
+   shift on past versions too (in particular since an important use of
+   LIMB_HIGHBIT_TO_MASK is in udiv_qrnnd_preinv).  */
+
+#define LIMB_HIGHBIT_TO_MASK(n)						\
+  (((mp_limb_signed_t) -1 >> 1) < 0					\
+   ? (mp_limb_signed_t) (n) >> (GMP_LIMB_BITS - 1)			\
+   : (n) & GMP_LIMB_HIGHBIT ? MP_LIMB_T_MAX : CNST_LIMB(0))
+
+
+/* Use a library function for invert_limb, if available. */
+#define  mpn_invert_limb __MPN(invert_limb)
+__GMP_DECLSPEC mp_limb_t mpn_invert_limb (mp_limb_t) ATTRIBUTE_CONST;
+#if ! defined (invert_limb) && HAVE_NATIVE_mpn_invert_limb
+#define invert_limb(invxl,xl)						\
+  do {									\
+    (invxl) = mpn_invert_limb (xl);					\
+  } while (0)
+#endif
+
+#ifndef invert_limb
+#define invert_limb(invxl,xl)						\
+  do {									\
+    mp_limb_t _dummy;							\
+    ASSERT ((xl) != 0);							\
+    udiv_qrnnd (invxl, _dummy, ~(xl), ~CNST_LIMB(0), xl);		\
+  } while (0)
+#endif
+
+#define invert_pi1(dinv, d1, d0)					\
+  do {									\
+    mp_limb_t _v, _p, _t1, _t0, _mask;					\
+    invert_limb (_v, d1);						\
+    _p = (d1) * _v;							\
+    _p += (d0);								\
+    if (_p < (d0))							\
+      {									\
+	_v--;								\
+	_mask = -(mp_limb_t) (_p >= (d1));				\
+	_p -= (d1);							\
+	_v += _mask;							\
+	_p -= _mask & (d1);						\
+      }									\
+    umul_ppmm (_t1, _t0, d0, _v);					\
+    _p += _t1;								\
+    if (_p < _t1)							\
+      {									\
+	_v--;								\
+	if (UNLIKELY (_p >= (d1)))					\
+	  {								\
+	    if (_p > (d1) || _t0 >= (d0))				\
+	      _v--;							\
+	  }								\
+      }									\
+    (dinv).inv32 = _v;							\
+  } while (0)
+
+
+/* udiv_qrnnd_preinv -- Based on work by Niels Möller and Torbjörn Granlund.
+   We write things strangely below, to help gcc.  A more straightforward
+   version:
+	_r = (nl) - _qh * (d);
+	_t = _r + (d);
+	if (_r >= _ql)
+	  {
+	    _qh--;
+	    _r = _t;
+	  }
+   For one operation shorter critical path, one may want to use this form:
+	_p = _qh * (d)
+	_s = (nl) + (d);
+	_r = (nl) - _p;
+	_t = _s - _p;
+	if (_r >= _ql)
+	  {
+	    _qh--;
+	    _r = _t;
+	  }
+*/
+#define udiv_qrnnd_preinv(q, r, nh, nl, d, di)				\
+  do {									\
+    mp_limb_t _qh, _ql, _r, _mask;					\
+    umul_ppmm (_qh, _ql, (nh), (di));					\
+    if (__builtin_constant_p (nl) && (nl) == 0)				\
+      {									\
+	_qh += (nh) + 1;						\
+	_r = - _qh * (d);						\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_qh += _mask;							\
+	_r += _mask & (d);						\
+      }									\
+    else								\
+      {									\
+	add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));		\
+	_r = (nl) - _qh * (d);						\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_qh += _mask;							\
+	_r += _mask & (d);						\
+	if (UNLIKELY (_r >= (d)))					\
+	  {								\
+	    _r -= (d);							\
+	    _qh++;							\
+	  }								\
+      }									\
+    (r) = _r;								\
+    (q) = _qh;								\
+  } while (0)
+
+/* Dividing (NH, NL) by D, returning the remainder only. Unlike
+   udiv_qrnnd_preinv, works also for the case NH == D, where the
+   quotient doesn't quite fit in a single limb. */
+#define udiv_rnnd_preinv(r, nh, nl, d, di)				\
+  do {									\
+    mp_limb_t _qh, _ql, _r, _mask;					\
+    umul_ppmm (_qh, _ql, (nh), (di));					\
+    if (__builtin_constant_p (nl) && (nl) == 0)				\
+      {									\
+	_r = ~(_qh + (nh)) * (d);					\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_r += _mask & (d);						\
+      }									\
+    else								\
+      {									\
+	add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));		\
+	_r = (nl) - _qh * (d);						\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_r += _mask & (d);						\
+	if (UNLIKELY (_r >= (d)))					\
+	  _r -= (d);							\
+      }									\
+    (r) = _r;								\
+  } while (0)
+
+/* Compute quotient the quotient and remainder for n / d. Requires d
+   >= B^2 / 2 and n < d B. di is the inverse
+
+     floor ((B^3 - 1) / (d0 + d1 B)) - B.
+
+   NOTE: Output variables are updated multiple times. Only some inputs
+   and outputs may overlap.
+*/
+#define udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv)		\
+  do {									\
+    mp_limb_t _q0, _t1, _t0, _mask;					\
+    umul_ppmm ((q), _q0, (n2), (dinv));					\
+    add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1));			\
+									\
+    /* Compute the two most significant limbs of n - q'd */		\
+    (r1) = (n1) - (d1) * (q);						\
+    sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0));			\
+    umul_ppmm (_t1, _t0, (d0), (q));					\
+    sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0);			\
+    (q)++;								\
+									\
+    /* Conditionally adjust q and the remainders */			\
+    _mask = - (mp_limb_t) ((r1) >= _q0);				\
+    (q) += _mask;							\
+    add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0));	\
+    if (UNLIKELY ((r1) >= (d1)))					\
+      {									\
+	if ((r1) > (d1) || (r0) >= (d0))				\
+	  {								\
+	    (q)++;							\
+	    sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0));		\
+	  }								\
+      }									\
+  } while (0)
+
+#ifndef mpn_preinv_divrem_1  /* if not done with cpuvec in a fat binary */
+#define   mpn_preinv_divrem_1 __MPN(preinv_divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int);
+#endif
+
+
+/* USE_PREINV_DIVREM_1 is whether to use mpn_preinv_divrem_1, as opposed to the
+   plain mpn_divrem_1.  The default is yes, since the few CISC chips where
+   preinv is not good have defines saying so.  */
+#ifndef USE_PREINV_DIVREM_1
+#define USE_PREINV_DIVREM_1   1
+#endif
+
+#if USE_PREINV_DIVREM_1
+#define MPN_DIVREM_OR_PREINV_DIVREM_1(qp,xsize,ap,size,d,dinv,shift)    \
+  mpn_preinv_divrem_1 (qp, xsize, ap, size, d, dinv, shift)
+#else
+#define MPN_DIVREM_OR_PREINV_DIVREM_1(qp,xsize,ap,size,d,dinv,shift)    \
+  mpn_divrem_1 (qp, xsize, ap, size, d)
+#endif
+
+#ifndef PREINV_MOD_1_TO_MOD_1_THRESHOLD
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD 10
+#endif
+
+/* This selection may seem backwards.  The reason mpn_mod_1 typically takes
+   over for larger sizes is that it uses the mod_1_1 function.  */
+#define MPN_MOD_OR_PREINV_MOD_1(src,size,divisor,inverse)		\
+  (BELOW_THRESHOLD (size, PREINV_MOD_1_TO_MOD_1_THRESHOLD)		\
+   ? mpn_preinv_mod_1 (src, size, divisor, inverse)			\
+   : mpn_mod_1 (src, size, divisor))
+
+
+#ifndef mpn_mod_34lsub1  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_34lsub1 __MPN(mod_34lsub1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_34lsub1 (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#endif
+
+
+/* DIVEXACT_1_THRESHOLD is at what size to use mpn_divexact_1, as opposed to
+   plain mpn_divrem_1.  Likewise BMOD_1_TO_MOD_1_THRESHOLD for
+   mpn_modexact_1_odd against plain mpn_mod_1.  On most CPUs divexact and
+   modexact are faster at all sizes, so the defaults are 0.  Those CPUs
+   where this is not right have a tuned threshold.  */
+#ifndef DIVEXACT_1_THRESHOLD
+#define DIVEXACT_1_THRESHOLD  0
+#endif
+#ifndef BMOD_1_TO_MOD_1_THRESHOLD
+#define BMOD_1_TO_MOD_1_THRESHOLD  10
+#endif
+
+#define MPN_DIVREM_OR_DIVEXACT_1(rp, up, n, d)				\
+  do {									\
+    if (BELOW_THRESHOLD (n, DIVEXACT_1_THRESHOLD))			\
+      ASSERT_NOCARRY (mpn_divrem_1 (rp, (mp_size_t) 0, up, n, d));	\
+    else								\
+      {									\
+	ASSERT (mpn_mod_1 (up, n, d) == 0);				\
+	mpn_divexact_1 (rp, up, n, d);					\
+      }									\
+  } while (0)
+
+#ifndef mpn_modexact_1c_odd  /* if not done with cpuvec in a fat binary */
+#define mpn_modexact_1c_odd __MPN(modexact_1c_odd)
+__GMP_DECLSPEC mp_limb_t mpn_modexact_1c_odd (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#if HAVE_NATIVE_mpn_modexact_1_odd
+#define   mpn_modexact_1_odd  __MPN(modexact_1_odd)
+__GMP_DECLSPEC mp_limb_t mpn_modexact_1_odd (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+#else
+#define mpn_modexact_1_odd(src,size,divisor) \
+  mpn_modexact_1c_odd (src, size, divisor, CNST_LIMB(0))
+#endif
+
+#define MPN_MOD_OR_MODEXACT_1_ODD(src,size,divisor)			\
+  (BELOW_THRESHOLD (size, BMOD_1_TO_MOD_1_THRESHOLD)			\
+   ? mpn_modexact_1_odd (src, size, divisor)				\
+   : mpn_mod_1 (src, size, divisor))
+
+/* binvert_limb() sets inv to the multiplicative inverse of n modulo
+   2^GMP_NUMB_BITS, ie. satisfying inv*n == 1 mod 2^GMP_NUMB_BITS.
+   n must be odd (otherwise such an inverse doesn't exist).
+
+   This is not to be confused with invert_limb(), which is completely
+   different.
+
+   The table lookup gives an inverse with the low 8 bits valid, and each
+   multiply step doubles the number of bits.  See Jebelean "An algorithm for
+   exact division" end of section 4 (reference in gmp.texi).
+
+   Possible enhancement: Could use UHWtype until the last step, if half-size
+   multiplies are faster (might help under _LONG_LONG_LIMB).
+
+   Alternative: As noted in Granlund and Montgomery "Division by Invariant
+   Integers using Multiplication" (reference in gmp.texi), n itself gives a
+   3-bit inverse immediately, and could be used instead of a table lookup.
+   A 4-bit inverse can be obtained effectively from xoring bits 1 and 2 into
+   bit 3, for instance with (((n + 2) & 4) << 1) ^ n.  */
+
+#define binvert_limb_table  __gmp_binvert_limb_table
+__GMP_DECLSPEC extern const unsigned char  binvert_limb_table[128];
+
+#define binvert_limb(inv,n)						\
+  do {									\
+    mp_limb_t  __n = (n);						\
+    mp_limb_t  __inv;							\
+    ASSERT ((__n & 1) == 1);						\
+									\
+    __inv = binvert_limb_table[(__n/2) & 0x7F]; /*  8 */		\
+    if (GMP_NUMB_BITS > 8)   __inv = 2 * __inv - __inv * __inv * __n;	\
+    if (GMP_NUMB_BITS > 16)  __inv = 2 * __inv - __inv * __inv * __n;	\
+    if (GMP_NUMB_BITS > 32)  __inv = 2 * __inv - __inv * __inv * __n;	\
+									\
+    if (GMP_NUMB_BITS > 64)						\
+      {									\
+	int  __invbits = 64;						\
+	do {								\
+	  __inv = 2 * __inv - __inv * __inv * __n;			\
+	  __invbits *= 2;						\
+	} while (__invbits < GMP_NUMB_BITS);				\
+      }									\
+									\
+    ASSERT ((__inv * __n & GMP_NUMB_MASK) == 1);			\
+    (inv) = __inv & GMP_NUMB_MASK;					\
+  } while (0)
+#define modlimb_invert binvert_limb  /* backward compatibility */
+
+/* Multiplicative inverse of 3, modulo 2^GMP_NUMB_BITS.
+   Eg. 0xAAAAAAAB for 32 bits, 0xAAAAAAAAAAAAAAAB for 64 bits.
+   GMP_NUMB_MAX/3*2+1 is right when GMP_NUMB_BITS is even, but when it's odd
+   we need to start from GMP_NUMB_MAX>>1. */
+#define MODLIMB_INVERSE_3 (((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 2)) / 3) * 2 + 1)
+
+/* ceil(GMP_NUMB_MAX/3) and ceil(2*GMP_NUMB_MAX/3).
+   These expressions work because GMP_NUMB_MAX%3 != 0 for all GMP_NUMB_BITS. */
+#define GMP_NUMB_CEIL_MAX_DIV3   (GMP_NUMB_MAX / 3 + 1)
+#define GMP_NUMB_CEIL_2MAX_DIV3  ((GMP_NUMB_MAX>>1) / 3 + 1 + GMP_NUMB_HIGHBIT)
+
+
+/* Set r to -a mod d.  a>=d is allowed.  Can give r>d.  All should be limbs.
+
+   It's not clear whether this is the best way to do this calculation.
+   Anything congruent to -a would be fine for the one limb congruence
+   tests.  */
+
+#define NEG_MOD(r, a, d)						\
+  do {									\
+    ASSERT ((d) != 0);							\
+    ASSERT_LIMB (a);							\
+    ASSERT_LIMB (d);							\
+									\
+    if ((a) <= (d))							\
+      {									\
+	/* small a is reasonably likely */				\
+	(r) = (d) - (a);						\
+      }									\
+    else								\
+      {									\
+	unsigned   __twos;						\
+	mp_limb_t  __dnorm;						\
+	count_leading_zeros (__twos, d);				\
+	__twos -= GMP_NAIL_BITS;					\
+	__dnorm = (d) << __twos;					\
+	(r) = ((a) <= __dnorm ? __dnorm : 2*__dnorm) - (a);		\
+      }									\
+									\
+    ASSERT_LIMB (r);							\
+  } while (0)
+
+/* A bit mask of all the least significant zero bits of n, or -1 if n==0. */
+#define LOW_ZEROS_MASK(n)  (((n) & -(n)) - 1)
+
+
+/* ULONG_PARITY sets "p" to 1 if there's an odd number of 1 bits in "n", or
+   to 0 if there's an even number.  "n" should be an unsigned long and "p"
+   an int.  */
+
+#if defined (__GNUC__) && ! defined (NO_ASM) && HAVE_HOST_CPU_alpha_CIX
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    int __p;								\
+    __asm__ ("ctpop %1, %0" : "=r" (__p) : "r" (n));			\
+    (p) = __p & 1;							\
+  } while (0)
+#endif
+
+/* Cray intrinsic _popcnt. */
+#ifdef _CRAY
+#define ULONG_PARITY(p, n)      \
+  do {                          \
+    (p) = _popcnt (n) & 1;      \
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && defined (__ia64)
+/* unsigned long is either 32 or 64 bits depending on the ABI, zero extend
+   to a 64 bit unsigned long long for popcnt */
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    unsigned long long  __n = (unsigned long) (n);			\
+    int  __p;								\
+    __asm__ ("popcnt %0 = %1" : "=r" (__p) : "r" (__n));		\
+    (p) = __p & 1;							\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && HAVE_HOST_CPU_FAMILY_x86
+#if __GMP_GNUC_PREREQ (3,1)
+#define __GMP_qm "=Qm"
+#define __GMP_q "=Q"
+#else
+#define __GMP_qm "=qm"
+#define __GMP_q "=q"
+#endif
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    char	   __p;							\
+    unsigned long  __n = (n);						\
+    __n ^= (__n >> 16);							\
+    __asm__ ("xorb %h1, %b1\n\t"					\
+	     "setpo %0"							\
+	 : __GMP_qm (__p), __GMP_q (__n)				\
+	 : "1" (__n));							\
+    (p) = __p;								\
+  } while (0)
+#endif
+
+#if ! defined (ULONG_PARITY)
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    unsigned long  __n = (n);						\
+    int  __p = 0;							\
+    do									\
+      {									\
+	__p ^= 0x96696996L >> (__n & 0x1F);				\
+	__n >>= 5;							\
+      }									\
+    while (__n != 0);							\
+									\
+    (p) = __p & 1;							\
+  } while (0)
+#endif
+
+
+/* 3 cycles on 604 or 750 since shifts and rlwimi's can pair.  gcc (as of
+   version 3.1 at least) doesn't seem to know how to generate rlwimi for
+   anything other than bit-fields, so use "asm".  */
+#if defined (__GNUC__) && ! defined (NO_ASM)                    \
+  && HAVE_HOST_CPU_FAMILY_powerpc && GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    mp_limb_t  __bswapl_src = (src);					\
+    mp_limb_t  __tmp1 = __bswapl_src >> 24;		/* low byte */	\
+    mp_limb_t  __tmp2 = __bswapl_src << 24;		/* high byte */	\
+    __asm__ ("rlwimi %0, %2, 24, 16, 23"		/* 2nd low */	\
+	 : "=r" (__tmp1) : "0" (__tmp1), "r" (__bswapl_src));		\
+    __asm__ ("rlwimi %0, %2,  8,  8, 15"		/* 3nd high */	\
+	 : "=r" (__tmp2) : "0" (__tmp2), "r" (__bswapl_src));		\
+    (dst) = __tmp1 | __tmp2;				/* whole */	\
+  } while (0)
+#endif
+
+/* bswap is available on i486 and up and is fast.  A combination rorw $8 /
+   roll $16 / rorw $8 is used in glibc for plain i386 (and in the linux
+   kernel with xchgb instead of rorw), but this is not done here, because
+   i386 means generic x86 and mixing word and dword operations will cause
+   partial register stalls on P6 chips.  */
+#if defined (__GNUC__) && ! defined (NO_ASM)            \
+  && HAVE_HOST_CPU_FAMILY_x86 && ! HAVE_HOST_CPU_i386   \
+  && GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    __asm__ ("bswap %0" : "=r" (dst) : "0" (src));			\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (NO_ASM)            \
+  && defined (__amd64__) && GMP_LIMB_BITS == 64
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    __asm__ ("bswap %q0" : "=r" (dst) : "0" (src));			\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && defined (__ia64) && GMP_LIMB_BITS == 64
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    __asm__ ("mux1 %0 = %1, @rev" : "=r" (dst) :  "r" (src));		\
+  } while (0)
+#endif
+
+/* As per glibc. */
+#if defined (__GNUC__) && ! defined (NO_ASM)                    \
+  && HAVE_HOST_CPU_FAMILY_m68k && GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    mp_limb_t  __bswapl_src = (src);					\
+    __asm__ ("ror%.w %#8, %0\n\t"					\
+	     "swap   %0\n\t"						\
+	     "ror%.w %#8, %0"						\
+	     : "=d" (dst)						\
+	     : "0" (__bswapl_src));					\
+  } while (0)
+#endif
+
+#if ! defined (BSWAP_LIMB)
+#if GMP_LIMB_BITS == 8
+#define BSWAP_LIMB(dst, src)				\
+  do { (dst) = (src); } while (0)
+#endif
+#if GMP_LIMB_BITS == 16
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    (dst) = ((src) << 8) + ((src) >> 8);				\
+  } while (0)
+#endif
+#if GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    (dst) =								\
+      ((src) << 24)							\
+      + (((src) & 0xFF00) << 8)						\
+      + (((src) >> 8) & 0xFF00)						\
+      + ((src) >> 24);							\
+  } while (0)
+#endif
+#if GMP_LIMB_BITS == 64
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    (dst) =								\
+      ((src) << 56)							\
+      + (((src) & 0xFF00) << 40)					\
+      + (((src) & 0xFF0000) << 24)					\
+      + (((src) & 0xFF000000) << 8)					\
+      + (((src) >> 8) & 0xFF000000)					\
+      + (((src) >> 24) & 0xFF0000)					\
+      + (((src) >> 40) & 0xFF00)					\
+      + ((src) >> 56);							\
+  } while (0)
+#endif
+#endif
+
+#if ! defined (BSWAP_LIMB)
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    mp_limb_t  __bswapl_src = (src);					\
+    mp_limb_t  __dstl = 0;						\
+    int	       __i;							\
+    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)			\
+      {									\
+	__dstl = (__dstl << 8) | (__bswapl_src & 0xFF);			\
+	__bswapl_src >>= 8;						\
+      }									\
+    (dst) = __dstl;							\
+  } while (0)
+#endif
+
+
+/* Apparently lwbrx might be slow on some PowerPC chips, so restrict it to
+   those we know are fast.  */
+#if defined (__GNUC__) && ! defined (NO_ASM)				\
+  && GMP_LIMB_BITS == 32 && HAVE_LIMB_BIG_ENDIAN			\
+  && (HAVE_HOST_CPU_powerpc604						\
+      || HAVE_HOST_CPU_powerpc604e					\
+      || HAVE_HOST_CPU_powerpc750					\
+      || HAVE_HOST_CPU_powerpc7400)
+#define BSWAP_LIMB_FETCH(limb, src)					\
+  do {									\
+    mp_srcptr  __blf_src = (src);					\
+    mp_limb_t  __limb;							\
+    __asm__ ("lwbrx %0, 0, %1"						\
+	     : "=r" (__limb)						\
+	     : "r" (__blf_src),						\
+	       "m" (*__blf_src));					\
+    (limb) = __limb;							\
+  } while (0)
+#endif
+
+#if ! defined (BSWAP_LIMB_FETCH)
+#define BSWAP_LIMB_FETCH(limb, src)  BSWAP_LIMB (limb, *(src))
+#endif
+
+
+/* On the same basis that lwbrx might be slow, restrict stwbrx to those we
+   know are fast.  FIXME: Is this necessary?  */
+#if defined (__GNUC__) && ! defined (NO_ASM)				\
+  && GMP_LIMB_BITS == 32 && HAVE_LIMB_BIG_ENDIAN			\
+  && (HAVE_HOST_CPU_powerpc604						\
+      || HAVE_HOST_CPU_powerpc604e					\
+      || HAVE_HOST_CPU_powerpc750					\
+      || HAVE_HOST_CPU_powerpc7400)
+#define BSWAP_LIMB_STORE(dst, limb)					\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_limb_t  __limb = (limb);						\
+    __asm__ ("stwbrx %1, 0, %2"						\
+	     : "=m" (*__dst)						\
+	     : "r" (__limb),						\
+	       "r" (__dst));						\
+  } while (0)
+#endif
+
+#if ! defined (BSWAP_LIMB_STORE)
+#define BSWAP_LIMB_STORE(dst, limb)  BSWAP_LIMB (*(dst), limb)
+#endif
+
+
+/* Byte swap limbs from {src,size} and store at {dst,size}. */
+#define MPN_BSWAP(dst, src, size)					\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_srcptr  __src = (src);						\
+    mp_size_t  __size = (size);						\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));			\
+    CRAY_Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < __size; __i++)					\
+      {									\
+	BSWAP_LIMB_FETCH (*__dst, __src);				\
+	__dst++;							\
+	__src++;							\
+      }									\
+  } while (0)
+
+/* Byte swap limbs from {dst,size} and store in reverse order at {src,size}. */
+#define MPN_BSWAP_REVERSE(dst, src, size)				\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_size_t  __size = (size);						\
+    mp_srcptr  __src = (src) + __size - 1;				\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    ASSERT (! MPN_OVERLAP_P (dst, size, src, size));			\
+    CRAY_Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < __size; __i++)					\
+      {									\
+	BSWAP_LIMB_FETCH (*__dst, __src);				\
+	__dst++;							\
+	__src--;							\
+      }									\
+  } while (0)
+
+
+/* No processor claiming to be SPARC v9 compliant seems to
+   implement the POPC instruction.  Disable pattern for now.  */
+#if 0
+#if defined __GNUC__ && defined __sparc_v9__ && GMP_LIMB_BITS == 64
+#define popc_limb(result, input)					\
+  do {									\
+    DItype __res;							\
+    __asm__ ("popc %1,%0" : "=r" (result) : "rI" (input));		\
+  } while (0)
+#endif
+#endif
+
+#if defined (__GNUC__) && ! defined (NO_ASM) && HAVE_HOST_CPU_alpha_CIX
+#define popc_limb(result, input)					\
+  do {									\
+    __asm__ ("ctpop %1, %0" : "=r" (result) : "r" (input));		\
+  } while (0)
+#endif
+
+/* Cray intrinsic. */
+#ifdef _CRAY
+#define popc_limb(result, input)					\
+  do {									\
+    (result) = _popcnt (input);						\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && defined (__ia64) && GMP_LIMB_BITS == 64
+#define popc_limb(result, input)					\
+  do {									\
+    __asm__ ("popcnt %0 = %1" : "=r" (result) : "r" (input));		\
+  } while (0)
+#endif
+
+/* Cool population count of an mp_limb_t.
+   You have to figure out how this works, We won't tell you!
+
+   The constants could also be expressed as:
+     0x55... = [2^N / 3]     = [(2^N-1)/3]
+     0x33... = [2^N / 5]     = [(2^N-1)/5]
+     0x0f... = [2^N / 17]    = [(2^N-1)/17]
+     (N is GMP_LIMB_BITS, [] denotes truncation.) */
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 8
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x = ((__x >> 4) + __x);						\
+    (result) = __x & 0x0f;						\
+  } while (0)
+#endif
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 16
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x += (__x >> 4);							\
+    __x = ((__x >> 8) & MP_LIMB_T_MAX/4369)+(__x & MP_LIMB_T_MAX/4369);	\
+    (result) = __x;							\
+  } while (0)
+#endif
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 32
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x = ((__x >> 4) + __x) & MP_LIMB_T_MAX/17;			\
+    __x = ((__x >> 8) + __x);						\
+    __x = ((__x >> 16) + __x);						\
+    (result) = __x & 0xff;						\
+  } while (0)
+#endif
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 64
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x = ((__x >> 4) + __x) & MP_LIMB_T_MAX/17;			\
+    __x = ((__x >> 8) + __x);						\
+    __x = ((__x >> 16) + __x);						\
+    __x = ((__x >> 32) + __x);						\
+    (result) = __x & 0xff;						\
+  } while (0)
+#endif
+
+
+/* Define stuff for longlong.h.  */
+#if HAVE_ATTRIBUTE_MODE
+typedef unsigned int UQItype	__attribute__ ((mode (QI)));
+typedef		 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef unsigned int UDItype	__attribute__ ((mode (DI)));
+#else
+typedef unsigned char UQItype;
+typedef		 long SItype;
+typedef unsigned long USItype;
+#if HAVE_LONG_LONG
+typedef	long long int DItype;
+typedef unsigned long long int UDItype;
+#else /* Assume `long' gives us a wide enough type.  Needed for hppa2.0w.  */
+typedef long int DItype;
+typedef unsigned long int UDItype;
+#endif
+#endif
+
+typedef mp_limb_t UWtype;
+typedef unsigned int UHWtype;
+#define W_TYPE_SIZE GMP_LIMB_BITS
+
+/* Define ieee_double_extract and _GMP_IEEE_FLOATS.
+
+   Bit field packing is "implementation defined" according to C99, which
+   leaves us at the compiler's mercy here.  For some systems packing is
+   defined in the ABI (eg. x86).  In any case so far it seems universal that
+   little endian systems pack from low to high, and big endian from high to
+   low within the given type.
+
+   Within the fields we rely on the integer endianness being the same as the
+   float endianness, this is true everywhere we know of and it'd be a fairly
+   strange system that did anything else.  */
+
+#if HAVE_DOUBLE_IEEE_LITTLE_SWAPPED
+#define _GMP_IEEE_FLOATS 1
+union ieee_double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t manh:20;
+      gmp_uint_least32_t exp:11;
+      gmp_uint_least32_t sig:1;
+      gmp_uint_least32_t manl:32;
+    } s;
+  double d;
+};
+#endif
+
+#if HAVE_DOUBLE_IEEE_LITTLE_ENDIAN
+#define _GMP_IEEE_FLOATS 1
+union ieee_double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t manl:32;
+      gmp_uint_least32_t manh:20;
+      gmp_uint_least32_t exp:11;
+      gmp_uint_least32_t sig:1;
+    } s;
+  double d;
+};
+#endif
+
+#if HAVE_DOUBLE_IEEE_BIG_ENDIAN
+#define _GMP_IEEE_FLOATS 1
+union ieee_double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t sig:1;
+      gmp_uint_least32_t exp:11;
+      gmp_uint_least32_t manh:20;
+      gmp_uint_least32_t manl:32;
+    } s;
+  double d;
+};
+#endif
+
+#if HAVE_DOUBLE_VAX_D
+union double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t man3:7;	/* highest 7 bits */
+      gmp_uint_least32_t exp:8;		/* excess-128 exponent */
+      gmp_uint_least32_t sig:1;
+      gmp_uint_least32_t man2:16;
+      gmp_uint_least32_t man1:16;
+      gmp_uint_least32_t man0:16;	/* lowest 16 bits */
+    } s;
+  double d;
+};
+#endif
+
+/* Use (4.0 * ...) instead of (2.0 * ...) to work around buggy compilers
+   that don't convert ulong->double correctly (eg. SunOS 4 native cc).  */
+#define MP_BASE_AS_DOUBLE (4.0 * ((mp_limb_t) 1 << (GMP_NUMB_BITS - 2)))
+/* Maximum number of limbs it will take to store any `double'.
+   We assume doubles have 53 mantissa bits.  */
+#define LIMBS_PER_DOUBLE ((53 + GMP_NUMB_BITS - 2) / GMP_NUMB_BITS + 1)
+
+__GMP_DECLSPEC int __gmp_extract_double (mp_ptr, double);
+
+#define mpn_get_d __gmpn_get_d
+__GMP_DECLSPEC double mpn_get_d (mp_srcptr, mp_size_t, mp_size_t, long) __GMP_ATTRIBUTE_PURE;
+
+
+/* DOUBLE_NAN_INF_ACTION executes code a_nan if x is a NaN, or executes
+   a_inf if x is an infinity.  Both are considered unlikely values, for
+   branch prediction.  */
+
+#if _GMP_IEEE_FLOATS
+#define DOUBLE_NAN_INF_ACTION(x, a_nan, a_inf)				\
+  do {									\
+    union ieee_double_extract  u;					\
+    u.d = (x);								\
+    if (UNLIKELY (u.s.exp == 0x7FF))					\
+      {									\
+	if (u.s.manl == 0 && u.s.manh == 0)				\
+	  { a_inf; }							\
+	else								\
+	  { a_nan; }							\
+      }									\
+  } while (0)
+#endif
+
+#if HAVE_DOUBLE_VAX_D || HAVE_DOUBLE_VAX_G || HAVE_DOUBLE_CRAY_CFP
+/* no nans or infs in these formats */
+#define DOUBLE_NAN_INF_ACTION(x, a_nan, a_inf)  \
+  do { } while (0)
+#endif
+
+#ifndef DOUBLE_NAN_INF_ACTION
+/* Unknown format, try something generic.
+   NaN should be "unordered", so x!=x.
+   Inf should be bigger than DBL_MAX.  */
+#define DOUBLE_NAN_INF_ACTION(x, a_nan, a_inf)				\
+  do {									\
+    {									\
+      if (UNLIKELY ((x) != (x)))					\
+	{ a_nan; }							\
+      else if (UNLIKELY ((x) > DBL_MAX || (x) < -DBL_MAX))		\
+	{ a_inf; }							\
+    }									\
+  } while (0)
+#endif
+
+/* On m68k, x86 and amd64, gcc (and maybe other compilers) can hold doubles
+   in the coprocessor, which means a bigger exponent range than normal, and
+   depending on the rounding mode, a bigger mantissa than normal.  (See
+   "Disappointments" in the gcc manual.)  FORCE_DOUBLE stores and fetches
+   "d" through memory to force any rounding and overflows to occur.
+
+   On amd64, and on x86s with SSE2, gcc (depending on options) uses the xmm
+   registers, where there's no such extra precision and no need for the
+   FORCE_DOUBLE.  We don't bother to detect this since the present uses for
+   FORCE_DOUBLE are only in test programs and default generic C code.
+
+   Not quite sure that an "automatic volatile" will use memory, but it does
+   in gcc.  An asm("":"=m"(d):"0"(d)) can't be used to trick gcc, since
+   apparently matching operands like "0" are only allowed on a register
+   output.  gcc 3.4 warns about this, though in fact it and past versions
+   seem to put the operand through memory as hoped.  */
+
+#if (HAVE_HOST_CPU_FAMILY_m68k || HAVE_HOST_CPU_FAMILY_x86      \
+     || defined (__amd64__))
+#define FORCE_DOUBLE(d) \
+  do { volatile double __gmp_force = (d); (d) = __gmp_force; } while (0)
+#else
+#define FORCE_DOUBLE(d)  do { } while (0)
+#endif
+
+
+__GMP_DECLSPEC extern const unsigned char __gmp_digit_value_tab[];
+
+__GMP_DECLSPEC extern int __gmp_junk;
+__GMP_DECLSPEC extern const int __gmp_0;
+__GMP_DECLSPEC void __gmp_exception (int) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_divide_by_zero (void) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_sqrt_of_negative (void) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_overflow_in_mpz (void) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_invalid_operation (void) ATTRIBUTE_NORETURN;
+#define GMP_ERROR(code)   __gmp_exception (code)
+#define DIVIDE_BY_ZERO    __gmp_divide_by_zero ()
+#define SQRT_OF_NEGATIVE  __gmp_sqrt_of_negative ()
+#define MPZ_OVERFLOW      __gmp_overflow_in_mpz ()
+
+#if defined _LONG_LONG_LIMB
+#define CNST_LIMB(C) ((mp_limb_t) C##LL)
+#else /* not _LONG_LONG_LIMB */
+#define CNST_LIMB(C) ((mp_limb_t) C##L)
+#endif /* _LONG_LONG_LIMB */
+
+/* Stuff used by mpn/generic/perfsqr.c and mpz/prime_p.c */
+#if GMP_NUMB_BITS == 2
+#define PP 0x3					/* 3 */
+#define PP_FIRST_OMITTED 5
+#endif
+#if GMP_NUMB_BITS == 4
+#define PP 0xF					/* 3 x 5 */
+#define PP_FIRST_OMITTED 7
+#endif
+#if GMP_NUMB_BITS == 8
+#define PP 0x69					/* 3 x 5 x 7 */
+#define PP_FIRST_OMITTED 11
+#endif
+#if GMP_NUMB_BITS == 16
+#define PP 0x3AA7				/* 3 x 5 x 7 x 11 x 13 */
+#define PP_FIRST_OMITTED 17
+#endif
+#if GMP_NUMB_BITS == 32
+#define PP 0xC0CFD797L				/* 3 x 5 x 7 x 11 x ... x 29 */
+#define PP_INVERTED 0x53E5645CL
+#define PP_FIRST_OMITTED 31
+#endif
+#if GMP_NUMB_BITS == 64
+#define PP CNST_LIMB(0xE221F97C30E94E1D)	/* 3 x 5 x 7 x 11 x ... x 53 */
+#define PP_INVERTED CNST_LIMB(0x21CFE6CFC938B36B)
+#define PP_FIRST_OMITTED 59
+#endif
+#ifndef PP_FIRST_OMITTED
+#define PP_FIRST_OMITTED 3
+#endif
+
+typedef struct
+{
+  mp_limb_t d0, d1;
+} mp_double_limb_t;
+
+#define mpn_gcd_22 __MPN (gcd_22)
+__GMP_DECLSPEC mp_double_limb_t mpn_gcd_22 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+/* BIT1 means a result value in bit 1 (second least significant bit), with a
+   zero bit representing +1 and a one bit representing -1.  Bits other than
+   bit 1 are garbage.  These are meant to be kept in "int"s, and casts are
+   used to ensure the expressions are "int"s even if a and/or b might be
+   other types.
+
+   JACOBI_TWOS_U_BIT1 and JACOBI_RECIP_UU_BIT1 are used in mpn_jacobi_base
+   and their speed is important.  Expressions are used rather than
+   conditionals to accumulate sign changes, which effectively means XORs
+   instead of conditional JUMPs. */
+
+/* (a/0), with a signed; is 1 if a=+/-1, 0 otherwise */
+#define JACOBI_S0(a)   (((a) == 1) | ((a) == -1))
+
+/* (a/0), with a unsigned; is 1 if a=+/-1, 0 otherwise */
+#define JACOBI_U0(a)   ((a) == 1)
+
+/* FIXME: JACOBI_LS0 and JACOBI_0LS are the same, so delete one and
+   come up with a better name. */
+
+/* (a/0), with a given by low and size;
+   is 1 if a=+/-1, 0 otherwise */
+#define JACOBI_LS0(alow,asize) \
+  (((asize) == 1 || (asize) == -1) && (alow) == 1)
+
+/* (a/0), with a an mpz_t;
+   fetch of low limb always valid, even if size is zero */
+#define JACOBI_Z0(a)   JACOBI_LS0 (PTR(a)[0], SIZ(a))
+
+/* (0/b), with b unsigned; is 1 if b=1, 0 otherwise */
+#define JACOBI_0U(b)   ((b) == 1)
+
+/* (0/b), with b unsigned; is 1 if b=+/-1, 0 otherwise */
+#define JACOBI_0S(b)   ((b) == 1 || (b) == -1)
+
+/* (0/b), with b given by low and size; is 1 if b=+/-1, 0 otherwise */
+#define JACOBI_0LS(blow,bsize) \
+  (((bsize) == 1 || (bsize) == -1) && (blow) == 1)
+
+/* Convert a bit1 to +1 or -1. */
+#define JACOBI_BIT1_TO_PN(result_bit1) \
+  (1 - ((int) (result_bit1) & 2))
+
+/* (2/b), with b unsigned and odd;
+   is (-1)^((b^2-1)/8) which is 1 if b==1,7mod8 or -1 if b==3,5mod8 and
+   hence obtained from (b>>1)^b */
+#define JACOBI_TWO_U_BIT1(b) \
+  ((int) (((b) >> 1) ^ (b)))
+
+/* (2/b)^twos, with b unsigned and odd */
+#define JACOBI_TWOS_U_BIT1(twos, b) \
+  ((int) ((twos) << 1) & JACOBI_TWO_U_BIT1 (b))
+
+/* (2/b)^twos, with b unsigned and odd */
+#define JACOBI_TWOS_U(twos, b) \
+  (JACOBI_BIT1_TO_PN (JACOBI_TWOS_U_BIT1 (twos, b)))
+
+/* (-1/b), with b odd (signed or unsigned);
+   is (-1)^((b-1)/2) */
+#define JACOBI_N1B_BIT1(b) \
+  ((int) (b))
+
+/* (a/b) effect due to sign of a: signed/unsigned, b odd;
+   is (-1/b) if a<0, or +1 if a>=0 */
+#define JACOBI_ASGN_SU_BIT1(a, b) \
+  ((((a) < 0) << 1) & JACOBI_N1B_BIT1(b))
+
+/* (a/b) effect due to sign of b: signed/signed;
+   is -1 if a and b both negative, +1 otherwise */
+#define JACOBI_BSGN_SS_BIT1(a, b) \
+  ((((a)<0) & ((b)<0)) << 1)
+
+/* (a/b) effect due to sign of b: signed/mpz;
+   is -1 if a and b both negative, +1 otherwise */
+#define JACOBI_BSGN_SZ_BIT1(a, b) \
+  JACOBI_BSGN_SS_BIT1 (a, SIZ(b))
+
+/* (a/b) effect due to sign of b: mpz/signed;
+   is -1 if a and b both negative, +1 otherwise */
+#define JACOBI_BSGN_ZS_BIT1(a, b) \
+  JACOBI_BSGN_SZ_BIT1 (b, a)
+
+/* (a/b) reciprocity to switch to (b/a), a,b both unsigned and odd;
+   is (-1)^((a-1)*(b-1)/4), which means +1 if either a,b==1mod4, or -1 if
+   both a,b==3mod4, achieved in bit 1 by a&b.  No ASSERT()s about a,b odd
+   because this is used in a couple of places with only bit 1 of a or b
+   valid. */
+#define JACOBI_RECIP_UU_BIT1(a, b) \
+  ((int) ((a) & (b)))
+
+/* Strip low zero limbs from {b_ptr,b_size} by incrementing b_ptr and
+   decrementing b_size.  b_low should be b_ptr[0] on entry, and will be
+   updated for the new b_ptr.  result_bit1 is updated according to the
+   factors of 2 stripped, as per (a/2).  */
+#define JACOBI_STRIP_LOW_ZEROS(result_bit1, a, b_ptr, b_size, b_low)	\
+  do {									\
+    ASSERT ((b_size) >= 1);						\
+    ASSERT ((b_low) == (b_ptr)[0]);					\
+									\
+    while (UNLIKELY ((b_low) == 0))					\
+      {									\
+	(b_size)--;							\
+	ASSERT ((b_size) >= 1);						\
+	(b_ptr)++;							\
+	(b_low) = *(b_ptr);						\
+									\
+	ASSERT (((a) & 1) != 0);					\
+	if ((GMP_NUMB_BITS % 2) == 1)					\
+	  (result_bit1) ^= JACOBI_TWO_U_BIT1(a);			\
+      }									\
+  } while (0)
+
+/* Set a_rem to {a_ptr,a_size} reduced modulo b, either using mod_1 or
+   modexact_1_odd, but in either case leaving a_rem<b.  b must be odd and
+   unsigned.  modexact_1_odd effectively calculates -a mod b, and
+   result_bit1 is adjusted for the factor of -1.
+
+   The way mpn_modexact_1_odd sometimes bases its remainder on a_size and
+   sometimes on a_size-1 means if GMP_NUMB_BITS is odd we can't know what
+   factor to introduce into result_bit1, so for that case use mpn_mod_1
+   unconditionally.
+
+   FIXME: mpn_modexact_1_odd is more efficient, so some way to get it used
+   for odd GMP_NUMB_BITS would be good.  Perhaps it could mung its result,
+   or not skip a divide step, or something. */
+
+#define JACOBI_MOD_OR_MODEXACT_1_ODD(result_bit1, a_rem, a_ptr, a_size, b) \
+  do {									   \
+    mp_srcptr  __a_ptr	= (a_ptr);					   \
+    mp_size_t  __a_size = (a_size);					   \
+    mp_limb_t  __b	= (b);						   \
+									   \
+    ASSERT (__a_size >= 1);						   \
+    ASSERT (__b & 1);							   \
+									   \
+    if ((GMP_NUMB_BITS % 2) != 0					   \
+	|| ABOVE_THRESHOLD (__a_size, BMOD_1_TO_MOD_1_THRESHOLD))	   \
+      {									   \
+	(a_rem) = mpn_mod_1 (__a_ptr, __a_size, __b);			   \
+      }									   \
+    else								   \
+      {									   \
+	(result_bit1) ^= JACOBI_N1B_BIT1 (__b);				   \
+	(a_rem) = mpn_modexact_1_odd (__a_ptr, __a_size, __b);		   \
+      }									   \
+  } while (0)
+
+/* State for the Jacobi computation using Lehmer. */
+#define jacobi_table __gmp_jacobi_table
+__GMP_DECLSPEC extern const unsigned char jacobi_table[208];
+
+/* Bit layout for the initial state. b must be odd.
+
+      3  2  1 0
+   +--+--+--+--+
+   |a1|a0|b1| s|
+   +--+--+--+--+
+
+ */
+static inline unsigned
+mpn_jacobi_init (unsigned a, unsigned b, unsigned s)
+{
+  ASSERT (b & 1);
+  ASSERT (s <= 1);
+  return ((a & 3) << 2) + (b & 2) + s;
+}
+
+static inline int
+mpn_jacobi_finish (unsigned bits)
+{
+  /* (a, b) = (1,0) or (0,1) */
+  ASSERT ( (bits & 14) == 0);
+
+  return 1-2*(bits & 1);
+}
+
+static inline unsigned
+mpn_jacobi_update (unsigned bits, unsigned denominator, unsigned q)
+{
+  /* FIXME: Could halve table size by not including the e bit in the
+   * index, and instead xor when updating. Then the lookup would be
+   * like
+   *
+   *   bits ^= table[((bits & 30) << 2) + (denominator << 2) + q];
+   */
+
+  ASSERT (bits < 26);
+  ASSERT (denominator < 2);
+  ASSERT (q < 4);
+
+  /* For almost all calls, denominator is constant and quite often q
+     is constant too. So use addition rather than or, so the compiler
+     can put the constant part can into the offset of an indexed
+     addressing instruction.
+
+     With constant denominator, the below table lookup is compiled to
+
+       C Constant q = 1, constant denominator = 1
+       movzbl table+5(%eax,8), %eax
+
+     or
+
+       C q in %edx, constant denominator = 1
+       movzbl table+4(%edx,%eax,8), %eax
+
+     One could maintain the state preshifted 3 bits, to save a shift
+     here, but at least on x86, that's no real saving.
+  */
+  return jacobi_table[(bits << 3) + (denominator << 2) + q];
+}
+
+/* Matrix multiplication */
+#define   mpn_matrix22_mul __MPN(matrix22_mul)
+__GMP_DECLSPEC void      mpn_matrix22_mul (mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_matrix22_mul_itch __MPN(matrix22_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_matrix22_mul_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#ifndef MATRIX22_STRASSEN_THRESHOLD
+#define MATRIX22_STRASSEN_THRESHOLD 30
+#endif
+
+/* HGCD definitions */
+
+/* Extract one numb, shifting count bits left
+    ________  ________
+   |___xh___||___xl___|
+	  |____r____|
+   >count <
+
+   The count includes any nail bits, so it should work fine if count
+   is computed using count_leading_zeros. If GMP_NAIL_BITS > 0, all of
+   xh, xl and r include nail bits. Must have 0 < count < GMP_LIMB_BITS.
+
+   FIXME: Omit masking with GMP_NUMB_MASK, and let callers do that for
+   those calls where the count high bits of xh may be non-zero.
+*/
+
+#define MPN_EXTRACT_NUMB(count, xh, xl)				\
+  ((((xh) << ((count) - GMP_NAIL_BITS)) & GMP_NUMB_MASK) |	\
+   ((xl) >> (GMP_LIMB_BITS - (count))))
+
+
+/* The matrix non-negative M = (u, u'; v,v') keeps track of the
+   reduction (a;b) = M (alpha; beta) where alpha, beta are smaller
+   than a, b. The determinant must always be one, so that M has an
+   inverse (v', -u'; -v, u). Elements always fit in GMP_NUMB_BITS - 1
+   bits. */
+struct hgcd_matrix1
+{
+  mp_limb_t u[2][2];
+};
+
+#define mpn_hgcd2 __MPN (hgcd2)
+__GMP_DECLSPEC int mpn_hgcd2 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t,	struct hgcd_matrix1 *);
+
+#define mpn_hgcd_mul_matrix1_vector __MPN (hgcd_mul_matrix1_vector)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_mul_matrix1_vector (const struct hgcd_matrix1 *, mp_ptr, mp_srcptr, mp_ptr, mp_size_t);
+
+#define mpn_matrix22_mul1_inverse_vector __MPN (matrix22_mul1_inverse_vector)
+__GMP_DECLSPEC mp_size_t mpn_matrix22_mul1_inverse_vector (const struct hgcd_matrix1 *, mp_ptr, mp_srcptr, mp_ptr, mp_size_t);
+
+#define mpn_hgcd2_jacobi __MPN (hgcd2_jacobi)
+__GMP_DECLSPEC int mpn_hgcd2_jacobi (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1 *, unsigned *);
+
+struct hgcd_matrix
+{
+  mp_size_t alloc;		/* for sanity checking only */
+  mp_size_t n;
+  mp_ptr p[2][2];
+};
+
+#define MPN_HGCD_MATRIX_INIT_ITCH(n) (4 * ((n+1)/2 + 1))
+
+#define mpn_hgcd_matrix_init __MPN (hgcd_matrix_init)
+__GMP_DECLSPEC void mpn_hgcd_matrix_init (struct hgcd_matrix *, mp_size_t, mp_ptr);
+
+#define mpn_hgcd_matrix_update_q __MPN (hgcd_matrix_update_q)
+__GMP_DECLSPEC void mpn_hgcd_matrix_update_q (struct hgcd_matrix *, mp_srcptr, mp_size_t, unsigned, mp_ptr);
+
+#define mpn_hgcd_matrix_mul_1 __MPN (hgcd_matrix_mul_1)
+__GMP_DECLSPEC void mpn_hgcd_matrix_mul_1 (struct hgcd_matrix *, const struct hgcd_matrix1 *, mp_ptr);
+
+#define mpn_hgcd_matrix_mul __MPN (hgcd_matrix_mul)
+__GMP_DECLSPEC void mpn_hgcd_matrix_mul (struct hgcd_matrix *, const struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_matrix_adjust __MPN (hgcd_matrix_adjust)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_matrix_adjust (const struct hgcd_matrix *, mp_size_t, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+#define mpn_hgcd_step __MPN(hgcd_step)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_step (mp_size_t, mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_reduce __MPN(hgcd_reduce)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_reduce (struct hgcd_matrix *, mp_ptr, mp_ptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define mpn_hgcd_reduce_itch __MPN(hgcd_reduce_itch)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_reduce_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_hgcd_itch __MPN (hgcd_itch)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_hgcd __MPN (hgcd)
+__GMP_DECLSPEC mp_size_t mpn_hgcd (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_appr_itch __MPN (hgcd_appr_itch)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_appr_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_hgcd_appr __MPN (hgcd_appr)
+__GMP_DECLSPEC int mpn_hgcd_appr (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_jacobi __MPN (hgcd_jacobi)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_jacobi (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, unsigned *, mp_ptr);
+
+typedef void gcd_subdiv_step_hook(void *, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, int);
+
+/* Needs storage for the quotient */
+#define MPN_GCD_SUBDIV_STEP_ITCH(n) (n)
+
+#define mpn_gcd_subdiv_step __MPN(gcd_subdiv_step)
+__GMP_DECLSPEC mp_size_t mpn_gcd_subdiv_step (mp_ptr, mp_ptr, mp_size_t, mp_size_t, gcd_subdiv_step_hook *, void *, mp_ptr);
+
+struct gcdext_ctx
+{
+  /* Result parameters. */
+  mp_ptr gp;
+  mp_size_t gn;
+  mp_ptr up;
+  mp_size_t *usize;
+
+  /* Cofactors updated in each step. */
+  mp_size_t un;
+  mp_ptr u0, u1, tp;
+};
+
+#define mpn_gcdext_hook __MPN (gcdext_hook)
+gcd_subdiv_step_hook mpn_gcdext_hook;
+
+#define MPN_GCDEXT_LEHMER_N_ITCH(n) (4*(n) + 3)
+
+#define mpn_gcdext_lehmer_n __MPN(gcdext_lehmer_n)
+__GMP_DECLSPEC mp_size_t mpn_gcdext_lehmer_n (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+/* 4*(an + 1) + 4*(bn + 1) + an */
+#define MPN_GCDEXT_LEHMER_ITCH(an, bn) (5*(an) + 4*(bn) + 8)
+
+#ifndef HGCD_THRESHOLD
+#define HGCD_THRESHOLD 400
+#endif
+
+#ifndef HGCD_APPR_THRESHOLD
+#define HGCD_APPR_THRESHOLD 400
+#endif
+
+#ifndef HGCD_REDUCE_THRESHOLD
+#define HGCD_REDUCE_THRESHOLD 1000
+#endif
+
+#ifndef GCD_DC_THRESHOLD
+#define GCD_DC_THRESHOLD 1000
+#endif
+
+#ifndef GCDEXT_DC_THRESHOLD
+#define GCDEXT_DC_THRESHOLD 600
+#endif
+
+/* Definitions for mpn_set_str and mpn_get_str */
+struct powers
+{
+  mp_ptr p;			/* actual power value */
+  mp_size_t n;			/* # of limbs at p */
+  mp_size_t shift;		/* weight of lowest limb, in limb base B */
+  size_t digits_in_base;	/* number of corresponding digits */
+  int base;
+};
+typedef struct powers powers_t;
+#define mpn_str_powtab_alloc(n) ((n) + 2 * GMP_LIMB_BITS) /* FIXME: This can perhaps be trimmed */
+#define mpn_dc_set_str_itch(n) ((n) + GMP_LIMB_BITS)
+#define mpn_dc_get_str_itch(n) ((n) + GMP_LIMB_BITS)
+
+#define mpn_compute_powtab __MPN(compute_powtab)
+__GMP_DECLSPEC size_t mpn_compute_powtab (powers_t *, mp_ptr, mp_size_t, int);
+#define   mpn_dc_set_str __MPN(dc_set_str)
+__GMP_DECLSPEC mp_size_t mpn_dc_set_str (mp_ptr, const unsigned char *, size_t, const powers_t *, mp_ptr);
+#define   mpn_bc_set_str __MPN(bc_set_str)
+__GMP_DECLSPEC mp_size_t mpn_bc_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+
+/* __GMPF_BITS_TO_PREC applies a minimum 53 bits, rounds upwards to a whole
+   limb and adds an extra limb.  __GMPF_PREC_TO_BITS drops that extra limb,
+   hence giving back the user's size in bits rounded up.  Notice that
+   converting prec->bits->prec gives an unchanged value.  */
+#define __GMPF_BITS_TO_PREC(n)						\
+  ((mp_size_t) ((__GMP_MAX (53, n) + 2 * GMP_NUMB_BITS - 1) / GMP_NUMB_BITS))
+#define __GMPF_PREC_TO_BITS(n) \
+  ((mp_bitcnt_t) (n) * GMP_NUMB_BITS - GMP_NUMB_BITS)
+
+__GMP_DECLSPEC extern mp_size_t __gmp_default_fp_limb_precision;
+
+/* Compute the number of base-b digits corresponding to nlimbs limbs, rounding
+   down.  */
+#define DIGITS_IN_BASE_PER_LIMB(res, nlimbs, b)				\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    umul_ppmm (_ph, _dummy,						\
+	       mp_bases[b].logb2, GMP_NUMB_BITS * (mp_limb_t) (nlimbs));\
+    res = _ph;								\
+  } while (0)
+
+/* Compute the number of limbs corresponding to ndigits base-b digits, rounding
+   up.  */
+#define LIMBS_PER_DIGIT_IN_BASE(res, ndigits, b)			\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    umul_ppmm (_ph, _dummy, mp_bases[b].log2b, (mp_limb_t) (ndigits));	\
+    res = 8 * _ph / GMP_NUMB_BITS + 2;					\
+  } while (0)
+
+
+/* Set n to the number of significant digits an mpf of the given _mp_prec
+   field, in the given base.  This is a rounded up value, designed to ensure
+   there's enough digits to reproduce all the guaranteed part of the value.
+
+   There are prec many limbs, but the high might be only "1" so forget it
+   and just count prec-1 limbs into chars.  +1 rounds that upwards, and a
+   further +1 is because the limbs usually won't fall on digit boundaries.
+
+   FIXME: If base is a power of 2 and the bits per digit divides
+   GMP_LIMB_BITS then the +2 is unnecessary.  This happens always for
+   base==2, and in base==16 with the current 32 or 64 bit limb sizes. */
+
+#define MPF_SIGNIFICANT_DIGITS(n, base, prec)				\
+  do {									\
+    size_t rawn;							\
+    ASSERT (base >= 2 && base < numberof (mp_bases));			\
+    DIGITS_IN_BASE_PER_LIMB (rawn, (prec) - 1, base);			\
+    n = rawn + 2;							\
+  } while (0)
+
+
+/* Decimal point string, from the current C locale.  Needs <langinfo.h> for
+   nl_langinfo and constants, preferably with _GNU_SOURCE defined to get
+   DECIMAL_POINT from glibc, and needs <locale.h> for localeconv, each under
+   their respective #if HAVE_FOO_H.
+
+   GLIBC recommends nl_langinfo because getting only one facet can be
+   faster, apparently. */
+
+/* DECIMAL_POINT seems to need _GNU_SOURCE defined to get it from glibc. */
+#if HAVE_NL_LANGINFO && defined (DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (nl_langinfo (DECIMAL_POINT))
+#endif
+/* RADIXCHAR is deprecated, still in unix98 or some such. */
+#if HAVE_NL_LANGINFO && defined (RADIXCHAR) && ! defined (GMP_DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (nl_langinfo (RADIXCHAR))
+#endif
+/* localeconv is slower since it returns all locale stuff */
+#if HAVE_LOCALECONV && ! defined (GMP_DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (localeconv()->decimal_point)
+#endif
+#if ! defined (GMP_DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (".")
+#endif
+
+
+#define DOPRNT_CONV_FIXED        1
+#define DOPRNT_CONV_SCIENTIFIC   2
+#define DOPRNT_CONV_GENERAL      3
+
+#define DOPRNT_JUSTIFY_NONE      0
+#define DOPRNT_JUSTIFY_LEFT      1
+#define DOPRNT_JUSTIFY_RIGHT     2
+#define DOPRNT_JUSTIFY_INTERNAL  3
+
+#define DOPRNT_SHOWBASE_YES      1
+#define DOPRNT_SHOWBASE_NO       2
+#define DOPRNT_SHOWBASE_NONZERO  3
+
+struct doprnt_params_t {
+  int         base;          /* negative for upper case */
+  int         conv;          /* choices above */
+  const char  *expfmt;       /* exponent format */
+  int         exptimes4;     /* exponent multiply by 4 */
+  char        fill;          /* character */
+  int         justify;       /* choices above */
+  int         prec;          /* prec field, or -1 for all digits */
+  int         showbase;      /* choices above */
+  int         showpoint;     /* if radix point always shown */
+  int         showtrailing;  /* if trailing zeros wanted */
+  char        sign;          /* '+', ' ', or '\0' */
+  int         width;         /* width field */
+};
+
+#if _GMP_H_HAVE_VA_LIST
+
+typedef int (*doprnt_format_t) (void *, const char *, va_list);
+typedef int (*doprnt_memory_t) (void *, const char *, size_t);
+typedef int (*doprnt_reps_t)   (void *, int, int);
+typedef int (*doprnt_final_t)  (void *);
+
+struct doprnt_funs_t {
+  doprnt_format_t  format;
+  doprnt_memory_t  memory;
+  doprnt_reps_t    reps;
+  doprnt_final_t   final;   /* NULL if not required */
+};
+
+extern const struct doprnt_funs_t  __gmp_fprintf_funs;
+extern const struct doprnt_funs_t  __gmp_sprintf_funs;
+extern const struct doprnt_funs_t  __gmp_snprintf_funs;
+extern const struct doprnt_funs_t  __gmp_obstack_printf_funs;
+extern const struct doprnt_funs_t  __gmp_ostream_funs;
+
+/* "buf" is a __gmp_allocate_func block of "alloc" many bytes.  The first
+   "size" of these have been written.  "alloc > size" is maintained, so
+   there's room to store a '\0' at the end.  "result" is where the
+   application wants the final block pointer.  */
+struct gmp_asprintf_t {
+  char    **result;
+  char    *buf;
+  size_t  size;
+  size_t  alloc;
+};
+
+#define GMP_ASPRINTF_T_INIT(d, output)					\
+  do {									\
+    (d).result = (output);						\
+    (d).alloc = 256;							\
+    (d).buf = (char *) (*__gmp_allocate_func) ((d).alloc);		\
+    (d).size = 0;							\
+  } while (0)
+
+/* If a realloc is necessary, use twice the size actually required, so as to
+   avoid repeated small reallocs.  */
+#define GMP_ASPRINTF_T_NEED(d, n)					\
+  do {									\
+    size_t  alloc, newsize, newalloc;					\
+    ASSERT ((d)->alloc >= (d)->size + 1);				\
+									\
+    alloc = (d)->alloc;							\
+    newsize = (d)->size + (n);						\
+    if (alloc <= newsize)						\
+      {									\
+	newalloc = 2*newsize;						\
+	(d)->alloc = newalloc;						\
+	(d)->buf = __GMP_REALLOCATE_FUNC_TYPE ((d)->buf,		\
+					       alloc, newalloc, char);	\
+      }									\
+  } while (0)
+
+__GMP_DECLSPEC int __gmp_asprintf_memory (struct gmp_asprintf_t *, const char *, size_t);
+__GMP_DECLSPEC int __gmp_asprintf_reps (struct gmp_asprintf_t *, int, int);
+__GMP_DECLSPEC int __gmp_asprintf_final (struct gmp_asprintf_t *);
+
+/* buf is where to write the next output, and size is how much space is left
+   there.  If the application passed size==0 then that's what we'll have
+   here, and nothing at all should be written.  */
+struct gmp_snprintf_t {
+  char    *buf;
+  size_t  size;
+};
+
+/* Add the bytes printed by the call to the total retval, or bail out on an
+   error.  */
+#define DOPRNT_ACCUMULATE(call)						\
+  do {									\
+    int  __ret;								\
+    __ret = call;							\
+    if (__ret == -1)							\
+      goto error;							\
+    retval += __ret;							\
+  } while (0)
+#define DOPRNT_ACCUMULATE_FUN(fun, params)				\
+  do {									\
+    ASSERT ((fun) != NULL);						\
+    DOPRNT_ACCUMULATE ((*(fun)) params);				\
+  } while (0)
+
+#define DOPRNT_FORMAT(fmt, ap)						\
+  DOPRNT_ACCUMULATE_FUN (funs->format, (data, fmt, ap))
+#define DOPRNT_MEMORY(ptr, len)						\
+  DOPRNT_ACCUMULATE_FUN (funs->memory, (data, ptr, len))
+#define DOPRNT_REPS(c, n)						\
+  DOPRNT_ACCUMULATE_FUN (funs->reps, (data, c, n))
+
+#define DOPRNT_STRING(str)      DOPRNT_MEMORY (str, strlen (str))
+
+#define DOPRNT_REPS_MAYBE(c, n)						\
+  do {									\
+    if ((n) != 0)							\
+      DOPRNT_REPS (c, n);						\
+  } while (0)
+#define DOPRNT_MEMORY_MAYBE(ptr, len)					\
+  do {									\
+    if ((len) != 0)							\
+      DOPRNT_MEMORY (ptr, len);						\
+  } while (0)
+
+__GMP_DECLSPEC int __gmp_doprnt (const struct doprnt_funs_t *, void *, const char *, va_list);
+__GMP_DECLSPEC int __gmp_doprnt_integer (const struct doprnt_funs_t *, void *, const struct doprnt_params_t *, const char *);
+
+#define __gmp_doprnt_mpf __gmp_doprnt_mpf2
+__GMP_DECLSPEC int __gmp_doprnt_mpf (const struct doprnt_funs_t *, void *, const struct doprnt_params_t *, const char *, mpf_srcptr);
+
+__GMP_DECLSPEC int __gmp_replacement_vsnprintf (char *, size_t, const char *, va_list);
+#endif /* _GMP_H_HAVE_VA_LIST */
+
+
+typedef int (*gmp_doscan_scan_t)  (void *, const char *, ...);
+typedef void *(*gmp_doscan_step_t) (void *, int);
+typedef int (*gmp_doscan_get_t)   (void *);
+typedef int (*gmp_doscan_unget_t) (int, void *);
+
+struct gmp_doscan_funs_t {
+  gmp_doscan_scan_t   scan;
+  gmp_doscan_step_t   step;
+  gmp_doscan_get_t    get;
+  gmp_doscan_unget_t  unget;
+};
+extern const struct gmp_doscan_funs_t  __gmp_fscanf_funs;
+extern const struct gmp_doscan_funs_t  __gmp_sscanf_funs;
+
+#if _GMP_H_HAVE_VA_LIST
+__GMP_DECLSPEC int __gmp_doscan (const struct gmp_doscan_funs_t *, void *, const char *, va_list);
+#endif
+
+
+/* For testing and debugging.  */
+#define MPZ_CHECK_FORMAT(z)						\
+  do {									\
+    ASSERT_ALWAYS (SIZ(z) == 0 || PTR(z)[ABSIZ(z) - 1] != 0);		\
+    ASSERT_ALWAYS (ALLOC(z) >= ABSIZ(z));				\
+    ASSERT_ALWAYS_MPN (PTR(z), ABSIZ(z));				\
+  } while (0)
+
+#define MPQ_CHECK_FORMAT(q)						\
+  do {									\
+    MPZ_CHECK_FORMAT (mpq_numref (q));					\
+    MPZ_CHECK_FORMAT (mpq_denref (q));					\
+    ASSERT_ALWAYS (SIZ(mpq_denref(q)) >= 1);				\
+									\
+    if (SIZ(mpq_numref(q)) == 0)					\
+      {									\
+	/* should have zero as 0/1 */					\
+	ASSERT_ALWAYS (SIZ(mpq_denref(q)) == 1				\
+		       && PTR(mpq_denref(q))[0] == 1);			\
+      }									\
+    else								\
+      {									\
+	/* should have no common factors */				\
+	mpz_t  g;							\
+	mpz_init (g);							\
+	mpz_gcd (g, mpq_numref(q), mpq_denref(q));			\
+	ASSERT_ALWAYS (mpz_cmp_ui (g, 1) == 0);				\
+	mpz_clear (g);							\
+      }									\
+  } while (0)
+
+#define MPF_CHECK_FORMAT(f)						\
+  do {									\
+    ASSERT_ALWAYS (PREC(f) >= __GMPF_BITS_TO_PREC(53));			\
+    ASSERT_ALWAYS (ABSIZ(f) <= PREC(f)+1);				\
+    if (SIZ(f) == 0)							\
+      ASSERT_ALWAYS (EXP(f) == 0);					\
+    if (SIZ(f) != 0)							\
+      ASSERT_ALWAYS (PTR(f)[ABSIZ(f) - 1] != 0);			\
+  } while (0)
+
+
+/* Enhancement: The "mod" and "gcd_1" functions below could have
+   __GMP_ATTRIBUTE_PURE, but currently (gcc 3.3) that's not supported on
+   function pointers, only actual functions.  It probably doesn't make much
+   difference to the gmp code, since hopefully we arrange calls so there's
+   no great need for the compiler to move things around.  */
+
+#if WANT_FAT_BINARY && (HAVE_HOST_CPU_FAMILY_x86 || HAVE_HOST_CPU_FAMILY_x86_64)
+/* NOTE: The function pointers in this struct are also in CPUVEC_FUNCS_LIST
+   in mpn/x86/x86-defs.m4 and mpn/x86_64/x86_64-defs.m4.  Be sure to update
+   those when changing here.  */
+struct cpuvec_t {
+  DECL_add_n           ((*add_n));
+  DECL_addlsh1_n       ((*addlsh1_n));
+  DECL_addlsh2_n       ((*addlsh2_n));
+  DECL_addmul_1        ((*addmul_1));
+  DECL_addmul_2        ((*addmul_2));
+  DECL_bdiv_dbm1c      ((*bdiv_dbm1c));
+  DECL_cnd_add_n       ((*cnd_add_n));
+  DECL_cnd_sub_n       ((*cnd_sub_n));
+  DECL_com             ((*com));
+  DECL_copyd           ((*copyd));
+  DECL_copyi           ((*copyi));
+  DECL_divexact_1      ((*divexact_1));
+  DECL_divrem_1        ((*divrem_1));
+  DECL_gcd_11          ((*gcd_11));
+  DECL_lshift          ((*lshift));
+  DECL_lshiftc         ((*lshiftc));
+  DECL_mod_1           ((*mod_1));
+  DECL_mod_1_1p        ((*mod_1_1p));
+  DECL_mod_1_1p_cps    ((*mod_1_1p_cps));
+  DECL_mod_1s_2p       ((*mod_1s_2p));
+  DECL_mod_1s_2p_cps   ((*mod_1s_2p_cps));
+  DECL_mod_1s_4p       ((*mod_1s_4p));
+  DECL_mod_1s_4p_cps   ((*mod_1s_4p_cps));
+  DECL_mod_34lsub1     ((*mod_34lsub1));
+  DECL_modexact_1c_odd ((*modexact_1c_odd));
+  DECL_mul_1           ((*mul_1));
+  DECL_mul_basecase    ((*mul_basecase));
+  DECL_mullo_basecase  ((*mullo_basecase));
+  DECL_preinv_divrem_1 ((*preinv_divrem_1));
+  DECL_preinv_mod_1    ((*preinv_mod_1));
+  DECL_redc_1          ((*redc_1));
+  DECL_redc_2          ((*redc_2));
+  DECL_rshift          ((*rshift));
+  DECL_sqr_basecase    ((*sqr_basecase));
+  DECL_sub_n           ((*sub_n));
+  DECL_sublsh1_n       ((*sublsh1_n));
+  DECL_submul_1        ((*submul_1));
+  mp_size_t            mul_toom22_threshold;
+  mp_size_t            mul_toom33_threshold;
+  mp_size_t            sqr_toom2_threshold;
+  mp_size_t            sqr_toom3_threshold;
+  mp_size_t            bmod_1_to_mod_1_threshold;
+};
+__GMP_DECLSPEC extern struct cpuvec_t __gmpn_cpuvec;
+__GMP_DECLSPEC extern int __gmpn_cpuvec_initialized;
+#endif /* x86 fat binary */
+
+__GMP_DECLSPEC void __gmpn_cpuvec_init (void);
+
+/* Get a threshold "field" from __gmpn_cpuvec, running __gmpn_cpuvec_init()
+   if that hasn't yet been done (to establish the right values).  */
+#define CPUVEC_THRESHOLD(field)						      \
+  ((LIKELY (__gmpn_cpuvec_initialized) ? 0 : (__gmpn_cpuvec_init (), 0)),     \
+   __gmpn_cpuvec.field)
+
+
+#if HAVE_NATIVE_mpn_add_nc
+#define mpn_add_nc __MPN(add_nc)
+__GMP_DECLSPEC mp_limb_t mpn_add_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#else
+static inline
+mp_limb_t
+mpn_add_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t ci)
+{
+  mp_limb_t co;
+  co = mpn_add_n (rp, up, vp, n);
+  co += mpn_add_1 (rp, rp, n, ci);
+  return co;
+}
+#endif
+
+#if HAVE_NATIVE_mpn_sub_nc
+#define mpn_sub_nc __MPN(sub_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sub_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#else
+static inline mp_limb_t
+mpn_sub_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t ci)
+{
+  mp_limb_t co;
+  co = mpn_sub_n (rp, up, vp, n);
+  co += mpn_sub_1 (rp, rp, n, ci);
+  return co;
+}
+#endif
+
+#if TUNE_PROGRAM_BUILD
+/* Some extras wanted when recompiling some .c files for use by the tune
+   program.  Not part of a normal build.
+
+   It's necessary to keep these thresholds as #defines (just to an
+   identically named variable), since various defaults are established based
+   on #ifdef in the .c files.  For some this is not so (the defaults are
+   instead established above), but all are done this way for consistency. */
+
+#undef	MUL_TOOM22_THRESHOLD
+#define MUL_TOOM22_THRESHOLD		mul_toom22_threshold
+extern mp_size_t			mul_toom22_threshold;
+
+#undef	MUL_TOOM33_THRESHOLD
+#define MUL_TOOM33_THRESHOLD		mul_toom33_threshold
+extern mp_size_t			mul_toom33_threshold;
+
+#undef	MUL_TOOM44_THRESHOLD
+#define MUL_TOOM44_THRESHOLD		mul_toom44_threshold
+extern mp_size_t			mul_toom44_threshold;
+
+#undef	MUL_TOOM6H_THRESHOLD
+#define MUL_TOOM6H_THRESHOLD		mul_toom6h_threshold
+extern mp_size_t			mul_toom6h_threshold;
+
+#undef	MUL_TOOM8H_THRESHOLD
+#define MUL_TOOM8H_THRESHOLD		mul_toom8h_threshold
+extern mp_size_t			mul_toom8h_threshold;
+
+#undef	MUL_TOOM32_TO_TOOM43_THRESHOLD
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD	mul_toom32_to_toom43_threshold
+extern mp_size_t			mul_toom32_to_toom43_threshold;
+
+#undef	MUL_TOOM32_TO_TOOM53_THRESHOLD
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD	mul_toom32_to_toom53_threshold
+extern mp_size_t			mul_toom32_to_toom53_threshold;
+
+#undef	MUL_TOOM42_TO_TOOM53_THRESHOLD
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD	mul_toom42_to_toom53_threshold
+extern mp_size_t			mul_toom42_to_toom53_threshold;
+
+#undef	MUL_TOOM42_TO_TOOM63_THRESHOLD
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD	mul_toom42_to_toom63_threshold
+extern mp_size_t			mul_toom42_to_toom63_threshold;
+
+#undef  MUL_TOOM43_TO_TOOM54_THRESHOLD
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD	mul_toom43_to_toom54_threshold;
+extern mp_size_t			mul_toom43_to_toom54_threshold;
+
+#undef	MUL_FFT_THRESHOLD
+#define MUL_FFT_THRESHOLD		mul_fft_threshold
+extern mp_size_t			mul_fft_threshold;
+
+#undef	MUL_FFT_MODF_THRESHOLD
+#define MUL_FFT_MODF_THRESHOLD		mul_fft_modf_threshold
+extern mp_size_t			mul_fft_modf_threshold;
+
+#undef	MUL_FFT_TABLE
+#define MUL_FFT_TABLE			{ 0 }
+
+#undef	MUL_FFT_TABLE3
+#define MUL_FFT_TABLE3			{ {0,0} }
+
+/* A native mpn_sqr_basecase is not tuned and SQR_BASECASE_THRESHOLD should
+   remain as zero (always use it). */
+#if ! HAVE_NATIVE_mpn_sqr_basecase
+#undef	SQR_BASECASE_THRESHOLD
+#define SQR_BASECASE_THRESHOLD		sqr_basecase_threshold
+extern mp_size_t			sqr_basecase_threshold;
+#endif
+
+#if TUNE_PROGRAM_BUILD_SQR
+#undef	SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD		SQR_TOOM2_MAX_GENERIC
+#else
+#undef	SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD		sqr_toom2_threshold
+extern mp_size_t			sqr_toom2_threshold;
+#endif
+
+#undef	SQR_TOOM3_THRESHOLD
+#define SQR_TOOM3_THRESHOLD		sqr_toom3_threshold
+extern mp_size_t			sqr_toom3_threshold;
+
+#undef	SQR_TOOM4_THRESHOLD
+#define SQR_TOOM4_THRESHOLD		sqr_toom4_threshold
+extern mp_size_t			sqr_toom4_threshold;
+
+#undef	SQR_TOOM6_THRESHOLD
+#define SQR_TOOM6_THRESHOLD		sqr_toom6_threshold
+extern mp_size_t			sqr_toom6_threshold;
+
+#undef	SQR_TOOM8_THRESHOLD
+#define SQR_TOOM8_THRESHOLD		sqr_toom8_threshold
+extern mp_size_t			sqr_toom8_threshold;
+
+#undef  SQR_FFT_THRESHOLD
+#define SQR_FFT_THRESHOLD		sqr_fft_threshold
+extern mp_size_t			sqr_fft_threshold;
+
+#undef  SQR_FFT_MODF_THRESHOLD
+#define SQR_FFT_MODF_THRESHOLD		sqr_fft_modf_threshold
+extern mp_size_t			sqr_fft_modf_threshold;
+
+#undef	SQR_FFT_TABLE
+#define SQR_FFT_TABLE			{ 0 }
+
+#undef	SQR_FFT_TABLE3
+#define SQR_FFT_TABLE3			{ {0,0} }
+
+#undef	MULLO_BASECASE_THRESHOLD
+#define MULLO_BASECASE_THRESHOLD	mullo_basecase_threshold
+extern mp_size_t			mullo_basecase_threshold;
+
+#undef	MULLO_DC_THRESHOLD
+#define MULLO_DC_THRESHOLD		mullo_dc_threshold
+extern mp_size_t			mullo_dc_threshold;
+
+#undef	MULLO_MUL_N_THRESHOLD
+#define MULLO_MUL_N_THRESHOLD		mullo_mul_n_threshold
+extern mp_size_t			mullo_mul_n_threshold;
+
+#undef	SQRLO_BASECASE_THRESHOLD
+#define SQRLO_BASECASE_THRESHOLD	sqrlo_basecase_threshold
+extern mp_size_t			sqrlo_basecase_threshold;
+
+#undef	SQRLO_DC_THRESHOLD
+#define SQRLO_DC_THRESHOLD		sqrlo_dc_threshold
+extern mp_size_t			sqrlo_dc_threshold;
+
+#undef	SQRLO_SQR_THRESHOLD
+#define SQRLO_SQR_THRESHOLD		sqrlo_sqr_threshold
+extern mp_size_t			sqrlo_sqr_threshold;
+
+#undef	MULMID_TOOM42_THRESHOLD
+#define MULMID_TOOM42_THRESHOLD		mulmid_toom42_threshold
+extern mp_size_t			mulmid_toom42_threshold;
+
+#undef	DIV_QR_2_PI2_THRESHOLD
+#define DIV_QR_2_PI2_THRESHOLD		div_qr_2_pi2_threshold
+extern mp_size_t			div_qr_2_pi2_threshold;
+
+#undef	DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD		dc_div_qr_threshold
+extern mp_size_t			dc_div_qr_threshold;
+
+#undef	DC_DIVAPPR_Q_THRESHOLD
+#define DC_DIVAPPR_Q_THRESHOLD		dc_divappr_q_threshold
+extern mp_size_t			dc_divappr_q_threshold;
+
+#undef	DC_BDIV_Q_THRESHOLD
+#define DC_BDIV_Q_THRESHOLD		dc_bdiv_q_threshold
+extern mp_size_t			dc_bdiv_q_threshold;
+
+#undef	DC_BDIV_QR_THRESHOLD
+#define DC_BDIV_QR_THRESHOLD		dc_bdiv_qr_threshold
+extern mp_size_t			dc_bdiv_qr_threshold;
+
+#undef	MU_DIV_QR_THRESHOLD
+#define MU_DIV_QR_THRESHOLD		mu_div_qr_threshold
+extern mp_size_t			mu_div_qr_threshold;
+
+#undef	MU_DIVAPPR_Q_THRESHOLD
+#define MU_DIVAPPR_Q_THRESHOLD		mu_divappr_q_threshold
+extern mp_size_t			mu_divappr_q_threshold;
+
+#undef	MUPI_DIV_QR_THRESHOLD
+#define MUPI_DIV_QR_THRESHOLD		mupi_div_qr_threshold
+extern mp_size_t			mupi_div_qr_threshold;
+
+#undef	MU_BDIV_QR_THRESHOLD
+#define MU_BDIV_QR_THRESHOLD		mu_bdiv_qr_threshold
+extern mp_size_t			mu_bdiv_qr_threshold;
+
+#undef	MU_BDIV_Q_THRESHOLD
+#define MU_BDIV_Q_THRESHOLD		mu_bdiv_q_threshold
+extern mp_size_t			mu_bdiv_q_threshold;
+
+#undef	INV_MULMOD_BNM1_THRESHOLD
+#define INV_MULMOD_BNM1_THRESHOLD	inv_mulmod_bnm1_threshold
+extern mp_size_t			inv_mulmod_bnm1_threshold;
+
+#undef	INV_NEWTON_THRESHOLD
+#define INV_NEWTON_THRESHOLD		inv_newton_threshold
+extern mp_size_t			inv_newton_threshold;
+
+#undef	INV_APPR_THRESHOLD
+#define INV_APPR_THRESHOLD		inv_appr_threshold
+extern mp_size_t			inv_appr_threshold;
+
+#undef	BINV_NEWTON_THRESHOLD
+#define BINV_NEWTON_THRESHOLD		binv_newton_threshold
+extern mp_size_t			binv_newton_threshold;
+
+#undef	REDC_1_TO_REDC_2_THRESHOLD
+#define REDC_1_TO_REDC_2_THRESHOLD	redc_1_to_redc_2_threshold
+extern mp_size_t			redc_1_to_redc_2_threshold;
+
+#undef	REDC_2_TO_REDC_N_THRESHOLD
+#define REDC_2_TO_REDC_N_THRESHOLD	redc_2_to_redc_n_threshold
+extern mp_size_t			redc_2_to_redc_n_threshold;
+
+#undef	REDC_1_TO_REDC_N_THRESHOLD
+#define REDC_1_TO_REDC_N_THRESHOLD	redc_1_to_redc_n_threshold
+extern mp_size_t			redc_1_to_redc_n_threshold;
+
+#undef	MATRIX22_STRASSEN_THRESHOLD
+#define MATRIX22_STRASSEN_THRESHOLD	matrix22_strassen_threshold
+extern mp_size_t			matrix22_strassen_threshold;
+
+typedef int hgcd2_func_t (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t,
+			  struct hgcd_matrix1 *);
+extern hgcd2_func_t *hgcd2_func;
+
+#undef	HGCD_THRESHOLD
+#define HGCD_THRESHOLD			hgcd_threshold
+extern mp_size_t			hgcd_threshold;
+
+#undef	HGCD_APPR_THRESHOLD
+#define HGCD_APPR_THRESHOLD		hgcd_appr_threshold
+extern mp_size_t			hgcd_appr_threshold;
+
+#undef	HGCD_REDUCE_THRESHOLD
+#define HGCD_REDUCE_THRESHOLD		hgcd_reduce_threshold
+extern mp_size_t			hgcd_reduce_threshold;
+
+#undef	GCD_DC_THRESHOLD
+#define GCD_DC_THRESHOLD		gcd_dc_threshold
+extern mp_size_t			gcd_dc_threshold;
+
+#undef  GCDEXT_DC_THRESHOLD
+#define GCDEXT_DC_THRESHOLD		gcdext_dc_threshold
+extern mp_size_t			gcdext_dc_threshold;
+
+#undef  DIV_QR_1N_PI1_METHOD
+#define DIV_QR_1N_PI1_METHOD		div_qr_1n_pi1_method
+extern int				div_qr_1n_pi1_method;
+
+#undef  DIV_QR_1_NORM_THRESHOLD
+#define DIV_QR_1_NORM_THRESHOLD		div_qr_1_norm_threshold
+extern mp_size_t			div_qr_1_norm_threshold;
+
+#undef  DIV_QR_1_UNNORM_THRESHOLD
+#define DIV_QR_1_UNNORM_THRESHOLD	div_qr_1_unnorm_threshold
+extern mp_size_t			div_qr_1_unnorm_threshold;
+
+#undef  DIVREM_1_NORM_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD		divrem_1_norm_threshold
+extern mp_size_t			divrem_1_norm_threshold;
+
+#undef  DIVREM_1_UNNORM_THRESHOLD
+#define DIVREM_1_UNNORM_THRESHOLD	divrem_1_unnorm_threshold
+extern mp_size_t			divrem_1_unnorm_threshold;
+
+#undef	MOD_1_NORM_THRESHOLD
+#define MOD_1_NORM_THRESHOLD		mod_1_norm_threshold
+extern mp_size_t			mod_1_norm_threshold;
+
+#undef	MOD_1_UNNORM_THRESHOLD
+#define MOD_1_UNNORM_THRESHOLD		mod_1_unnorm_threshold
+extern mp_size_t			mod_1_unnorm_threshold;
+
+#undef  MOD_1_1P_METHOD
+#define MOD_1_1P_METHOD			mod_1_1p_method
+extern int				mod_1_1p_method;
+
+#undef	MOD_1N_TO_MOD_1_1_THRESHOLD
+#define MOD_1N_TO_MOD_1_1_THRESHOLD	mod_1n_to_mod_1_1_threshold
+extern mp_size_t			mod_1n_to_mod_1_1_threshold;
+
+#undef	MOD_1U_TO_MOD_1_1_THRESHOLD
+#define MOD_1U_TO_MOD_1_1_THRESHOLD	mod_1u_to_mod_1_1_threshold
+extern mp_size_t			mod_1u_to_mod_1_1_threshold;
+
+#undef	MOD_1_1_TO_MOD_1_2_THRESHOLD
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD	mod_1_1_to_mod_1_2_threshold
+extern mp_size_t			mod_1_1_to_mod_1_2_threshold;
+
+#undef	MOD_1_2_TO_MOD_1_4_THRESHOLD
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD	mod_1_2_to_mod_1_4_threshold
+extern mp_size_t			mod_1_2_to_mod_1_4_threshold;
+
+#undef	PREINV_MOD_1_TO_MOD_1_THRESHOLD
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD	preinv_mod_1_to_mod_1_threshold
+extern mp_size_t			preinv_mod_1_to_mod_1_threshold;
+
+#if ! UDIV_PREINV_ALWAYS
+#undef	DIVREM_2_THRESHOLD
+#define DIVREM_2_THRESHOLD		divrem_2_threshold
+extern mp_size_t			divrem_2_threshold;
+#endif
+
+#undef	MULMOD_BNM1_THRESHOLD
+#define MULMOD_BNM1_THRESHOLD		mulmod_bnm1_threshold
+extern mp_size_t			mulmod_bnm1_threshold;
+
+#undef	SQRMOD_BNM1_THRESHOLD
+#define SQRMOD_BNM1_THRESHOLD		sqrmod_bnm1_threshold
+extern mp_size_t			sqrmod_bnm1_threshold;
+
+#undef	GET_STR_DC_THRESHOLD
+#define GET_STR_DC_THRESHOLD		get_str_dc_threshold
+extern mp_size_t			get_str_dc_threshold;
+
+#undef  GET_STR_PRECOMPUTE_THRESHOLD
+#define GET_STR_PRECOMPUTE_THRESHOLD	get_str_precompute_threshold
+extern mp_size_t			get_str_precompute_threshold;
+
+#undef	SET_STR_DC_THRESHOLD
+#define SET_STR_DC_THRESHOLD		set_str_dc_threshold
+extern mp_size_t			set_str_dc_threshold;
+
+#undef  SET_STR_PRECOMPUTE_THRESHOLD
+#define SET_STR_PRECOMPUTE_THRESHOLD	set_str_precompute_threshold
+extern mp_size_t			set_str_precompute_threshold;
+
+#undef  FAC_ODD_THRESHOLD
+#define FAC_ODD_THRESHOLD		fac_odd_threshold
+extern  mp_size_t			fac_odd_threshold;
+
+#undef  FAC_DSC_THRESHOLD
+#define FAC_DSC_THRESHOLD		fac_dsc_threshold
+extern  mp_size_t			fac_dsc_threshold;
+
+#undef  FFT_TABLE_ATTRS
+#define FFT_TABLE_ATTRS
+extern mp_size_t  mpn_fft_table[2][MPN_FFT_TABLE_SIZE];
+#define FFT_TABLE3_SIZE 2000	/* generous space for tuning */
+extern struct fft_table_nk mpn_fft_table3[2][FFT_TABLE3_SIZE];
+
+/* Sizes the tune program tests up to, used in a couple of recompilations. */
+#undef MUL_TOOM22_THRESHOLD_LIMIT
+#undef MUL_TOOM33_THRESHOLD_LIMIT
+#undef MULLO_BASECASE_THRESHOLD_LIMIT
+#undef SQRLO_BASECASE_THRESHOLD_LIMIT
+#undef SQRLO_DC_THRESHOLD_LIMIT
+#undef SQR_TOOM3_THRESHOLD_LIMIT
+#define SQR_TOOM2_MAX_GENERIC           200
+#define MUL_TOOM22_THRESHOLD_LIMIT      700
+#define MUL_TOOM33_THRESHOLD_LIMIT      700
+#define SQR_TOOM3_THRESHOLD_LIMIT       400
+#define MUL_TOOM44_THRESHOLD_LIMIT     1000
+#define SQR_TOOM4_THRESHOLD_LIMIT      1000
+#define MUL_TOOM6H_THRESHOLD_LIMIT     1100
+#define SQR_TOOM6_THRESHOLD_LIMIT      1100
+#define MUL_TOOM8H_THRESHOLD_LIMIT     1200
+#define SQR_TOOM8_THRESHOLD_LIMIT      1200
+#define MULLO_BASECASE_THRESHOLD_LIMIT  200
+#define SQRLO_BASECASE_THRESHOLD_LIMIT  200
+#define SQRLO_DC_THRESHOLD_LIMIT        400
+#define GET_STR_THRESHOLD_LIMIT         150
+#define FAC_DSC_THRESHOLD_LIMIT        2048
+
+#endif /* TUNE_PROGRAM_BUILD */
+
+#if defined (__cplusplus)
+}
+#endif
+
+/* FIXME: Make these itch functions less conservative.  Also consider making
+   them dependent on just 'an', and compute the allocation directly from 'an'
+   instead of via n.  */
+
+/* toom22/toom2: Scratch need is 2*(an + k), k is the recursion depth.
+   k is ths smallest k such that
+     ceil(an/2^k) < MUL_TOOM22_THRESHOLD.
+   which implies that
+     k = bitsize of floor ((an-1)/(MUL_TOOM22_THRESHOLD-1))
+       = 1 + floor (log_2 (floor ((an-1)/(MUL_TOOM22_THRESHOLD-1))))
+*/
+#define mpn_toom22_mul_itch(an, bn) \
+  (2 * ((an) + GMP_NUMB_BITS))
+#define mpn_toom2_sqr_itch(an) \
+  (2 * ((an) + GMP_NUMB_BITS))
+
+/* toom33/toom3: Scratch need is 5an/2 + 10k, k is the recursion depth.
+   We use 3an + C, so that we can use a smaller constant.
+ */
+#define mpn_toom33_mul_itch(an, bn) \
+  (3 * (an) + GMP_NUMB_BITS)
+#define mpn_toom3_sqr_itch(an) \
+  (3 * (an) + GMP_NUMB_BITS)
+
+/* toom33/toom3: Scratch need is 8an/3 + 13k, k is the recursion depth.
+   We use 3an + C, so that we can use a smaller constant.
+ */
+#define mpn_toom44_mul_itch(an, bn) \
+  (3 * (an) + GMP_NUMB_BITS)
+#define mpn_toom4_sqr_itch(an) \
+  (3 * (an) + GMP_NUMB_BITS)
+
+#define mpn_toom6_sqr_itch(n)						\
+  (((n) - SQR_TOOM6_THRESHOLD)*2 +					\
+   MAX(SQR_TOOM6_THRESHOLD*2 + GMP_NUMB_BITS*6,				\
+       mpn_toom4_sqr_itch(SQR_TOOM6_THRESHOLD)))
+
+#define MUL_TOOM6H_MIN							\
+  ((MUL_TOOM6H_THRESHOLD > MUL_TOOM44_THRESHOLD) ?			\
+    MUL_TOOM6H_THRESHOLD : MUL_TOOM44_THRESHOLD)
+#define mpn_toom6_mul_n_itch(n)						\
+  (((n) - MUL_TOOM6H_MIN)*2 +						\
+   MAX(MUL_TOOM6H_MIN*2 + GMP_NUMB_BITS*6,				\
+       mpn_toom44_mul_itch(MUL_TOOM6H_MIN,MUL_TOOM6H_MIN)))
+
+static inline mp_size_t
+mpn_toom6h_mul_itch (mp_size_t an, mp_size_t bn) {
+  mp_size_t estimatedN;
+  estimatedN = (an + bn) / (size_t) 10 + 1;
+  return mpn_toom6_mul_n_itch (estimatedN * 6);
+}
+
+#define mpn_toom8_sqr_itch(n)						\
+  ((((n)*15)>>3) - ((SQR_TOOM8_THRESHOLD*15)>>3) +			\
+   MAX(((SQR_TOOM8_THRESHOLD*15)>>3) + GMP_NUMB_BITS*6,			\
+       mpn_toom6_sqr_itch(SQR_TOOM8_THRESHOLD)))
+
+#define MUL_TOOM8H_MIN							\
+  ((MUL_TOOM8H_THRESHOLD > MUL_TOOM6H_MIN) ?				\
+    MUL_TOOM8H_THRESHOLD : MUL_TOOM6H_MIN)
+#define mpn_toom8_mul_n_itch(n)						\
+  ((((n)*15)>>3) - ((MUL_TOOM8H_MIN*15)>>3) +				\
+   MAX(((MUL_TOOM8H_MIN*15)>>3) + GMP_NUMB_BITS*6,			\
+       mpn_toom6_mul_n_itch(MUL_TOOM8H_MIN)))
+
+static inline mp_size_t
+mpn_toom8h_mul_itch (mp_size_t an, mp_size_t bn) {
+  mp_size_t estimatedN;
+  estimatedN = (an + bn) / (size_t) 14 + 1;
+  return mpn_toom8_mul_n_itch (estimatedN * 8);
+}
+
+static inline mp_size_t
+mpn_toom32_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (2 * an >= 3 * bn ? (an - 1) / (size_t) 3 : (bn - 1) >> 1);
+  mp_size_t itch = 2 * n + 1;
+
+  return itch;
+}
+
+static inline mp_size_t
+mpn_toom42_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = an >= 2 * bn ? (an + 3) >> 2 : (bn + 1) >> 1;
+  return 6 * n + 3;
+}
+
+static inline mp_size_t
+mpn_toom43_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (3 * an >= 4 * bn ? (an - 1) >> 2 : (bn - 1) / (size_t) 3);
+
+  return 6*n + 4;
+}
+
+static inline mp_size_t
+mpn_toom52_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (2 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) >> 1);
+  return 6*n + 4;
+}
+
+static inline mp_size_t
+mpn_toom53_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (3 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 3);
+  return 10 * n + 10;
+}
+
+static inline mp_size_t
+mpn_toom62_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (an >= 3 * bn ? (an - 1) / (size_t) 6 : (bn - 1) >> 1);
+  return 10 * n + 10;
+}
+
+static inline mp_size_t
+mpn_toom63_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (an >= 2 * bn ? (an - 1) / (size_t) 6 : (bn - 1) / (size_t) 3);
+  return 9 * n + 3;
+}
+
+static inline mp_size_t
+mpn_toom54_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (4 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 4);
+  return 9 * n + 3;
+}
+
+/* let S(n) = space required for input size n,
+   then S(n) = 3 floor(n/2) + 1 + S(floor(n/2)).   */
+#define mpn_toom42_mulmid_itch(n) \
+  (3 * (n) + GMP_NUMB_BITS)
+
+#if 0
+#define mpn_fft_mul mpn_mul_fft_full
+#else
+#define mpn_fft_mul mpn_nussbaumer_mul
+#endif
+
+#ifdef __cplusplus
+
+/* 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_traits<char>::length, but char_traits
+   isn't available in gcc 2.95.4.  */
+
+class gmp_allocated_string {
+ public:
+  char *str;
+  size_t len;
+  gmp_allocated_string(char *arg)
+  {
+    str = arg;
+    len = std::strlen (str);
+  }
+  ~gmp_allocated_string()
+  {
+    (*__gmp_free_func) (str, len+1);
+  }
+};
+
+std::istream &__gmpz_operator_in_nowhite (std::istream &, mpz_ptr, char);
+int __gmp_istream_set_base (std::istream &, char &, bool &, bool &);
+void __gmp_istream_set_digits (std::string &, std::istream &, char &, bool &, int);
+void __gmp_doprnt_params_from_ios (struct doprnt_params_t *, std::ios &);
+std::ostream& __gmp_doprnt_integer_ostream (std::ostream &, struct doprnt_params_t *, char *);
+extern const struct doprnt_funs_t  __gmp_asprintf_funs_noformat;
+
+#endif /* __cplusplus */
+
+#endif /* __GMP_IMPL_H__ */
diff --git a/gmpxx.h b/gmpxx.h
new file mode 100644
index 0000000..62d159c
--- /dev/null
+++ b/gmpxx.h
@@ -0,0 +1,3871 @@
+/* gmpxx.h -- C++ class wrapper for GMP types.  -*- C++ -*-
+
+Copyright 2001-2003, 2006, 2008, 2011-2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_PLUSPLUS__
+#define __GMP_PLUSPLUS__
+
+#include <iosfwd>
+
+#include <cstring>  /* for strlen */
+#include <limits>  /* numeric_limits */
+#include <utility>
+#include <algorithm>  /* swap */
+#include <string>
+#ifdef __EXCEPTIONS
+#include <stdexcept>
+#else
+#include <cstdlib>
+#include <iostream>
+#endif
+#include <cfloat>
+#include <gmp.h>
+
+// wrapper for gcc's __builtin_constant_p
+// __builtin_constant_p has been in gcc since forever,
+// but g++-3.4 miscompiles it.
+#if __GMP_GNUC_PREREQ(4, 2)
+#define __GMPXX_CONSTANT(X) __builtin_constant_p(X)
+#else
+#define __GMPXX_CONSTANT(X) false
+#endif
+#define __GMPXX_CONSTANT_TRUE(X) (__GMPXX_CONSTANT(X) && (X))
+
+// Use C++11 features
+#ifndef __GMPXX_USE_CXX11
+#if __cplusplus >= 201103L
+#define __GMPXX_USE_CXX11 1
+#else
+#define __GMPXX_USE_CXX11 0
+#endif
+#endif
+
+#if __GMPXX_USE_CXX11
+#define __GMPXX_NOEXCEPT noexcept
+#include <type_traits> // for common_type
+#else
+#define __GMPXX_NOEXCEPT
+#endif
+
+// Max allocations for plain types when converted to GMP types
+#if GMP_NAIL_BITS != 0 && ! defined _LONG_LONG_LIMB
+#define __GMPZ_ULI_LIMBS 2
+#else
+#define __GMPZ_ULI_LIMBS 1
+#endif
+
+#define __GMPXX_BITS_TO_LIMBS(n)  (((n) + (GMP_NUMB_BITS - 1)) / GMP_NUMB_BITS)
+#define __GMPZ_DBL_LIMBS __GMPXX_BITS_TO_LIMBS(DBL_MAX_EXP)+1
+#define __GMPQ_NUM_DBL_LIMBS __GMPZ_DBL_LIMBS
+#define __GMPQ_DEN_DBL_LIMBS __GMPXX_BITS_TO_LIMBS(DBL_MANT_DIG+1-DBL_MIN_EXP)+1
+// The final +1s are a security margin. The current implementation of
+// mpq_set_d seems to need it for the denominator.
+
+inline void __mpz_set_ui_safe(mpz_ptr p, unsigned long l)
+{
+  p->_mp_size = (l != 0);
+  p->_mp_d[0] = l & GMP_NUMB_MASK;
+#if __GMPZ_ULI_LIMBS > 1
+  l >>= GMP_NUMB_BITS;
+  p->_mp_d[1] = l;
+  p->_mp_size += (l != 0);
+#endif
+}
+
+inline void __mpz_set_si_safe(mpz_ptr p, long l)
+{
+  if(l < 0)
+  {
+    __mpz_set_ui_safe(p, -static_cast<unsigned long>(l));
+    mpz_neg(p, p);
+  }
+  else
+    __mpz_set_ui_safe(p, l);
+    // Note: we know the high bit of l is 0 so we could do slightly better
+}
+
+// Fake temporary variables
+#define __GMPXX_TMPZ_UI							\
+  mpz_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS];					\
+  temp->_mp_d = limbs;							\
+  __mpz_set_ui_safe (temp, l)
+#define __GMPXX_TMPZ_SI							\
+  mpz_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS];					\
+  temp->_mp_d = limbs;							\
+  __mpz_set_si_safe (temp, l)
+#define __GMPXX_TMPZ_D							\
+  mpz_t temp;								\
+  mp_limb_t limbs[__GMPZ_DBL_LIMBS];					\
+  temp->_mp_d = limbs;							\
+  temp->_mp_alloc = __GMPZ_DBL_LIMBS;					\
+  mpz_set_d (temp, d)
+
+#define __GMPXX_TMPQ_UI							\
+  mpq_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS+1];					\
+  mpq_numref(temp)->_mp_d = limbs;					\
+  __mpz_set_ui_safe (mpq_numref(temp), l);				\
+  mpq_denref(temp)->_mp_d = limbs + __GMPZ_ULI_LIMBS;			\
+  mpq_denref(temp)->_mp_size = 1;					\
+  mpq_denref(temp)->_mp_d[0] = 1
+#define __GMPXX_TMPQ_SI							\
+  mpq_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS+1];					\
+  mpq_numref(temp)->_mp_d = limbs;					\
+  __mpz_set_si_safe (mpq_numref(temp), l);				\
+  mpq_denref(temp)->_mp_d = limbs + __GMPZ_ULI_LIMBS;			\
+  mpq_denref(temp)->_mp_size = 1;					\
+  mpq_denref(temp)->_mp_d[0] = 1
+#define __GMPXX_TMPQ_D							\
+  mpq_t temp;								\
+  mp_limb_t limbs[__GMPQ_NUM_DBL_LIMBS + __GMPQ_DEN_DBL_LIMBS];		\
+  mpq_numref(temp)->_mp_d = limbs;					\
+  mpq_numref(temp)->_mp_alloc = __GMPQ_NUM_DBL_LIMBS;			\
+  mpq_denref(temp)->_mp_d = limbs + __GMPQ_NUM_DBL_LIMBS;		\
+  mpq_denref(temp)->_mp_alloc = __GMPQ_DEN_DBL_LIMBS;			\
+  mpq_set_d (temp, d)
+
+inline unsigned long __gmpxx_abs_ui (signed long l)
+{
+  return l >= 0 ? static_cast<unsigned long>(l)
+	  : -static_cast<unsigned long>(l);
+}
+
+/**************** Function objects ****************/
+/* Any evaluation of a __gmp_expr ends up calling one of these functions
+   all intermediate functions being inline, the evaluation should optimize
+   to a direct call to the relevant function, thus yielding no overhead
+   over the C interface. */
+
+struct __gmp_unary_plus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); }
+  static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); }
+};
+
+struct __gmp_unary_minus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); }
+  static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); }
+};
+
+struct __gmp_unary_com
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); }
+};
+
+struct __gmp_binary_plus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_add(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+    // Ideally, those checks should happen earlier so that the tree
+    // generated for a+0+b would just be sum(a,b).
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_add_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (l >= 0)
+      eval(z, w, static_cast<unsigned long>(l));
+    else
+      mpz_sub_ui(z, w, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_add (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_add(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else if (__GMPXX_CONSTANT(l) && l == 1)
+    {
+      mpz_add (mpq_numref(q), mpq_numref(r), mpq_denref(r));
+      if (q != r) mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+    else
+    {
+      if (q == r)
+        mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l);
+      else
+      {
+        mpz_mul_ui(mpq_numref(q), mpq_denref(r), l);
+        mpz_add(mpq_numref(q), mpq_numref(q), mpq_numref(r));
+        mpz_set(mpq_denref(q), mpq_denref(r));
+      }
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static inline void eval(mpq_ptr q, mpq_srcptr r, signed long int l);
+  // defined after __gmp_binary_minus
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_add (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  { eval(q, r, d); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z)
+  {
+    if (q == r)
+      mpz_addmul(mpq_numref(q), mpq_denref(q), z);
+    else
+    {
+      mpz_mul(mpq_numref(q), mpq_denref(r), z);
+      mpz_add(mpq_numref(q), mpq_numref(q), mpq_numref(r));
+      mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+  }
+  static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r)
+  { eval(q, r, z); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_add(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_add_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_add_ui(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_add_ui(f, g, l);
+    else
+      mpf_sub_ui(f, g, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_add(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  { eval(f, g, d); }
+};
+
+struct __gmp_binary_minus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_sub(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_sub_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      mpz_neg(z, w);
+    }
+    else
+      mpz_ui_sub(z, l, w);
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (l >= 0)
+      eval(z, w, static_cast<unsigned long>(l));
+    else
+      mpz_add_ui(z, w, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  {
+    if (l >= 0)
+      eval(z, static_cast<unsigned long>(l), w);
+    else
+      {
+        mpz_add_ui(z, w, -static_cast<unsigned long>(l));
+        mpz_neg(z, z);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_sub (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  {  __GMPXX_TMPZ_D;    mpz_sub (z, temp, w); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_sub(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else if (__GMPXX_CONSTANT(l) && l == 1)
+    {
+      mpz_sub (mpq_numref(q), mpq_numref(r), mpq_denref(r));
+      if (q != r) mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+    else
+    {
+      if (q == r)
+        mpz_submul_ui(mpq_numref(q), mpq_denref(q), l);
+      else
+      {
+        mpz_mul_ui(mpq_numref(q), mpq_denref(r), l);
+        mpz_sub(mpq_numref(q), mpq_numref(r), mpq_numref(q));
+        mpz_set(mpq_denref(q), mpq_denref(r));
+      }
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  { eval(q, r, l); mpq_neg(q, q); }
+  static void eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+  {
+    if (l >= 0)
+      eval(q, r, static_cast<unsigned long>(l));
+    else
+      __gmp_binary_plus::eval(q, r, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  { eval(q, r, l); mpq_neg(q, q); }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_sub (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  {  __GMPXX_TMPQ_D;    mpq_sub (q, temp, r); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z)
+  {
+    if (q == r)
+      mpz_submul(mpq_numref(q), mpq_denref(q), z);
+    else
+    {
+      mpz_mul(mpq_numref(q), mpq_denref(r), z);
+      mpz_sub(mpq_numref(q), mpq_numref(r), mpq_numref(q));
+      mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+  }
+  static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r)
+  { eval(q, r, z); mpq_neg(q, q); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_sub(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_sub_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_ui_sub(f, l, g); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_sub_ui(f, g, l);
+    else
+      mpf_add_ui(f, g, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  {
+    if (l >= 0)
+      mpf_sub_ui(f, g, l);
+    else
+      mpf_add_ui(f, g, -static_cast<unsigned long>(l));
+    mpf_neg(f, f);
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_sub(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_sub(f, temp, g);
+    mpf_clear(temp);
+  }
+};
+
+// defined here so it can reference __gmp_binary_minus
+inline void
+__gmp_binary_plus::eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+{
+  if (l >= 0)
+    eval(q, r, static_cast<unsigned long>(l));
+  else
+    __gmp_binary_minus::eval(q, r, -static_cast<unsigned long>(l));
+}
+
+struct __gmp_binary_lshift
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_mul_2exp(z, w, l);
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else
+      mpq_mul_2exp(q, r, l);
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, mp_bitcnt_t l)
+  { mpf_mul_2exp(f, g, l); }
+};
+
+struct __gmp_binary_rshift
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_fdiv_q_2exp(z, w, l);
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else
+      mpq_div_2exp(q, r, l);
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, mp_bitcnt_t l)
+  { mpf_div_2exp(f, g, l); }
+};
+
+struct __gmp_binary_multiplies
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_mul(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+// gcc-3.3 doesn't have __builtin_ctzl. Don't bother optimizing for old gcc.
+#if __GMP_GNUC_PREREQ(3, 4)
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0)
+    {
+      if (l == 0)
+      {
+        z->_mp_size = 0;
+      }
+      else
+      {
+        __gmp_binary_lshift::eval(z, w, __builtin_ctzl(l));
+      }
+    }
+    else
+#endif
+      mpz_mul_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      eval(z, w, static_cast<unsigned long>(l));
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+        eval(z, w, -static_cast<unsigned long>(l));
+	mpz_neg(z, z);
+      }
+    else
+      mpz_mul_si (z, w, l);
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_mul (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_mul(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+#if __GMP_GNUC_PREREQ(3, 4)
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0)
+    {
+      if (l == 0)
+      {
+	mpq_set_ui(q, 0, 1);
+      }
+      else
+      {
+        __gmp_binary_lshift::eval(q, r, __builtin_ctzl(l));
+      }
+    }
+    else
+#endif
+    {
+      __GMPXX_TMPQ_UI;
+      mpq_mul (q, r, temp);
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static void eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      eval(q, r, static_cast<unsigned long>(l));
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+        eval(q, r, -static_cast<unsigned long>(l));
+	mpq_neg(q, q);
+      }
+    else
+      {
+	__GMPXX_TMPQ_SI;
+	mpq_mul (q, r, temp);
+      }
+  }
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_mul (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  { eval(q, r, d); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_mul(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_mul_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_mul_ui(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_mul_ui(f, g, l);
+    else
+      {
+	mpf_mul_ui(f, g, -static_cast<unsigned long>(l));
+	mpf_neg(f, f);
+      }
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_mul(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  { eval(f, g, d); }
+};
+
+struct __gmp_binary_divides
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_tdiv_q(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+#if __GMP_GNUC_PREREQ(3, 4)
+    // Don't optimize division by 0...
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0 && l != 0)
+    {
+      if (l == 1)
+      {
+        if (z != w) mpz_set(z, w);
+      }
+      else
+        mpz_tdiv_q_2exp(z, w, __builtin_ctzl(l));
+        // warning: do not use rshift (fdiv)
+    }
+    else
+#endif
+      mpz_tdiv_q_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  {
+    if (mpz_sgn(w) >= 0)
+      {
+	if (mpz_fits_ulong_p(w))
+	  mpz_set_ui(z, l / mpz_get_ui(w));
+	else
+	  mpz_set_ui(z, 0);
+      }
+    else
+      {
+	mpz_neg(z, w);
+	if (mpz_fits_ulong_p(z))
+	  {
+	    mpz_set_ui(z, l / mpz_get_ui(z));
+	    mpz_neg(z, z);
+	  }
+	else
+	  mpz_set_ui(z, 0);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (l >= 0)
+      eval(z, w, static_cast<unsigned long>(l));
+    else
+      {
+	eval(z, w, -static_cast<unsigned long>(l));
+	mpz_neg(z, z);
+      }
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  {
+    if (mpz_fits_slong_p(w))
+      mpz_set_si(z, l / mpz_get_si(w));
+    else
+      {
+        /* if w is bigger than a long then the quotient must be zero, unless
+           l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */
+        mpz_set_si (z, (mpz_cmpabs_ui (w, __gmpxx_abs_ui(l)) == 0 ? -1 : 0));
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_q (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_q (z, temp, w); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_div(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+#if __GMP_GNUC_PREREQ(3, 4)
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0 && l != 0)
+      __gmp_binary_rshift::eval(q, r, __builtin_ctzl(l));
+    else
+#endif
+    {
+      __GMPXX_TMPQ_UI;
+      mpq_div (q, r, temp);
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpq_set_ui(q, 0, 1);
+    else if (__GMPXX_CONSTANT_TRUE(l == 1))
+      mpq_inv(q, r);
+    else
+      {
+	__GMPXX_TMPQ_UI;
+	mpq_div (q, temp, r);
+      }
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      eval(q, r, static_cast<unsigned long>(l));
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+        eval(q, r, -static_cast<unsigned long>(l));
+	mpq_neg(q, q);
+      }
+    else
+      {
+	__GMPXX_TMPQ_SI;
+	mpq_div (q, r, temp);
+      }
+  }
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpq_set_ui(q, 0, 1);
+    else if (__GMPXX_CONSTANT_TRUE(l == 1))
+      mpq_inv(q, r);
+    else if (__GMPXX_CONSTANT_TRUE(l == -1))
+      {
+	mpq_inv(q, r);
+	mpq_neg(q, q);
+      }
+    else
+      {
+	__GMPXX_TMPQ_SI;
+	mpq_div (q, temp, r);
+      }
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_div (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  {  __GMPXX_TMPQ_D;    mpq_div (q, temp, r); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_div(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_div_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_ui_div(f, l, g); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_div_ui(f, g, l);
+    else
+      {
+	mpf_div_ui(f, g, -static_cast<unsigned long>(l));
+	mpf_neg(f, f);
+      }
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  {
+    if (l >= 0)
+      mpf_ui_div(f, l, g);
+    else
+      {
+	mpf_ui_div(f, -static_cast<unsigned long>(l), g);
+	mpf_neg(f, f);
+      }
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_div(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_div(f, temp, g);
+    mpf_clear(temp);
+  }
+};
+
+struct __gmp_binary_modulus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_tdiv_r(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  { mpz_tdiv_r_ui(z, w, l); }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  {
+    if (mpz_sgn(w) >= 0)
+      {
+	if (mpz_fits_ulong_p(w))
+	  mpz_set_ui(z, l % mpz_get_ui(w));
+	else
+	  mpz_set_ui(z, l);
+      }
+    else
+      {
+	mpz_neg(z, w);
+	if (mpz_fits_ulong_p(z))
+	  mpz_set_ui(z, l % mpz_get_ui(z));
+	else
+	  mpz_set_ui(z, l);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    mpz_tdiv_r_ui (z, w, __gmpxx_abs_ui(l));
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  {
+    if (mpz_fits_slong_p(w))
+      mpz_set_si(z, l % mpz_get_si(w));
+    else
+      {
+        /* if w is bigger than a long then the remainder is l unchanged,
+           unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */
+        mpz_set_si (z, mpz_cmpabs_ui (w, __gmpxx_abs_ui(l)) == 0 ? 0 : l);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_r (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_r (z, temp, w); }
+};
+
+struct __gmp_binary_and
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_and(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {  __GMPXX_TMPZ_UI;   mpz_and (z, w, temp);  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {  __GMPXX_TMPZ_SI;   mpz_and (z, w, temp);  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_and (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d);  }
+};
+
+struct __gmp_binary_ior
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_ior(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {  __GMPXX_TMPZ_UI;   mpz_ior (z, w, temp);  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {  __GMPXX_TMPZ_SI;   mpz_ior (z, w, temp);  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_ior (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d);  }
+};
+
+struct __gmp_binary_xor
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_xor(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {  __GMPXX_TMPZ_UI;   mpz_xor (z, w, temp);  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {  __GMPXX_TMPZ_SI;   mpz_xor (z, w, temp);  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_xor (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d);  }
+};
+
+struct __gmp_cmp_function
+{
+  static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); }
+
+  static int eval(mpz_srcptr z, unsigned long int l)
+  { return mpz_cmp_ui(z, l); }
+  static int eval(unsigned long int l, mpz_srcptr z)
+  { return -mpz_cmp_ui(z, l); }
+  static int eval(mpz_srcptr z, signed long int l)
+  { return mpz_cmp_si(z, l); }
+  static int eval(signed long int l, mpz_srcptr z)
+  { return -mpz_cmp_si(z, l); }
+  static int eval(mpz_srcptr z, double d)
+  { return mpz_cmp_d(z, d); }
+  static int eval(double d, mpz_srcptr z)
+  { return -mpz_cmp_d(z, d); }
+
+  static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); }
+
+  static int eval(mpq_srcptr q, unsigned long int l)
+  { return mpq_cmp_ui(q, l, 1); }
+  static int eval(unsigned long int l, mpq_srcptr q)
+  { return -mpq_cmp_ui(q, l, 1); }
+  static int eval(mpq_srcptr q, signed long int l)
+  { return mpq_cmp_si(q, l, 1); }
+  static int eval(signed long int l, mpq_srcptr q)
+  { return -mpq_cmp_si(q, l, 1); }
+  static int eval(mpq_srcptr q, double d)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (q, temp); }
+  static int eval(double d, mpq_srcptr q)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (temp, q); }
+  static int eval(mpq_srcptr q, mpz_srcptr z)
+  { return mpq_cmp_z(q, z); }
+  static int eval(mpz_srcptr z, mpq_srcptr q)
+  { return -mpq_cmp_z(q, z); }
+
+  static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); }
+
+  static int eval(mpf_srcptr f, unsigned long int l)
+  { return mpf_cmp_ui(f, l); }
+  static int eval(unsigned long int l, mpf_srcptr f)
+  { return -mpf_cmp_ui(f, l); }
+  static int eval(mpf_srcptr f, signed long int l)
+  { return mpf_cmp_si(f, l); }
+  static int eval(signed long int l, mpf_srcptr f)
+  { return -mpf_cmp_si(f, l); }
+  static int eval(mpf_srcptr f, double d)
+  { return mpf_cmp_d(f, d); }
+  static int eval(double d, mpf_srcptr f)
+  { return -mpf_cmp_d(f, d); }
+  static int eval(mpf_srcptr f, mpz_srcptr z)
+  { return mpf_cmp_z(f, z); }
+  static int eval(mpz_srcptr z, mpf_srcptr f)
+  { return -mpf_cmp_z(f, z); }
+  static int eval(mpf_srcptr f, mpq_srcptr q)
+  {
+    mpf_t qf;
+    mpf_init(qf); /* Should we use the precision of f?  */
+    mpf_set_q(qf, q);
+    int ret = eval(f, qf);
+    mpf_clear(qf);
+    return ret;
+  }
+  static int eval(mpq_srcptr q, mpf_srcptr f)
+  { return -eval(f, q); }
+};
+
+struct __gmp_binary_equal
+{
+  static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; }
+
+  static bool eval(mpz_srcptr z, unsigned long int l)
+  { return mpz_cmp_ui(z, l) == 0; }
+  static bool eval(unsigned long int l, mpz_srcptr z)
+  { return eval(z, l); }
+  static bool eval(mpz_srcptr z, signed long int l)
+  { return mpz_cmp_si(z, l) == 0; }
+  static bool eval(signed long int l, mpz_srcptr z)
+  { return eval(z, l); }
+  static bool eval(mpz_srcptr z, double d)
+  { return mpz_cmp_d(z, d) == 0; }
+  static bool eval(double d, mpz_srcptr z)
+  { return eval(z, d); }
+
+  static bool eval(mpq_srcptr q, mpq_srcptr r)
+  { return mpq_equal(q, r) != 0; }
+
+  static bool eval(mpq_srcptr q, unsigned long int l)
+  { return ((__GMPXX_CONSTANT(l) && l == 0) ||
+	    mpz_cmp_ui(mpq_denref(q), 1) == 0) &&
+      mpz_cmp_ui(mpq_numref(q), l) == 0; }
+  static bool eval(unsigned long int l, mpq_srcptr q)
+  { return eval(q, l); }
+  static bool eval(mpq_srcptr q, signed long int l)
+  { return ((__GMPXX_CONSTANT(l) && l == 0) ||
+	    mpz_cmp_ui(mpq_denref(q), 1) == 0) &&
+      mpz_cmp_si(mpq_numref(q), l) == 0; }
+  static bool eval(signed long int l, mpq_srcptr q)
+  { return eval(q, l); }
+  static bool eval(mpq_srcptr q, double d)
+  {  __GMPXX_TMPQ_D;    return mpq_equal (q, temp) != 0; }
+  static bool eval(double d, mpq_srcptr q)
+  { return eval(q, d); }
+  static bool eval(mpq_srcptr q, mpz_srcptr z)
+  { return mpz_cmp_ui(mpq_denref(q), 1) == 0 && mpz_cmp(mpq_numref(q), z) == 0; }
+  static bool eval(mpz_srcptr z, mpq_srcptr q)
+  { return eval(q, z); }
+
+  static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; }
+
+  static bool eval(mpf_srcptr f, unsigned long int l)
+  { return mpf_cmp_ui(f, l) == 0; }
+  static bool eval(unsigned long int l, mpf_srcptr f)
+  { return eval(f, l); }
+  static bool eval(mpf_srcptr f, signed long int l)
+  { return mpf_cmp_si(f, l) == 0; }
+  static bool eval(signed long int l, mpf_srcptr f)
+  { return eval(f, l); }
+  static bool eval(mpf_srcptr f, double d)
+  { return mpf_cmp_d(f, d) == 0; }
+  static bool eval(double d, mpf_srcptr f)
+  { return eval(f, d); }
+  static bool eval(mpf_srcptr f, mpz_srcptr z)
+  { return mpf_cmp_z(f, z) == 0; }
+  static bool eval(mpz_srcptr z, mpf_srcptr f)
+  { return eval(f, z); }
+  static bool eval(mpf_srcptr f, mpq_srcptr q)
+  { return __gmp_cmp_function::eval(f, q) == 0; }
+  static bool eval(mpq_srcptr q, mpf_srcptr f)
+  { return eval(f, q); }
+};
+
+struct __gmp_binary_less
+{
+  static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; }
+
+  static bool eval(mpz_srcptr z, unsigned long int l)
+  { return mpz_cmp_ui(z, l) < 0; }
+  static bool eval(unsigned long int l, mpz_srcptr z)
+  { return mpz_cmp_ui(z, l) > 0; }
+  static bool eval(mpz_srcptr z, signed long int l)
+  { return mpz_cmp_si(z, l) < 0; }
+  static bool eval(signed long int l, mpz_srcptr z)
+  { return mpz_cmp_si(z, l) > 0; }
+  static bool eval(mpz_srcptr z, double d)
+  { return mpz_cmp_d(z, d) < 0; }
+  static bool eval(double d, mpz_srcptr z)
+  { return mpz_cmp_d(z, d) > 0; }
+
+  static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; }
+
+  static bool eval(mpq_srcptr q, unsigned long int l)
+  { return mpq_cmp_ui(q, l, 1) < 0; }
+  static bool eval(unsigned long int l, mpq_srcptr q)
+  { return mpq_cmp_ui(q, l, 1) > 0; }
+  static bool eval(mpq_srcptr q, signed long int l)
+  { return mpq_cmp_si(q, l, 1) < 0; }
+  static bool eval(signed long int l, mpq_srcptr q)
+  { return mpq_cmp_si(q, l, 1) > 0; }
+  static bool eval(mpq_srcptr q, double d)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (q, temp) < 0; }
+  static bool eval(double d, mpq_srcptr q)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (temp, q) < 0; }
+  static bool eval(mpq_srcptr q, mpz_srcptr z)
+  { return mpq_cmp_z(q, z) < 0; }
+  static bool eval(mpz_srcptr z, mpq_srcptr q)
+  { return mpq_cmp_z(q, z) > 0; }
+
+  static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; }
+
+  static bool eval(mpf_srcptr f, unsigned long int l)
+  { return mpf_cmp_ui(f, l) < 0; }
+  static bool eval(unsigned long int l, mpf_srcptr f)
+  { return mpf_cmp_ui(f, l) > 0; }
+  static bool eval(mpf_srcptr f, signed long int l)
+  { return mpf_cmp_si(f, l) < 0; }
+  static bool eval(signed long int l, mpf_srcptr f)
+  { return mpf_cmp_si(f, l) > 0; }
+  static bool eval(mpf_srcptr f, double d)
+  { return mpf_cmp_d(f, d) < 0; }
+  static bool eval(double d, mpf_srcptr f)
+  { return mpf_cmp_d(f, d) > 0; }
+  static bool eval(mpf_srcptr f, mpz_srcptr z)
+  { return mpf_cmp_z(f, z) < 0; }
+  static bool eval(mpz_srcptr z, mpf_srcptr f)
+  { return mpf_cmp_z(f, z) > 0; }
+  static bool eval(mpf_srcptr f, mpq_srcptr q)
+  { return __gmp_cmp_function::eval(f, q) < 0; }
+  static bool eval(mpq_srcptr q, mpf_srcptr f)
+  { return __gmp_cmp_function::eval(q, f) < 0; }
+};
+
+struct __gmp_binary_greater
+{
+  template <class T, class U>
+  static inline bool eval(T t, U u) { return __gmp_binary_less::eval(u, t); }
+};
+
+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); }
+};
+
+struct __gmp_unary_decrement
+{
+  static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); }
+  static void eval(mpq_ptr q)
+  { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); }
+  static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); }
+};
+
+struct __gmp_abs_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); }
+  static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); }
+};
+
+struct __gmp_trunc_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); }
+};
+
+struct __gmp_floor_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); }
+};
+
+struct __gmp_ceil_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); }
+};
+
+struct __gmp_sqrt_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); }
+};
+
+struct __gmp_hypot_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  {
+    mpf_t temp;
+    mpf_init2(temp, mpf_get_prec(f));
+    mpf_mul(temp, g, g);
+    mpf_mul(f, h, h);
+    mpf_add(f, f, temp);
+    mpf_sqrt(f, f);
+    mpf_clear(temp);
+  }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  {
+    mpf_t temp;
+    mpf_init2(temp, mpf_get_prec(f));
+    mpf_mul(temp, g, g);
+    mpf_set_ui(f, l);
+    mpf_mul_ui(f, f, l);
+    mpf_add(f, f, temp);
+    mpf_clear(temp);
+    mpf_sqrt(f, f);
+  }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  { eval(f, g, __gmpxx_abs_ui(l)); }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, mpf_get_prec(f));
+    mpf_mul(temp, g, g);
+    mpf_set_d(f, d);
+    mpf_mul(f, f, f);
+    mpf_add(f, f, temp);
+    mpf_sqrt(f, f);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  { eval(f, g, d); }
+};
+
+struct __gmp_sgn_function
+{
+  static int eval(mpz_srcptr z) { return mpz_sgn(z); }
+  static int eval(mpq_srcptr q) { return mpq_sgn(q); }
+  static int eval(mpf_srcptr f) { return mpf_sgn(f); }
+};
+
+struct __gmp_gcd_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_gcd(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  { mpz_gcd_ui(z, w, l); }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  { eval(z, w, __gmpxx_abs_ui(l)); }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_gcd (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+};
+
+struct __gmp_lcm_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_lcm(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  { mpz_lcm_ui(z, w, l); }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  { eval(z, w, __gmpxx_abs_ui(l)); }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_lcm (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+};
+
+struct __gmp_rand_function
+{
+  static void eval(mpz_ptr z, gmp_randstate_t s, mp_bitcnt_t l)
+  { mpz_urandomb(z, s, l); }
+  static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w)
+  { mpz_urandomm(z, s, w); }
+  static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec)
+  { mpf_urandomb(f, s, prec); }
+};
+
+struct __gmp_fac_function
+{
+  static void eval(mpz_ptr z, unsigned long l) { mpz_fac_ui(z, l); }
+  static void eval(mpz_ptr z, signed long l)
+  {
+    if (l < 0)
+#ifdef __EXCEPTIONS
+      throw std::domain_error ("factorial(negative)");
+#else
+      {
+        std::cerr << "std::domain_error: factorial(negative)\n";
+        std::abort();
+      }
+#endif
+    eval(z, static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w)
+  {
+    if (!mpz_fits_ulong_p(w))
+      {
+	if (mpz_sgn(w) < 0)
+#ifdef __EXCEPTIONS
+	  throw std::domain_error ("factorial(negative)");
+#else
+         {
+	    std::cerr << "std::domain_error: factorial(negative)\n";
+           std::abort();
+         }
+#endif
+	else
+#ifdef __EXCEPTIONS
+	  throw std::bad_alloc(); // or std::overflow_error ("factorial")?
+#else
+         {
+	    std::cerr << "std::bad_alloc\n";
+           std::abort();
+         }
+#endif
+      }
+    eval(z, mpz_get_ui(w));
+  }
+  static void eval(mpz_ptr z, double d)
+  {  __GMPXX_TMPZ_D;    eval (z, temp); }
+};
+
+struct __gmp_primorial_function
+{
+  static void eval(mpz_ptr z, unsigned long l) { mpz_primorial_ui(z, l); }
+  static void eval(mpz_ptr z, signed long l)
+  {
+    if (l < 0)
+#ifdef __EXCEPTIONS
+      throw std::domain_error ("primorial(negative)");
+#else
+      {
+        std::cerr << "std::domain_error: primorial(negative)\n";
+        std::abort();
+      }
+#endif
+    eval(z, static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w)
+  {
+    if (!mpz_fits_ulong_p(w))
+      {
+	if (mpz_sgn(w) < 0)
+#ifdef __EXCEPTIONS
+	  throw std::domain_error ("primorial(negative)");
+#else
+         {
+	    std::cerr << "std::domain_error: primorial(negative)\n";
+           std::abort();
+         }
+#endif
+	else
+#ifdef __EXCEPTIONS
+	  throw std::bad_alloc(); // or std::overflow_error ("primorial")?
+#else
+         {
+	    std::cerr << "std::bad_alloc\n";
+           std::abort();
+         }
+#endif
+      }
+    eval(z, mpz_get_ui(w));
+  }
+  static void eval(mpz_ptr z, double d)
+  {  __GMPXX_TMPZ_D;    eval (z, temp); }
+};
+
+struct __gmp_fib_function
+{
+  static void eval(mpz_ptr z, unsigned long l) { mpz_fib_ui(z, l); }
+  static void eval(mpz_ptr z, signed long l)
+  {
+    if (l < 0)
+      {
+	eval(z, -static_cast<unsigned long>(l));
+	if ((l & 1) == 0)
+	  mpz_neg(z, z);
+      }
+    else
+      eval(z, static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w)
+  {
+    if (!mpz_fits_slong_p(w))
+#ifdef __EXCEPTIONS
+      throw std::bad_alloc(); // or std::overflow_error ("fibonacci")?
+#else
+      {
+        std::cerr << "std::bad_alloc\n";
+        std::abort();
+      }
+#endif
+    eval(z, mpz_get_si(w));
+  }
+  static void eval(mpz_ptr z, double d)
+  {  __GMPXX_TMPZ_D;    eval (z, temp); }
+};
+
+
+/**************** Auxiliary classes ****************/
+
+/* this is much the same as gmp_allocated_string in gmp-impl.h
+   since gmp-impl.h is not publicly available, I redefine it here
+   I use a different name to avoid possible clashes */
+
+extern "C" {
+  typedef void (*__gmp_freefunc_t) (void *, size_t);
+}
+struct __gmp_alloc_cstring
+{
+  char *str;
+  __gmp_alloc_cstring(char *s) { str = s; }
+  ~__gmp_alloc_cstring()
+  {
+    __gmp_freefunc_t freefunc;
+    mp_get_memory_functions (NULL, NULL, &freefunc);
+    (*freefunc) (str, std::strlen(str)+1);
+  }
+};
+
+
+// general expression template class
+template <class T, class U>
+class __gmp_expr;
+
+
+// templates for resolving expression types
+template <class T>
+struct __gmp_resolve_ref
+{
+  typedef T ref_type;
+};
+
+template <class T, class U>
+struct __gmp_resolve_ref<__gmp_expr<T, U> >
+{
+  typedef const __gmp_expr<T, U> & ref_type;
+};
+
+
+template <class T, class U = T>
+struct __gmp_resolve_expr;
+
+template <>
+struct __gmp_resolve_expr<mpz_t>
+{
+  typedef mpz_t value_type;
+  typedef mpz_ptr ptr_type;
+  typedef mpz_srcptr srcptr_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpq_t>
+{
+  typedef mpq_t value_type;
+  typedef mpq_ptr ptr_type;
+  typedef mpq_srcptr srcptr_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpf_t>
+{
+  typedef mpf_t value_type;
+  typedef mpf_ptr ptr_type;
+  typedef mpf_srcptr srcptr_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpz_t, mpq_t>
+{
+  typedef mpq_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpq_t, mpz_t>
+{
+  typedef mpq_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpz_t, mpf_t>
+{
+  typedef mpf_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpf_t, mpz_t>
+{
+  typedef mpf_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpq_t, mpf_t>
+{
+  typedef mpf_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpf_t, mpq_t>
+{
+  typedef mpf_t value_type;
+};
+
+#if __GMPXX_USE_CXX11
+namespace std {
+  template <class T, class U, class V, class W>
+  struct common_type <__gmp_expr<T, U>, __gmp_expr<V, W> >
+  {
+  private:
+    typedef typename __gmp_resolve_expr<T, V>::value_type X;
+  public:
+    typedef __gmp_expr<X, X> type;
+  };
+
+  template <class T, class U>
+  struct common_type <__gmp_expr<T, U> >
+  {
+    typedef __gmp_expr<T, T> type;
+  };
+
+#define __GMPXX_DECLARE_COMMON_TYPE(typ)	\
+  template <class T, class U>			\
+  struct common_type <__gmp_expr<T, U>, typ >	\
+  {						\
+    typedef __gmp_expr<T, T> type;		\
+  };						\
+						\
+  template <class T, class U>			\
+  struct common_type <typ, __gmp_expr<T, U> >	\
+  {						\
+    typedef __gmp_expr<T, T> type;		\
+  }
+
+  __GMPXX_DECLARE_COMMON_TYPE(signed char);
+  __GMPXX_DECLARE_COMMON_TYPE(unsigned char);
+  __GMPXX_DECLARE_COMMON_TYPE(signed int);
+  __GMPXX_DECLARE_COMMON_TYPE(unsigned int);
+  __GMPXX_DECLARE_COMMON_TYPE(signed short int);
+  __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(float);
+  __GMPXX_DECLARE_COMMON_TYPE(double);
+#undef __GMPXX_DECLARE_COMMON_TYPE
+}
+#endif
+
+// classes for evaluating unary and binary expressions
+template <class T, class Op>
+struct __gmp_unary_expr
+{
+  typename __gmp_resolve_ref<T>::ref_type val;
+
+  __gmp_unary_expr(const T &v) : val(v) { }
+private:
+  __gmp_unary_expr();
+};
+
+template <class T, class U, class Op>
+struct __gmp_binary_expr
+{
+  typename __gmp_resolve_ref<T>::ref_type val1;
+  typename __gmp_resolve_ref<U>::ref_type val2;
+
+  __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { }
+private:
+  __gmp_binary_expr();
+};
+
+
+
+/**************** Macros for in-class declarations ****************/
+/* This is just repetitive code that is easier to maintain if it's written
+   only once */
+
+#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun)                         \
+  template <class T, class U>                                         \
+  __gmp_expr<value_type, value_type> & fun(const __gmp_expr<T, U> &);
+
+#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \
+  __gmp_expr & fun(signed char);              \
+  __gmp_expr & fun(unsigned char);            \
+  __gmp_expr & fun(signed int);               \
+  __gmp_expr & fun(unsigned int);             \
+  __gmp_expr & fun(signed short int);         \
+  __gmp_expr & fun(unsigned short int);       \
+  __gmp_expr & fun(signed long int);          \
+  __gmp_expr & fun(unsigned long int);        \
+  __gmp_expr & fun(float);                    \
+  __gmp_expr & fun(double);                   \
+  /* __gmp_expr & fun(long double); */
+
+#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \
+__GMPP_DECLARE_COMPOUND_OPERATOR(fun)        \
+__GMPN_DECLARE_COMPOUND_OPERATOR(fun)
+
+#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \
+  __gmp_expr & fun(mp_bitcnt_t);
+
+#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \
+  inline __gmp_expr & fun();                  \
+  inline __gmp_expr fun(int);
+
+#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(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=(float f) { assign_d(f); return *this; } \
+  __gmp_expr & operator=(double d) { assign_d(d); return *this; }
+
+#define __GMPP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                 \
+template <class U>                                                           \
+static __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr);
+
+#define __GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, bigtype) \
+static inline __gmp_expr<T, __gmp_unary_expr<bigtype, eval_fun> >            \
+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 __GMPND_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, double)
+
+#define __GMPN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                 \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed char)           \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned char)         \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed int)            \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned int)          \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed short int)      \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned short int)    \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed long int)       \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned long int)     \
+__GMPND_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, float)                 \
+__GMPND_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, double)
+
+#define __GMP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                  \
+__GMPP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                         \
+__GMPN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)
+
+/**************** mpz_class -- wrapper for mpz_t ****************/
+
+template <>
+class __gmp_expr<mpz_t, mpz_t>
+{
+private:
+  typedef mpz_t value_type;
+  value_type mp;
+
+  // Helper functions used for all arithmetic types
+  void assign_ui(unsigned long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      __get_mp()->_mp_size = 0;
+    else
+      mpz_set_ui(mp, l);
+  }
+  void assign_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      assign_ui(l);
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+	assign_ui(-static_cast<unsigned long>(l));
+	mpz_neg(mp, mp);
+      }
+    else
+      mpz_set_si(mp, l);
+  }
+  void assign_d (double d)
+  {
+    mpz_set_d (mp, d);
+  }
+
+  void init_ui(unsigned long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpz_init(mp);
+    else
+      mpz_init_set_ui(mp, l);
+  }
+  void init_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      init_ui(l);
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+	init_ui(-static_cast<unsigned long>(l));
+	mpz_neg(mp, mp);
+      }
+    else
+      mpz_init_set_si(mp, l);
+  }
+  void init_d (double d)
+  {
+    mpz_init_set_d (mp, d);
+  }
+
+public:
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+
+  // constructors and destructor
+  __gmp_expr() __GMPXX_NOEXCEPT { mpz_init(mp); }
+
+  __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&z) noexcept
+  { *__get_mp() = *z.__get_mp(); mpz_init(z.mp); }
+#endif
+  template <class T>
+  __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
+  { mpz_init(mp); __gmp_set_expr(mp, expr); }
+  template <class T, class U>
+  explicit __gmp_expr(const __gmp_expr<T, U> &expr)
+  { mpz_init(mp); __gmp_set_expr(mp, expr); }
+
+  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+
+  explicit __gmp_expr(const char *s, int base = 0)
+  {
+    if (mpz_init_set_str (mp, s, base) != 0)
+      {
+        mpz_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpz_set_str");
+#else
+        {
+          std::cerr << "std::invalid_argument: mpz_set_str\n";
+          std::abort();
+        }
+#endif
+      }
+  }
+  explicit __gmp_expr(const std::string &s, int base = 0)
+  {
+    if (mpz_init_set_str(mp, s.c_str(), base) != 0)
+      {
+        mpz_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpz_set_str");
+#else
+        {
+          std::cerr << "std::invalid_argument: mpz_set_str\n";
+          std::abort();
+        }
+#endif
+      }
+  }
+
+  explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); }
+
+  ~__gmp_expr() { mpz_clear(mp); }
+
+  void swap(__gmp_expr& z) __GMPXX_NOEXCEPT
+  { std::swap(*__get_mp(), *z.__get_mp()); }
+
+  // assignment operators
+  __gmp_expr & operator=(const __gmp_expr &z)
+  { mpz_set(mp, z.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&z) noexcept
+  { swap(z); return *this; }
+#endif
+  template <class T, class U>
+  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
+  { __gmp_set_expr(mp, expr); return *this; }
+
+  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+  __gmp_expr & operator=(const char *s)
+  {
+    if (mpz_set_str (mp, s, 0) != 0)
+#ifdef __EXCEPTIONS
+      throw std::invalid_argument ("mpz_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpz_set_str\n";
+        std::abort();
+      }
+#endif
+    return *this;
+  }
+  __gmp_expr & operator=(const std::string &s)
+  {
+    if (mpz_set_str(mp, s.c_str(), 0) != 0)
+#ifdef __EXCEPTIONS
+      throw std::invalid_argument ("mpz_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpz_set_str\n";
+        std::abort();
+      }
+#endif
+    return *this;
+  }
+
+  // string input/output functions
+  int set_str(const char *s, int base)
+  { return mpz_set_str(mp, s, base); }
+  int set_str(const std::string &s, int base)
+  { return mpz_set_str(mp, s.c_str(), base); }
+  std::string get_str(int base = 10) const
+  {
+    __gmp_alloc_cstring temp(mpz_get_str(0, base, mp));
+    return std::string(temp.str);
+  }
+
+  // conversion functions
+  mpz_srcptr __get_mp() const { return mp; }
+  mpz_ptr __get_mp() { return mp; }
+  mpz_srcptr get_mpz_t() const { return mp; }
+  mpz_ptr get_mpz_t() { return mp; }
+
+  signed long int get_si() const { return mpz_get_si(mp); }
+  unsigned long int get_ui() const { return mpz_get_ui(mp); }
+  double get_d() const { return mpz_get_d(mp); }
+
+  // bool fits_schar_p() const { return mpz_fits_schar_p(mp); }
+  // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); }
+  bool fits_sint_p() const { return mpz_fits_sint_p(mp); }
+  bool fits_uint_p() const { return mpz_fits_uint_p(mp); }
+  bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); }
+  bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); }
+  bool fits_slong_p() const { return mpz_fits_slong_p(mp); }
+  bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); }
+  // bool fits_float_p() const { return mpz_fits_float_p(mp); }
+  // bool fits_double_p() const { return mpz_fits_double_p(mp); }
+  // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); }
+
+#if __GMPXX_USE_CXX11
+  explicit operator bool() const { return __get_mp()->_mp_size != 0; }
+#endif
+
+  // member operators
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator%=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator&=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator|=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator^=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
+
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
+
+  __GMP_DECLARE_UNARY_STATIC_MEMFUN(mpz_t, factorial, __gmp_fac_function)
+  __GMP_DECLARE_UNARY_STATIC_MEMFUN(mpz_t, primorial, __gmp_primorial_function)
+  __GMP_DECLARE_UNARY_STATIC_MEMFUN(mpz_t, fibonacci, __gmp_fib_function)
+};
+
+typedef __gmp_expr<mpz_t, mpz_t> mpz_class;
+
+
+/**************** mpq_class -- wrapper for mpq_t ****************/
+
+template <>
+class __gmp_expr<mpq_t, mpq_t>
+{
+private:
+  typedef mpq_t value_type;
+  value_type mp;
+
+  // Helper functions used for all arithmetic types
+  void assign_ui(unsigned long l) { mpq_set_ui(mp, l, 1); }
+  void assign_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      assign_ui(l);
+    else
+      mpq_set_si(mp, l, 1);
+  }
+  void assign_d (double d)        { mpq_set_d (mp, d); }
+
+  void init_ui(unsigned long l)	{ mpq_init(mp); get_num() = l; }
+  void init_si(signed long l)	{ mpq_init(mp); get_num() = l; }
+  void init_d (double d)	{ mpq_init(mp); assign_d (d); }
+
+public:
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+  void canonicalize() { mpq_canonicalize(mp); }
+
+  // constructors and destructor
+  __gmp_expr() { mpq_init(mp); }
+
+  __gmp_expr(const __gmp_expr &q)
+  {
+    mpz_init_set(mpq_numref(mp), mpq_numref(q.mp));
+    mpz_init_set(mpq_denref(mp), mpq_denref(q.mp));
+  }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&q)
+  { *mp = *q.mp; mpq_init(q.mp); }
+  __gmp_expr(mpz_class &&z)
+  {
+    *mpq_numref(mp) = *z.get_mpz_t();
+    mpz_init_set_ui(mpq_denref(mp), 1);
+    mpz_init(z.get_mpz_t());
+  }
+#endif
+  template <class T>
+  __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
+  { mpq_init(mp); __gmp_set_expr(mp, expr); }
+  template <class T>
+  __gmp_expr(const __gmp_expr<mpq_t, T> &expr)
+  { mpq_init(mp); __gmp_set_expr(mp, expr); }
+  template <class T, class U>
+  explicit __gmp_expr(const __gmp_expr<T, U> &expr)
+  { mpq_init(mp); __gmp_set_expr(mp, expr); }
+
+  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+
+  explicit __gmp_expr(const char *s, int base = 0)
+  {
+    mpq_init (mp);
+    // If s is the literal 0, we meant to call another constructor.
+    // If s just happens to evaluate to 0, we would crash, so whatever.
+    if (s == 0)
+      {
+	// Don't turn mpq_class(0,0) into 0
+	mpz_set_si(mpq_denref(mp), base);
+      }
+    else if (mpq_set_str(mp, s, base) != 0)
+      {
+        mpq_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpq_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpq_set_str\n";
+        std::abort();
+      }
+#endif
+      }
+  }
+  explicit __gmp_expr(const std::string &s, int base = 0)
+  {
+    mpq_init(mp);
+    if (mpq_set_str (mp, s.c_str(), base) != 0)
+      {
+        mpq_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpq_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpq_set_str\n";
+        std::abort();
+      }
+#endif
+      }
+  }
+  explicit __gmp_expr(mpq_srcptr q)
+  {
+    mpz_init_set(mpq_numref(mp), mpq_numref(q));
+    mpz_init_set(mpq_denref(mp), mpq_denref(q));
+  }
+
+  __gmp_expr(const mpz_class &num, const mpz_class &den)
+  {
+    mpz_init_set(mpq_numref(mp), num.get_mpz_t());
+    mpz_init_set(mpq_denref(mp), den.get_mpz_t());
+  }
+
+  ~__gmp_expr() { mpq_clear(mp); }
+
+  void swap(__gmp_expr& q) __GMPXX_NOEXCEPT { std::swap(*mp, *q.mp); }
+
+  // assignment operators
+  __gmp_expr & operator=(const __gmp_expr &q)
+  { mpq_set(mp, q.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&q) noexcept
+  { swap(q); return *this; }
+  __gmp_expr & operator=(mpz_class &&z) noexcept
+  { get_num() = std::move(z); get_den() = 1u; return *this; }
+#endif
+  template <class T, class U>
+  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
+  { __gmp_set_expr(mp, expr); return *this; }
+
+  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+  __gmp_expr & operator=(const char *s)
+  {
+    if (mpq_set_str (mp, s, 0) != 0)
+#ifdef __EXCEPTIONS
+      throw std::invalid_argument ("mpq_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpq_set_str\n";
+        std::abort();
+      }
+#endif
+    return *this;
+  }
+  __gmp_expr & operator=(const std::string &s)
+  {
+    if (mpq_set_str(mp, s.c_str(), 0) != 0)
+#ifdef __EXCEPTIONS
+      throw std::invalid_argument ("mpq_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpq_set_str\n";
+        std::abort();
+      }
+#endif
+    return *this;
+  }
+
+  // string input/output functions
+  int set_str(const char *s, int base)
+  { return mpq_set_str(mp, s, base); }
+  int set_str(const std::string &s, int base)
+  { return mpq_set_str(mp, s.c_str(), base); }
+  std::string get_str(int base = 10) const
+  {
+    __gmp_alloc_cstring temp(mpq_get_str(0, base, mp));
+    return std::string(temp.str);
+  }
+
+  // conversion functions
+
+  // casting a reference to an mpz_t to mpz_class & is a dirty hack.
+  // It kind of works because the internal representation of mpz_class is
+  // exactly an mpz_t, but compilers are allowed to assume that mpq_class
+  // and mpz_class do not alias... In mpz_class, we avoid using mp directly,
+  // to reduce the risks of such problematic optimizations.
+  const mpz_class & get_num() const
+  { return reinterpret_cast<const mpz_class &>(*mpq_numref(mp)); }
+  mpz_class & get_num()
+  { return reinterpret_cast<mpz_class &>(*mpq_numref(mp)); }
+  const mpz_class & get_den() const
+  { return reinterpret_cast<const mpz_class &>(*mpq_denref(mp)); }
+  mpz_class & get_den()
+  { return reinterpret_cast<mpz_class &>(*mpq_denref(mp)); }
+
+  mpq_srcptr __get_mp() const { return mp; }
+  mpq_ptr __get_mp() { return mp; }
+  mpq_srcptr get_mpq_t() const { return mp; }
+  mpq_ptr get_mpq_t() { return mp; }
+
+  mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); }
+  mpz_ptr get_num_mpz_t() { return mpq_numref(mp); }
+  mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); }
+  mpz_ptr get_den_mpz_t() { return mpq_denref(mp); }
+
+  double get_d() const { return mpq_get_d(mp); }
+
+#if __GMPXX_USE_CXX11
+  explicit operator bool() const { return mpq_numref(mp)->_mp_size != 0; }
+#endif
+
+  // compound assignments
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
+
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
+};
+
+typedef __gmp_expr<mpq_t, mpq_t> mpq_class;
+
+
+/**************** mpf_class -- wrapper for mpf_t ****************/
+
+template <>
+class __gmp_expr<mpf_t, mpf_t>
+{
+private:
+  typedef mpf_t value_type;
+  value_type mp;
+
+  // Helper functions used for all arithmetic types
+  void assign_ui(unsigned long l) { mpf_set_ui(mp, l); }
+  void assign_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      assign_ui(l);
+    else
+      mpf_set_si(mp, l);
+  }
+  void assign_d (double d)        { mpf_set_d (mp, d); }
+
+  void init_ui(unsigned long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpf_init(mp);
+    else
+      mpf_init_set_ui(mp, l);
+  }
+  void init_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      init_ui(l);
+    else
+      mpf_init_set_si(mp, l);
+  }
+  void init_d (double d)	{ mpf_init_set_d (mp, d); }
+
+public:
+  mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); }
+
+  void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); }
+  void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); }
+
+  // constructors and destructor
+  __gmp_expr() { mpf_init(mp); }
+
+  __gmp_expr(const __gmp_expr &f)
+  { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&f)
+  { *mp = *f.mp; mpf_init2(f.mp, get_prec()); }
+#endif
+  __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set(mp, f.mp); }
+  template <class T, class U>
+  __gmp_expr(const __gmp_expr<T, U> &expr)
+  { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); }
+  template <class T, class U>
+  __gmp_expr(const __gmp_expr<T, U> &expr, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); }
+
+  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+
+  __gmp_expr(signed char c, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, c); }
+  __gmp_expr(unsigned char c, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, c); }
+
+  __gmp_expr(signed int i, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, i); }
+  __gmp_expr(unsigned int i, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, i); }
+
+  __gmp_expr(signed short int s, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, s); }
+  __gmp_expr(unsigned short int s, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, s); }
+
+  __gmp_expr(signed long int l, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, l); }
+  __gmp_expr(unsigned long int l, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, l); }
+
+  __gmp_expr(float f, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_d(mp, f); }
+  __gmp_expr(double d, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_d(mp, d); }
+  // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); }
+  // __gmp_expr(long double ld, mp_bitcnt_t prec)
+  // { mpf_init2(mp, prec); mpf_set_d(mp, ld); }
+
+  explicit __gmp_expr(const char *s)
+  {
+    if (mpf_init_set_str (mp, s, 0) != 0)
+      {
+        mpf_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpf_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpf_set_str\n";
+        std::abort();
+      }
+#endif
+      }
+  }
+  __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0)
+  {
+    mpf_init2(mp, prec);
+    if (mpf_set_str(mp, s, base) != 0)
+      {
+        mpf_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpf_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpf_set_str\n";
+        std::abort();
+      }
+#endif
+      }
+  }
+  explicit __gmp_expr(const std::string &s)
+  {
+    if (mpf_init_set_str(mp, s.c_str(), 0) != 0)
+      {
+        mpf_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpf_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpf_set_str\n";
+        std::abort();
+      }
+#endif
+      }
+  }
+  __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0)
+  {
+    mpf_init2(mp, prec);
+    if (mpf_set_str(mp, s.c_str(), base) != 0)
+      {
+        mpf_clear (mp);
+#ifdef __EXCEPTIONS
+        throw std::invalid_argument ("mpf_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpf_set_str\n";
+        std::abort();
+      }
+#endif
+      }
+  }
+
+  explicit __gmp_expr(mpf_srcptr f)
+  { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); }
+  __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set(mp, f); }
+
+  ~__gmp_expr() { mpf_clear(mp); }
+
+  void swap(__gmp_expr& f) __GMPXX_NOEXCEPT { std::swap(*mp, *f.mp); }
+
+  // assignment operators
+  __gmp_expr & operator=(const __gmp_expr &f)
+  { mpf_set(mp, f.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&f) noexcept
+  { swap(f); return *this; }
+#endif
+  template <class T, class U>
+  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
+  { __gmp_set_expr(mp, expr); return *this; }
+
+  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+  __gmp_expr & operator=(const char *s)
+  {
+    if (mpf_set_str (mp, s, 0) != 0)
+#ifdef __EXCEPTIONS
+      throw std::invalid_argument ("mpf_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpf_set_str\n";
+        std::abort();
+      }
+#endif
+    return *this;
+  }
+  __gmp_expr & operator=(const std::string &s)
+  {
+    if (mpf_set_str(mp, s.c_str(), 0) != 0)
+#ifdef __EXCEPTIONS
+      throw std::invalid_argument ("mpf_set_str");
+#else
+      {
+        std::cerr << "std::invalid_argument: mpf_set_str\n";
+        std::abort();
+      }
+#endif
+    return *this;
+  }
+
+  // string input/output functions
+  int set_str(const char *s, int base)
+  { return mpf_set_str(mp, s, base); }
+  int set_str(const std::string &s, int base)
+  { return mpf_set_str(mp, s.c_str(), base); }
+  std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const
+  {
+    __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp));
+    return std::string(temp.str);
+  }
+
+  // conversion functions
+  mpf_srcptr __get_mp() const { return mp; }
+  mpf_ptr __get_mp() { return mp; }
+  mpf_srcptr get_mpf_t() const { return mp; }
+  mpf_ptr get_mpf_t() { return mp; }
+
+  signed long int get_si() const { return mpf_get_si(mp); }
+  unsigned long int get_ui() const { return mpf_get_ui(mp); }
+  double get_d() const { return mpf_get_d(mp); }
+
+  // bool fits_schar_p() const { return mpf_fits_schar_p(mp); }
+  // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); }
+  bool fits_sint_p() const { return mpf_fits_sint_p(mp); }
+  bool fits_uint_p() const { return mpf_fits_uint_p(mp); }
+  bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); }
+  bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); }
+  bool fits_slong_p() const { return mpf_fits_slong_p(mp); }
+  bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); }
+  // bool fits_float_p() const { return mpf_fits_float_p(mp); }
+  // bool fits_double_p() const { return mpf_fits_double_p(mp); }
+  // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); }
+
+#if __GMPXX_USE_CXX11
+  explicit operator bool() const { return mpf_sgn(mp) != 0; }
+#endif
+
+  // compound assignments
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
+
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
+};
+
+typedef __gmp_expr<mpf_t, mpf_t> mpf_class;
+
+
+
+/**************** User-defined literals ****************/
+
+#if __GMPXX_USE_CXX11
+inline mpz_class operator"" _mpz(const char* s)
+{
+  return mpz_class(s);
+}
+
+inline mpq_class operator"" _mpq(const char* s)
+{
+  mpq_class q;
+  q.get_num() = s;
+  return q;
+}
+
+inline mpf_class operator"" _mpf(const char* s)
+{
+  return mpf_class(s);
+}
+#endif
+
+/**************** I/O operators ****************/
+
+// these should (and will) be provided separately
+
+template <class T, class U>
+inline std::ostream & operator<<
+(std::ostream &o, const __gmp_expr<T, U> &expr)
+{
+  __gmp_expr<T, T> const& temp(expr);
+  return o << temp.__get_mp();
+}
+
+template <class T>
+inline std::istream & operator>>(std::istream &i, __gmp_expr<T, T> &expr)
+{
+  return i >> expr.__get_mp();
+}
+
+/*
+// you might want to uncomment this
+inline std::istream & operator>>(std::istream &i, mpq_class &q)
+{
+  i >> q.get_mpq_t();
+  q.canonicalize();
+  return i;
+}
+*/
+
+
+/**************** Functions for type conversion ****************/
+
+inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w)
+{
+  mpz_set(z, w.get_mpz_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr<mpz_t, T> &expr)
+{
+  expr.eval(z);
+}
+
+template <class T>
+inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr<mpq_t, T> &expr)
+{
+  mpq_class const& temp(expr);
+  mpz_set_q(z, temp.get_mpq_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr<mpf_t, T> &expr)
+{
+  mpf_class const& temp(expr);
+  mpz_set_f(z, temp.get_mpf_t());
+}
+
+inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z)
+{
+  mpq_set_z(q, z.get_mpz_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr<mpz_t, T> &expr)
+{
+  __gmp_set_expr(mpq_numref(q), expr);
+  mpz_set_ui(mpq_denref(q), 1);
+}
+
+inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r)
+{
+  mpq_set(q, r.get_mpq_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr<mpq_t, T> &expr)
+{
+  expr.eval(q);
+}
+
+template <class T>
+inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr<mpf_t, T> &expr)
+{
+  mpf_class const& temp(expr);
+  mpq_set_f(q, temp.get_mpf_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr<mpz_t, T> &expr)
+{
+  mpz_class const& temp(expr);
+  mpf_set_z(f, temp.get_mpz_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr<mpq_t, T> &expr)
+{
+  mpq_class const& temp(expr);
+  mpf_set_q(f, temp.get_mpq_t());
+}
+
+inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g)
+{
+  mpf_set(f, g.get_mpf_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr<mpf_t, T> &expr)
+{
+  expr.eval(f);
+}
+
+
+/* Temporary objects */
+
+template <class T>
+class __gmp_temp
+{
+  __gmp_expr<T, T> val;
+  public:
+  template<class U, class V>
+  __gmp_temp(U const& u, V) : val (u) {}
+  typename __gmp_resolve_expr<T>::srcptr_type
+  __get_mp() const { return val.__get_mp(); }
+};
+
+template <>
+class __gmp_temp <mpf_t>
+{
+  mpf_class val;
+  public:
+  template<class U>
+  __gmp_temp(U const& u, mpf_ptr res) : val (u, mpf_get_prec(res)) {}
+  mpf_srcptr __get_mp() const { return val.__get_mp(); }
+};
+
+/**************** Specializations of __gmp_expr ****************/
+/* The eval() method of __gmp_expr<T, U> evaluates the corresponding
+   expression and assigns the result to its argument, which is either an
+   mpz_t, mpq_t, or mpf_t as specified by the T argument.
+   Compound expressions are evaluated recursively (temporaries are created
+   to hold intermediate values), while for simple expressions the eval()
+   method of the appropriate function object (available as the Op argument
+   of either __gmp_unary_expr<T, Op> or __gmp_binary_expr<T, U, Op>) is
+   called. */
+
+
+/**************** Unary expressions ****************/
+/* cases:
+   - simple:   argument is mp*_class, that is, __gmp_expr<T, T>
+   - compound: argument is __gmp_expr<T, U> (with U not equal to T) */
+
+
+// simple expressions
+
+template <class T, class Op>
+class __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val_type;
+
+  __gmp_unary_expr<val_type, Op> expr;
+public:
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val.__get_mp()); }
+  const val_type & get_val() const { return expr.val; }
+  mp_bitcnt_t get_prec() const { return expr.val.get_prec(); }
+};
+
+
+// simple expressions, U is a built-in numerical type
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_unary_expr<U, Op> >
+{
+private:
+  typedef U val_type;
+
+  __gmp_unary_expr<val_type, Op> expr;
+public:
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val); }
+  const val_type & get_val() const { return expr.val; }
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+};
+
+
+// compound expressions
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val_type;
+
+  __gmp_unary_expr<val_type, Op> expr;
+public:
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { expr.val.eval(p); Op::eval(p, p); }
+  const val_type & get_val() const { return expr.val; }
+  mp_bitcnt_t get_prec() const { return expr.val.get_prec(); }
+};
+
+
+/**************** Binary expressions ****************/
+/* simple:
+   - arguments are both mp*_class
+   - one argument is mp*_class, one is a built-in type
+   compound:
+   - one is mp*_class, one is __gmp_expr<T, U>
+   - one is __gmp_expr<T, U>, one is built-in
+   - both arguments are __gmp_expr<...> */
+
+
+// simple expressions
+
+template <class T, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+
+// simple expressions, U is a built-in numerical type
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef U val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val1.__get_mp(), expr.val2); }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val1.get_prec(); }
+};
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef U val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val1, expr.val2.__get_mp()); }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val2.get_prec(); }
+};
+
+
+// compound expressions, one argument is a subexpression
+
+template <class T, class U, class V, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<U, V>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef __gmp_expr<U, V> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val1.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val2);
+      Op::eval(p, expr.val1.__get_mp(), p);
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val2, p);
+      Op::eval(p, expr.val1.__get_mp(), temp.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class V, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<U, V> val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val2.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val1);
+      Op::eval(p, p, expr.val2.__get_mp());
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val1, p);
+      Op::eval(p, temp.__get_mp(), expr.val2.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef __gmp_expr<T, U> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val1.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val2);
+      Op::eval(p, expr.val1.__get_mp(), p);
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val2, p);
+      Op::eval(p, expr.val1.__get_mp(), temp.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val2.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val1);
+      Op::eval(p, p, expr.val2.__get_mp());
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val1, p);
+      Op::eval(p, temp.__get_mp(), expr.val2.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+
+// one argument is a subexpression, one is a built-in
+
+template <class T, class U, class V, class Op>
+class __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef V val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    expr.val1.eval(p);
+    Op::eval(p, p, expr.val2);
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val1.get_prec(); }
+};
+
+template <class T, class U, class V, class Op>
+class __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+{
+private:
+  typedef U val1_type;
+  typedef __gmp_expr<T, V> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    expr.val2.eval(p);
+    Op::eval(p, expr.val1, p);
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val2.get_prec(); }
+};
+
+
+// both arguments are subexpressions
+
+template <class T, class U, class V, class W, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef __gmp_expr<V, W> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    __gmp_temp<T> temp2(expr.val2, p);
+    expr.val1.eval(p);
+    Op::eval(p, p, temp2.__get_mp());
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class V, class W, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+{
+private:
+  typedef __gmp_expr<U, V> val1_type;
+  typedef __gmp_expr<T, W> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    __gmp_temp<T> temp1(expr.val1, p);
+    expr.val2.eval(p);
+    Op::eval(p, temp1.__get_mp(), p);
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class V, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef __gmp_expr<T, V> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    __gmp_temp<T> temp2(expr.val2, p);
+    expr.val1.eval(p);
+    Op::eval(p, p, temp2.__get_mp());
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+
+/**************** Special cases ****************/
+
+/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments
+   can be done directly without first converting the mpz to mpq.
+   Appropriate specializations of __gmp_expr are required. */
+
+
+#define __GMPZQ_DEFINE_EXPR(eval_fun)                                       \
+                                                                            \
+template <>                                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr<mpz_class, mpq_class, eval_fun> > \
+{                                                                           \
+private:                                                                    \
+  typedef mpz_class val1_type;                                              \
+  typedef mpq_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); }      \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <>                                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr<mpq_class, mpz_class, eval_fun> > \
+{                                                                           \
+private:                                                                    \
+  typedef mpq_class val1_type;                                              \
+  typedef mpz_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); }      \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<mpz_class, __gmp_expr<mpq_t, T>, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef mpz_class val1_type;                                              \
+  typedef __gmp_expr<mpq_t, T> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpq_class temp(expr.val2);                                              \
+    eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<mpq_class, __gmp_expr<mpz_t, T>, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef mpq_class val1_type;                                              \
+  typedef __gmp_expr<mpz_t, T> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp(expr.val2);                                              \
+    eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, mpq_class, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpz_t, T> val1_type;                                   \
+  typedef mpq_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp(expr.val1);                                              \
+    eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<__gmp_expr<mpq_t, T>, mpz_class, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpq_t, T> val1_type;                                   \
+  typedef mpz_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpq_class temp(expr.val1);                                              \
+    eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T, class U>                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr                                   \
+<__gmp_expr<mpz_t, T>, __gmp_expr<mpq_t, U>, eval_fun> >                    \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpz_t, T> val1_type;                                   \
+  typedef __gmp_expr<mpq_t, U> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp1(expr.val1);                                             \
+    expr.val2.eval(q);                                                      \
+    eval_fun::eval(q, temp1.get_mpz_t(), q);                                \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T, class U>                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr                                   \
+<__gmp_expr<mpq_t, T>, __gmp_expr<mpz_t, U>, eval_fun> >                    \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpq_t, T> val1_type;                                   \
+  typedef __gmp_expr<mpz_t, U> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp2(expr.val2);                                             \
+    expr.val1.eval(q);                                             \
+    eval_fun::eval(q, q, temp2.get_mpz_t());                \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};
+
+
+__GMPZQ_DEFINE_EXPR(__gmp_binary_plus)
+__GMPZQ_DEFINE_EXPR(__gmp_binary_minus)
+
+
+
+/**************** Macros for defining functions ****************/
+/* Results of operators and functions are instances of __gmp_expr<T, U>.
+   T determines the numerical type of the expression: it can be either
+   mpz_t, mpq_t, or mpf_t.  When the arguments of a binary
+   expression have different numerical types, __gmp_resolve_expr is used
+   to determine the "larger" type.
+   U is either __gmp_unary_expr<V, Op> or __gmp_binary_expr<V, W, Op>,
+   where V and W are the arguments' types -- they can in turn be
+   expressions, thus allowing to build compound expressions to any
+   degree of complexity.
+   Op is a function object that must have an eval() method accepting
+   appropriate arguments.
+   Actual evaluation of a __gmp_expr<T, U> object is done when it gets
+   assigned to an mp*_class ("lazy" evaluation): this is done by calling
+   its eval() method. */
+
+
+// non-member unary operators and functions
+
+#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun)                           \
+                                                                             \
+template <class T, class U>                                                  \
+inline __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr)                                            \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >(expr); \
+}
+
+// variant that only works for one of { mpz, mpq, mpf }
+
+#define __GMP_DEFINE_UNARY_FUNCTION_1(T, fun, eval_fun)                      \
+                                                                             \
+template <class U>                                                           \
+inline __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr)                                            \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >(expr); \
+}
+
+#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \
+                                                              \
+template <class T, class U>                                   \
+inline type fun(const __gmp_expr<T, U> &expr)                 \
+{                                                             \
+  __gmp_expr<T, T> const& temp(expr); \
+  return eval_fun::eval(temp.__get_mp());                     \
+}
+
+
+// non-member binary operators and functions
+
+#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun)                   \
+                                                                       \
+template <class T, class U, class V, class W>                          \
+inline __gmp_expr<typename __gmp_resolve_expr<T, V>::value_type,       \
+__gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, eval_fun> >      \
+fun(const __gmp_expr<T, U> &expr1, const __gmp_expr<V, W> &expr2)      \
+{                                                                      \
+  return __gmp_expr<typename __gmp_resolve_expr<T, V>::value_type,     \
+     __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, eval_fun> > \
+    (expr1, expr2);                                                    \
+}
+
+#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype)       \
+                                                                           \
+template <class T, class U>                                                \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >               \
+fun(const __gmp_expr<T, U> &expr, type t)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >(expr, t); \
+}                                                                          \
+                                                                           \
+template <class T, class U>                                                \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >               \
+fun(type t, const __gmp_expr<T, U> &expr)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >(t, expr); \
+}
+
+#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type)          \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int)
+
+#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type)            \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int)
+
+#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double)
+
+#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type)     \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double)
+
+#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun)              \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float)              \
+__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \
+__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun)        \
+__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun)
+
+// variant that only works for one of { mpz, mpq, mpf }
+
+#define __GMPP_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)              \
+                                                                       \
+template <class U, class W>                                            \
+inline __gmp_expr<T,                                                   \
+__gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, W>, eval_fun> >      \
+fun(const __gmp_expr<T, U> &expr1, const __gmp_expr<T, W> &expr2)      \
+{                                                                      \
+  return __gmp_expr<T,                                                 \
+     __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, W>, eval_fun> > \
+    (expr1, expr2);                                                    \
+}
+
+#define __GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, bigtype)  \
+                                                                           \
+template <class U>                                                         \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >               \
+fun(const __gmp_expr<T, U> &expr, type t)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >(expr, t); \
+}                                                                          \
+                                                                           \
+template <class U>                                                         \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >               \
+fun(type t, const __gmp_expr<T, U> &expr)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >(t, expr); \
+}
+
+#define __GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type)          \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, signed long int)
+
+#define __GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type)          \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, unsigned long int)
+
+#define __GMPND_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type) \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, double)
+
+#define __GMPNLD_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type)     \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, long double)
+
+#define __GMPN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)              \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, float)              \
+__GMPND_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun) \
+__GMPP_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)        \
+__GMPN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)
+
+
+#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun)                 \
+                                                                       \
+template <class T, class U>                                            \
+inline __gmp_expr                                                      \
+<T, __gmp_binary_expr<__gmp_expr<T, U>, mp_bitcnt_t, eval_fun> > \
+fun(const __gmp_expr<T, U> &expr, mp_bitcnt_t l)                 \
+{                                                                      \
+  return __gmp_expr<T, __gmp_binary_expr                               \
+    <__gmp_expr<T, U>, mp_bitcnt_t, eval_fun> >(expr, l);        \
+}
+
+
+#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)         \
+                                                                        \
+template <class T, class U, class V, class W>                           \
+inline type fun(const __gmp_expr<T, U> &expr1,                          \
+		const __gmp_expr<V, W> &expr2)                          \
+{                                                                       \
+  __gmp_expr<T, T> const& temp1(expr1);                                 \
+  __gmp_expr<V, V> const& temp2(expr2);                                 \
+  return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp());            \
+}
+
+#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun,   \
+					    type2, bigtype)        \
+                                                                   \
+template <class T, class U>                                        \
+inline type fun(const __gmp_expr<T, U> &expr, type2 t)             \
+{                                                                  \
+  __gmp_expr<T, T> const& temp(expr);      \
+  return eval_fun::eval(temp.__get_mp(), static_cast<bigtype>(t)); \
+}                                                                  \
+                                                                   \
+template <class T, class U>                                        \
+inline type fun(type2 t, const __gmp_expr<T, U> &expr)             \
+{                                                                  \
+  __gmp_expr<T, T> const& temp(expr);      \
+  return eval_fun::eval(static_cast<bigtype>(t), temp.__get_mp()); \
+}
+
+#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun,                \
+				    type2, signed long int)
+
+#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun,                \
+				    type2, unsigned long int)
+
+#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double)
+
+#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2)     \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double)
+
+#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)              \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float)              \
+__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \
+__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)        \
+__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)
+
+
+// member operators
+
+#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)                 \
+                                                                             \
+template <class T, class U>                                                  \
+inline type##_class & type##_class::fun(const __gmp_expr<T, U> &expr)        \
+{                                                                            \
+  __gmp_set_expr(mp, __gmp_expr<type##_t, __gmp_binary_expr                  \
+		 <type##_class, __gmp_expr<T, U>, eval_fun> >(*this, expr)); \
+  return *this;                                                              \
+}
+
+#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun,    \
+					 type2, bigtype)         \
+                                                                 \
+inline type##_class & type##_class::fun(type2 t)                 \
+{                                                                \
+  __gmp_set_expr(mp, __gmp_expr<type##_t, __gmp_binary_expr      \
+		 <type##_class, bigtype, eval_fun> >(*this, t)); \
+  return *this;                                                  \
+}
+
+#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun,                \
+				 type2, signed long int)
+
+#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun,                \
+				 type2, unsigned long int)
+
+#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double)
+
+#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2)     \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double)
+
+#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)              \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float)              \
+__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \
+__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)        \
+__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)
+
+#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun)
+
+#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun)
+
+#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun)
+
+
+
+#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun)  \
+                                                                \
+inline type##_class & type##_class::fun(mp_bitcnt_t l)    \
+{                                                               \
+  __gmp_set_expr(mp, __gmp_expr<type##_t, __gmp_binary_expr     \
+    <type##_class, mp_bitcnt_t, eval_fun> >(*this, l));   \
+  return *this;                                                 \
+}
+
+#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun)
+
+#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun)
+
+#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun)
+
+
+
+#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \
+                                                             \
+inline type##_class & type##_class::fun()                    \
+{                                                            \
+  eval_fun::eval(mp);                                        \
+  return *this;                                              \
+}                                                            \
+                                                             \
+inline type##_class type##_class::fun(int)                   \
+{                                                            \
+  type##_class temp(*this);                                  \
+  eval_fun::eval(mp);                                        \
+  return temp;                                               \
+}
+
+#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun)
+
+#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun)
+
+#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun)
+
+
+#define __GMPP_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                  \
+template <class U>                                                           \
+__gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr)                                            \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >(expr); \
+}
+
+#define __GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, bigtype)  \
+inline __gmp_expr<T, __gmp_unary_expr<bigtype, eval_fun> >                   \
+fun(type expr)                                                               \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<bigtype, eval_fun> >(expr);          \
+}
+
+#define __GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, signed long)
+#define __GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, unsigned long)
+#define __GMPND_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, double)
+
+#define __GMPN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                 \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed char)           \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned char)         \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed int)            \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned int)          \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed short int)      \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned short int)    \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed long int)       \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned long int)     \
+__GMPND_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, float)                 \
+__GMPND_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, double)                \
+
+#define __GMP_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                  \
+__GMPP_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                         \
+__GMPN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                         \
+
+
+/**************** Arithmetic operators and functions ****************/
+
+// non-member operators and functions
+
+__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus)
+__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, operator~, __gmp_unary_com)
+
+__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus)
+__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus)
+__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies)
+__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator%, __gmp_binary_modulus)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator&, __gmp_binary_and)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator|, __gmp_binary_ior)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator^, __gmp_binary_xor)
+
+__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift)
+__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift)
+
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, ! __gmp_binary_equal)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, ! __gmp_binary_greater)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, ! __gmp_binary_less)
+
+__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, trunc, __gmp_trunc_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, floor, __gmp_floor_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, ceil, __gmp_ceil_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, sqrt, __gmp_sqrt_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, sqrt, __gmp_sqrt_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, factorial, __gmp_fac_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, primorial, __gmp_primorial_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, fibonacci, __gmp_fib_function)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpf_t, hypot, __gmp_hypot_function)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, gcd, __gmp_gcd_function)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, lcm, __gmp_lcm_function)
+
+__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function)
+
+template <class T>
+void swap(__gmp_expr<T, T>& x, __gmp_expr<T, T>& y) __GMPXX_NOEXCEPT
+{ x.swap(y); }
+
+// member operators for mpz_class
+
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus)
+
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor)
+
+__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift)
+__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift)
+
+__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment)
+__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement)
+
+__GMP_DEFINE_UNARY_STATIC_MEMFUN(mpz_t, mpz_class::factorial, __gmp_fac_function)
+__GMP_DEFINE_UNARY_STATIC_MEMFUN(mpz_t, mpz_class::primorial, __gmp_primorial_function)
+__GMP_DEFINE_UNARY_STATIC_MEMFUN(mpz_t, mpz_class::fibonacci, __gmp_fib_function)
+
+// member operators for mpq_class
+
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus)
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus)
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies)
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides)
+
+__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift)
+__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift)
+
+__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment)
+__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement)
+
+// member operators for mpf_class
+
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus)
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus)
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies)
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides)
+
+__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift)
+__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift)
+
+__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment)
+__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement)
+
+
+
+/**************** Class wrapper for gmp_randstate_t ****************/
+
+class __gmp_urandomb_value { };
+class __gmp_urandomm_value { };
+
+template <>
+class __gmp_expr<mpz_t, __gmp_urandomb_value>
+{
+private:
+  __gmp_randstate_struct *state;
+  mp_bitcnt_t bits;
+public:
+  __gmp_expr(gmp_randstate_t s, mp_bitcnt_t l) : state(s), bits(l) { }
+  void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); }
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+};
+
+template <>
+class __gmp_expr<mpz_t, __gmp_urandomm_value>
+{
+private:
+  __gmp_randstate_struct *state;
+  mpz_class range;
+public:
+  __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { }
+  void eval(mpz_ptr z) const
+  { __gmp_rand_function::eval(z, state, range.get_mpz_t()); }
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+};
+
+template <>
+class __gmp_expr<mpf_t, __gmp_urandomb_value>
+{
+private:
+  __gmp_randstate_struct *state;
+  mp_bitcnt_t bits;
+public:
+  __gmp_expr(gmp_randstate_t s, mp_bitcnt_t l) : state(s), bits(l) { }
+  void eval(mpf_ptr f) const
+  {
+    __gmp_rand_function::eval(f, state,
+	(bits>0) ? bits : mpf_get_prec(f));
+  }
+  mp_bitcnt_t get_prec() const
+  {
+    if (bits == 0)
+      return mpf_get_default_prec();
+    else
+      return bits;
+  }
+};
+
+extern "C" {
+  typedef void __gmp_randinit_default_t (gmp_randstate_t);
+  typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t);
+  typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t);
+}
+
+class gmp_randclass
+{
+private:
+  gmp_randstate_t state;
+
+  // copy construction and assignment not allowed
+  gmp_randclass(const gmp_randclass &);
+  void operator=(const gmp_randclass &);
+public:
+  // constructors and destructor
+  gmp_randclass(gmp_randalg_t alg, unsigned long int size)
+  {
+    switch (alg)
+      {
+      case GMP_RAND_ALG_LC: // no other cases for now
+      default:
+	gmp_randinit(state, alg, size);
+	break;
+      }
+  }
+
+  // gmp_randinit_default
+  gmp_randclass(__gmp_randinit_default_t* f) { f(state); }
+
+  // gmp_randinit_lc_2exp
+  gmp_randclass(__gmp_randinit_lc_2exp_t* f,
+		mpz_class z, unsigned long int l1, mp_bitcnt_t l2)
+  { f(state, z.get_mpz_t(), l1, l2); }
+
+  // gmp_randinit_lc_2exp_size
+  gmp_randclass(__gmp_randinit_lc_2exp_size_t* f,
+		mp_bitcnt_t size)
+  {
+    if (f (state, size) == 0)
+#ifdef __EXCEPTIONS
+      throw std::length_error ("gmp_randinit_lc_2exp_size");
+#else
+      {
+        std::cerr << "std::length_error: gmp_randinit_lc_2exp_size\n";
+        std::abort();
+      }
+#endif
+  }
+
+  ~gmp_randclass() { gmp_randclear(state); }
+
+  // initialize
+  void seed(); // choose a random seed some way (?)
+  void seed(unsigned long int s) { gmp_randseed_ui(state, s); }
+  void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); }
+
+  // get random number
+  __gmp_expr<mpz_t, __gmp_urandomb_value> get_z_bits(mp_bitcnt_t l)
+  { return __gmp_expr<mpz_t, __gmp_urandomb_value>(state, l); }
+  __gmp_expr<mpz_t, __gmp_urandomb_value> get_z_bits(const mpz_class &z)
+  { return get_z_bits(z.get_ui()); }
+  // FIXME: z.get_bitcnt_t() ?
+
+  __gmp_expr<mpz_t, __gmp_urandomm_value> get_z_range(const mpz_class &z)
+  { return __gmp_expr<mpz_t, __gmp_urandomm_value>(state, z); }
+
+  __gmp_expr<mpf_t, __gmp_urandomb_value> get_f(mp_bitcnt_t prec = 0)
+  { return __gmp_expr<mpf_t, __gmp_urandomb_value>(state, prec); }
+};
+
+
+/**************** Specialize std::numeric_limits ****************/
+
+namespace std {
+  template <> class numeric_limits<mpz_class>
+  {
+  public:
+    static const bool is_specialized = true;
+    static mpz_class min() { return mpz_class(); }
+    static mpz_class max() { return mpz_class(); }
+    static mpz_class lowest() { return mpz_class(); }
+    static const int digits = 0;
+    static const int digits10 = 0;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = true;
+    static const bool is_exact = true;
+    static const int radix = 2;
+    static mpz_class epsilon() { return mpz_class(); }
+    static mpz_class round_error() { return mpz_class(); }
+    static const int min_exponent = 0;
+    static const int min_exponent10 = 0;
+    static const int max_exponent = 0;
+    static const int max_exponent10 = 0;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = false;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_absent;
+    static const bool has_denorm_loss = false;
+    static mpz_class infinity() { return mpz_class(); }
+    static mpz_class quiet_NaN() { return mpz_class(); }
+    static mpz_class signaling_NaN() { return mpz_class(); }
+    static mpz_class denorm_min() { return mpz_class(); }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_toward_zero;
+  };
+
+  template <> class numeric_limits<mpq_class>
+  {
+  public:
+    static const bool is_specialized = true;
+    static mpq_class min() { return mpq_class(); }
+    static mpq_class max() { return mpq_class(); }
+    static mpq_class lowest() { return mpq_class(); }
+    static const int digits = 0;
+    static const int digits10 = 0;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = false;
+    static const bool is_exact = true;
+    static const int radix = 2;
+    static mpq_class epsilon() { return mpq_class(); }
+    static mpq_class round_error() { return mpq_class(); }
+    static const int min_exponent = 0;
+    static const int min_exponent10 = 0;
+    static const int max_exponent = 0;
+    static const int max_exponent10 = 0;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = false;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_absent;
+    static const bool has_denorm_loss = false;
+    static mpq_class infinity() { return mpq_class(); }
+    static mpq_class quiet_NaN() { return mpq_class(); }
+    static mpq_class signaling_NaN() { return mpq_class(); }
+    static mpq_class denorm_min() { return mpq_class(); }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_toward_zero;
+  };
+
+  template <> class numeric_limits<mpf_class>
+  {
+  public:
+    static const bool is_specialized = true;
+    static mpf_class min() { return mpf_class(); }
+    static mpf_class max() { return mpf_class(); }
+    static mpf_class lowest() { return mpf_class(); }
+    static const int digits = 0;
+    static const int digits10 = 0;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = false;
+    static const bool is_exact = false;
+    static const int radix = 2;
+    static mpf_class epsilon() { return mpf_class(); }
+    static mpf_class round_error() { return mpf_class(); }
+    static const int min_exponent = 0;
+    static const int min_exponent10 = 0;
+    static const int max_exponent = 0;
+    static const int max_exponent10 = 0;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = false;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_absent;
+    static const bool has_denorm_loss = false;
+    static mpf_class infinity() { return mpf_class(); }
+    static mpf_class quiet_NaN() { return mpf_class(); }
+    static mpf_class signaling_NaN() { return mpf_class(); }
+    static mpf_class denorm_min() { return mpf_class(); }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_indeterminate;
+  };
+}
+
+
+/**************** #undef all private macros ****************/
+
+#undef __GMPP_DECLARE_COMPOUND_OPERATOR
+#undef __GMPN_DECLARE_COMPOUND_OPERATOR
+#undef __GMP_DECLARE_COMPOUND_OPERATOR
+#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI
+#undef __GMP_DECLARE_INCREMENT_OPERATOR
+#undef __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+#undef __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+#undef __GMPZQ_DEFINE_EXPR
+
+#undef __GMP_DEFINE_UNARY_FUNCTION_1
+#undef __GMP_DEFINE_UNARY_FUNCTION
+#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION
+
+#undef __GMPP_DEFINE_BINARY_FUNCTION
+#undef __GMPNN_DEFINE_BINARY_FUNCTION
+#undef __GMPNS_DEFINE_BINARY_FUNCTION
+#undef __GMPNU_DEFINE_BINARY_FUNCTION
+#undef __GMPND_DEFINE_BINARY_FUNCTION
+#undef __GMPNLD_DEFINE_BINARY_FUNCTION
+#undef __GMPN_DEFINE_BINARY_FUNCTION
+#undef __GMP_DEFINE_BINARY_FUNCTION
+
+#undef __GMP_DEFINE_BINARY_FUNCTION_UI
+
+#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION
+
+#undef __GMPZ_DEFINE_COMPOUND_OPERATOR
+
+#undef __GMPP_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNN_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNS_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNU_DEFINE_COMPOUND_OPERATOR
+#undef __GMPND_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR
+#undef __GMPN_DEFINE_COMPOUND_OPERATOR
+#undef __GMP_DEFINE_COMPOUND_OPERATOR
+
+#undef __GMPQ_DEFINE_COMPOUND_OPERATOR
+#undef __GMPF_DEFINE_COMPOUND_OPERATOR
+
+#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI
+#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI
+#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI
+#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI
+
+#undef __GMP_DEFINE_INCREMENT_OPERATOR
+#undef __GMPZ_DEFINE_INCREMENT_OPERATOR
+#undef __GMPQ_DEFINE_INCREMENT_OPERATOR
+#undef __GMPF_DEFINE_INCREMENT_OPERATOR
+
+#undef __GMPXX_CONSTANT_TRUE
+#undef __GMPXX_CONSTANT
+
+#endif /* __GMP_PLUSPLUS__ */
diff --git a/invalid.c b/invalid.c
new file mode 100644
index 0000000..e09eab2
--- /dev/null
+++ b/invalid.c
@@ -0,0 +1,82 @@
+/* __gmp_invalid_operation -- invalid floating point operation.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <signal.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for getpid */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* Incidentally, kill is not available on mingw, but that's ok, it has raise
+   and we'll be using that.  */
+#if ! HAVE_RAISE
+#define raise(sig)   kill (getpid(), sig)
+#endif
+
+
+/* __gmp_invalid_operation is for an invalid floating point operation, like
+   mpz_set_d on a NaN or Inf.  It's done as a subroutine to minimize code in
+   places raising an exception.
+
+   feraiseexcept(FE_INVALID) is not used here, since unfortunately on most
+   systems it would require libm.
+
+   Alternatives:
+
+   It might be possible to check whether a hardware "invalid operation" trap
+   is enabled or not before raising a signal.  This would require all
+   callers to be prepared to continue with some bogus result.  Bogus returns
+   are bad, but presumably an application disabling the trap is prepared for
+   that.
+
+   On some systems (eg. BSD) the signal handler can find out the reason for
+   a SIGFPE (overflow, invalid, div-by-zero, etc).  Perhaps we could get
+   that into our raise too.
+
+   i386 GLIBC implements feraiseexcept(FE_INVALID) with an asm fdiv 0/0.
+   That would both respect the exceptions mask and give a reason code in a
+   BSD signal.  */
+
+void
+__gmp_invalid_operation (void)
+{
+  raise (SIGFPE);
+  abort ();
+}
diff --git a/longlong.h b/longlong.h
new file mode 100644
index 0000000..be1c3cb
--- /dev/null
+++ b/longlong.h
@@ -0,0 +1,2289 @@
+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
+
+Copyright 1991-1994, 1996, 1997, 1999-2005, 2007-2009, 2011-2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* You have to define the following before including this file:
+
+   UWtype -- An unsigned type, default type for operations (typically a "word")
+   UHWtype -- An unsigned type, at least half the size of UWtype
+   UDWtype -- An unsigned type, at least twice as large a UWtype
+   W_TYPE_SIZE -- size in bits of UWtype
+
+   SItype, USItype -- Signed and unsigned 32 bit types
+   DItype, UDItype -- Signed and unsigned 64 bit types
+
+   On a 32 bit machine UWtype should typically be USItype;
+   on a 64 bit machine, UWtype should typically be UDItype.
+
+   Optionally, define:
+
+   LONGLONG_STANDALONE -- Avoid code that needs machine-dependent support files
+   NO_ASM -- Disable inline asm
+
+
+   CAUTION!  Using this version of longlong.h outside of GMP is not safe.  You
+   need to include gmp.h and gmp-impl.h, or certain things might not work as
+   expected.
+*/
+
+#define __BITS4 (W_TYPE_SIZE / 4)
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+/* This is used to make sure no undesirable sharing between different libraries
+   that use this file takes place.  */
+#ifndef __MPN
+#define __MPN(x) __##x
+#endif
+
+/* Define auxiliary asm macros.
+
+   1) umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two
+   UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype
+   word product in HIGH_PROD and LOW_PROD.
+
+   2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
+   UDWtype product.  This is just a variant of umul_ppmm.
+
+   3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+   denominator) divides a UDWtype, composed by the UWtype integers
+   HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+   in QUOTIENT and the remainder in REMAINDER.  HIGH_NUMERATOR must be less
+   than DENOMINATOR for correct operation.  If, in addition, the most
+   significant bit of DENOMINATOR must be 1, then the pre-processor symbol
+   UDIV_NEEDS_NORMALIZATION is defined to 1.
+
+   4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+   denominator).  Like udiv_qrnnd but the numbers are signed.  The quotient
+   is rounded towards 0.
+
+   5) count_leading_zeros(count, x) counts the number of zero-bits from the
+   msb to the first non-zero bit in the UWtype X.  This is the number of
+   steps X needs to be shifted left to set the msb.  Undefined for X == 0,
+   unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
+
+   6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
+   from the least significant end.
+
+   7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+   high_addend_2, low_addend_2) adds two UWtype integers, composed by
+   HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
+   respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
+   (i.e. carry out) is not stored anywhere, and is lost.
+
+   8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+   high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+   composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+   LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
+   and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
+   and is lost.
+
+   If any of these macros are left undefined for a particular CPU,
+   C macros are used.
+
+
+   Notes:
+
+   For add_ssaaaa the two high and two low addends can both commute, but
+   unfortunately gcc only supports one "%" commutative in each asm block.
+   This has always been so but is only documented in recent versions
+   (eg. pre-release 3.3).  Having two or more "%"s can cause an internal
+   compiler error in certain rare circumstances.
+
+   Apparently it was only the last "%" that was ever actually respected, so
+   the code has been updated to leave just that.  Clearly there's a free
+   choice whether high or low should get it, if there's a reason to favour
+   one over the other.  Also obviously when the constraints on the two
+   operands are identical there's no benefit to the reloader in any "%" at
+   all.
+
+   */
+
+/* The CPUs come in alphabetical order below.
+
+   Please add support for more CPUs here, or improve the current support
+   for the CPUs below!  */
+
+
+/* count_leading_zeros_gcc_clz is count_leading_zeros implemented with gcc
+   3.4 __builtin_clzl or __builtin_clzll, according to our limb size.
+   Similarly count_trailing_zeros_gcc_ctz using __builtin_ctzl or
+   __builtin_ctzll.
+
+   These builtins are only used when we check what code comes out, on some
+   chips they're merely libgcc calls, where we will instead want an inline
+   in that case (either asm or generic C).
+
+   These builtins are better than an asm block of the same insn, since an
+   asm block doesn't give gcc any information about scheduling or resource
+   usage.  We keep an asm block for use on prior versions of gcc though.
+
+   For reference, __builtin_ffs existed in gcc prior to __builtin_clz, but
+   it's not used (for count_leading_zeros) because it generally gives extra
+   code to ensure the result is 0 when the input is 0, which we don't need
+   or want.  */
+
+#ifdef _LONG_LONG_LIMB
+#define count_leading_zeros_gcc_clz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_clzll (x);		\
+  } while (0)
+#else
+#define count_leading_zeros_gcc_clz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_clzl (x);		\
+  } while (0)
+#endif
+
+#ifdef _LONG_LONG_LIMB
+#define count_trailing_zeros_gcc_ctz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_ctzll (x);		\
+  } while (0)
+#else
+#define count_trailing_zeros_gcc_ctz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_ctzl (x);		\
+  } while (0)
+#endif
+
+
+/* FIXME: The macros using external routines like __MPN(count_leading_zeros)
+   don't need to be under !NO_ASM */
+#if ! defined (NO_ASM)
+
+#if defined (__alpha) && W_TYPE_SIZE == 64
+/* Most alpha-based machines, except Cray systems. */
+#if defined (__GNUC__)
+#if __GMP_GNUC_PREREQ (3,3)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (ph) = __builtin_alpha_umulh (__m0, __m1);				\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#else
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("umulh %r1,%2,%0"						\
+	     : "=r" (ph)						\
+	     : "%rJ" (__m0), "rI" (__m1));				\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#else /* ! __GNUC__ */
+#include <machine/builtins.h>
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (ph) = __UMULH (__m0, __m1);					\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+#endif /* LONGLONG_STANDALONE */
+
+/* clz_tab is required in all configurations, since mpn/alpha/cntlz.asm
+   always goes into libgmp.so, even when not actually used.  */
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+
+#if defined (__GNUC__) && HAVE_HOST_CPU_alpha_CIX
+#define count_leading_zeros(COUNT,X) \
+  __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X))
+#define count_trailing_zeros(COUNT,X) \
+  __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X))
+#endif /* clz/ctz using cix */
+
+#if ! defined (count_leading_zeros)				\
+  && defined (__GNUC__) && ! defined (LONGLONG_STANDALONE)
+/* ALPHA_CMPBGE_0 gives "cmpbge $31,src,dst", ie. test src bytes == 0.
+   "$31" is written explicitly in the asm, since an "r" constraint won't
+   select reg 31.  There seems no need to worry about "r31" syntax for cray,
+   since gcc itself (pre-release 3.4) emits just $31 in various places.	 */
+#define ALPHA_CMPBGE_0(dst, src)					\
+  do { asm ("cmpbge $31, %1, %0" : "=r" (dst) : "r" (src)); } while (0)
+/* Zero bytes are turned into bits with cmpbge, a __clz_tab lookup counts
+   them, locating the highest non-zero byte.  A second __clz_tab lookup
+   counts the leading zero bits in that byte, giving the result.  */
+#define count_leading_zeros(count, x)					\
+  do {									\
+    UWtype  __clz__b, __clz__c, __clz__x = (x);				\
+    ALPHA_CMPBGE_0 (__clz__b,  __clz__x);	    /* zero bytes */	\
+    __clz__b = __clz_tab [(__clz__b >> 1) ^ 0x7F];  /* 8 to 1 byte */	\
+    __clz__b = __clz__b * 8 - 7;		    /* 57 to 1 shift */ \
+    __clz__x >>= __clz__b;						\
+    __clz__c = __clz_tab [__clz__x];		    /* 8 to 1 bit */	\
+    __clz__b = 65 - __clz__b;						\
+    (count) = __clz__b - __clz__c;					\
+  } while (0)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif /* clz using cmpbge */
+
+#if ! defined (count_leading_zeros) && ! defined (LONGLONG_STANDALONE)
+#if HAVE_ATTRIBUTE_CONST
+long __MPN(count_leading_zeros) (UDItype) __attribute__ ((const));
+#else
+long __MPN(count_leading_zeros) (UDItype);
+#endif
+#define count_leading_zeros(count, x) \
+  ((count) = __MPN(count_leading_zeros) (x))
+#endif /* clz using mpn */
+#endif /* __alpha */
+
+#if defined (__AVR) && W_TYPE_SIZE == 8
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    unsigned short __p = (unsigned short) (m0) * (m1);			\
+    (ph) = __p >> 8;							\
+    (pl) = __p;								\
+  } while (0)
+#endif /* AVR */
+
+#if defined (_CRAY) && W_TYPE_SIZE == 64
+#include <intrinsics.h>
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+long __MPN(count_leading_zeros) (UDItype);
+#define count_leading_zeros(count, x) \
+  ((count) = _leadz ((UWtype) (x)))
+#if defined (_CRAYIEEE)		/* I.e., Cray T90/ieee, T3D, and T3E */
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (ph) = _int_mult_upper (__m0, __m1);				\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#endif /* LONGLONG_STANDALONE */
+#endif /* _CRAYIEEE */
+#endif /* _CRAY */
+
+#if defined (__ia64) && W_TYPE_SIZE == 64
+/* This form encourages gcc (pre-release 3.4 at least) to emit predicated
+   "sub r=r,r" and "sub r=r,r,1", giving a 2 cycle latency.  The generic
+   code using "al<bl" arithmetically comes out making an actual 0 or 1 in a
+   register, which takes an extra cycle.  */
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)      \
+  do {						\
+    UWtype __x;					\
+    __x = (al) - (bl);				\
+    if ((al) < (bl))				\
+      (sh) = (ah) - (bh) - 1;			\
+    else					\
+      (sh) = (ah) - (bh);			\
+    (sl) = __x;					\
+  } while (0)
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)
+/* Do both product parts in assembly, since that gives better code with
+   all gcc versions.  Some callers will just use the upper part, and in
+   that situation we waste an instruction, but not any cycles.  */
+#define umul_ppmm(ph, pl, m0, m1) \
+    __asm__ ("xma.hu %0 = %2, %3, f0\n\txma.l %1 = %2, %3, f0"		\
+	     : "=&f" (ph), "=f" (pl)					\
+	     : "f" (m0), "f" (m1))
+#define count_leading_zeros(count, x) \
+  do {									\
+    UWtype _x = (x), _y, _a, _c;					\
+    __asm__ ("mux1 %0 = %1, @rev" : "=r" (_y) : "r" (_x));		\
+    __asm__ ("czx1.l %0 = %1" : "=r" (_a) : "r" (-_y | _y));		\
+    _c = (_a - 1) << 3;							\
+    _x >>= _c;								\
+    if (_x >= 1 << 4)							\
+      _x >>= 4, _c += 4;						\
+    if (_x >= 1 << 2)							\
+      _x >>= 2, _c += 2;						\
+    _c += _x >> 1;							\
+    (count) =  W_TYPE_SIZE - 1 - _c;					\
+  } while (0)
+/* similar to what gcc does for __builtin_ffs, but 0 based rather than 1
+   based, and we don't need a special case for x==0 here */
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    UWtype __ctz_x = (x);						\
+    __asm__ ("popcnt %0 = %1"						\
+	     : "=r" (count)						\
+	     : "r" ((__ctz_x-1) & ~__ctz_x));				\
+  } while (0)
+#endif
+#if defined (__INTEL_COMPILER)
+#include <ia64intrin.h>
+#define umul_ppmm(ph, pl, m0, m1)					\
+  do {									\
+    UWtype __m0 = (m0), __m1 = (m1);					\
+    ph = _m64_xmahu (__m0, __m1, 0);					\
+    pl = __m0 * __m1;							\
+  } while (0)
+#endif
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+#endif
+#endif
+
+
+#if defined (__GNUC__)
+
+/* We sometimes need to clobber "cc" with gcc2, but that would not be
+   understood by gcc1.  Use cpp to avoid major code duplication.  */
+#if __GNUC__ < 2
+#define __CLOBBER_CC
+#define __AND_CLOBBER_CC
+#else /* __GNUC__ >= 2 */
+#define __CLOBBER_CC : "cc"
+#define __AND_CLOBBER_CC , "cc"
+#endif /* __GNUC__ < 2 */
+
+#if (defined (__a29k__) || defined (_AM29K)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add %1,%4,%5\n\taddc %0,%2,%3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub %1,%4,%5\n\tsubc %0,%2,%3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "r" (ah), "rI" (bh), "r" (al), "rI" (bl))
+#define umul_ppmm(xh, xl, m0, m1) \
+  do {									\
+    USItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("multiplu %0,%1,%2"					\
+	     : "=r" (xl)						\
+	     : "r" (__m0), "r" (__m1));					\
+    __asm__ ("multmu %0,%1,%2"						\
+	     : "=r" (xh)						\
+	     : "r" (__m0), "r" (__m1));					\
+  } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("dividu %0,%3,%4"						\
+	   : "=r" (q), "=q" (r)						\
+	   : "1" (n1), "r" (n0), "r" (d))
+#define count_leading_zeros(count, x) \
+    __asm__ ("clz %0,%1"						\
+	     : "=r" (count)						\
+	     : "r" (x))
+#define COUNT_LEADING_ZEROS_0 32
+#endif /* __a29k__ */
+
+#if defined (__arc__)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add.f\t%1, %4, %5\n\tadc\t%0, %2, %3"			\
+	   : "=r" (sh),							\
+	     "=&r" (sl)							\
+	   : "r"  ((USItype) (ah)),					\
+	     "rICal" ((USItype) (bh)),					\
+	     "%r" ((USItype) (al)),					\
+	     "rICal" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub.f\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	   : "=r" (sh),							\
+	     "=&r" (sl)							\
+	   : "r" ((USItype) (ah)),					\
+	     "rICal" ((USItype) (bh)),					\
+	     "r" ((USItype) (al)),					\
+	     "rICal" ((USItype) (bl)))
+#endif
+
+#if defined (__arm__) && (defined (__thumb2__) || !defined (__thumb__)) \
+    && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && -(USItype)(bl) < (USItype)(bl))	\
+      __asm__ ("subs\t%1, %4, %5\n\tadc\t%0, %2, %3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh),					\
+		 "%r" (al), "rI" (-(USItype)(bl)) __CLOBBER_CC);	\
+    else								\
+      __asm__ ("adds\t%1, %4, %5\n\tadc\t%0, %2, %3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC);	\
+  } while (0)
+/* FIXME: Extend the immediate range for the low word by using both ADDS and
+   SUBS, since they set carry in the same way.  We need separate definitions
+   for thumb and non-thumb since thumb lacks RSC.  */
+#if defined (__thumb__)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (ah) && __builtin_constant_p (bh)		\
+	&& (ah) == (bh))						\
+      __asm__ ("subs\t%1, %2, %3\n\tsbc\t%0, %0, %0"			\
+	       : "=r" (sh), "=r" (sl)					\
+	       : "r" (al), "rI" (bl) __CLOBBER_CC);			\
+    else if (__builtin_constant_p (al))					\
+      __asm__ ("rsbs\t%1, %5, %4\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+    else								\
+      __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+    } while (0)
+#else
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (ah) && __builtin_constant_p (bh)		\
+	&& (ah) == (bh))						\
+      __asm__ ("subs\t%1, %2, %3\n\tsbc\t%0, %0, %0"			\
+	       : "=r" (sh), "=r" (sl)					\
+	       : "r" (al), "rI" (bl) __CLOBBER_CC);			\
+    else if (__builtin_constant_p (al))					\
+      {									\
+	if (__builtin_constant_p (ah))					\
+	  __asm__ ("rsbs\t%1, %5, %4\n\trsc\t%0, %3, %2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "rI" (ah), "r" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+	else								\
+	  __asm__ ("rsbs\t%1, %5, %4\n\tsbc\t%0, %2, %3"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r" (ah), "rI" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+      }									\
+    else if (__builtin_constant_p (ah))					\
+      {									\
+	if (__builtin_constant_p (bl))					\
+	  __asm__ ("subs\t%1, %4, %5\n\trsc\t%0, %3, %2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "rI" (ah), "r" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+	else								\
+	  __asm__ ("rsbs\t%1, %5, %4\n\trsc\t%0, %3, %2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "rI" (ah), "r" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+      }									\
+    else								\
+      __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+    } while (0)
+#endif
+#if defined (__ARM_ARCH_2__) || defined (__ARM_ARCH_2A__) \
+    || defined (__ARM_ARCH_3__)
+#define umul_ppmm(xh, xl, a, b)						\
+  do {									\
+    register USItype __t0, __t1, __t2;					\
+    __asm__ ("%@ Inlined umul_ppmm\n"					\
+	   "	mov	%2, %5, lsr #16\n"				\
+	   "	mov	%0, %6, lsr #16\n"				\
+	   "	bic	%3, %5, %2, lsl #16\n"				\
+	   "	bic	%4, %6, %0, lsl #16\n"				\
+	   "	mul	%1, %3, %4\n"					\
+	   "	mul	%4, %2, %4\n"					\
+	   "	mul	%3, %0, %3\n"					\
+	   "	mul	%0, %2, %0\n"					\
+	   "	adds	%3, %4, %3\n"					\
+	   "	addcs	%0, %0, #65536\n"				\
+	   "	adds	%1, %1, %3, lsl #16\n"				\
+	   "	adc	%0, %0, %3, lsr #16"				\
+	   : "=&r" ((USItype) (xh)), "=r" ((USItype) (xl)),		\
+	     "=&r" (__t0), "=&r" (__t1), "=r" (__t2)			\
+	   : "r" ((USItype) (a)), "r" ((USItype) (b)) __CLOBBER_CC);	\
+  } while (0)
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __r;							\
+    (q) = __MPN(udiv_qrnnd) (&__r, (n1), (n0), (d));			\
+    (r) = __r;								\
+  } while (0)
+extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype);
+#endif /* LONGLONG_STANDALONE */
+#else /* ARMv4 or newer */
+#define umul_ppmm(xh, xl, a, b) \
+  __asm__ ("umull %0,%1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b))
+#define smul_ppmm(xh, xl, a, b) \
+  __asm__ ("smull %0,%1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b))
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+#endif /* LONGLONG_STANDALONE */
+#endif /* defined(__ARM_ARCH_2__) ... */
+#define count_leading_zeros(count, x)  count_leading_zeros_gcc_clz(count, x)
+#define count_trailing_zeros(count, x)  count_trailing_zeros_gcc_ctz(count, x)
+#endif /* __arm__ */
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && ~(UDItype)(bl) <= (UDItype)(bl))	\
+      __asm__ ("subs\t%1, %x4, %5\n\tadc\t%0, %x2, %x3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "rZ" ((UDItype)(ah)), "rZ" ((UDItype)(bh)),		\
+		 "%r" ((UDItype)(al)), "rI" (-(UDItype)(bl)) __CLOBBER_CC);\
+    else								\
+      __asm__ ("adds\t%1, %x4, %5\n\tadc\t%0, %x2, %x3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "rZ" ((UDItype)(ah)), "rZ" ((UDItype)(bh)),		\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl)) __CLOBBER_CC);\
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && ~(UDItype)(bl) <= (UDItype)(bl))	\
+      __asm__ ("adds\t%1, %x4, %5\n\tsbc\t%0, %x2, %x3"			\
+	       : "=r,r" (sh), "=&r,&r" (sl)				\
+	       : "rZ,rZ" ((UDItype)(ah)), "rZ,rZ" ((UDItype)(bh)),	\
+		 "r,Z"   ((UDItype)(al)), "rI,r" (-(UDItype)(bl)) __CLOBBER_CC);\
+    else								\
+      __asm__ ("subs\t%1, %x4, %5\n\tsbc\t%0, %x2, %x3"			\
+	       : "=r,r" (sh), "=&r,&r" (sl)				\
+	       : "rZ,rZ" ((UDItype)(ah)), "rZ,rZ" ((UDItype)(bh)),	\
+		 "r,Z"   ((UDItype)(al)), "rI,r"  ((UDItype)(bl)) __CLOBBER_CC);\
+  } while(0);
+#if __GMP_GNUC_PREREQ (4,9)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
+    __ll_UTItype __ll = (__ll_UTItype)(u) * (v);			\
+    w1 = __ll >> 64;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("umulh\t%0, %1, %2" : "=r" (ph) : "r" (__m0), "r" (__m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#define count_leading_zeros(count, x)  count_leading_zeros_gcc_clz(count, x)
+#define count_trailing_zeros(count, x)  count_trailing_zeros_gcc_ctz(count, x)
+#endif /* __aarch64__ */
+
+#if defined (__clipper__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("mulwux %2,%0"						\
+	   : "=r" (__x.__ll)						\
+	   : "%0" ((USItype)(u)), "r" ((USItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define smul_ppmm(w1, w0, u, v) \
+  ({union {DItype __ll;							\
+	   struct {SItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("mulwx %2,%0"						\
+	   : "=r" (__x.__ll)						\
+	   : "%0" ((SItype)(u)), "r" ((SItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define __umulsidi3(u, v) \
+  ({UDItype __w;							\
+    __asm__ ("mulwux %2,%0"						\
+	     : "=r" (__w) : "%0" ((USItype)(u)), "r" ((USItype)(v)));	\
+    __w; })
+#endif /* __clipper__ */
+
+/* Fujitsu vector computers.  */
+#if defined (__uxp__) && W_TYPE_SIZE == 32
+#define umul_ppmm(ph, pl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mult.lu %1,%2,%0"	: "=r" (__x.__ll) : "%r" (u), "rK" (v));\
+    (ph) = __x.__i.__h;							\
+    (pl) = __x.__i.__l;							\
+  } while (0)
+#define smul_ppmm(ph, pl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mult.l %1,%2,%0" : "=r" (__x.__ll) : "%r" (u), "rK" (v));	\
+    (ph) = __x.__i.__h;							\
+    (pl) = __x.__i.__l;							\
+  } while (0)
+#endif
+
+#if defined (__gmicro__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add.w %5,%1\n\taddx %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub.w %5,%1\n\tsubx %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+  __asm__ ("mulx %3,%0,%1"						\
+	   : "=g" (ph), "=r" (pl)					\
+	   : "%0" ((USItype)(m0)), "g" ((USItype)(m1)))
+#define udiv_qrnnd(q, r, nh, nl, d) \
+  __asm__ ("divx %4,%0,%1"						\
+	   : "=g" (q), "=r" (r)						\
+	   : "1" ((USItype)(nh)), "0" ((USItype)(nl)), "g" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+  __asm__ ("bsch/1 %1,%0"						\
+	   : "=g" (count) : "g" ((USItype)(x)), "0" ((USItype)0))
+#endif
+
+#if defined (__hppa) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add%I5 %5,%r4,%1\n\taddc %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "%rM" (al), "rI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub%I4 %4,%r5,%1\n\tsubb %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "rI" (al), "rM" (bl))
+#if defined (_PA_RISC1_1)
+#define umul_ppmm(wh, wl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("xmpyu %1,%2,%0" : "=*f" (__x.__ll) : "*f" (u), "*f" (v));	\
+    (wh) = __x.__i.__h;							\
+    (wl) = __x.__i.__l;							\
+  } while (0)
+#endif
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __tmp;							\
+    __asm__ (								\
+       "ldi		1,%0\n"						\
+"	extru,=		%1,15,16,%%r0	; Bits 31..16 zero?\n"		\
+"	extru,tr	%1,15,16,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		16(%0),%0	; Yes.  Perform add.\n"		\
+"	extru,=		%1,23,8,%%r0	; Bits 15..8 zero?\n"		\
+"	extru,tr	%1,23,8,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		8(%0),%0	; Yes.  Perform add.\n"		\
+"	extru,=		%1,27,4,%%r0	; Bits 7..4 zero?\n"		\
+"	extru,tr	%1,27,4,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		4(%0),%0	; Yes.  Perform add.\n"		\
+"	extru,=		%1,29,2,%%r0	; Bits 3..2 zero?\n"		\
+"	extru,tr	%1,29,2,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		2(%0),%0	; Yes.  Perform add.\n"		\
+"	extru		%1,30,1,%1	; Extract bit 1.\n"		\
+"	sub		%0,%1,%0	; Subtract it.\n"		\
+	: "=r" (count), "=r" (__tmp) : "1" (x));			\
+  } while (0)
+#endif /* hppa */
+
+/* These macros are for ABI=2.0w.  In ABI=2.0n they can't be used, since GCC
+   (3.2) puts longlong into two adjacent 32-bit registers.  Presumably this
+   is just a case of no direct support for 2.0n but treating it like 1.0. */
+#if defined (__hppa) && W_TYPE_SIZE == 64 && ! defined (_LONG_LONG_LIMB)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add%I5 %5,%r4,%1\n\tadd,dc %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "%rM" (al), "rI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub%I4 %4,%r5,%1\n\tsub,db %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "rI" (al), "rM" (bl))
+#endif /* hppa */
+
+#if (defined (__i370__) || defined (__s390__) || defined (__mvs__)) && W_TYPE_SIZE == 32
+#if defined (__zarch__) || defined (HAVE_HOST_CPU_s390_zarch)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl)				\
+  do {									\
+/*  if (__builtin_constant_p (bl))					\
+      __asm__ ("alfi\t%1,%o5\n\talcr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0"  (ah), "r" (bh), "%1" (al), "n" (bl) __CLOBBER_CC);\
+    else								\
+*/    __asm__ ("alr\t%1,%5\n\talcr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0"  (ah), "r" (bh), "%1" (al), "r" (bl)__CLOBBER_CC);	\
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+  do {									\
+/*  if (__builtin_constant_p (bl))					\
+      __asm__ ("slfi\t%1,%o5\n\tslbr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0" (ah), "r" (bh), "1" (al), "n" (bl) __CLOBBER_CC);	\
+    else								\
+*/    __asm__ ("slr\t%1,%5\n\tslbr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0" (ah), "r" (bh), "1" (al), "r" (bl) __CLOBBER_CC);	\
+  } while (0)
+#if __GMP_GNUC_PREREQ (4,5)
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__ll = (UDItype) (m0) * (UDItype) (m1);				\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#else
+#if 0
+/* FIXME: this fails if gcc knows about the 64-bit registers.  Use only
+   with a new enough processor pretending we have 32-bit registers.  */
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mlr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "%0" (m0), "r" (m1));					\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#else
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+  /* When we have 64-bit regs and gcc is aware of that, we cannot simply use
+     DImode for the product, since that would be allocated to a single 64-bit
+     register, whereas mlr uses the low 32-bits of an even-odd register pair.
+  */									\
+    register USItype __r0 __asm__ ("0");				\
+    register USItype __r1 __asm__ ("1") = (m0);				\
+    __asm__ ("mlr\t%0,%3"						\
+	     : "=r" (__r0), "=r" (__r1)					\
+	     : "r" (__r1), "r" (m1));					\
+    (xh) = __r0; (xl) = __r1;						\
+  } while (0)
+#endif /* if 0 */
+#endif
+#if 0
+/* FIXME: this fails if gcc knows about the 64-bit registers.  Use only
+   with a new enough processor pretending we have 32-bit registers.  */
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("dlr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "0" (__x.__ll), "r" (d));				\
+    (q) = __x.__i.__l; (r) = __x.__i.__h;				\
+  } while (0)
+#else
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    register USItype __r0 __asm__ ("0") = (n1);				\
+    register USItype __r1 __asm__ ("1") = (n0);				\
+    __asm__ ("dlr\t%0,%4"						\
+	     : "=r" (__r0), "=r" (__r1)					\
+	     : "r" (__r0), "r" (__r1), "r" (d));			\
+    (q) = __r1; (r) = __r0;						\
+  } while (0)
+#endif /* if 0 */
+#else /* if __zarch__ */
+/* FIXME: this fails if gcc knows about the 64-bit registers.  */
+#define smul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {DItype __ll;							\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "%0" (m0), "r" (m1));					\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+/* FIXME: this fails if gcc knows about the 64-bit registers.  */
+#define sdiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    union {DItype __ll;							\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("dr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "0" (__x.__ll), "r" (d));				\
+    (q) = __x.__i.__l; (r) = __x.__i.__h;				\
+  } while (0)
+#endif /* if __zarch__ */
+#endif
+
+#if defined (__s390x__) && W_TYPE_SIZE == 64
+/* We need to cast operands with register constraints, otherwise their types
+   will be assumed to be SImode by gcc.  For these machines, such operations
+   will insert a value into the low 32 bits, and leave the high 32 bits with
+   garbage.  */
+#define add_ssaaaa(sh, sl, ah, al, bh, bl)				\
+  do {									\
+    __asm__ ("algr\t%1,%5\n\talcgr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0"  ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+		 "%1" ((UDItype)(al)), "r" ((UDItype)(bl)) __CLOBBER_CC); \
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+  do {									\
+    __asm__ ("slgr\t%1,%5\n\tslbgr\t%0,%3"				\
+	     : "=r" (sh), "=&r" (sl)					\
+	     : "0" ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+	       "1" ((UDItype)(al)), "r" ((UDItype)(bl)) __CLOBBER_CC);	\
+  } while (0)
+#if !defined (__clang__)
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {unsigned int __attribute__ ((mode(TI))) __ll;		\
+	   struct {UDItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mlgr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "%0" ((UDItype)(m0)), "r" ((UDItype)(m1)));		\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    union {unsigned int __attribute__ ((mode(TI))) __ll;		\
+	   struct {UDItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("dlgr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "0" (__x.__ll), "r" ((UDItype)(d)));			\
+    (q) = __x.__i.__l; (r) = __x.__i.__h;				\
+  } while (0)
+#endif
+#if 0 /* FIXME: Enable for z10 (?) */
+#define count_leading_zeros(cnt, x)					\
+  do {									\
+    union {unsigned int __attribute__ ((mode(TI))) __ll;		\
+	   struct {UDItype __h, __l;} __i;				\
+	  } __clr_cnt;							\
+    __asm__ ("flogr\t%0,%1"						\
+	     : "=r" (__clr_cnt.__ll)					\
+	     : "r" (x) __CLOBBER_CC);					\
+    (cnt) = __clr_cnt.__i.__h;						\
+  } while (0)
+#endif
+#endif
+
+/* On x86 and x86_64, every asm implicitly clobbers "flags" and "fpsr",
+   so we don't need __CLOBBER_CC.  */
+#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addl %5,%k1\n\tadcl %3,%k0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subl %5,%k1\n\tsbbl %3,%k0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mull %3"							\
+	   : "=a" (w0), "=d" (w1)					\
+	   : "%0" ((USItype)(u)), "rm" ((USItype)(v)))
+#define udiv_qrnnd(q, r, n1, n0, dx) /* d renamed to dx avoiding "=d" */\
+  __asm__ ("divl %4"		     /* stringification in K&R C */	\
+	   : "=a" (q), "=d" (r)						\
+	   : "0" ((USItype)(n0)), "1" ((USItype)(n1)), "rm" ((USItype)(dx)))
+
+#if HAVE_HOST_CPU_i586 || HAVE_HOST_CPU_pentium || HAVE_HOST_CPU_pentiummmx
+/* Pentium bsrl takes between 10 and 72 cycles depending where the most
+   significant 1 bit is, hence the use of the following alternatives.  bsfl
+   is slow too, between 18 and 42 depending where the least significant 1
+   bit is, so let the generic count_trailing_zeros below make use of the
+   count_leading_zeros here too.  */
+
+#if HAVE_HOST_CPU_pentiummmx && ! defined (LONGLONG_STANDALONE)
+/* The following should be a fixed 14 or 15 cycles, but possibly plus an L1
+   cache miss reading from __clz_tab.  For P55 it's favoured over the float
+   below so as to avoid mixing MMX and x87, since the penalty for switching
+   between the two is about 100 cycles.
+
+   The asm block sets __shift to -3 if the high 24 bits are clear, -2 for
+   16, -1 for 8, or 0 otherwise.  This could be written equivalently as
+   follows, but as of gcc 2.95.2 it results in conditional jumps.
+
+       __shift = -(__n < 0x1000000);
+       __shift -= (__n < 0x10000);
+       __shift -= (__n < 0x100);
+
+   The middle two sbbl and cmpl's pair, and with luck something gcc
+   generates might pair with the first cmpl and the last sbbl.  The "32+1"
+   constant could be folded into __clz_tab[], but it doesn't seem worth
+   making a different table just for that.  */
+
+#define count_leading_zeros(c,n)					\
+  do {									\
+    USItype  __n = (n);							\
+    USItype  __shift;							\
+    __asm__ ("cmpl  $0x1000000, %1\n"					\
+	     "sbbl  %0, %0\n"						\
+	     "cmpl  $0x10000, %1\n"					\
+	     "sbbl  $0, %0\n"						\
+	     "cmpl  $0x100, %1\n"					\
+	     "sbbl  $0, %0\n"						\
+	     : "=&r" (__shift) : "r"  (__n));				\
+    __shift = __shift*8 + 24 + 1;					\
+    (c) = 32 + 1 - __shift - __clz_tab[__n >> __shift];			\
+  } while (0)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#define COUNT_LEADING_ZEROS_0   31   /* n==0 indistinguishable from n==1 */
+
+#else /* ! pentiummmx || LONGLONG_STANDALONE */
+/* The following should be a fixed 14 cycles or so.  Some scheduling
+   opportunities should be available between the float load/store too.  This
+   sort of code is used in gcc 3 for __builtin_ffs (with "n&-n") and is
+   apparently suggested by the Intel optimizing manual (don't know exactly
+   where).  gcc 2.95 or up will be best for this, so the "double" is
+   correctly aligned on the stack.  */
+#define count_leading_zeros(c,n)					\
+  do {									\
+    union {								\
+      double    d;							\
+      unsigned  a[2];							\
+    } __u;								\
+    __u.d = (UWtype) (n);						\
+    (c) = 0x3FF + 31 - (__u.a[1] >> 20);				\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0   (0x3FF + 31)
+#endif /* pentiummx */
+
+#else /* ! pentium */
+
+#if __GMP_GNUC_PREREQ (3,4)  /* using bsrl */
+#define count_leading_zeros(count,x)  count_leading_zeros_gcc_clz(count,x)
+#endif /* gcc clz */
+
+/* On P6, gcc prior to 3.0 generates a partial register stall for
+   __cbtmp^31, due to using "xorb $31" instead of "xorl $31", the former
+   being 1 code byte smaller.  "31-__cbtmp" is a workaround, probably at the
+   cost of one extra instruction.  Do this for "i386" too, since that means
+   generic x86.  */
+#if ! defined (count_leading_zeros) && __GNUC__ < 3			\
+  && (HAVE_HOST_CPU_i386						\
+      || HAVE_HOST_CPU_i686						\
+      || HAVE_HOST_CPU_pentiumpro					\
+      || HAVE_HOST_CPU_pentium2						\
+      || HAVE_HOST_CPU_pentium3)
+#define count_leading_zeros(count, x)					\
+  do {									\
+    USItype __cbtmp;							\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsrl %1,%0" : "=r" (__cbtmp) : "rm" ((USItype)(x)));	\
+    (count) = 31 - __cbtmp;						\
+  } while (0)
+#endif /* gcc<3 asm bsrl */
+
+#ifndef count_leading_zeros
+#define count_leading_zeros(count, x)					\
+  do {									\
+    USItype __cbtmp;							\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsrl %1,%0" : "=r" (__cbtmp) : "rm" ((USItype)(x)));	\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#endif /* asm bsrl */
+
+#if __GMP_GNUC_PREREQ (3,4)  /* using bsfl */
+#define count_trailing_zeros(count,x)  count_trailing_zeros_gcc_ctz(count,x)
+#endif /* gcc ctz */
+
+#ifndef count_trailing_zeros
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsfl %1,%k0" : "=r" (count) : "rm" ((USItype)(x)));	\
+  } while (0)
+#endif /* asm bsfl */
+
+#endif /* ! pentium */
+
+#endif /* 80x86 */
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addq %5,%q1\n\tadcq %3,%q0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((UDItype)(ah)), "rme" ((UDItype)(bh)),		\
+	     "%1" ((UDItype)(al)), "rme" ((UDItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subq %5,%q1\n\tsbbq %3,%q0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((UDItype)(ah)), "rme" ((UDItype)(bh)),		\
+	     "1" ((UDItype)(al)), "rme" ((UDItype)(bl)))
+#if X86_ASM_MULX \
+   && (HAVE_HOST_CPU_haswell || HAVE_HOST_CPU_broadwell \
+       || HAVE_HOST_CPU_skylake || HAVE_HOST_CPU_bd4 || HAVE_HOST_CPU_zen)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulx\t%3, %q0, %q1"						\
+	   : "=r" (w0), "=r" (w1)					\
+	   : "%d" ((UDItype)(u)), "rm" ((UDItype)(v)))
+#else
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulq\t%3"							\
+	   : "=a" (w0), "=d" (w1)					\
+	   : "%0" ((UDItype)(u)), "rm" ((UDItype)(v)))
+#endif
+#define udiv_qrnnd(q, r, n1, n0, dx) /* d renamed to dx avoiding "=d" */\
+  __asm__ ("divq %4"		     /* stringification in K&R C */	\
+	   : "=a" (q), "=d" (r)						\
+	   : "0" ((UDItype)(n0)), "1" ((UDItype)(n1)), "rm" ((UDItype)(dx)))
+
+#if HAVE_HOST_CPU_haswell || HAVE_HOST_CPU_broadwell || HAVE_HOST_CPU_skylake \
+  || HAVE_HOST_CPU_k10 || HAVE_HOST_CPU_bd1 || HAVE_HOST_CPU_bd2	\
+  || HAVE_HOST_CPU_bd3 || HAVE_HOST_CPU_bd4 || HAVE_HOST_CPU_zen	\
+  || HAVE_HOST_CPU_bobcat || HAVE_HOST_CPU_jaguar
+#define count_leading_zeros(count, x)					\
+  do {									\
+    /* This is lzcnt, spelled for older assemblers.  Destination and */	\
+    /* source must be a 64-bit registers, hence cast and %q.         */	\
+    __asm__ ("rep;bsr\t%1, %q0" : "=r" (count) : "rm" ((UDItype)(x)));	\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0 64
+#else
+#define count_leading_zeros(count, x)					\
+  do {									\
+    UDItype __cbtmp;							\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsr\t%1,%0" : "=r" (__cbtmp) : "rm" ((UDItype)(x)));	\
+    (count) = __cbtmp ^ 63;						\
+  } while (0)
+#endif
+
+#if HAVE_HOST_CPU_bd2 || HAVE_HOST_CPU_bd3 || HAVE_HOST_CPU_bd4 \
+  || HAVE_HOST_CPU_zen || HAVE_HOST_CPU_jaguar
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    /* This is tzcnt, spelled for older assemblers.  Destination and */	\
+    /* source must be a 64-bit registers, hence cast and %q.         */	\
+    __asm__ ("rep;bsf\t%1, %q0" : "=r" (count) : "rm" ((UDItype)(x)));	\
+  } while (0)
+#define COUNT_TRAILING_ZEROS_0 64
+#else
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsf\t%1, %q0" : "=r" (count) : "rm" ((UDItype)(x)));	\
+  } while (0)
+#endif
+#endif /* __amd64__ */
+
+#if defined (__i860__) && W_TYPE_SIZE == 32
+#define rshift_rhlc(r,h,l,c) \
+  __asm__ ("shr %3,r0,r0\;shrd %1,%2,%0"				\
+	   "=r" (r) : "r" (h), "r" (l), "rn" (c))
+#endif /* i860 */
+
+#if defined (__i960__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("cmpo 1,0\;addc %5,%4,%1\;addc %3,%2,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "dI" (ah), "dI" (bh), "%dI" (al), "dI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("cmpo 0,0\;subc %5,%4,%1\;subc %3,%2,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "dI" (ah), "dI" (bh), "dI" (al), "dI" (bl))
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("emul %2,%1,%0"						\
+	   : "=d" (__x.__ll) : "%dI" (u), "dI" (v));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define __umulsidi3(u, v) \
+  ({UDItype __w;							\
+    __asm__ ("emul %2,%1,%0" : "=d" (__w) : "%dI" (u), "dI" (v));	\
+    __w; })
+#define udiv_qrnnd(q, r, nh, nl, d) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __nn;							\
+    __nn.__i.__h = (nh); __nn.__i.__l = (nl);				\
+    __asm__ ("ediv %d,%n,%0"						\
+	   : "=d" (__rq.__ll) : "dI" (__nn.__ll), "dI" (d));		\
+    (r) = __rq.__i.__l; (q) = __rq.__i.__h;				\
+  } while (0)
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __cbtmp;							\
+    __asm__ ("scanbit %1,%0" : "=r" (__cbtmp) : "r" (x));		\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0 (-32) /* sic */
+#if defined (__i960mx)		/* what is the proper symbol to test??? */
+#define rshift_rhlc(r,h,l,c) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __nn;							\
+    __nn.__i.__h = (h); __nn.__i.__l = (l);				\
+    __asm__ ("shre %2,%1,%0" : "=d" (r) : "dI" (__nn.__ll), "dI" (c));	\
+  }
+#endif /* i960mx */
+#endif /* i960 */
+
+
+#if defined (__loongarch64) && W_TYPE_SIZE == 64
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __u = (u), __v = (v);					\
+    (w0) = __u * __v;							\
+    (w1) = (unsigned __int128__) __u * __v >> 64;			\
+  } while (0)
+#endif
+
+
+#if (defined (__mc68000__) || defined (__mc68020__) || defined(mc68020) \
+     || defined (__m68k__) || defined (__mc5200__) || defined (__mc5206e__) \
+     || defined (__mc5307__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0"				\
+	   : "=d" (sh), "=&d" (sl)					\
+	   : "0"  ((USItype)(ah)), "d" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0"				\
+	   : "=d" (sh), "=&d" (sl)					\
+	   : "0" ((USItype)(ah)), "d" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r.  */
+#if defined (__mc68020__) || defined(mc68020) \
+     || defined (__mc68030__) || defined (mc68030) \
+     || defined (__mc68040__) || defined (mc68040) \
+     || defined (__mcpu32__) || defined (mcpu32) \
+     || defined (__NeXT__)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulu%.l %3,%1:%0"						\
+	   : "=d" (w0), "=d" (w1)					\
+	   : "%0" ((USItype)(u)), "dmi" ((USItype)(v)))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("divu%.l %4,%1:%0"						\
+	   : "=d" (q), "=d" (r)						\
+	   : "0" ((USItype)(n0)), "1" ((USItype)(n1)), "dmi" ((USItype)(d)))
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("divs%.l %4,%1:%0"						\
+	   : "=d" (q), "=d" (r)						\
+	   : "0" ((USItype)(n0)), "1" ((USItype)(n1)), "dmi" ((USItype)(d)))
+#else /* for other 68k family members use 16x16->32 multiplication */
+#define umul_ppmm(xh, xl, a, b) \
+  do { USItype __umul_tmp1, __umul_tmp2;				\
+	__asm__ ("| Inlined umul_ppmm\n"				\
+"	move%.l	%5,%3\n"						\
+"	move%.l	%2,%0\n"						\
+"	move%.w	%3,%1\n"						\
+"	swap	%3\n"							\
+"	swap	%0\n"							\
+"	mulu%.w	%2,%1\n"						\
+"	mulu%.w	%3,%0\n"						\
+"	mulu%.w	%2,%3\n"						\
+"	swap	%2\n"							\
+"	mulu%.w	%5,%2\n"						\
+"	add%.l	%3,%2\n"						\
+"	jcc	1f\n"							\
+"	add%.l	%#0x10000,%0\n"						\
+"1:	move%.l	%2,%3\n"						\
+"	clr%.w	%2\n"							\
+"	swap	%2\n"							\
+"	swap	%3\n"							\
+"	clr%.w	%3\n"							\
+"	add%.l	%3,%1\n"						\
+"	addx%.l	%2,%0\n"						\
+"	| End inlined umul_ppmm"					\
+	      : "=&d" (xh), "=&d" (xl),					\
+		"=&d" (__umul_tmp1), "=&d" (__umul_tmp2)			\
+	      : "%2" ((USItype)(a)), "d" ((USItype)(b)));		\
+  } while (0)
+#endif /* not mc68020 */
+/* The '020, '030, '040 and '060 have bitfield insns.
+   GCC 3.4 defines __mc68020__ when in CPU32 mode, check for __mcpu32__ to
+   exclude bfffo on that chip (bitfield insns not available).  */
+#if (defined (__mc68020__) || defined (mc68020)    \
+     || defined (__mc68030__) || defined (mc68030) \
+     || defined (__mc68040__) || defined (mc68040) \
+     || defined (__mc68060__) || defined (mc68060) \
+     || defined (__NeXT__))			   \
+  && ! defined (__mcpu32__)
+#define count_leading_zeros(count, x) \
+  __asm__ ("bfffo %1{%b2:%b2},%0"					\
+	   : "=d" (count)						\
+	   : "od" ((USItype) (x)), "n" (0))
+#define COUNT_LEADING_ZEROS_0 32
+#endif
+#endif /* mc68000 */
+
+#if defined (__m88000__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rJ" (bh), "%rJ" (al), "rJ" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rJ" (bh), "rJ" (al), "rJ" (bl))
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __cbtmp;							\
+    __asm__ ("ff1 %0,%1" : "=r" (__cbtmp) : "r" (x));			\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0 63 /* sic */
+#if defined (__m88110__)
+#define umul_ppmm(wh, wl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mulu.d %0,%1,%2" : "=r" (__x.__ll) : "r" (u), "r" (v));	\
+    (wh) = __x.__i.__h;							\
+    (wl) = __x.__i.__l;							\
+  } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x, __q;							\
+  __x.__i.__h = (n1); __x.__i.__l = (n0);				\
+  __asm__ ("divu.d %0,%1,%2"						\
+	   : "=r" (__q.__ll) : "r" (__x.__ll), "r" (d));		\
+  (r) = (n0) - __q.__l * (d); (q) = __q.__l; })
+#endif /* __m88110__ */
+#endif /* __m88000__ */
+
+#if defined (__mips) && W_TYPE_SIZE == 32
+#if __GMP_GNUC_PREREQ (4,4)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __ll = (UDItype)(u) * (v);					\
+    w1 = __ll >> 32;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm) && __GMP_GNUC_PREREQ (2,7) && !defined (__clang__)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("multu %2,%3" : "=l" (w0), "=h" (w1) : "d" (u), "d" (v))
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("multu %2,%3\n\tmflo %0\n\tmfhi %1"				\
+	   : "=d" (w0), "=d" (w1) : "d" (u), "d" (v))
+#endif
+#endif /* __mips */
+
+#if (defined (__mips) && __mips >= 3) && W_TYPE_SIZE == 64
+#if defined (_MIPS_ARCH_MIPS64R6)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __m0 = (u), __m1 = (v);					\
+    (w0) = __m0 * __m1;							\
+    __asm__ ("dmuhu\t%0, %1, %2" : "=d" (w1) : "d" (__m0), "d" (__m1));	\
+  } while (0)
+#endif
+#if !defined (umul_ppmm) && __GMP_GNUC_PREREQ (4,4)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
+    __ll_UTItype __ll = (__ll_UTItype)(u) * (v);			\
+    w1 = __ll >> 64;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm) && __GMP_GNUC_PREREQ (2,7) && !defined (__clang__)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("dmultu %2,%3"						\
+	   : "=l" (w0), "=h" (w1)					\
+	   : "d" ((UDItype)(u)), "d" ((UDItype)(v)))
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("dmultu %2,%3\n\tmflo %0\n\tmfhi %1"				\
+	   : "=d" (w0), "=d" (w1)					\
+	   : "d" ((UDItype)(u)), "d" ((UDItype)(v)))
+#endif
+#endif /* __mips */
+
+#if defined (__mmix__) && W_TYPE_SIZE == 64
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("MULU %0,%2,%3" : "=r" (w0), "=z" (w1) : "r" (u), "r" (v))
+#endif
+
+#if defined (__ns32000__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("meid %2,%0"							\
+	   : "=g" (__x.__ll)						\
+	   : "%0" ((USItype)(u)), "g" ((USItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define __umulsidi3(u, v) \
+  ({UDItype __w;							\
+    __asm__ ("meid %2,%0"						\
+	     : "=g" (__w)						\
+	     : "%0" ((USItype)(u)), "g" ((USItype)(v)));		\
+    __w; })
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __x.__i.__h = (n1); __x.__i.__l = (n0);				\
+  __asm__ ("deid %2,%0"							\
+	   : "=g" (__x.__ll)						\
+	   : "0" (__x.__ll), "g" ((USItype)(d)));			\
+  (r) = __x.__i.__l; (q) = __x.__i.__h; })
+#define count_trailing_zeros(count,x) \
+  do {									\
+    __asm__ ("ffsd	%2,%0"						\
+	     : "=r" (count)						\
+	     : "0" ((USItype) 0), "r" ((USItype) (x)));			\
+  } while (0)
+#endif /* __ns32000__ */
+
+/* In the past we had a block of various #defines tested
+       _ARCH_PPC    - AIX
+       _ARCH_PWR    - AIX
+       __powerpc__  - gcc
+       __POWERPC__  - BEOS
+       __ppc__      - Darwin
+       PPC          - old gcc, GNU/Linux, SysV
+   The plain PPC test was not good for vxWorks, since PPC is defined on all
+   CPUs there (eg. m68k too), as a constant one is expected to compare
+   CPU_FAMILY against.
+
+   At any rate, this was pretty unattractive and a bit fragile.  The use of
+   HAVE_HOST_CPU_FAMILY is designed to cut through it all and be sure of
+   getting the desired effect.
+
+   ENHANCE-ME: We should test _IBMR2 here when we add assembly support for
+   the system vendor compilers.  (Is that vendor compilers with inline asm,
+   or what?)  */
+
+#if (HAVE_HOST_CPU_FAMILY_power || HAVE_HOST_CPU_FAMILY_powerpc)	\
+  && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bh) && (bh) == 0)				\
+      __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0)		\
+      __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)	\
+		 __CLOBBER_CC);						\
+    else								\
+      __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "r" (bh), "%r" (al), "rI" (bl)		\
+		 __CLOBBER_CC);						\
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (ah) && (ah) == 0)				\
+      __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0)		\
+      __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == 0)			\
+      __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0)		\
+      __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else								\
+      __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "r" (bh), "rI" (al), "r" (bl)		\
+		 __CLOBBER_CC);						\
+  } while (0)
+#define count_leading_zeros(count, x) \
+  __asm__ ("cntlzw %0,%1" : "=r" (count) : "r" (x))
+#define COUNT_LEADING_ZEROS_0 32
+#if HAVE_HOST_CPU_FAMILY_powerpc
+#if __GMP_GNUC_PREREQ (4,4)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __ll = (UDItype)(u) * (v);					\
+    w1 = __ll >> 32;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    USItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#define smul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    SItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#else
+#define smul_ppmm(xh, xl, m0, m1) \
+  __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1))
+#define sdiv_qrnnd(q, r, nh, nl, d) \
+  __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d))
+#endif
+#endif /* 32-bit POWER architecture variants.  */
+
+/* We should test _IBMR2 here when we add assembly support for the system
+   vendor compilers.  */
+#if HAVE_HOST_CPU_FAMILY_powerpc && W_TYPE_SIZE == 64
+#if !defined (_LONG_LONG_LIMB)
+/* _LONG_LONG_LIMB is ABI=mode32 where adde operates on 32-bit values.  So
+   use adde etc only when not _LONG_LONG_LIMB.  */
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bh) && (bh) == 0)				\
+      __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r"  ((UDItype)(ah)),					\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl))		\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0)		\
+      __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r"  ((UDItype)(ah)),					\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl))		\
+		 __CLOBBER_CC);						\
+    else								\
+      __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r"  ((UDItype)(ah)), "r"  ((UDItype)(bh)),		\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl))		\
+		 __CLOBBER_CC);						\
+  } while (0)
+/* We use "*rI" for the constant operand here, since with just "I", gcc barfs.
+   This might seem strange, but gcc folds away the dead code late.  */
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl)					\
+	&& (bl) > -0x8000 && (bl) <= 0x8000 && (bl) != 0) {		\
+	if (__builtin_constant_p (ah) && (ah) == 0)			\
+	  __asm__ ("addic %1,%3,%4\n\tsubfze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "r" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0)	\
+	  __asm__ ("addic %1,%3,%4\n\tsubfme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "r" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == 0)		\
+	  __asm__ ("addic %1,%3,%4\n\taddme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r" ((UDItype)(ah)),				\
+		     "r" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0)	\
+	  __asm__ ("addic %1,%3,%4\n\taddze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r" ((UDItype)(ah)),				\
+		     "r" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else								\
+	  __asm__ ("addic %1,%4,%5\n\tsubfe %0,%3,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r" ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+		     "r" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+    } else {								\
+	if (__builtin_constant_p (ah) && (ah) == 0)			\
+	  __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0)	\
+	  __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == 0)		\
+	  __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)),				\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0)	\
+	  __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)),				\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else								\
+	  __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+    }									\
+  } while (0)
+#endif /* ! _LONG_LONG_LIMB */
+#define count_leading_zeros(count, x) \
+  __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x))
+#define COUNT_LEADING_ZEROS_0 64
+#if __GMP_GNUC_PREREQ (4,8)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
+    __ll_UTItype __ll = (__ll_UTItype)(u) * (v);			\
+    w1 = __ll >> 64;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (__m0), "r" (__m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#define smul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    DItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (__m0), "r" (__m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif /* 64-bit PowerPC.  */
+
+#if defined (__pyr__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addw %5,%1\n\taddwc %3,%0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subw %5,%1\n\tsubwb %3,%0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+/* This insn works on Pyramids with AP, XP, or MI CPUs, but not with SP.  */
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+  __asm__ ("movw %1,%R0\n\tuemul %2,%0"					\
+	   : "=&r" (__x.__ll)						\
+	   : "g" ((USItype) (u)), "g" ((USItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#endif /* __pyr__ */
+
+#if defined (__ibm032__) /* RT/ROMP */  && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("a %1,%5\n\tae %0,%3"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((USItype)(ah)), "r" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "r" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("s %1,%5\n\tse %0,%3"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((USItype)(ah)), "r" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "r" ((USItype)(bl)))
+#define smul_ppmm(ph, pl, m0, m1) \
+  __asm__ (								\
+       "s	r2,r2\n"						\
+"	mts r10,%2\n"							\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	cas	%0,r2,r0\n"						\
+"	mfs	r10,%1"							\
+	   : "=r" (ph), "=r" (pl)					\
+	   : "%r" ((USItype)(m0)), "r" ((USItype)(m1))			\
+	   : "r2")
+#define count_leading_zeros(count, x) \
+  do {									\
+    if ((x) >= 0x10000)							\
+      __asm__ ("clz	%0,%1"						\
+	       : "=r" (count) : "r" ((USItype)(x) >> 16));		\
+    else								\
+      {									\
+	__asm__ ("clz	%0,%1"						\
+		 : "=r" (count) : "r" ((USItype)(x)));			\
+	(count) += 16;							\
+      }									\
+  } while (0)
+#endif /* RT/ROMP */
+
+#if defined (__riscv) && defined (__riscv_mul) && W_TYPE_SIZE == 64
+#define umul_ppmm(ph, pl, u, v) \
+  do {									\
+    UDItype __u = (u), __v = (v);					\
+    (pl) = __u * __v;							\
+    __asm__ ("mulhu\t%0, %1, %2" : "=r" (ph) : "%r" (__u), "r" (__v));	\
+  } while (0)
+#endif
+
+#if (defined (__SH2__) || defined (__SH3__) || defined (__SH4__)) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0"		\
+	   : "=r" (w1), "=r" (w0) : "r" (u), "r" (v) : "macl", "mach")
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rI" (bh),"%rJ" (al), "rI" (bl)			\
+	   __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rI" (bh), "rJ" (al), "rI" (bl)	\
+	   __CLOBBER_CC)
+/* FIXME: When gcc -mcpu=v9 is used on solaris, gcc/config/sol2-sld-64.h
+   doesn't define anything to indicate that to us, it only sets __sparcv8. */
+#if defined (__sparc_v9__) || defined (__sparcv9)
+/* Perhaps we should use floating-point operations here?  */
+#if 0
+/* Triggers a bug making mpz/tests/t-gcd.c fail.
+   Perhaps we simply need explicitly zero-extend the inputs?  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulx %2,%3,%%g1; srl %%g1,0,%1; srlx %%g1,32,%0" :		\
+	   "=r" (w1), "=r" (w0) : "r" (u), "r" (v) : "g1")
+#else
+/* Use v8 umul until above bug is fixed.  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (w1), "=r" (w0) : "r" (u), "r" (v))
+#endif
+/* Use a plain v8 divide for v9.  */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    USItype __q;							\
+    __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0"			\
+	     : "=r" (__q) : "r" (n1), "r" (n0), "r" (d));		\
+    (r) = (n0) - __q * (d);						\
+    (q) = __q;								\
+  } while (0)
+#else
+#if defined (__sparc_v8__)   /* gcc normal */				\
+  || defined (__sparcv8)     /* gcc solaris */				\
+  || HAVE_HOST_CPU_supersparc
+/* Don't match immediate range because, 1) it is not often useful,
+   2) the 'I' flag thinks of the range as a 13 bit signed interval,
+   while we want to match a 13 bit interval, sign extended to 32 bits,
+   but INTERPRETED AS UNSIGNED.  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (w1), "=r" (w0) : "r" (u), "r" (v))
+
+#if HAVE_HOST_CPU_supersparc
+#else
+/* Don't use this on SuperSPARC because its udiv only handles 53 bit
+   dividends and will trap to the kernel for the rest. */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    USItype __q;							\
+    __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0"			\
+	     : "=r" (__q) : "r" (n1), "r" (n0), "r" (d));		\
+    (r) = (n0) - __q * (d);						\
+    (q) = __q;								\
+  } while (0)
+#endif /* HAVE_HOST_CPU_supersparc */
+
+#else /* ! __sparc_v8__ */
+#if defined (__sparclite__)
+/* This has hardware multiply but not divide.  It also has two additional
+   instructions scan (ffs from high bit) and divscc.  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (w1), "=r" (w0) : "r" (u), "r" (v))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("! Inlined udiv_qrnnd\n"					\
+"	wr	%%g0,%2,%%y	! Not a delayed write for sparclite\n"	\
+"	tst	%%g0\n"							\
+"	divscc	%3,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%0\n"						\
+"	rd	%%y,%1\n"						\
+"	bl,a 1f\n"							\
+"	add	%1,%4,%1\n"						\
+"1:	! End of inline udiv_qrnnd"					\
+	   : "=r" (q), "=r" (r) : "r" (n1), "r" (n0), "rI" (d)		\
+	   : "%g1" __AND_CLOBBER_CC)
+#define count_leading_zeros(count, x) \
+  __asm__ ("scan %1,1,%0" : "=r" (count) : "r" (x))
+/* Early sparclites return 63 for an argument of 0, but they warn that future
+   implementations might change this.  Therefore, leave COUNT_LEADING_ZEROS_0
+   undefined.  */
+#endif /* __sparclite__ */
+#endif /* __sparc_v8__ */
+#endif /* __sparc_v9__ */
+/* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd.  */
+#ifndef umul_ppmm
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("! Inlined umul_ppmm\n"					\
+"	wr	%%g0,%2,%%y	! SPARC has 0-3 delay insn after a wr\n" \
+"	sra	%3,31,%%g2	! Don't move this insn\n"		\
+"	and	%2,%%g2,%%g2	! Don't move this insn\n"		\
+"	andcc	%%g0,0,%%g1	! Don't move this insn\n"		\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,0,%%g1\n"						\
+"	add	%%g1,%%g2,%0\n"						\
+"	rd	%%y,%1"							\
+	   : "=r" (w1), "=r" (w0) : "%rI" (u), "r" (v)			\
+	   : "%g1", "%g2" __AND_CLOBBER_CC)
+#endif
+#ifndef udiv_qrnnd
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __r;							\
+    (q) = __MPN(udiv_qrnnd) (&__r, (n1), (n0), (d));			\
+    (r) = __r;								\
+  } while (0)
+extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype);
+#endif /* LONGLONG_STANDALONE */
+#endif /* udiv_qrnnd */
+#endif /* __sparc__ */
+
+#if defined (__sparc__) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ (								\
+       "addcc	%r4,%5,%1\n"						\
+      "	addccc	%r6,%7,%%g0\n"						\
+      "	addc	%r2,%3,%0"						\
+       : "=r" (sh), "=&r" (sl)						\
+       : "rJ"  ((UDItype)(ah)), "rI" ((UDItype)(bh)),			\
+	 "%rJ" ((UDItype)(al)), "rI" ((UDItype)(bl)),			\
+	 "%rJ" ((UDItype)(al) >> 32), "rI" ((UDItype)(bl) >> 32)	\
+	   __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ (								\
+       "subcc	%r4,%5,%1\n"						\
+      "	subccc	%r6,%7,%%g0\n"						\
+      "	subc	%r2,%3,%0"						\
+       : "=r" (sh), "=&r" (sl)						\
+       : "rJ" ((UDItype)(ah)), "rI" ((UDItype)(bh)),			\
+	 "rJ" ((UDItype)(al)), "rI" ((UDItype)(bl)),			\
+	 "rJ" ((UDItype)(al) >> 32), "rI" ((UDItype)(bl) >> 32)		\
+	   __CLOBBER_CC)
+#if __VIS__ >= 0x300
+#undef add_ssaaaa
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ (								\
+       "addcc	%r4, %5, %1\n"						\
+      "	addxc	%r2, %r3, %0"						\
+	  : "=r" (sh), "=&r" (sl)					\
+       : "rJ"  ((UDItype)(ah)), "rJ" ((UDItype)(bh)),			\
+	 "%rJ" ((UDItype)(al)), "rI" ((UDItype)(bl)) __CLOBBER_CC)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (pl) = __m0 * __m1;							\
+    __asm__ ("umulxhi\t%2, %1, %0"					\
+	     : "=r" (ph)						\
+	     : "%r" (__m0), "r" (__m1));				\
+  } while (0)
+#define count_leading_zeros(count, x) \
+  __asm__ ("lzd\t%1,%0" : "=r" (count) : "r" (x))
+/* Needed by count_leading_zeros_32 in sparc64.h.  */
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif
+#endif
+
+#if (defined (__vax) || defined (__vax__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addl2 %5,%1\n\tadwc %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subl2 %5,%1\n\tsbwc %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define smul_ppmm(xh, xl, m0, m1) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+    USItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("emul %1,%2,$0,%0"						\
+	     : "=g" (__x.__ll) : "g" (__m0), "g" (__m1));		\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    union {DItype __ll;							\
+	   struct {SItype __l, __h;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("ediv %3,%2,%0,%1"						\
+	     : "=g" (q), "=g" (r) : "g" (__x.__ll), "g" (d));		\
+  } while (0)
+#if 0
+/* FIXME: This instruction appears to be unimplemented on some systems (vax
+   8800 maybe). */
+#define count_trailing_zeros(count,x)					\
+  do {									\
+    __asm__ ("ffs 0, 31, %1, %0"					\
+	     : "=g" (count)						\
+	     : "g" ((USItype) (x)));					\
+  } while (0)
+#endif
+#endif /* vax */
+
+#if defined (__z8000__) && W_TYPE_SIZE == 16
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add	%H1,%H5\n\tadc	%H0,%H3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((unsigned int)(ah)), "r" ((unsigned int)(bh)),	\
+	     "%1" ((unsigned int)(al)), "rQR" ((unsigned int)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub	%H1,%H5\n\tsbc	%H0,%H3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((unsigned int)(ah)), "r" ((unsigned int)(bh)),	\
+	     "1" ((unsigned int)(al)), "rQR" ((unsigned int)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+  do {									\
+    union {long int __ll;						\
+	   struct {unsigned int __h, __l;} __i;				\
+	  } __x;							\
+    unsigned int __m0 = (m0), __m1 = (m1);				\
+    __asm__ ("mult	%S0,%H3"					\
+	     : "=r" (__x.__i.__h), "=r" (__x.__i.__l)			\
+	     : "%1" (m0), "rQR" (m1));					\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+    (xh) += ((((signed int) __m0 >> 15) & __m1)				\
+	     + (((signed int) __m1 >> 15) & __m0));			\
+  } while (0)
+#endif /* __z8000__ */
+
+#endif /* __GNUC__ */
+
+#endif /* NO_ASM */
+
+
+/* FIXME: "sidi" here is highly doubtful, should sometimes be "diti".  */
+#if !defined (umul_ppmm) && defined (__umulsidi3)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDWtype __ll = __umulsidi3 (m0, m1);				\
+    ph = (UWtype) (__ll >> W_TYPE_SIZE);				\
+    pl = (UWtype) __ll;							\
+  } while (0)
+#endif
+
+#if !defined (__umulsidi3)
+#define __umulsidi3(u, v) \
+  ({UWtype __hi, __lo;							\
+    umul_ppmm (__hi, __lo, u, v);					\
+    ((UDWtype) __hi << W_TYPE_SIZE) | __lo; })
+#endif
+
+
+#if defined (__cplusplus)
+#define __longlong_h_C "C"
+#else
+#define __longlong_h_C
+#endif
+
+/* Use mpn_umul_ppmm or mpn_udiv_qrnnd functions, if they exist.  The "_r"
+   forms have "reversed" arguments, meaning the pointer is last, which
+   sometimes allows better parameter passing, in particular on 64-bit
+   hppa. */
+
+#define mpn_umul_ppmm  __MPN(umul_ppmm)
+extern __longlong_h_C UWtype mpn_umul_ppmm (UWtype *, UWtype, UWtype);
+
+#if ! defined (umul_ppmm) && HAVE_NATIVE_mpn_umul_ppmm  \
+  && ! defined (LONGLONG_STANDALONE)
+#define umul_ppmm(wh, wl, u, v)						\
+  do {									\
+    UWtype __umul_ppmm__p0;						\
+    (wh) = mpn_umul_ppmm (&__umul_ppmm__p0, (UWtype) (u), (UWtype) (v));\
+    (wl) = __umul_ppmm__p0;						\
+  } while (0)
+#endif
+
+#define mpn_umul_ppmm_r  __MPN(umul_ppmm_r)
+extern __longlong_h_C UWtype mpn_umul_ppmm_r (UWtype, UWtype, UWtype *);
+
+#if ! defined (umul_ppmm) && HAVE_NATIVE_mpn_umul_ppmm_r	\
+  && ! defined (LONGLONG_STANDALONE)
+#define umul_ppmm(wh, wl, u, v)						\
+  do {									\
+    UWtype __umul_p0;							\
+    (wh) = mpn_umul_ppmm_r ((UWtype) (u), (UWtype) (v), &__umul_p0);	\
+    (wl) = __umul_p0;							\
+  } while (0)
+#endif
+
+#define mpn_udiv_qrnnd  __MPN(udiv_qrnnd)
+extern __longlong_h_C UWtype mpn_udiv_qrnnd (UWtype *, UWtype, UWtype, UWtype);
+
+#if ! defined (udiv_qrnnd) && HAVE_NATIVE_mpn_udiv_qrnnd	\
+  && ! defined (LONGLONG_STANDALONE)
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    UWtype __udiv_qrnnd_r;						\
+    (q) = mpn_udiv_qrnnd (&__udiv_qrnnd_r,				\
+			  (UWtype) (n1), (UWtype) (n0), (UWtype) d);	\
+    (r) = __udiv_qrnnd_r;						\
+  } while (0)
+#endif
+
+#define mpn_udiv_qrnnd_r  __MPN(udiv_qrnnd_r)
+extern __longlong_h_C UWtype mpn_udiv_qrnnd_r (UWtype, UWtype, UWtype, UWtype *);
+
+#if ! defined (udiv_qrnnd) && HAVE_NATIVE_mpn_udiv_qrnnd_r	\
+  && ! defined (LONGLONG_STANDALONE)
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    UWtype __udiv_qrnnd_r;						\
+    (q) = mpn_udiv_qrnnd_r ((UWtype) (n1), (UWtype) (n0), (UWtype) d,	\
+			    &__udiv_qrnnd_r);				\
+    (r) = __udiv_qrnnd_r;						\
+  } while (0)
+#endif
+
+
+/* If this machine has no inline assembler, use C macros.  */
+
+#if !defined (add_ssaaaa)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    UWtype __x;								\
+    UWtype __al = (al);							\
+    UWtype __bl = (bl);							\
+    __x = __al + __bl;							\
+    (sh) = (ah) + (bh) + (__x < __al);					\
+    (sl) = __x;								\
+  } while (0)
+#endif
+
+#if !defined (sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    UWtype __x;								\
+    UWtype __al = (al);							\
+    UWtype __bl = (bl);							\
+    __x = __al - __bl;							\
+    (sh) = (ah) - (bh) - (__al < __bl);					\
+    (sl) = __x;								\
+  } while (0)
+#endif
+
+/* If we lack umul_ppmm but have smul_ppmm, define umul_ppmm in terms of
+   smul_ppmm.  */
+#if !defined (umul_ppmm) && defined (smul_ppmm)
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UWtype __w1;							\
+    UWtype __xm0 = (u), __xm1 = (v);					\
+    smul_ppmm (__w1, w0, __xm0, __xm1);					\
+    (w1) = __w1 + (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1)		\
+		+ (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0);		\
+  } while (0)
+#endif
+
+/* If we still don't have umul_ppmm, define it using plain C.
+
+   For reference, when this code is used for squaring (ie. u and v identical
+   expressions), gcc recognises __x1 and __x2 are the same and generates 3
+   multiplies, not 4.  The subsequent additions could be optimized a bit,
+   but the only place GMP currently uses such a square is mpn_sqr_basecase,
+   and chips obliged to use this generic C umul will have plenty of worse
+   performance problems than a couple of extra instructions on the diagonal
+   of sqr_basecase.  */
+
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UWtype __x0, __x1, __x2, __x3;					\
+    UHWtype __ul, __vl, __uh, __vh;					\
+    UWtype __u = (u), __v = (v);					\
+									\
+    __ul = __ll_lowpart (__u);						\
+    __uh = __ll_highpart (__u);						\
+    __vl = __ll_lowpart (__v);						\
+    __vh = __ll_highpart (__v);						\
+									\
+    __x0 = (UWtype) __ul * __vl;					\
+    __x1 = (UWtype) __ul * __vh;					\
+    __x2 = (UWtype) __uh * __vl;					\
+    __x3 = (UWtype) __uh * __vh;					\
+									\
+    __x1 += __ll_highpart (__x0);/* this can't give carry */		\
+    __x1 += __x2;		/* but this indeed can */		\
+    if (__x1 < __x2)		/* did we get it? */			\
+      __x3 += __ll_B;		/* yes, add it in the proper pos. */	\
+									\
+    (w1) = __x3 + __ll_highpart (__x1);					\
+    (w0) = (__x1 << W_TYPE_SIZE/2) + __ll_lowpart (__x0);		\
+  } while (0)
+#endif
+
+/* If we don't have smul_ppmm, define it using umul_ppmm (which surely will
+   exist in one form or another.  */
+#if !defined (smul_ppmm)
+#define smul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UWtype __w1;							\
+    UWtype __xm0 = (u), __xm1 = (v);					\
+    umul_ppmm (__w1, w0, __xm0, __xm1);					\
+    (w1) = __w1 - (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1)		\
+		- (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0);		\
+  } while (0)
+#endif
+
+/* Define this unconditionally, so it can be used for debugging.  */
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+  do {									\
+    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;			\
+									\
+    ASSERT ((d) != 0);							\
+    ASSERT ((n1) < (d));						\
+									\
+    __d1 = __ll_highpart (d);						\
+    __d0 = __ll_lowpart (d);						\
+									\
+    __q1 = (n1) / __d1;							\
+    __r1 = (n1) - __q1 * __d1;						\
+    __m = __q1 * __d0;							\
+    __r1 = __r1 * __ll_B | __ll_highpart (n0);				\
+    if (__r1 < __m)							\
+      {									\
+	__q1--, __r1 += (d);						\
+	if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+	  if (__r1 < __m)						\
+	    __q1--, __r1 += (d);					\
+      }									\
+    __r1 -= __m;							\
+									\
+    __q0 = __r1 / __d1;							\
+    __r0 = __r1  - __q0 * __d1;						\
+    __m = __q0 * __d0;							\
+    __r0 = __r0 * __ll_B | __ll_lowpart (n0);				\
+    if (__r0 < __m)							\
+      {									\
+	__q0--, __r0 += (d);						\
+	if (__r0 >= (d))						\
+	  if (__r0 < __m)						\
+	    __q0--, __r0 += (d);					\
+      }									\
+    __r0 -= __m;							\
+									\
+    (q) = __q1 * __ll_B | __q0;						\
+    (r) = __r0;								\
+  } while (0)
+
+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
+   __udiv_w_sdiv (defined in libgcc or elsewhere).  */
+#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) \
+  && ! defined (LONGLONG_STANDALONE)
+#define udiv_qrnnd(q, r, nh, nl, d) \
+  do {									\
+    UWtype __r;								\
+    (q) = __MPN(udiv_w_sdiv) (&__r, nh, nl, d);				\
+    (r) = __r;								\
+  } while (0)
+__GMP_DECLSPEC UWtype __MPN(udiv_w_sdiv) (UWtype *, UWtype, UWtype, UWtype);
+#endif
+
+/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c.  */
+#if !defined (udiv_qrnnd)
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+#endif
+
+#if !defined (count_leading_zeros)
+#define count_leading_zeros(count, x) \
+  do {									\
+    UWtype __xr = (x);							\
+    UWtype __a;								\
+									\
+    if (W_TYPE_SIZE == 32)						\
+      {									\
+	__a = __xr < ((UWtype) 1 << 2*__BITS4)				\
+	  ? (__xr < ((UWtype) 1 << __BITS4) ? 1 : __BITS4 + 1)		\
+	  : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 + 1		\
+	  : 3*__BITS4 + 1);						\
+      }									\
+    else								\
+      {									\
+	for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8)			\
+	  if (((__xr >> __a) & 0xff) != 0)				\
+	    break;							\
+	++__a;								\
+      }									\
+									\
+    (count) = W_TYPE_SIZE + 1 - __a - __clz_tab[__xr >> __a];		\
+  } while (0)
+/* This version gives a well-defined value for zero. */
+#define COUNT_LEADING_ZEROS_0 (W_TYPE_SIZE - 1)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#define COUNT_LEADING_ZEROS_SLOW
+#endif
+
+/* clz_tab needed by mpn/x86/pentium/mod_1.asm in a fat binary */
+#if HAVE_HOST_CPU_FAMILY_x86 && WANT_FAT_BINARY
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif
+
+#ifdef COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+extern const unsigned char __GMP_DECLSPEC __clz_tab[129];
+#endif
+
+#if !defined (count_trailing_zeros)
+#if !defined (COUNT_LEADING_ZEROS_SLOW)
+/* Define count_trailing_zeros using an asm count_leading_zeros.  */
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    UWtype __ctz_x = (x);						\
+    UWtype __ctz_c;							\
+    ASSERT (__ctz_x != 0);						\
+    count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x);			\
+    (count) = W_TYPE_SIZE - 1 - __ctz_c;				\
+  } while (0)
+#else
+/* Define count_trailing_zeros in plain C, assuming small counts are common.
+   We use clz_tab without ado, since the C count_leading_zeros above will have
+   pulled it in.  */
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    UWtype __ctz_x = (x);						\
+    int __ctz_c;							\
+									\
+    if (LIKELY ((__ctz_x & 0xff) != 0))					\
+      (count) = __clz_tab[__ctz_x & -__ctz_x] - 2;			\
+    else								\
+      {									\
+	for (__ctz_c = 8 - 2; __ctz_c < W_TYPE_SIZE - 2; __ctz_c += 8)	\
+	  {								\
+	    __ctz_x >>= 8;						\
+	    if (LIKELY ((__ctz_x & 0xff) != 0))				\
+	      break;							\
+	  }								\
+									\
+	(count) = __ctz_c + __clz_tab[__ctz_x & -__ctz_x];		\
+      }									\
+  } while (0)
+#endif
+#endif
+
+#ifndef UDIV_NEEDS_NORMALIZATION
+#define UDIV_NEEDS_NORMALIZATION 0
+#endif
+
+/* Whether udiv_qrnnd is actually implemented with udiv_qrnnd_preinv, and
+   that hence the latter should always be used.  */
+#ifndef UDIV_PREINV_ALWAYS
+#define UDIV_PREINV_ALWAYS 0
+#endif
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..5e00191
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,145 @@
+/* Memory allocation routines.
+
+Copyright 1991, 1993, 1994, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc, realloc, free */
+
+#include "gmp-impl.h"
+
+
+void * (*__gmp_allocate_func) (size_t) = __gmp_default_allocate;
+void * (*__gmp_reallocate_func) (void *, size_t, size_t) = __gmp_default_reallocate;
+void   (*__gmp_free_func) (void *, size_t) = __gmp_default_free;
+
+
+/* Default allocation functions.  In case of failure to allocate/reallocate
+   an error message is written to stderr and the program aborts.  */
+
+void *
+__gmp_default_allocate (size_t size)
+{
+  void *ret;
+#ifdef DEBUG
+  size_t req_size = size;
+  size += 2 * GMP_LIMB_BYTES;
+#endif
+  ret = malloc (size);
+  if (ret == 0)
+    {
+      fprintf (stderr, "GNU MP: Cannot allocate memory (size=%lu)\n", (long) size);
+      abort ();
+    }
+
+#ifdef DEBUG
+  {
+    mp_ptr p = ret;
+    p++;
+    p[-1] = (0xdeadbeef << 31) + 0xdeafdeed;
+    if (req_size % GMP_LIMB_BYTES == 0)
+      p[req_size / GMP_LIMB_BYTES] = ~((0xdeadbeef << 31) + 0xdeafdeed);
+    ret = p;
+  }
+#endif
+  return ret;
+}
+
+void *
+__gmp_default_reallocate (void *oldptr, size_t old_size, size_t new_size)
+{
+  void *ret;
+
+#ifdef DEBUG
+  size_t req_size = new_size;
+
+  if (old_size != 0)
+    {
+      mp_ptr p = oldptr;
+      if (p[-1] != (0xdeadbeef << 31) + 0xdeafdeed)
+	{
+	  fprintf (stderr, "gmp: (realloc) data clobbered before allocation block\n");
+	  abort ();
+	}
+      if (old_size % GMP_LIMB_BYTES == 0)
+	if (p[old_size / GMP_LIMB_BYTES] != ~((0xdeadbeef << 31) + 0xdeafdeed))
+	  {
+	    fprintf (stderr, "gmp: (realloc) data clobbered after allocation block\n");
+	    abort ();
+	  }
+      oldptr = p - 1;
+    }
+
+  new_size += 2 * GMP_LIMB_BYTES;
+#endif
+
+  ret = realloc (oldptr, new_size);
+  if (ret == 0)
+    {
+      fprintf (stderr, "GNU MP: Cannot reallocate memory (old_size=%lu new_size=%lu)\n", (long) old_size, (long) new_size);
+      abort ();
+    }
+
+#ifdef DEBUG
+  {
+    mp_ptr p = ret;
+    p++;
+    p[-1] = (0xdeadbeef << 31) + 0xdeafdeed;
+    if (req_size % GMP_LIMB_BYTES == 0)
+      p[req_size / GMP_LIMB_BYTES] = ~((0xdeadbeef << 31) + 0xdeafdeed);
+    ret = p;
+  }
+#endif
+  return ret;
+}
+
+void
+__gmp_default_free (void *blk_ptr, size_t blk_size)
+{
+#ifdef DEBUG
+  {
+    mp_ptr p = blk_ptr;
+    if (blk_size != 0)
+      {
+	if (p[-1] != (0xdeadbeef << 31) + 0xdeafdeed)
+	  {
+	    fprintf (stderr, "gmp: (free) data clobbered before allocation block\n");
+	    abort ();
+	  }
+	if (blk_size % GMP_LIMB_BYTES == 0)
+	  if (p[blk_size / GMP_LIMB_BYTES] != ~((0xdeadbeef << 31) + 0xdeafdeed))
+	    {
+	      fprintf (stderr, "gmp: (free) data clobbered after allocation block\n");
+	      abort ();
+	    }
+      }
+    blk_ptr = p - 1;
+  }
+#endif
+  free (blk_ptr);
+}
diff --git a/mini-gmp/mini-gmp.c b/mini-gmp/mini-gmp.c
new file mode 100644
index 0000000..69a72bf
--- /dev/null
+++ b/mini-gmp/mini-gmp.c
@@ -0,0 +1,4627 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+   Contributed to the GNU project by Niels Möller
+   Additional functionalities and improvements by Marco Bodrato.
+
+Copyright 1991-1997, 1999-2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* NOTE: All functions in this file which are not declared in
+   mini-gmp.h are internal, and are not intended to be compatible
+   with GMP or with future versions of mini-gmp. */
+
+/* Much of the material copied from GMP files, including: gmp-impl.h,
+   longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
+   mpn/generic/lshift.c, mpn/generic/mul_1.c,
+   mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
+   mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
+   mpn/generic/submul_1.c. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mini-gmp.h"
+
+#if !defined(MINI_GMP_DONT_USE_FLOAT_H)
+#include <float.h>
+#endif
+
+
+/* Macros */
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0)
+#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
+
+#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
+#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
+
+#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
+#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
+
+#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
+#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
+
+#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b)))
+
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+#define GMP_DBL_MANT_BITS DBL_MANT_DIG
+#else
+#define GMP_DBL_MANT_BITS (53)
+#endif
+
+/* Return non-zero if xp,xsize and yp,ysize overlap.
+   If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
+   overlap.  If both these are false, there's an overlap. */
+#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize)				\
+  ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))
+
+#define gmp_assert_nocarry(x) do { \
+    mp_limb_t __cy = (x);	   \
+    assert (__cy == 0);		   \
+    (void) (__cy);		   \
+  } while (0)
+
+#define gmp_clz(count, x) do {						\
+    mp_limb_t __clz_x = (x);						\
+    unsigned __clz_c = 0;						\
+    int LOCAL_SHIFT_BITS = 8;						\
+    if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)				\
+      for (;								\
+	   (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0;	\
+	   __clz_c += 8)						\
+	{ __clz_x <<= LOCAL_SHIFT_BITS;	}				\
+    for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++)		\
+      __clz_x <<= 1;							\
+    (count) = __clz_c;							\
+  } while (0)
+
+#define gmp_ctz(count, x) do {						\
+    mp_limb_t __ctz_x = (x);						\
+    unsigned __ctz_c = 0;						\
+    gmp_clz (__ctz_c, __ctz_x & - __ctz_x);				\
+    (count) = GMP_LIMB_BITS - 1 - __ctz_c;				\
+  } while (0)
+
+#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    mp_limb_t __x;							\
+    __x = (al) + (bl);							\
+    (sh) = (ah) + (bh) + (__x < (al));					\
+    (sl) = __x;								\
+  } while (0)
+
+#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    mp_limb_t __x;							\
+    __x = (al) - (bl);							\
+    (sh) = (ah) - (bh) - ((al) < (bl));					\
+    (sl) = __x;								\
+  } while (0)
+
+#define gmp_umul_ppmm(w1, w0, u, v)					\
+  do {									\
+    int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;				\
+    if (sizeof(unsigned int) * CHAR_BIT >= 2 * GMP_LIMB_BITS)		\
+      {									\
+	unsigned int __ww = (unsigned int) (u) * (v);			\
+	w0 = (mp_limb_t) __ww;						\
+	w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS);			\
+      }									\
+    else if (GMP_ULONG_BITS >= 2 * GMP_LIMB_BITS)			\
+      {									\
+	unsigned long int __ww = (unsigned long int) (u) * (v);		\
+	w0 = (mp_limb_t) __ww;						\
+	w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS);			\
+      }									\
+    else {								\
+      mp_limb_t __x0, __x1, __x2, __x3;					\
+      unsigned __ul, __vl, __uh, __vh;					\
+      mp_limb_t __u = (u), __v = (v);					\
+      assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));		\
+									\
+      __ul = __u & GMP_LLIMB_MASK;					\
+      __uh = __u >> (GMP_LIMB_BITS / 2);				\
+      __vl = __v & GMP_LLIMB_MASK;					\
+      __vh = __v >> (GMP_LIMB_BITS / 2);				\
+									\
+      __x0 = (mp_limb_t) __ul * __vl;					\
+      __x1 = (mp_limb_t) __ul * __vh;					\
+      __x2 = (mp_limb_t) __uh * __vl;					\
+      __x3 = (mp_limb_t) __uh * __vh;					\
+									\
+      __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */	\
+      __x1 += __x2;		/* but this indeed can */		\
+      if (__x1 < __x2)		/* did we get it? */			\
+	__x3 += GMP_HLIMB_BIT;	/* yes, add it in the proper pos. */	\
+									\
+      (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2));			\
+      (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK);	\
+    }									\
+  } while (0)
+
+/* If mp_limb_t is of size smaller than int, plain u*v implies
+   automatic promotion to *signed* int, and then multiply may overflow
+   and cause undefined behavior. Explicitly cast to unsigned int for
+   that case. */
+#define gmp_umullo_limb(u, v) \
+  ((sizeof(mp_limb_t) >= sizeof(int)) ? (u)*(v) : (unsigned int)(u) * (v))
+
+#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di)			\
+  do {									\
+    mp_limb_t _qh, _ql, _r, _mask;					\
+    gmp_umul_ppmm (_qh, _ql, (nh), (di));				\
+    gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));		\
+    _r = (nl) - gmp_umullo_limb (_qh, (d));				\
+    _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */		\
+    _qh += _mask;							\
+    _r += _mask & (d);							\
+    if (_r >= (d))							\
+      {									\
+	_r -= (d);							\
+	_qh++;								\
+      }									\
+									\
+    (r) = _r;								\
+    (q) = _qh;								\
+  } while (0)
+
+#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv)		\
+  do {									\
+    mp_limb_t _q0, _t1, _t0, _mask;					\
+    gmp_umul_ppmm ((q), _q0, (n2), (dinv));				\
+    gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1));			\
+									\
+    /* Compute the two most significant limbs of n - q'd */		\
+    (r1) = (n1) - gmp_umullo_limb ((d1), (q));				\
+    gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0));		\
+    gmp_umul_ppmm (_t1, _t0, (d0), (q));				\
+    gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0);			\
+    (q)++;								\
+									\
+    /* Conditionally adjust q and the remainders */			\
+    _mask = - (mp_limb_t) ((r1) >= _q0);				\
+    (q) += _mask;							\
+    gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
+    if ((r1) >= (d1))							\
+      {									\
+	if ((r1) > (d1) || (r0) >= (d0))				\
+	  {								\
+	    (q)++;							\
+	    gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0));	\
+	  }								\
+      }									\
+  } while (0)
+
+/* Swap macros. */
+#define MP_LIMB_T_SWAP(x, y)						\
+  do {									\
+    mp_limb_t __mp_limb_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_limb_t_swap__tmp;					\
+  } while (0)
+#define MP_SIZE_T_SWAP(x, y)						\
+  do {									\
+    mp_size_t __mp_size_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_size_t_swap__tmp;					\
+  } while (0)
+#define MP_BITCNT_T_SWAP(x,y)			\
+  do {						\
+    mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x);	\
+    (x) = (y);					\
+    (y) = __mp_bitcnt_t_swap__tmp;		\
+  } while (0)
+#define MP_PTR_SWAP(x, y)						\
+  do {									\
+    mp_ptr __mp_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mp_ptr_swap__tmp;						\
+  } while (0)
+#define MP_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mp_srcptr __mp_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_srcptr_swap__tmp;					\
+  } while (0)
+
+#define MPN_PTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_PTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+#define MPN_SRCPTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_SRCPTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+
+#define MPZ_PTR_SWAP(x, y)						\
+  do {									\
+    mpz_ptr __mpz_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mpz_ptr_swap__tmp;						\
+  } while (0)
+#define MPZ_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mpz_srcptr __mpz_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mpz_srcptr_swap__tmp;					\
+  } while (0)
+
+const int mp_bits_per_limb = GMP_LIMB_BITS;
+
+
+/* Memory allocation and other helper functions. */
+static void
+gmp_die (const char *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+  abort();
+}
+
+static void *
+gmp_default_alloc (size_t size)
+{
+  void *p;
+
+  assert (size > 0);
+
+  p = malloc (size);
+  if (!p)
+    gmp_die("gmp_default_alloc: Virtual memory exhausted.");
+
+  return p;
+}
+
+static void *
+gmp_default_realloc (void *old, size_t unused_old_size, size_t new_size)
+{
+  void * p;
+
+  p = realloc (old, new_size);
+
+  if (!p)
+    gmp_die("gmp_default_realloc: Virtual memory exhausted.");
+
+  return p;
+}
+
+static void
+gmp_default_free (void *p, size_t unused_size)
+{
+  free (p);
+}
+
+static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
+static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
+static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
+
+void
+mp_get_memory_functions (void *(**alloc_func) (size_t),
+			 void *(**realloc_func) (void *, size_t, size_t),
+			 void (**free_func) (void *, size_t))
+{
+  if (alloc_func)
+    *alloc_func = gmp_allocate_func;
+
+  if (realloc_func)
+    *realloc_func = gmp_reallocate_func;
+
+  if (free_func)
+    *free_func = gmp_free_func;
+}
+
+void
+mp_set_memory_functions (void *(*alloc_func) (size_t),
+			 void *(*realloc_func) (void *, size_t, size_t),
+			 void (*free_func) (void *, size_t))
+{
+  if (!alloc_func)
+    alloc_func = gmp_default_alloc;
+  if (!realloc_func)
+    realloc_func = gmp_default_realloc;
+  if (!free_func)
+    free_func = gmp_default_free;
+
+  gmp_allocate_func = alloc_func;
+  gmp_reallocate_func = realloc_func;
+  gmp_free_func = free_func;
+}
+
+#define gmp_alloc(size) ((*gmp_allocate_func)((size)))
+#define gmp_free(p, size) ((*gmp_free_func) ((p), (size)))
+#define gmp_realloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size))
+
+static mp_ptr
+gmp_alloc_limbs (mp_size_t size)
+{
+  return (mp_ptr) gmp_alloc (size * sizeof (mp_limb_t));
+}
+
+static mp_ptr
+gmp_realloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size)
+{
+  assert (size > 0);
+  return (mp_ptr) gmp_realloc (old, old_size * sizeof (mp_limb_t), size * sizeof (mp_limb_t));
+}
+
+static void
+gmp_free_limbs (mp_ptr old, mp_size_t size)
+{
+  gmp_free (old, size * sizeof (mp_limb_t));
+}
+
+
+/* MPN interface */
+
+void
+mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    d[i] = s[i];
+}
+
+void
+mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+  while (--n >= 0)
+    d[n] = s[n];
+}
+
+int
+mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  while (--n >= 0)
+    {
+      if (ap[n] != bp[n])
+	return ap[n] > bp[n] ? 1 : -1;
+    }
+  return 0;
+}
+
+static int
+mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  if (an != bn)
+    return an < bn ? -1 : 1;
+  else
+    return mpn_cmp (ap, bp, an);
+}
+
+static mp_size_t
+mpn_normalized_size (mp_srcptr xp, mp_size_t n)
+{
+  while (n > 0 && xp[n-1] == 0)
+    --n;
+  return n;
+}
+
+int
+mpn_zero_p(mp_srcptr rp, mp_size_t n)
+{
+  return mpn_normalized_size (rp, n) == 0;
+}
+
+void
+mpn_zero (mp_ptr rp, mp_size_t n)
+{
+  while (--n >= 0)
+    rp[n] = 0;
+}
+
+mp_limb_t
+mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_size_t i;
+
+  assert (n > 0);
+  i = 0;
+  do
+    {
+      mp_limb_t r = ap[i] + b;
+      /* Carry out */
+      b = (r < b);
+      rp[i] = r;
+    }
+  while (++i < n);
+
+  return b;
+}
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  for (i = 0, cy = 0; i < n; i++)
+    {
+      mp_limb_t a, b, r;
+      a = ap[i]; b = bp[i];
+      r = a + cy;
+      cy = (r < cy);
+      r += b;
+      cy += (r < b);
+      rp[i] = r;
+    }
+  return cy;
+}
+
+mp_limb_t
+mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_limb_t cy;
+
+  assert (an >= bn);
+
+  cy = mpn_add_n (rp, ap, bp, bn);
+  if (an > bn)
+    cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
+  return cy;
+}
+
+mp_limb_t
+mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_size_t i;
+
+  assert (n > 0);
+
+  i = 0;
+  do
+    {
+      mp_limb_t a = ap[i];
+      /* Carry out */
+      mp_limb_t cy = a < b;
+      rp[i] = a - b;
+      b = cy;
+    }
+  while (++i < n);
+
+  return b;
+}
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  for (i = 0, cy = 0; i < n; i++)
+    {
+      mp_limb_t a, b;
+      a = ap[i]; b = bp[i];
+      b += cy;
+      cy = (b < cy);
+      cy += (a < b);
+      rp[i] = a - b;
+    }
+  return cy;
+}
+
+mp_limb_t
+mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_limb_t cy;
+
+  assert (an >= bn);
+
+  cy = mpn_sub_n (rp, ap, bp, bn);
+  if (an > bn)
+    cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
+  return cy;
+}
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl;
+
+  assert (n >= 1);
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl, rl;
+
+  assert (n >= 1);
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      rl = *rp;
+      lpl = rl + lpl;
+      cl += lpl < rl;
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl, rl;
+
+  assert (n >= 1);
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      rl = *rp;
+      lpl = rl - lpl;
+      cl += lpl > rl;
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+mp_limb_t
+mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
+{
+  assert (un >= vn);
+  assert (vn >= 1);
+  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un));
+  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn));
+
+  /* We first multiply by the low order limb. This result can be
+     stored, not added, to rp. We also avoid a loop for zeroing this
+     way. */
+
+  rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+
+  /* Now accumulate the product of up[] and the next higher limb from
+     vp[]. */
+
+  while (--vn >= 1)
+    {
+      rp += 1, vp += 1;
+      rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
+    }
+  return rp[un];
+}
+
+void
+mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mpn_mul (rp, ap, n, bp, n);
+}
+
+void
+mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
+{
+  mpn_mul (rp, ap, n, ap, n);
+}
+
+mp_limb_t
+mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_limb_t retval;
+
+  assert (n >= 1);
+  assert (cnt >= 1);
+  assert (cnt < GMP_LIMB_BITS);
+
+  up += n;
+  rp += n;
+
+  tnc = GMP_LIMB_BITS - cnt;
+  low_limb = *--up;
+  retval = low_limb >> tnc;
+  high_limb = (low_limb << cnt);
+
+  while (--n != 0)
+    {
+      low_limb = *--up;
+      *--rp = high_limb | (low_limb >> tnc);
+      high_limb = (low_limb << cnt);
+    }
+  *--rp = high_limb;
+
+  return retval;
+}
+
+mp_limb_t
+mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_limb_t retval;
+
+  assert (n >= 1);
+  assert (cnt >= 1);
+  assert (cnt < GMP_LIMB_BITS);
+
+  tnc = GMP_LIMB_BITS - cnt;
+  high_limb = *up++;
+  retval = (high_limb << tnc);
+  low_limb = high_limb >> cnt;
+
+  while (--n != 0)
+    {
+      high_limb = *up++;
+      *rp++ = low_limb | (high_limb << tnc);
+      low_limb = high_limb >> cnt;
+    }
+  *rp = low_limb;
+
+  return retval;
+}
+
+static mp_bitcnt_t
+mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un,
+		 mp_limb_t ux)
+{
+  unsigned cnt;
+
+  assert (ux == 0 || ux == GMP_LIMB_MAX);
+  assert (0 <= i && i <= un );
+
+  while (limb == 0)
+    {
+      i++;
+      if (i == un)
+	return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
+      limb = ux ^ up[i];
+    }
+  gmp_ctz (cnt, limb);
+  return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
+}
+
+mp_bitcnt_t
+mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+  mp_size_t i;
+  i = bit / GMP_LIMB_BITS;
+
+  return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+			  i, ptr, i, 0);
+}
+
+mp_bitcnt_t
+mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+  mp_size_t i;
+  i = bit / GMP_LIMB_BITS;
+
+  return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+			  i, ptr, i, GMP_LIMB_MAX);
+}
+
+void
+mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  while (--n >= 0)
+    *rp++ = ~ *up++;
+}
+
+mp_limb_t
+mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  while (*up == 0)
+    {
+      *rp = 0;
+      if (!--n)
+	return 0;
+      ++up; ++rp;
+    }
+  *rp = - *up;
+  mpn_com (++rp, ++up, --n);
+  return 1;
+}
+
+
+/* MPN division interface. */
+
+/* The 3/2 inverse is defined as
+
+     m = floor( (B^3-1) / (B u1 + u0)) - B
+*/
+mp_limb_t
+mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
+{
+  mp_limb_t r, m;
+
+  {
+    mp_limb_t p, ql;
+    unsigned ul, uh, qh;
+
+    assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));
+    /* For notation, let b denote the half-limb base, so that B = b^2.
+       Split u1 = b uh + ul. */
+    ul = u1 & GMP_LLIMB_MASK;
+    uh = u1 >> (GMP_LIMB_BITS / 2);
+
+    /* Approximation of the high half of quotient. Differs from the 2/1
+       inverse of the half limb uh, since we have already subtracted
+       u0. */
+    qh = (u1 ^ GMP_LIMB_MAX) / uh;
+
+    /* Adjust to get a half-limb 3/2 inverse, i.e., we want
+
+       qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
+	   = floor( (b (~u) + b-1) / u),
+
+       and the remainder
+
+       r = b (~u) + b-1 - qh (b uh + ul)
+       = b (~u - qh uh) + b-1 - qh ul
+
+       Subtraction of qh ul may underflow, which implies adjustments.
+       But by normalization, 2 u >= B > qh ul, so we need to adjust by
+       at most 2.
+    */
+
+    r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
+
+    p = (mp_limb_t) qh * ul;
+    /* Adjustment steps taken from udiv_qrnnd_c */
+    if (r < p)
+      {
+	qh--;
+	r += u1;
+	if (r >= u1) /* i.e. we didn't get carry when adding to r */
+	  if (r < p)
+	    {
+	      qh--;
+	      r += u1;
+	    }
+      }
+    r -= p;
+
+    /* Low half of the quotient is
+
+       ql = floor ( (b r + b-1) / u1).
+
+       This is a 3/2 division (on half-limbs), for which qh is a
+       suitable inverse. */
+
+    p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
+    /* Unlike full-limb 3/2, we can add 1 without overflow. For this to
+       work, it is essential that ql is a full mp_limb_t. */
+    ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
+
+    /* By the 3/2 trick, we don't need the high half limb. */
+    r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
+
+    if (r >= (GMP_LIMB_MAX & (p << (GMP_LIMB_BITS / 2))))
+      {
+	ql--;
+	r += u1;
+      }
+    m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
+    if (r >= u1)
+      {
+	m++;
+	r -= u1;
+      }
+  }
+
+  /* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a
+     3/2 inverse. */
+  if (u0 > 0)
+    {
+      mp_limb_t th, tl;
+      r = ~r;
+      r += u0;
+      if (r < u0)
+	{
+	  m--;
+	  if (r >= u1)
+	    {
+	      m--;
+	      r -= u1;
+	    }
+	  r -= u1;
+	}
+      gmp_umul_ppmm (th, tl, u0, m);
+      r += th;
+      if (r < th)
+	{
+	  m--;
+	  m -= ((r > u1) | ((r == u1) & (tl > u0)));
+	}
+    }
+
+  return m;
+}
+
+struct gmp_div_inverse
+{
+  /* Normalization shift count. */
+  unsigned shift;
+  /* Normalized divisor (d0 unused for mpn_div_qr_1) */
+  mp_limb_t d1, d0;
+  /* Inverse, for 2/1 or 3/2. */
+  mp_limb_t di;
+};
+
+static void
+mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
+{
+  unsigned shift;
+
+  assert (d > 0);
+  gmp_clz (shift, d);
+  inv->shift = shift;
+  inv->d1 = d << shift;
+  inv->di = mpn_invert_limb (inv->d1);
+}
+
+static void
+mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
+		     mp_limb_t d1, mp_limb_t d0)
+{
+  unsigned shift;
+
+  assert (d1 > 0);
+  gmp_clz (shift, d1);
+  inv->shift = shift;
+  if (shift > 0)
+    {
+      d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+      d0 <<= shift;
+    }
+  inv->d1 = d1;
+  inv->d0 = d0;
+  inv->di = mpn_invert_3by2 (d1, d0);
+}
+
+static void
+mpn_div_qr_invert (struct gmp_div_inverse *inv,
+		   mp_srcptr dp, mp_size_t dn)
+{
+  assert (dn > 0);
+
+  if (dn == 1)
+    mpn_div_qr_1_invert (inv, dp[0]);
+  else if (dn == 2)
+    mpn_div_qr_2_invert (inv, dp[1], dp[0]);
+  else
+    {
+      unsigned shift;
+      mp_limb_t d1, d0;
+
+      d1 = dp[dn-1];
+      d0 = dp[dn-2];
+      assert (d1 > 0);
+      gmp_clz (shift, d1);
+      inv->shift = shift;
+      if (shift > 0)
+	{
+	  d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+	  d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
+	}
+      inv->d1 = d1;
+      inv->d0 = d0;
+      inv->di = mpn_invert_3by2 (d1, d0);
+    }
+}
+
+/* Not matching current public gmp interface, rather corresponding to
+   the sbpi1_div_* functions. */
+static mp_limb_t
+mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
+		     const struct gmp_div_inverse *inv)
+{
+  mp_limb_t d, di;
+  mp_limb_t r;
+  mp_ptr tp = NULL;
+  mp_size_t tn = 0;
+
+  if (inv->shift > 0)
+    {
+      /* Shift, reusing qp area if possible. In-place shift if qp == np. */
+      tp = qp;
+      if (!tp)
+        {
+	   tn = nn;
+	   tp = gmp_alloc_limbs (tn);
+        }
+      r = mpn_lshift (tp, np, nn, inv->shift);
+      np = tp;
+    }
+  else
+    r = 0;
+
+  d = inv->d1;
+  di = inv->di;
+  while (--nn >= 0)
+    {
+      mp_limb_t q;
+
+      gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
+      if (qp)
+	qp[nn] = q;
+    }
+  if (tn)
+    gmp_free_limbs (tp, tn);
+
+  return r >> inv->shift;
+}
+
+static void
+mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		     const struct gmp_div_inverse *inv)
+{
+  unsigned shift;
+  mp_size_t i;
+  mp_limb_t d1, d0, di, r1, r0;
+
+  assert (nn >= 2);
+  shift = inv->shift;
+  d1 = inv->d1;
+  d0 = inv->d0;
+  di = inv->di;
+
+  if (shift > 0)
+    r1 = mpn_lshift (np, np, nn, shift);
+  else
+    r1 = 0;
+
+  r0 = np[nn - 1];
+
+  i = nn - 2;
+  do
+    {
+      mp_limb_t n0, q;
+      n0 = np[i];
+      gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
+
+      if (qp)
+	qp[i] = q;
+    }
+  while (--i >= 0);
+
+  if (shift > 0)
+    {
+      assert ((r0 & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - shift))) == 0);
+      r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
+      r1 >>= shift;
+    }
+
+  np[1] = r1;
+  np[0] = r0;
+}
+
+static void
+mpn_div_qr_pi1 (mp_ptr qp,
+		mp_ptr np, mp_size_t nn, mp_limb_t n1,
+		mp_srcptr dp, mp_size_t dn,
+		mp_limb_t dinv)
+{
+  mp_size_t i;
+
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+
+  assert (dn > 2);
+  assert (nn >= dn);
+
+  d1 = dp[dn - 1];
+  d0 = dp[dn - 2];
+
+  assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
+  /* Iteration variable is the index of the q limb.
+   *
+   * We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
+   * by            <d1,          d0,        dp[dn-3],  ..., dp[0] >
+   */
+
+  i = nn - dn;
+  do
+    {
+      mp_limb_t n0 = np[dn-1+i];
+
+      if (n1 == d1 && n0 == d0)
+	{
+	  q = GMP_LIMB_MAX;
+	  mpn_submul_1 (np+i, dp, dn, q);
+	  n1 = np[dn-1+i];	/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np + i, dp, dn-2, q);
+
+	  cy1 = n0 < cy;
+	  n0 = n0 - cy;
+	  cy = n1 < cy1;
+	  n1 = n1 - cy1;
+	  np[dn-2+i] = n0;
+
+	  if (cy != 0)
+	    {
+	      n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
+	      q--;
+	    }
+	}
+
+      if (qp)
+	qp[i] = q;
+    }
+  while (--i >= 0);
+
+  np[dn - 1] = n1;
+}
+
+static void
+mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		   mp_srcptr dp, mp_size_t dn,
+		   const struct gmp_div_inverse *inv)
+{
+  assert (dn > 0);
+  assert (nn >= dn);
+
+  if (dn == 1)
+    np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
+  else if (dn == 2)
+    mpn_div_qr_2_preinv (qp, np, nn, inv);
+  else
+    {
+      mp_limb_t nh;
+      unsigned shift;
+
+      assert (inv->d1 == dp[dn-1]);
+      assert (inv->d0 == dp[dn-2]);
+      assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
+
+      shift = inv->shift;
+      if (shift > 0)
+	nh = mpn_lshift (np, np, nn, shift);
+      else
+	nh = 0;
+
+      mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
+
+      if (shift > 0)
+	gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
+    }
+}
+
+static void
+mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
+{
+  struct gmp_div_inverse inv;
+  mp_ptr tp = NULL;
+
+  assert (dn > 0);
+  assert (nn >= dn);
+
+  mpn_div_qr_invert (&inv, dp, dn);
+  if (dn > 2 && inv.shift > 0)
+    {
+      tp = gmp_alloc_limbs (dn);
+      gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
+      dp = tp;
+    }
+  mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
+  if (tp)
+    gmp_free_limbs (tp, dn);
+}
+
+
+/* MPN base conversion. */
+static unsigned
+mpn_base_power_of_two_p (unsigned b)
+{
+  switch (b)
+    {
+    case 2: return 1;
+    case 4: return 2;
+    case 8: return 3;
+    case 16: return 4;
+    case 32: return 5;
+    case 64: return 6;
+    case 128: return 7;
+    case 256: return 8;
+    default: return 0;
+    }
+}
+
+struct mpn_base_info
+{
+  /* bb is the largest power of the base which fits in one limb, and
+     exp is the corresponding exponent. */
+  unsigned exp;
+  mp_limb_t bb;
+};
+
+static void
+mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
+{
+  mp_limb_t m;
+  mp_limb_t p;
+  unsigned exp;
+
+  m = GMP_LIMB_MAX / b;
+  for (exp = 1, p = b; p <= m; exp++)
+    p *= b;
+
+  info->exp = exp;
+  info->bb = p;
+}
+
+static mp_bitcnt_t
+mpn_limb_size_in_base_2 (mp_limb_t u)
+{
+  unsigned shift;
+
+  assert (u > 0);
+  gmp_clz (shift, u);
+  return GMP_LIMB_BITS - shift;
+}
+
+static size_t
+mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
+{
+  unsigned char mask;
+  size_t sn, j;
+  mp_size_t i;
+  unsigned shift;
+
+  sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
+	+ bits - 1) / bits;
+
+  mask = (1U << bits) - 1;
+
+  for (i = 0, j = sn, shift = 0; j-- > 0;)
+    {
+      unsigned char digit = up[i] >> shift;
+
+      shift += bits;
+
+      if (shift >= GMP_LIMB_BITS && ++i < un)
+	{
+	  shift -= GMP_LIMB_BITS;
+	  digit |= up[i] << (bits - shift);
+	}
+      sp[j] = digit & mask;
+    }
+  return sn;
+}
+
+/* We generate digits from the least significant end, and reverse at
+   the end. */
+static size_t
+mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
+		  const struct gmp_div_inverse *binv)
+{
+  mp_size_t i;
+  for (i = 0; w > 0; i++)
+    {
+      mp_limb_t h, l, r;
+
+      h = w >> (GMP_LIMB_BITS - binv->shift);
+      l = w << binv->shift;
+
+      gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
+      assert ((r & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - binv->shift))) == 0);
+      r >>= binv->shift;
+
+      sp[i] = r;
+    }
+  return i;
+}
+
+static size_t
+mpn_get_str_other (unsigned char *sp,
+		   int base, const struct mpn_base_info *info,
+		   mp_ptr up, mp_size_t un)
+{
+  struct gmp_div_inverse binv;
+  size_t sn;
+  size_t i;
+
+  mpn_div_qr_1_invert (&binv, base);
+
+  sn = 0;
+
+  if (un > 1)
+    {
+      struct gmp_div_inverse bbinv;
+      mpn_div_qr_1_invert (&bbinv, info->bb);
+
+      do
+	{
+	  mp_limb_t w;
+	  size_t done;
+	  w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
+	  un -= (up[un-1] == 0);
+	  done = mpn_limb_get_str (sp + sn, w, &binv);
+
+	  for (sn += done; done < info->exp; done++)
+	    sp[sn++] = 0;
+	}
+      while (un > 1);
+    }
+  sn += mpn_limb_get_str (sp + sn, up[0], &binv);
+
+  /* Reverse order */
+  for (i = 0; 2*i + 1 < sn; i++)
+    {
+      unsigned char t = sp[i];
+      sp[i] = sp[sn - i - 1];
+      sp[sn - i - 1] = t;
+    }
+
+  return sn;
+}
+
+size_t
+mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
+{
+  unsigned bits;
+
+  assert (un > 0);
+  assert (up[un-1] > 0);
+
+  bits = mpn_base_power_of_two_p (base);
+  if (bits)
+    return mpn_get_str_bits (sp, bits, up, un);
+  else
+    {
+      struct mpn_base_info info;
+
+      mpn_get_base_info (&info, base);
+      return mpn_get_str_other (sp, base, &info, up, un);
+    }
+}
+
+static mp_size_t
+mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
+		  unsigned bits)
+{
+  mp_size_t rn;
+  mp_limb_t limb;
+  unsigned shift;
+
+  for (limb = 0, rn = 0, shift = 0; sn-- > 0; )
+    {
+      limb |= (mp_limb_t) sp[sn] << shift;
+      shift += bits;
+      if (shift >= GMP_LIMB_BITS)
+	{
+	  shift -= GMP_LIMB_BITS;
+	  rp[rn++] = limb;
+	  /* Next line is correct also if shift == 0,
+	     bits == 8, and mp_limb_t == unsigned char. */
+	  limb = (unsigned int) sp[sn] >> (bits - shift);
+	}
+    }
+  if (limb != 0)
+    rp[rn++] = limb;
+  else
+    rn = mpn_normalized_size (rp, rn);
+  return rn;
+}
+
+/* Result is usually normalized, except for all-zero input, in which
+   case a single zero limb is written at *RP, and 1 is returned. */
+static mp_size_t
+mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
+		   mp_limb_t b, const struct mpn_base_info *info)
+{
+  mp_size_t rn;
+  mp_limb_t w;
+  unsigned k;
+  size_t j;
+
+  assert (sn > 0);
+
+  k = 1 + (sn - 1) % info->exp;
+
+  j = 0;
+  w = sp[j++];
+  while (--k != 0)
+    w = w * b + sp[j++];
+
+  rp[0] = w;
+
+  for (rn = 1; j < sn;)
+    {
+      mp_limb_t cy;
+
+      w = sp[j++];
+      for (k = 1; k < info->exp; k++)
+	w = w * b + sp[j++];
+
+      cy = mpn_mul_1 (rp, rp, rn, info->bb);
+      cy += mpn_add_1 (rp, rp, rn, w);
+      if (cy > 0)
+	rp[rn++] = cy;
+    }
+  assert (j == sn);
+
+  return rn;
+}
+
+mp_size_t
+mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
+{
+  unsigned bits;
+
+  if (sn == 0)
+    return 0;
+
+  bits = mpn_base_power_of_two_p (base);
+  if (bits)
+    return mpn_set_str_bits (rp, sp, sn, bits);
+  else
+    {
+      struct mpn_base_info info;
+
+      mpn_get_base_info (&info, base);
+      return mpn_set_str_other (rp, sp, sn, base, &info);
+    }
+}
+
+
+/* MPZ interface */
+void
+mpz_init (mpz_t r)
+{
+  static const mp_limb_t dummy_limb = GMP_LIMB_MAX & 0xc1a0;
+
+  r->_mp_alloc = 0;
+  r->_mp_size = 0;
+  r->_mp_d = (mp_ptr) &dummy_limb;
+}
+
+/* The utility of this function is a bit limited, since many functions
+   assigns the result variable using mpz_swap. */
+void
+mpz_init2 (mpz_t r, mp_bitcnt_t bits)
+{
+  mp_size_t rn;
+
+  bits -= (bits != 0);		/* Round down, except if 0 */
+  rn = 1 + bits / GMP_LIMB_BITS;
+
+  r->_mp_alloc = rn;
+  r->_mp_size = 0;
+  r->_mp_d = gmp_alloc_limbs (rn);
+}
+
+void
+mpz_clear (mpz_t r)
+{
+  if (r->_mp_alloc)
+    gmp_free_limbs (r->_mp_d, r->_mp_alloc);
+}
+
+static mp_ptr
+mpz_realloc (mpz_t r, mp_size_t size)
+{
+  size = GMP_MAX (size, 1);
+
+  if (r->_mp_alloc)
+    r->_mp_d = gmp_realloc_limbs (r->_mp_d, r->_mp_alloc, size);
+  else
+    r->_mp_d = gmp_alloc_limbs (size);
+  r->_mp_alloc = size;
+
+  if (GMP_ABS (r->_mp_size) > size)
+    r->_mp_size = 0;
+
+  return r->_mp_d;
+}
+
+/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs.  */
+#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc			\
+			  ? mpz_realloc(z,n)			\
+			  : (z)->_mp_d)
+
+/* MPZ assignment and basic conversions. */
+void
+mpz_set_si (mpz_t r, signed long int x)
+{
+  if (x >= 0)
+    mpz_set_ui (r, x);
+  else /* (x < 0) */
+    if (GMP_LIMB_BITS < GMP_ULONG_BITS)
+      {
+	mpz_set_ui (r, GMP_NEG_CAST (unsigned long int, x));
+	mpz_neg (r, r);
+      }
+  else
+    {
+      r->_mp_size = -1;
+      MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x);
+    }
+}
+
+void
+mpz_set_ui (mpz_t r, unsigned long int x)
+{
+  if (x > 0)
+    {
+      r->_mp_size = 1;
+      MPZ_REALLOC (r, 1)[0] = x;
+      if (GMP_LIMB_BITS < GMP_ULONG_BITS)
+	{
+	  int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
+	  while (x >>= LOCAL_GMP_LIMB_BITS)
+	    {
+	      ++ r->_mp_size;
+	      MPZ_REALLOC (r, r->_mp_size)[r->_mp_size - 1] = x;
+	    }
+	}
+    }
+  else
+    r->_mp_size = 0;
+}
+
+void
+mpz_set (mpz_t r, const mpz_t x)
+{
+  /* Allow the NOP r == x */
+  if (r != x)
+    {
+      mp_size_t n;
+      mp_ptr rp;
+
+      n = GMP_ABS (x->_mp_size);
+      rp = MPZ_REALLOC (r, n);
+
+      mpn_copyi (rp, x->_mp_d, n);
+      r->_mp_size = x->_mp_size;
+    }
+}
+
+void
+mpz_init_set_si (mpz_t r, signed long int x)
+{
+  mpz_init (r);
+  mpz_set_si (r, x);
+}
+
+void
+mpz_init_set_ui (mpz_t r, unsigned long int x)
+{
+  mpz_init (r);
+  mpz_set_ui (r, x);
+}
+
+void
+mpz_init_set (mpz_t r, const mpz_t x)
+{
+  mpz_init (r);
+  mpz_set (r, x);
+}
+
+int
+mpz_fits_slong_p (const mpz_t u)
+{
+  return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0;
+}
+
+static int
+mpn_absfits_ulong_p (mp_srcptr up, mp_size_t un)
+{
+  int ulongsize = GMP_ULONG_BITS / GMP_LIMB_BITS;
+  mp_limb_t ulongrem = 0;
+
+  if (GMP_ULONG_BITS % GMP_LIMB_BITS != 0)
+    ulongrem = (mp_limb_t) (ULONG_MAX >> GMP_LIMB_BITS * ulongsize) + 1;
+
+  return un <= ulongsize || (up[ulongsize] < ulongrem && un == ulongsize + 1);
+}
+
+int
+mpz_fits_ulong_p (const mpz_t u)
+{
+  mp_size_t us = u->_mp_size;
+
+  return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us);
+}
+
+int
+mpz_fits_sint_p (const mpz_t u)
+{
+  return mpz_cmp_si (u, INT_MAX) <= 0 && mpz_cmp_si (u, INT_MIN) >= 0;
+}
+
+int
+mpz_fits_uint_p (const mpz_t u)
+{
+  return u->_mp_size >= 0 && mpz_cmpabs_ui (u, UINT_MAX) <= 0;
+}
+
+int
+mpz_fits_sshort_p (const mpz_t u)
+{
+  return mpz_cmp_si (u, SHRT_MAX) <= 0 && mpz_cmp_si (u, SHRT_MIN) >= 0;
+}
+
+int
+mpz_fits_ushort_p (const mpz_t u)
+{
+  return u->_mp_size >= 0 && mpz_cmpabs_ui (u, USHRT_MAX) <= 0;
+}
+
+long int
+mpz_get_si (const mpz_t u)
+{
+  unsigned long r = mpz_get_ui (u);
+  unsigned long c = -LONG_MAX - LONG_MIN;
+
+  if (u->_mp_size < 0)
+    /* This expression is necessary to properly handle -LONG_MIN */
+    return -(long) c - (long) ((r - c) & LONG_MAX);
+  else
+    return (long) (r & LONG_MAX);
+}
+
+unsigned long int
+mpz_get_ui (const mpz_t u)
+{
+  if (GMP_LIMB_BITS < GMP_ULONG_BITS)
+    {
+      int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
+      unsigned long r = 0;
+      mp_size_t n = GMP_ABS (u->_mp_size);
+      n = GMP_MIN (n, 1 + (mp_size_t) (GMP_ULONG_BITS - 1) / GMP_LIMB_BITS);
+      while (--n >= 0)
+	r = (r << LOCAL_GMP_LIMB_BITS) + u->_mp_d[n];
+      return r;
+    }
+
+  return u->_mp_size == 0 ? 0 : u->_mp_d[0];
+}
+
+size_t
+mpz_size (const mpz_t u)
+{
+  return GMP_ABS (u->_mp_size);
+}
+
+mp_limb_t
+mpz_getlimbn (const mpz_t u, mp_size_t n)
+{
+  if (n >= 0 && n < GMP_ABS (u->_mp_size))
+    return u->_mp_d[n];
+  else
+    return 0;
+}
+
+void
+mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
+{
+  mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS);
+}
+
+mp_srcptr
+mpz_limbs_read (mpz_srcptr x)
+{
+  return x->_mp_d;
+}
+
+mp_ptr
+mpz_limbs_modify (mpz_t x, mp_size_t n)
+{
+  assert (n > 0);
+  return MPZ_REALLOC (x, n);
+}
+
+mp_ptr
+mpz_limbs_write (mpz_t x, mp_size_t n)
+{
+  return mpz_limbs_modify (x, n);
+}
+
+void
+mpz_limbs_finish (mpz_t x, mp_size_t xs)
+{
+  mp_size_t xn;
+  xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs));
+  x->_mp_size = xs < 0 ? -xn : xn;
+}
+
+static mpz_srcptr
+mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+  x->_mp_alloc = 0;
+  x->_mp_d = (mp_ptr) xp;
+  x->_mp_size = xs;
+  return x;
+}
+
+mpz_srcptr
+mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+  mpz_roinit_normal_n (x, xp, xs);
+  mpz_limbs_finish (x, xs);
+  return x;
+}
+
+
+/* Conversions and comparison to double. */
+void
+mpz_set_d (mpz_t r, double x)
+{
+  int sign;
+  mp_ptr rp;
+  mp_size_t rn, i;
+  double B;
+  double Bi;
+  mp_limb_t f;
+
+  /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
+     zero or infinity. */
+  if (x != x || x == x * 0.5)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  sign = x < 0.0 ;
+  if (sign)
+    x = - x;
+
+  if (x < 1.0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+  B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+  Bi = 1.0 / B;
+  for (rn = 1; x >= B; rn++)
+    x *= Bi;
+
+  rp = MPZ_REALLOC (r, rn);
+
+  f = (mp_limb_t) x;
+  x -= f;
+  assert (x < 1.0);
+  i = rn-1;
+  rp[i] = f;
+  while (--i >= 0)
+    {
+      x = B * x;
+      f = (mp_limb_t) x;
+      x -= f;
+      assert (x < 1.0);
+      rp[i] = f;
+    }
+
+  r->_mp_size = sign ? - rn : rn;
+}
+
+void
+mpz_init_set_d (mpz_t r, double x)
+{
+  mpz_init (r);
+  mpz_set_d (r, x);
+}
+
+double
+mpz_get_d (const mpz_t u)
+{
+  int m;
+  mp_limb_t l;
+  mp_size_t un;
+  double x;
+  double B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+
+  un = GMP_ABS (u->_mp_size);
+
+  if (un == 0)
+    return 0.0;
+
+  l = u->_mp_d[--un];
+  gmp_clz (m, l);
+  m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
+  if (m < 0)
+    l &= GMP_LIMB_MAX << -m;
+
+  for (x = l; --un >= 0;)
+    {
+      x = B*x;
+      if (m > 0) {
+	l = u->_mp_d[un];
+	m -= GMP_LIMB_BITS;
+	if (m < 0)
+	  l &= GMP_LIMB_MAX << -m;
+	x += l;
+      }
+    }
+
+  if (u->_mp_size < 0)
+    x = -x;
+
+  return x;
+}
+
+int
+mpz_cmpabs_d (const mpz_t x, double d)
+{
+  mp_size_t xn;
+  double B, Bi;
+  mp_size_t i;
+
+  xn = x->_mp_size;
+  d = GMP_ABS (d);
+
+  if (xn != 0)
+    {
+      xn = GMP_ABS (xn);
+
+      B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+      Bi = 1.0 / B;
+
+      /* Scale d so it can be compared with the top limb. */
+      for (i = 1; i < xn; i++)
+	d *= Bi;
+
+      if (d >= B)
+	return -1;
+
+      /* Compare floor(d) to top limb, subtract and cancel when equal. */
+      for (i = xn; i-- > 0;)
+	{
+	  mp_limb_t f, xl;
+
+	  f = (mp_limb_t) d;
+	  xl = x->_mp_d[i];
+	  if (xl > f)
+	    return 1;
+	  else if (xl < f)
+	    return -1;
+	  d = B * (d - f);
+	}
+    }
+  return - (d > 0.0);
+}
+
+int
+mpz_cmp_d (const mpz_t x, double d)
+{
+  if (x->_mp_size < 0)
+    {
+      if (d >= 0.0)
+	return -1;
+      else
+	return -mpz_cmpabs_d (x, d);
+    }
+  else
+    {
+      if (d < 0.0)
+	return 1;
+      else
+	return mpz_cmpabs_d (x, d);
+    }
+}
+
+
+/* MPZ comparisons and the like. */
+int
+mpz_sgn (const mpz_t u)
+{
+  return GMP_CMP (u->_mp_size, 0);
+}
+
+int
+mpz_cmp_si (const mpz_t u, long v)
+{
+  mp_size_t usize = u->_mp_size;
+
+  if (v >= 0)
+    return mpz_cmp_ui (u, v);
+  else if (usize >= 0)
+    return 1;
+  else
+    return - mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, v));
+}
+
+int
+mpz_cmp_ui (const mpz_t u, unsigned long v)
+{
+  mp_size_t usize = u->_mp_size;
+
+  if (usize < 0)
+    return -1;
+  else
+    return mpz_cmpabs_ui (u, v);
+}
+
+int
+mpz_cmp (const mpz_t a, const mpz_t b)
+{
+  mp_size_t asize = a->_mp_size;
+  mp_size_t bsize = b->_mp_size;
+
+  if (asize != bsize)
+    return (asize < bsize) ? -1 : 1;
+  else if (asize >= 0)
+    return mpn_cmp (a->_mp_d, b->_mp_d, asize);
+  else
+    return mpn_cmp (b->_mp_d, a->_mp_d, -asize);
+}
+
+int
+mpz_cmpabs_ui (const mpz_t u, unsigned long v)
+{
+  mp_size_t un = GMP_ABS (u->_mp_size);
+
+  if (! mpn_absfits_ulong_p (u->_mp_d, un))
+    return 1;
+  else
+    {
+      unsigned long uu = mpz_get_ui (u);
+      return GMP_CMP(uu, v);
+    }
+}
+
+int
+mpz_cmpabs (const mpz_t u, const mpz_t v)
+{
+  return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
+		   v->_mp_d, GMP_ABS (v->_mp_size));
+}
+
+void
+mpz_abs (mpz_t r, const mpz_t u)
+{
+  mpz_set (r, u);
+  r->_mp_size = GMP_ABS (r->_mp_size);
+}
+
+void
+mpz_neg (mpz_t r, const mpz_t u)
+{
+  mpz_set (r, u);
+  r->_mp_size = -r->_mp_size;
+}
+
+void
+mpz_swap (mpz_t u, mpz_t v)
+{
+  MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
+  MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size);
+}
+
+
+/* MPZ addition and subtraction */
+
+
+void
+mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+  mpz_t bb;
+  mpz_init_set_ui (bb, b);
+  mpz_add (r, a, bb);
+  mpz_clear (bb);
+}
+
+void
+mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+  mpz_ui_sub (r, b, a);
+  mpz_neg (r, r);
+}
+
+void
+mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
+{
+  mpz_neg (r, b);
+  mpz_add_ui (r, r, a);
+}
+
+static mp_size_t
+mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t an = GMP_ABS (a->_mp_size);
+  mp_size_t bn = GMP_ABS (b->_mp_size);
+  mp_ptr rp;
+  mp_limb_t cy;
+
+  if (an < bn)
+    {
+      MPZ_SRCPTR_SWAP (a, b);
+      MP_SIZE_T_SWAP (an, bn);
+    }
+
+  rp = MPZ_REALLOC (r, an + 1);
+  cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);
+
+  rp[an] = cy;
+
+  return an + cy;
+}
+
+static mp_size_t
+mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t an = GMP_ABS (a->_mp_size);
+  mp_size_t bn = GMP_ABS (b->_mp_size);
+  int cmp;
+  mp_ptr rp;
+
+  cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
+  if (cmp > 0)
+    {
+      rp = MPZ_REALLOC (r, an);
+      gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
+      return mpn_normalized_size (rp, an);
+    }
+  else if (cmp < 0)
+    {
+      rp = MPZ_REALLOC (r, bn);
+      gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
+      return -mpn_normalized_size (rp, bn);
+    }
+  else
+    return 0;
+}
+
+void
+mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t rn;
+
+  if ( (a->_mp_size ^ b->_mp_size) >= 0)
+    rn = mpz_abs_add (r, a, b);
+  else
+    rn = mpz_abs_sub (r, a, b);
+
+  r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+void
+mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t rn;
+
+  if ( (a->_mp_size ^ b->_mp_size) >= 0)
+    rn = mpz_abs_sub (r, a, b);
+  else
+    rn = mpz_abs_add (r, a, b);
+
+  r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+
+/* MPZ multiplication */
+void
+mpz_mul_si (mpz_t r, const mpz_t u, long int v)
+{
+  if (v < 0)
+    {
+      mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
+      mpz_neg (r, r);
+    }
+  else
+    mpz_mul_ui (r, u, v);
+}
+
+void
+mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+  mpz_t vv;
+  mpz_init_set_ui (vv, v);
+  mpz_mul (r, u, vv);
+  mpz_clear (vv);
+  return;
+}
+
+void
+mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  int sign;
+  mp_size_t un, vn, rn;
+  mpz_t t;
+  mp_ptr tp;
+
+  un = u->_mp_size;
+  vn = v->_mp_size;
+
+  if (un == 0 || vn == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  sign = (un ^ vn) < 0;
+
+  un = GMP_ABS (un);
+  vn = GMP_ABS (vn);
+
+  mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);
+
+  tp = t->_mp_d;
+  if (un >= vn)
+    mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
+  else
+    mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);
+
+  rn = un + vn;
+  rn -= tp[rn-1] == 0;
+
+  t->_mp_size = sign ? - rn : rn;
+  mpz_swap (r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
+{
+  mp_size_t un, rn;
+  mp_size_t limbs;
+  unsigned shift;
+  mp_ptr rp;
+
+  un = GMP_ABS (u->_mp_size);
+  if (un == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  limbs = bits / GMP_LIMB_BITS;
+  shift = bits % GMP_LIMB_BITS;
+
+  rn = un + limbs + (shift > 0);
+  rp = MPZ_REALLOC (r, rn);
+  if (shift > 0)
+    {
+      mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
+      rp[rn-1] = cy;
+      rn -= (cy == 0);
+    }
+  else
+    mpn_copyd (rp + limbs, u->_mp_d, un);
+
+  mpn_zero (rp, limbs);
+
+  r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
+}
+
+void
+mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+  mpz_t t;
+  mpz_init_set_ui (t, v);
+  mpz_mul (t, u, t);
+  mpz_add (r, r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+  mpz_t t;
+  mpz_init_set_ui (t, v);
+  mpz_mul (t, u, t);
+  mpz_sub (r, r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mpz_t t;
+  mpz_init (t);
+  mpz_mul (t, u, v);
+  mpz_add (r, r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_submul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mpz_t t;
+  mpz_init (t);
+  mpz_mul (t, u, v);
+  mpz_sub (r, r, t);
+  mpz_clear (t);
+}
+
+
+/* MPZ division */
+enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };
+
+/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
+static int
+mpz_div_qr (mpz_t q, mpz_t r,
+	    const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
+{
+  mp_size_t ns, ds, nn, dn, qs;
+  ns = n->_mp_size;
+  ds = d->_mp_size;
+
+  if (ds == 0)
+    gmp_die("mpz_div_qr: Divide by zero.");
+
+  if (ns == 0)
+    {
+      if (q)
+	q->_mp_size = 0;
+      if (r)
+	r->_mp_size = 0;
+      return 0;
+    }
+
+  nn = GMP_ABS (ns);
+  dn = GMP_ABS (ds);
+
+  qs = ds ^ ns;
+
+  if (nn < dn)
+    {
+      if (mode == GMP_DIV_CEIL && qs >= 0)
+	{
+	  /* q = 1, r = n - d */
+	  if (r)
+	    mpz_sub (r, n, d);
+	  if (q)
+	    mpz_set_ui (q, 1);
+	}
+      else if (mode == GMP_DIV_FLOOR && qs < 0)
+	{
+	  /* q = -1, r = n + d */
+	  if (r)
+	    mpz_add (r, n, d);
+	  if (q)
+	    mpz_set_si (q, -1);
+	}
+      else
+	{
+	  /* q = 0, r = d */
+	  if (r)
+	    mpz_set (r, n);
+	  if (q)
+	    q->_mp_size = 0;
+	}
+      return 1;
+    }
+  else
+    {
+      mp_ptr np, qp;
+      mp_size_t qn, rn;
+      mpz_t tq, tr;
+
+      mpz_init_set (tr, n);
+      np = tr->_mp_d;
+
+      qn = nn - dn + 1;
+
+      if (q)
+	{
+	  mpz_init2 (tq, qn * GMP_LIMB_BITS);
+	  qp = tq->_mp_d;
+	}
+      else
+	qp = NULL;
+
+      mpn_div_qr (qp, np, nn, d->_mp_d, dn);
+
+      if (qp)
+	{
+	  qn -= (qp[qn-1] == 0);
+
+	  tq->_mp_size = qs < 0 ? -qn : qn;
+	}
+      rn = mpn_normalized_size (np, dn);
+      tr->_mp_size = ns < 0 ? - rn : rn;
+
+      if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
+	{
+	  if (q)
+	    mpz_sub_ui (tq, tq, 1);
+	  if (r)
+	    mpz_add (tr, tr, d);
+	}
+      else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
+	{
+	  if (q)
+	    mpz_add_ui (tq, tq, 1);
+	  if (r)
+	    mpz_sub (tr, tr, d);
+	}
+
+      if (q)
+	{
+	  mpz_swap (tq, q);
+	  mpz_clear (tq);
+	}
+      if (r)
+	mpz_swap (tr, r);
+
+      mpz_clear (tr);
+
+      return rn != 0;
+    }
+}
+
+void
+mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL);
+}
+
+static void
+mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
+		enum mpz_div_round_mode mode)
+{
+  mp_size_t un, qn;
+  mp_size_t limb_cnt;
+  mp_ptr qp;
+  int adjust;
+
+  un = u->_mp_size;
+  if (un == 0)
+    {
+      q->_mp_size = 0;
+      return;
+    }
+  limb_cnt = bit_index / GMP_LIMB_BITS;
+  qn = GMP_ABS (un) - limb_cnt;
+  bit_index %= GMP_LIMB_BITS;
+
+  if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
+    /* Note: Below, the final indexing at limb_cnt is valid because at
+       that point we have qn > 0. */
+    adjust = (qn <= 0
+	      || !mpn_zero_p (u->_mp_d, limb_cnt)
+	      || (u->_mp_d[limb_cnt]
+		  & (((mp_limb_t) 1 << bit_index) - 1)));
+  else
+    adjust = 0;
+
+  if (qn <= 0)
+    qn = 0;
+  else
+    {
+      qp = MPZ_REALLOC (q, qn);
+
+      if (bit_index != 0)
+	{
+	  mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
+	  qn -= qp[qn - 1] == 0;
+	}
+      else
+	{
+	  mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
+	}
+    }
+
+  q->_mp_size = qn;
+
+  if (adjust)
+    mpz_add_ui (q, q, 1);
+  if (un < 0)
+    mpz_neg (q, q);
+}
+
+static void
+mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
+		enum mpz_div_round_mode mode)
+{
+  mp_size_t us, un, rn;
+  mp_ptr rp;
+  mp_limb_t mask;
+
+  us = u->_mp_size;
+  if (us == 0 || bit_index == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+  rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+  assert (rn > 0);
+
+  rp = MPZ_REALLOC (r, rn);
+  un = GMP_ABS (us);
+
+  mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);
+
+  if (rn > un)
+    {
+      /* Quotient (with truncation) is zero, and remainder is
+	 non-zero */
+      if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+	{
+	  /* Have to negate and sign extend. */
+	  mp_size_t i;
+
+	  gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un));
+	  for (i = un; i < rn - 1; i++)
+	    rp[i] = GMP_LIMB_MAX;
+
+	  rp[rn-1] = mask;
+	  us = -us;
+	}
+      else
+	{
+	  /* Just copy */
+	  if (r != u)
+	    mpn_copyi (rp, u->_mp_d, un);
+
+	  rn = un;
+	}
+    }
+  else
+    {
+      if (r != u)
+	mpn_copyi (rp, u->_mp_d, rn - 1);
+
+      rp[rn-1] = u->_mp_d[rn-1] & mask;
+
+      if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+	{
+	  /* If r != 0, compute 2^{bit_count} - r. */
+	  mpn_neg (rp, rp, rn);
+
+	  rp[rn-1] &= mask;
+
+	  /* us is not used for anything else, so we can modify it
+	     here to indicate flipped sign. */
+	  us = -us;
+	}
+    }
+  rn = mpn_normalized_size (rp, rn);
+  r->_mp_size = us < 0 ? -rn : rn;
+}
+
+void
+mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_p (const mpz_t n, const mpz_t d)
+{
+  return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+int
+mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m)
+{
+  mpz_t t;
+  int res;
+
+  /* a == b (mod 0) iff a == b */
+  if (mpz_sgn (m) == 0)
+    return (mpz_cmp (a, b) == 0);
+
+  mpz_init (t);
+  mpz_sub (t, a, b);
+  res = mpz_divisible_p (t, m);
+  mpz_clear (t);
+
+  return res;
+}
+
+static unsigned long
+mpz_div_qr_ui (mpz_t q, mpz_t r,
+	       const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
+{
+  unsigned long ret;
+  mpz_t rr, dd;
+
+  mpz_init (rr);
+  mpz_init_set_ui (dd, d);
+  mpz_div_qr (q, rr, n, dd, mode);
+  mpz_clear (dd);
+  ret = mpz_get_ui (rr);
+
+  if (r)
+    mpz_swap (r, rr);
+  mpz_clear (rr);
+
+  return ret;
+}
+
+unsigned long
+mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
+}
+unsigned long
+mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+unsigned long
+mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_ui (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_ui (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_ui (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_ui_p (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+
+/* GCD */
+static mp_limb_t
+mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
+{
+  unsigned shift;
+
+  assert ( (u | v) > 0);
+
+  if (u == 0)
+    return v;
+  else if (v == 0)
+    return u;
+
+  gmp_ctz (shift, u | v);
+
+  u >>= shift;
+  v >>= shift;
+
+  if ( (u & 1) == 0)
+    MP_LIMB_T_SWAP (u, v);
+
+  while ( (v & 1) == 0)
+    v >>= 1;
+
+  while (u != v)
+    {
+      if (u > v)
+	{
+	  u -= v;
+	  do
+	    u >>= 1;
+	  while ( (u & 1) == 0);
+	}
+      else
+	{
+	  v -= u;
+	  do
+	    v >>= 1;
+	  while ( (v & 1) == 0);
+	}
+    }
+  return u << shift;
+}
+
+unsigned long
+mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
+{
+  mpz_t t;
+  mpz_init_set_ui(t, v);
+  mpz_gcd (t, u, t);
+  if (v > 0)
+    v = mpz_get_ui (t);
+
+  if (g)
+    mpz_swap (t, g);
+
+  mpz_clear (t);
+
+  return v;
+}
+
+static mp_bitcnt_t
+mpz_make_odd (mpz_t r)
+{
+  mp_bitcnt_t shift;
+
+  assert (r->_mp_size > 0);
+  /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
+  shift = mpn_scan1 (r->_mp_d, 0);
+  mpz_tdiv_q_2exp (r, r, shift);
+
+  return shift;
+}
+
+void
+mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
+{
+  mpz_t tu, tv;
+  mp_bitcnt_t uz, vz, gz;
+
+  if (u->_mp_size == 0)
+    {
+      mpz_abs (g, v);
+      return;
+    }
+  if (v->_mp_size == 0)
+    {
+      mpz_abs (g, u);
+      return;
+    }
+
+  mpz_init (tu);
+  mpz_init (tv);
+
+  mpz_abs (tu, u);
+  uz = mpz_make_odd (tu);
+  mpz_abs (tv, v);
+  vz = mpz_make_odd (tv);
+  gz = GMP_MIN (uz, vz);
+
+  if (tu->_mp_size < tv->_mp_size)
+    mpz_swap (tu, tv);
+
+  mpz_tdiv_r (tu, tu, tv);
+  if (tu->_mp_size == 0)
+    {
+      mpz_swap (g, tv);
+    }
+  else
+    for (;;)
+      {
+	int c;
+
+	mpz_make_odd (tu);
+	c = mpz_cmp (tu, tv);
+	if (c == 0)
+	  {
+	    mpz_swap (g, tu);
+	    break;
+	  }
+	if (c < 0)
+	  mpz_swap (tu, tv);
+
+	if (tv->_mp_size == 1)
+	  {
+	    mp_limb_t *gp;
+
+	    mpz_tdiv_r (tu, tu, tv);
+	    gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */
+	    *gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]);
+
+	    g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */
+	    break;
+	  }
+	mpz_sub (tu, tu, tv);
+      }
+  mpz_clear (tu);
+  mpz_clear (tv);
+  mpz_mul_2exp (g, g, gz);
+}
+
+void
+mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
+{
+  mpz_t tu, tv, s0, s1, t0, t1;
+  mp_bitcnt_t uz, vz, gz;
+  mp_bitcnt_t power;
+
+  if (u->_mp_size == 0)
+    {
+      /* g = 0 u + sgn(v) v */
+      signed long sign = mpz_sgn (v);
+      mpz_abs (g, v);
+      if (s)
+	s->_mp_size = 0;
+      if (t)
+	mpz_set_si (t, sign);
+      return;
+    }
+
+  if (v->_mp_size == 0)
+    {
+      /* g = sgn(u) u + 0 v */
+      signed long sign = mpz_sgn (u);
+      mpz_abs (g, u);
+      if (s)
+	mpz_set_si (s, sign);
+      if (t)
+	t->_mp_size = 0;
+      return;
+    }
+
+  mpz_init (tu);
+  mpz_init (tv);
+  mpz_init (s0);
+  mpz_init (s1);
+  mpz_init (t0);
+  mpz_init (t1);
+
+  mpz_abs (tu, u);
+  uz = mpz_make_odd (tu);
+  mpz_abs (tv, v);
+  vz = mpz_make_odd (tv);
+  gz = GMP_MIN (uz, vz);
+
+  uz -= gz;
+  vz -= gz;
+
+  /* Cofactors corresponding to odd gcd. gz handled later. */
+  if (tu->_mp_size < tv->_mp_size)
+    {
+      mpz_swap (tu, tv);
+      MPZ_SRCPTR_SWAP (u, v);
+      MPZ_PTR_SWAP (s, t);
+      MP_BITCNT_T_SWAP (uz, vz);
+    }
+
+  /* Maintain
+   *
+   * u = t0 tu + t1 tv
+   * v = s0 tu + s1 tv
+   *
+   * where u and v denote the inputs with common factors of two
+   * eliminated, and det (s0, t0; s1, t1) = 2^p. Then
+   *
+   * 2^p tu =  s1 u - t1 v
+   * 2^p tv = -s0 u + t0 v
+   */
+
+  /* After initial division, tu = q tv + tu', we have
+   *
+   * u = 2^uz (tu' + q tv)
+   * v = 2^vz tv
+   *
+   * or
+   *
+   * t0 = 2^uz, t1 = 2^uz q
+   * s0 = 0,    s1 = 2^vz
+   */
+
+  mpz_tdiv_qr (t1, tu, tu, tv);
+  mpz_mul_2exp (t1, t1, uz);
+
+  mpz_setbit (s1, vz);
+  power = uz + vz;
+
+  if (tu->_mp_size > 0)
+    {
+      mp_bitcnt_t shift;
+      shift = mpz_make_odd (tu);
+      mpz_setbit (t0, uz + shift);
+      power += shift;
+
+      for (;;)
+	{
+	  int c;
+	  c = mpz_cmp (tu, tv);
+	  if (c == 0)
+	    break;
+
+	  if (c < 0)
+	    {
+	      /* tv = tv' + tu
+	       *
+	       * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
+	       * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */
+
+	      mpz_sub (tv, tv, tu);
+	      mpz_add (t0, t0, t1);
+	      mpz_add (s0, s0, s1);
+
+	      shift = mpz_make_odd (tv);
+	      mpz_mul_2exp (t1, t1, shift);
+	      mpz_mul_2exp (s1, s1, shift);
+	    }
+	  else
+	    {
+	      mpz_sub (tu, tu, tv);
+	      mpz_add (t1, t0, t1);
+	      mpz_add (s1, s0, s1);
+
+	      shift = mpz_make_odd (tu);
+	      mpz_mul_2exp (t0, t0, shift);
+	      mpz_mul_2exp (s0, s0, shift);
+	    }
+	  power += shift;
+	}
+    }
+  else
+    mpz_setbit (t0, uz);
+
+  /* Now tv = odd part of gcd, and -s0 and t0 are corresponding
+     cofactors. */
+
+  mpz_mul_2exp (tv, tv, gz);
+  mpz_neg (s0, s0);
+
+  /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
+     adjust cofactors, we need u / g and v / g */
+
+  mpz_divexact (s1, v, tv);
+  mpz_abs (s1, s1);
+  mpz_divexact (t1, u, tv);
+  mpz_abs (t1, t1);
+
+  while (power-- > 0)
+    {
+      /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
+      if (mpz_odd_p (s0) || mpz_odd_p (t0))
+	{
+	  mpz_sub (s0, s0, s1);
+	  mpz_add (t0, t0, t1);
+	}
+      assert (mpz_even_p (t0) && mpz_even_p (s0));
+      mpz_tdiv_q_2exp (s0, s0, 1);
+      mpz_tdiv_q_2exp (t0, t0, 1);
+    }
+
+  /* Arrange so that |s| < |u| / 2g */
+  mpz_add (s1, s0, s1);
+  if (mpz_cmpabs (s0, s1) > 0)
+    {
+      mpz_swap (s0, s1);
+      mpz_sub (t0, t0, t1);
+    }
+  if (u->_mp_size < 0)
+    mpz_neg (s0, s0);
+  if (v->_mp_size < 0)
+    mpz_neg (t0, t0);
+
+  mpz_swap (g, tv);
+  if (s)
+    mpz_swap (s, s0);
+  if (t)
+    mpz_swap (t, t0);
+
+  mpz_clear (tu);
+  mpz_clear (tv);
+  mpz_clear (s0);
+  mpz_clear (s1);
+  mpz_clear (t0);
+  mpz_clear (t1);
+}
+
+void
+mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mpz_t g;
+
+  if (u->_mp_size == 0 || v->_mp_size == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  mpz_init (g);
+
+  mpz_gcd (g, u, v);
+  mpz_divexact (g, u, g);
+  mpz_mul (r, g, v);
+
+  mpz_clear (g);
+  mpz_abs (r, r);
+}
+
+void
+mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
+{
+  if (v == 0 || u->_mp_size == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  v /= mpz_gcd_ui (NULL, u, v);
+  mpz_mul_ui (r, u, v);
+
+  mpz_abs (r, r);
+}
+
+int
+mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
+{
+  mpz_t g, tr;
+  int invertible;
+
+  if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
+    return 0;
+
+  mpz_init (g);
+  mpz_init (tr);
+
+  mpz_gcdext (g, tr, NULL, u, m);
+  invertible = (mpz_cmp_ui (g, 1) == 0);
+
+  if (invertible)
+    {
+      if (tr->_mp_size < 0)
+	{
+	  if (m->_mp_size >= 0)
+	    mpz_add (tr, tr, m);
+	  else
+	    mpz_sub (tr, tr, m);
+	}
+      mpz_swap (r, tr);
+    }
+
+  mpz_clear (g);
+  mpz_clear (tr);
+  return invertible;
+}
+
+
+/* Higher level operations (sqrt, pow and root) */
+
+void
+mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
+{
+  unsigned long bit;
+  mpz_t tr;
+  mpz_init_set_ui (tr, 1);
+
+  bit = GMP_ULONG_HIGHBIT;
+  do
+    {
+      mpz_mul (tr, tr, tr);
+      if (e & bit)
+	mpz_mul (tr, tr, b);
+      bit >>= 1;
+    }
+  while (bit > 0);
+
+  mpz_swap (r, tr);
+  mpz_clear (tr);
+}
+
+void
+mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
+{
+  mpz_t b;
+
+  mpz_init_set_ui (b, blimb);
+  mpz_pow_ui (r, b, e);
+  mpz_clear (b);
+}
+
+void
+mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
+{
+  mpz_t tr;
+  mpz_t base;
+  mp_size_t en, mn;
+  mp_srcptr mp;
+  struct gmp_div_inverse minv;
+  unsigned shift;
+  mp_ptr tp = NULL;
+
+  en = GMP_ABS (e->_mp_size);
+  mn = GMP_ABS (m->_mp_size);
+  if (mn == 0)
+    gmp_die ("mpz_powm: Zero modulo.");
+
+  if (en == 0)
+    {
+      mpz_set_ui (r, mpz_cmpabs_ui (m, 1));
+      return;
+    }
+
+  mp = m->_mp_d;
+  mpn_div_qr_invert (&minv, mp, mn);
+  shift = minv.shift;
+
+  if (shift > 0)
+    {
+      /* To avoid shifts, we do all our reductions, except the final
+	 one, using a *normalized* m. */
+      minv.shift = 0;
+
+      tp = gmp_alloc_limbs (mn);
+      gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
+      mp = tp;
+    }
+
+  mpz_init (base);
+
+  if (e->_mp_size < 0)
+    {
+      if (!mpz_invert (base, b, m))
+	gmp_die ("mpz_powm: Negative exponent and non-invertible base.");
+    }
+  else
+    {
+      mp_size_t bn;
+      mpz_abs (base, b);
+
+      bn = base->_mp_size;
+      if (bn >= mn)
+	{
+	  mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
+	  bn = mn;
+	}
+
+      /* We have reduced the absolute value. Now take care of the
+	 sign. Note that we get zero represented non-canonically as
+	 m. */
+      if (b->_mp_size < 0)
+	{
+	  mp_ptr bp = MPZ_REALLOC (base, mn);
+	  gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
+	  bn = mn;
+	}
+      base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
+    }
+  mpz_init_set_ui (tr, 1);
+
+  while (--en >= 0)
+    {
+      mp_limb_t w = e->_mp_d[en];
+      mp_limb_t bit;
+
+      bit = GMP_LIMB_HIGHBIT;
+      do
+	{
+	  mpz_mul (tr, tr, tr);
+	  if (w & bit)
+	    mpz_mul (tr, tr, base);
+	  if (tr->_mp_size > mn)
+	    {
+	      mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+	      tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+	    }
+	  bit >>= 1;
+	}
+      while (bit > 0);
+    }
+
+  /* Final reduction */
+  if (tr->_mp_size >= mn)
+    {
+      minv.shift = shift;
+      mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+      tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+    }
+  if (tp)
+    gmp_free_limbs (tp, mn);
+
+  mpz_swap (r, tr);
+  mpz_clear (tr);
+  mpz_clear (base);
+}
+
+void
+mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
+{
+  mpz_t e;
+
+  mpz_init_set_ui (e, elimb);
+  mpz_powm (r, b, e, m);
+  mpz_clear (e);
+}
+
+/* x=trunc(y^(1/z)), r=y-x^z */
+void
+mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
+{
+  int sgn;
+  mp_bitcnt_t bc;
+  mpz_t t, u;
+
+  sgn = y->_mp_size < 0;
+  if ((~z & sgn) != 0)
+    gmp_die ("mpz_rootrem: Negative argument, with even root.");
+  if (z == 0)
+    gmp_die ("mpz_rootrem: Zeroth root.");
+
+  if (mpz_cmpabs_ui (y, 1) <= 0) {
+    if (x)
+      mpz_set (x, y);
+    if (r)
+      r->_mp_size = 0;
+    return;
+  }
+
+  mpz_init (u);
+  mpz_init (t);
+  bc = (mpz_sizeinbase (y, 2) - 1) / z + 1;
+  mpz_setbit (t, bc);
+
+  if (z == 2) /* simplify sqrt loop: z-1 == 1 */
+    do {
+      mpz_swap (u, t);			/* u = x */
+      mpz_tdiv_q (t, y, u);		/* t = y/x */
+      mpz_add (t, t, u);		/* t = y/x + x */
+      mpz_tdiv_q_2exp (t, t, 1);	/* x'= (y/x + x)/2 */
+    } while (mpz_cmpabs (t, u) < 0);	/* |x'| < |x| */
+  else /* z != 2 */ {
+    mpz_t v;
+
+    mpz_init (v);
+    if (sgn)
+      mpz_neg (t, t);
+
+    do {
+      mpz_swap (u, t);			/* u = x */
+      mpz_pow_ui (t, u, z - 1);		/* t = x^(z-1) */
+      mpz_tdiv_q (t, y, t);		/* t = y/x^(z-1) */
+      mpz_mul_ui (v, u, z - 1);		/* v = x*(z-1) */
+      mpz_add (t, t, v);		/* t = y/x^(z-1) + x*(z-1) */
+      mpz_tdiv_q_ui (t, t, z);		/* x'=(y/x^(z-1) + x*(z-1))/z */
+    } while (mpz_cmpabs (t, u) < 0);	/* |x'| < |x| */
+
+    mpz_clear (v);
+  }
+
+  if (r) {
+    mpz_pow_ui (t, u, z);
+    mpz_sub (r, y, t);
+  }
+  if (x)
+    mpz_swap (x, u);
+  mpz_clear (u);
+  mpz_clear (t);
+}
+
+int
+mpz_root (mpz_t x, const mpz_t y, unsigned long z)
+{
+  int res;
+  mpz_t r;
+
+  mpz_init (r);
+  mpz_rootrem (x, r, y, z);
+  res = r->_mp_size == 0;
+  mpz_clear (r);
+
+  return res;
+}
+
+/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
+void
+mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+  mpz_rootrem (s, r, u, 2);
+}
+
+void
+mpz_sqrt (mpz_t s, const mpz_t u)
+{
+  mpz_rootrem (s, NULL, u, 2);
+}
+
+int
+mpz_perfect_square_p (const mpz_t u)
+{
+  if (u->_mp_size <= 0)
+    return (u->_mp_size == 0);
+  else
+    return mpz_root (NULL, u, 2);
+}
+
+int
+mpn_perfect_square_p (mp_srcptr p, mp_size_t n)
+{
+  mpz_t t;
+
+  assert (n > 0);
+  assert (p [n-1] != 0);
+  return mpz_root (NULL, mpz_roinit_normal_n (t, p, n), 2);
+}
+
+mp_size_t
+mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n)
+{
+  mpz_t s, r, u;
+  mp_size_t res;
+
+  assert (n > 0);
+  assert (p [n-1] != 0);
+
+  mpz_init (r);
+  mpz_init (s);
+  mpz_rootrem (s, r, mpz_roinit_normal_n (u, p, n), 2);
+
+  assert (s->_mp_size == (n+1)/2);
+  mpn_copyd (sp, s->_mp_d, s->_mp_size);
+  mpz_clear (s);
+  res = r->_mp_size;
+  if (rp)
+    mpn_copyd (rp, r->_mp_d, res);
+  mpz_clear (r);
+  return res;
+}
+
+/* Combinatorics */
+
+void
+mpz_mfac_uiui (mpz_t x, unsigned long n, unsigned long m)
+{
+  mpz_set_ui (x, n + (n == 0));
+  if (m + 1 < 2) return;
+  while (n > m + 1)
+    mpz_mul_ui (x, x, n -= m);
+}
+
+void
+mpz_2fac_ui (mpz_t x, unsigned long n)
+{
+  mpz_mfac_uiui (x, n, 2);
+}
+
+void
+mpz_fac_ui (mpz_t x, unsigned long n)
+{
+  mpz_mfac_uiui (x, n, 1);
+}
+
+void
+mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
+{
+  mpz_t t;
+
+  mpz_set_ui (r, k <= n);
+
+  if (k > (n >> 1))
+    k = (k <= n) ? n - k : 0;
+
+  mpz_init (t);
+  mpz_fac_ui (t, k);
+
+  for (; k > 0; --k)
+    mpz_mul_ui (r, r, n--);
+
+  mpz_divexact (r, r, t);
+  mpz_clear (t);
+}
+
+
+/* Primality testing */
+
+/* Computes Kronecker (a/b) with odd b, a!=0 and GCD(a,b) = 1 */
+/* Adapted from JACOBI_BASE_METHOD==4 in mpn/generic/jacbase.c */
+static int
+gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
+{
+  int c, bit = 0;
+
+  assert (b & 1);
+  assert (a != 0);
+  /* assert (mpn_gcd_11 (a, b) == 1); */
+
+  /* Below, we represent a and b shifted right so that the least
+     significant one bit is implicit. */
+  b >>= 1;
+
+  gmp_ctz(c, a);
+  a >>= 1;
+
+  for (;;)
+    {
+      a >>= c;
+      /* (2/b) = -1 if b = 3 or 5 mod 8 */
+      bit ^= c & (b ^ (b >> 1));
+      if (a < b)
+	{
+	  if (a == 0)
+	    return bit & 1 ? -1 : 1;
+	  bit ^= a & b;
+	  a = b - a;
+	  b -= a;
+	}
+      else
+	{
+	  a -= b;
+	  assert (a != 0);
+	}
+
+      gmp_ctz(c, a);
+      ++c;
+    }
+}
+
+static void
+gmp_lucas_step_k_2k (mpz_t V, mpz_t Qk, const mpz_t n)
+{
+  mpz_mod (Qk, Qk, n);
+  /* V_{2k} <- V_k ^ 2 - 2Q^k */
+  mpz_mul (V, V, V);
+  mpz_submul_ui (V, Qk, 2);
+  mpz_tdiv_r (V, V, n);
+  /* Q^{2k} = (Q^k)^2 */
+  mpz_mul (Qk, Qk, Qk);
+}
+
+/* Computes V_k, Q^k (mod n) for the Lucas' sequence */
+/* with P=1, Q=Q; k = (n>>b0)|1. */
+/* Requires an odd n > 4; b0 > 0; -2*Q must not overflow a long */
+/* Returns (U_k == 0) and sets V=V_k and Qk=Q^k. */
+static int
+gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q,
+	       mp_bitcnt_t b0, const mpz_t n)
+{
+  mp_bitcnt_t bs;
+  mpz_t U;
+  int res;
+
+  assert (b0 > 0);
+  assert (Q <= - (LONG_MIN / 2));
+  assert (Q >= - (LONG_MAX / 2));
+  assert (mpz_cmp_ui (n, 4) > 0);
+  assert (mpz_odd_p (n));
+
+  mpz_init_set_ui (U, 1); /* U1 = 1 */
+  mpz_set_ui (V, 1); /* V1 = 1 */
+  mpz_set_si (Qk, Q);
+
+  for (bs = mpz_sizeinbase (n, 2) - 1; --bs >= b0;)
+    {
+      /* U_{2k} <- U_k * V_k */
+      mpz_mul (U, U, V);
+      /* V_{2k} <- V_k ^ 2 - 2Q^k */
+      /* Q^{2k} = (Q^k)^2 */
+      gmp_lucas_step_k_2k (V, Qk, n);
+
+      /* A step k->k+1 is performed if the bit in $n$ is 1	*/
+      /* mpz_tstbit(n,bs) or the bit is 0 in $n$ but	*/
+      /* should be 1 in $n+1$ (bs == b0)			*/
+      if (b0 == bs || mpz_tstbit (n, bs))
+	{
+	  /* Q^{k+1} <- Q^k * Q */
+	  mpz_mul_si (Qk, Qk, Q);
+	  /* U_{k+1} <- (U_k + V_k) / 2 */
+	  mpz_swap (U, V); /* Keep in V the old value of U_k */
+	  mpz_add (U, U, V);
+	  /* We have to compute U/2, so we need an even value, */
+	  /* equivalent (mod n) */
+	  if (mpz_odd_p (U))
+	    mpz_add (U, U, n);
+	  mpz_tdiv_q_2exp (U, U, 1);
+	  /* V_{k+1} <-(D*U_k + V_k) / 2 =
+			U_{k+1} + (D-1)/2*U_k = U_{k+1} - 2Q*U_k */
+	  mpz_mul_si (V, V, -2*Q);
+	  mpz_add (V, U, V);
+	  mpz_tdiv_r (V, V, n);
+	}
+      mpz_tdiv_r (U, U, n);
+    }
+
+  res = U->_mp_size == 0;
+  mpz_clear (U);
+  return res;
+}
+
+/* Performs strong Lucas' test on x, with parameters suggested */
+/* for the BPSW test. Qk is only passed to recycle a variable. */
+/* Requires GCD (x,6) = 1.*/
+static int
+gmp_stronglucas (const mpz_t x, mpz_t Qk)
+{
+  mp_bitcnt_t b0;
+  mpz_t V, n;
+  mp_limb_t maxD, D; /* The absolute value is stored. */
+  long Q;
+  mp_limb_t tl;
+
+  /* Test on the absolute value. */
+  mpz_roinit_normal_n (n, x->_mp_d, GMP_ABS (x->_mp_size));
+
+  assert (mpz_odd_p (n));
+  /* assert (mpz_gcd_ui (NULL, n, 6) == 1); */
+  if (mpz_root (Qk, n, 2))
+    return 0; /* A square is composite. */
+
+  /* Check Ds up to square root (in case, n is prime)
+     or avoid overflows */
+  maxD = (Qk->_mp_size == 1) ? Qk->_mp_d [0] - 1 : GMP_LIMB_MAX;
+
+  D = 3;
+  /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */
+  /* For those Ds we have (D/n) = (n/|D|) */
+  do
+    {
+      if (D >= maxD)
+	return 1 + (D != GMP_LIMB_MAX); /* (1 + ! ~ D) */
+      D += 2;
+      tl = mpz_tdiv_ui (n, D);
+      if (tl == 0)
+	return 0;
+    }
+  while (gmp_jacobi_coprime (tl, D) == 1);
+
+  mpz_init (V);
+
+  /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
+  b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX);
+  /* b0 = mpz_scan0 (n, 0); */
+
+  /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
+  Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);
+
+  if (! gmp_lucas_mod (V, Qk, Q, b0, n))	/* If Ud != 0 */
+    while (V->_mp_size != 0 && --b0 != 0)	/* while Vk != 0 */
+      /* V <- V ^ 2 - 2Q^k */
+      /* Q^{2k} = (Q^k)^2 */
+      gmp_lucas_step_k_2k (V, Qk, n);
+
+  mpz_clear (V);
+  return (b0 != 0);
+}
+
+static int
+gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
+		 const mpz_t q, mp_bitcnt_t k)
+{
+  assert (k > 0);
+
+  /* Caller must initialize y to the base. */
+  mpz_powm (y, y, q, n);
+
+  if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
+    return 1;
+
+  while (--k > 0)
+    {
+      mpz_powm_ui (y, y, 2, n);
+      if (mpz_cmp (y, nm1) == 0)
+	return 1;
+    }
+  return 0;
+}
+
+/* This product is 0xc0cfd797, and fits in 32 bits. */
+#define GMP_PRIME_PRODUCT \
+  (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL)
+
+/* Bit (p+1)/2 is set, for each odd prime <= 61 */
+#define GMP_PRIME_MASK 0xc96996dcUL
+
+int
+mpz_probab_prime_p (const mpz_t n, int reps)
+{
+  mpz_t nm1;
+  mpz_t q;
+  mpz_t y;
+  mp_bitcnt_t k;
+  int is_prime;
+  int j;
+
+  /* Note that we use the absolute value of n only, for compatibility
+     with the real GMP. */
+  if (mpz_even_p (n))
+    return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0;
+
+  /* Above test excludes n == 0 */
+  assert (n->_mp_size != 0);
+
+  if (mpz_cmpabs_ui (n, 64) < 0)
+    return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2;
+
+  if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1)
+    return 0;
+
+  /* All prime factors are >= 31. */
+  if (mpz_cmpabs_ui (n, 31*31) < 0)
+    return 2;
+
+  mpz_init (nm1);
+  mpz_init (q);
+
+  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
+  mpz_abs (nm1, n);
+  nm1->_mp_d[0] -= 1;
+  /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
+  k = mpn_scan1 (nm1->_mp_d, 0);
+  mpz_tdiv_q_2exp (q, nm1, k);
+
+  /* BPSW test */
+  mpz_init_set_ui (y, 2);
+  is_prime = gmp_millerrabin (n, nm1, y, q, k) && gmp_stronglucas (n, y);
+  reps -= 24; /* skip the first 24 repetitions */
+
+  /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] =
+     j^2 + j + 41 using Euler's polynomial. We potentially stop early,
+     if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps >
+     30 (a[30] == 971 > 31*31 == 961). */
+
+  for (j = 0; is_prime & (j < reps); j++)
+    {
+      mpz_set_ui (y, (unsigned long) j*j+j+41);
+      if (mpz_cmp (y, nm1) >= 0)
+	{
+	  /* Don't try any further bases. This "early" break does not affect
+	     the result for any reasonable reps value (<=5000 was tested) */
+	  assert (j >= 30);
+	  break;
+	}
+      is_prime = gmp_millerrabin (n, nm1, y, q, k);
+    }
+  mpz_clear (nm1);
+  mpz_clear (q);
+  mpz_clear (y);
+
+  return is_prime;
+}
+
+
+/* Logical operations and bit manipulation. */
+
+/* Numbers are treated as if represented in two's complement (and
+   infinitely sign extended). For a negative values we get the two's
+   complement from -x = ~x + 1, where ~ is bitwise complement.
+   Negation transforms
+
+     xxxx10...0
+
+   into
+
+     yyyy10...0
+
+   where yyyy is the bitwise complement of xxxx. So least significant
+   bits, up to and including the first one bit, are unchanged, and
+   the more significant bits are all complemented.
+
+   To change a bit from zero to one in a negative number, subtract the
+   corresponding power of two from the absolute value. This can never
+   underflow. To change a bit from one to zero, add the corresponding
+   power of two, and this might overflow. E.g., if x = -001111, the
+   two's complement is 110001. Clearing the least significant bit, we
+   get two's complement 110000, and -010000. */
+
+int
+mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
+{
+  mp_size_t limb_index;
+  unsigned shift;
+  mp_size_t ds;
+  mp_size_t dn;
+  mp_limb_t w;
+  int bit;
+
+  ds = d->_mp_size;
+  dn = GMP_ABS (ds);
+  limb_index = bit_index / GMP_LIMB_BITS;
+  if (limb_index >= dn)
+    return ds < 0;
+
+  shift = bit_index % GMP_LIMB_BITS;
+  w = d->_mp_d[limb_index];
+  bit = (w >> shift) & 1;
+
+  if (ds < 0)
+    {
+      /* d < 0. Check if any of the bits below is set: If so, our bit
+	 must be complemented. */
+      if (shift > 0 && (mp_limb_t) (w << (GMP_LIMB_BITS - shift)) > 0)
+	return bit ^ 1;
+      while (--limb_index >= 0)
+	if (d->_mp_d[limb_index] > 0)
+	  return bit ^ 1;
+    }
+  return bit;
+}
+
+static void
+mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  mp_size_t dn, limb_index;
+  mp_limb_t bit;
+  mp_ptr dp;
+
+  dn = GMP_ABS (d->_mp_size);
+
+  limb_index = bit_index / GMP_LIMB_BITS;
+  bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+  if (limb_index >= dn)
+    {
+      mp_size_t i;
+      /* The bit should be set outside of the end of the number.
+	 We have to increase the size of the number. */
+      dp = MPZ_REALLOC (d, limb_index + 1);
+
+      dp[limb_index] = bit;
+      for (i = dn; i < limb_index; i++)
+	dp[i] = 0;
+      dn = limb_index + 1;
+    }
+  else
+    {
+      mp_limb_t cy;
+
+      dp = d->_mp_d;
+
+      cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
+      if (cy > 0)
+	{
+	  dp = MPZ_REALLOC (d, dn + 1);
+	  dp[dn++] = cy;
+	}
+    }
+
+  d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+static void
+mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  mp_size_t dn, limb_index;
+  mp_ptr dp;
+  mp_limb_t bit;
+
+  dn = GMP_ABS (d->_mp_size);
+  dp = d->_mp_d;
+
+  limb_index = bit_index / GMP_LIMB_BITS;
+  bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+  assert (limb_index < dn);
+
+  gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
+				 dn - limb_index, bit));
+  dn = mpn_normalized_size (dp, dn);
+  d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+void
+mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  if (!mpz_tstbit (d, bit_index))
+    {
+      if (d->_mp_size >= 0)
+	mpz_abs_add_bit (d, bit_index);
+      else
+	mpz_abs_sub_bit (d, bit_index);
+    }
+}
+
+void
+mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  if (mpz_tstbit (d, bit_index))
+    {
+      if (d->_mp_size >= 0)
+	mpz_abs_sub_bit (d, bit_index);
+      else
+	mpz_abs_add_bit (d, bit_index);
+    }
+}
+
+void
+mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
+    mpz_abs_sub_bit (d, bit_index);
+  else
+    mpz_abs_add_bit (d, bit_index);
+}
+
+void
+mpz_com (mpz_t r, const mpz_t u)
+{
+  mpz_add_ui (r, u, 1);
+  mpz_neg (r, r);
+}
+
+void
+mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, rn, i;
+  mp_ptr up, vp, rp;
+
+  mp_limb_t ux, vx, rx;
+  mp_limb_t uc, vc, rc;
+  mp_limb_t ul, vl, rl;
+
+  un = GMP_ABS (u->_mp_size);
+  vn = GMP_ABS (v->_mp_size);
+  if (un < vn)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (un, vn);
+    }
+  if (vn == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  uc = u->_mp_size < 0;
+  vc = v->_mp_size < 0;
+  rc = uc & vc;
+
+  ux = -uc;
+  vx = -vc;
+  rx = -rc;
+
+  /* If the smaller input is positive, higher limbs don't matter. */
+  rn = vx ? un : vn;
+
+  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  i = 0;
+  do
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ vx) + vc;
+      vc = vl < vc;
+
+      rl = ( (ul & vl) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  while (++i < vn);
+  assert (vc == 0);
+
+  for (; i < rn; i++)
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      rl = ( (ul & vx) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  if (rc)
+    rp[rn++] = rc;
+  else
+    rn = mpn_normalized_size (rp, rn);
+
+  r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, rn, i;
+  mp_ptr up, vp, rp;
+
+  mp_limb_t ux, vx, rx;
+  mp_limb_t uc, vc, rc;
+  mp_limb_t ul, vl, rl;
+
+  un = GMP_ABS (u->_mp_size);
+  vn = GMP_ABS (v->_mp_size);
+  if (un < vn)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (un, vn);
+    }
+  if (vn == 0)
+    {
+      mpz_set (r, u);
+      return;
+    }
+
+  uc = u->_mp_size < 0;
+  vc = v->_mp_size < 0;
+  rc = uc | vc;
+
+  ux = -uc;
+  vx = -vc;
+  rx = -rc;
+
+  /* If the smaller input is negative, by sign extension higher limbs
+     don't matter. */
+  rn = vx ? vn : un;
+
+  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  i = 0;
+  do
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ vx) + vc;
+      vc = vl < vc;
+
+      rl = ( (ul | vl) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  while (++i < vn);
+  assert (vc == 0);
+
+  for (; i < rn; i++)
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      rl = ( (ul | vx) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  if (rc)
+    rp[rn++] = rc;
+  else
+    rn = mpn_normalized_size (rp, rn);
+
+  r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, i;
+  mp_ptr up, vp, rp;
+
+  mp_limb_t ux, vx, rx;
+  mp_limb_t uc, vc, rc;
+  mp_limb_t ul, vl, rl;
+
+  un = GMP_ABS (u->_mp_size);
+  vn = GMP_ABS (v->_mp_size);
+  if (un < vn)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (un, vn);
+    }
+  if (vn == 0)
+    {
+      mpz_set (r, u);
+      return;
+    }
+
+  uc = u->_mp_size < 0;
+  vc = v->_mp_size < 0;
+  rc = uc ^ vc;
+
+  ux = -uc;
+  vx = -vc;
+  rx = -rc;
+
+  rp = MPZ_REALLOC (r, un + (mp_size_t) rc);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  i = 0;
+  do
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ vx) + vc;
+      vc = vl < vc;
+
+      rl = (ul ^ vl ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  while (++i < vn);
+  assert (vc == 0);
+
+  for (; i < un; i++)
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      rl = (ul ^ ux) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  if (rc)
+    rp[un++] = rc;
+  else
+    un = mpn_normalized_size (rp, un);
+
+  r->_mp_size = rx ? -un : un;
+}
+
+static unsigned
+gmp_popcount_limb (mp_limb_t x)
+{
+  unsigned c;
+
+  /* Do 16 bits at a time, to avoid limb-sized constants. */
+  int LOCAL_SHIFT_BITS = 16;
+  for (c = 0; x > 0;)
+    {
+      unsigned w = x - ((x >> 1) & 0x5555);
+      w = ((w >> 2) & 0x3333) + (w & 0x3333);
+      w =  (w >> 4) + w;
+      w = ((w >> 8) & 0x000f) + (w & 0x000f);
+      c += w;
+      if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)
+	x >>= LOCAL_SHIFT_BITS;
+      else
+	x = 0;
+    }
+  return c;
+}
+
+mp_bitcnt_t
+mpn_popcount (mp_srcptr p, mp_size_t n)
+{
+  mp_size_t i;
+  mp_bitcnt_t c;
+
+  for (c = 0, i = 0; i < n; i++)
+    c += gmp_popcount_limb (p[i]);
+
+  return c;
+}
+
+mp_bitcnt_t
+mpz_popcount (const mpz_t u)
+{
+  mp_size_t un;
+
+  un = u->_mp_size;
+
+  if (un < 0)
+    return ~(mp_bitcnt_t) 0;
+
+  return mpn_popcount (u->_mp_d, un);
+}
+
+mp_bitcnt_t
+mpz_hamdist (const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, i;
+  mp_limb_t uc, vc, ul, vl, comp;
+  mp_srcptr up, vp;
+  mp_bitcnt_t c;
+
+  un = u->_mp_size;
+  vn = v->_mp_size;
+
+  if ( (un ^ vn) < 0)
+    return ~(mp_bitcnt_t) 0;
+
+  comp = - (uc = vc = (un < 0));
+  if (uc)
+    {
+      assert (vn < 0);
+      un = -un;
+      vn = -vn;
+    }
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  if (un < vn)
+    MPN_SRCPTR_SWAP (up, un, vp, vn);
+
+  for (i = 0, c = 0; i < vn; i++)
+    {
+      ul = (up[i] ^ comp) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ comp) + vc;
+      vc = vl < vc;
+
+      c += gmp_popcount_limb (ul ^ vl);
+    }
+  assert (vc == 0);
+
+  for (; i < un; i++)
+    {
+      ul = (up[i] ^ comp) + uc;
+      uc = ul < uc;
+
+      c += gmp_popcount_limb (ul ^ comp);
+    }
+
+  return c;
+}
+
+mp_bitcnt_t
+mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+  mp_ptr up;
+  mp_size_t us, un, i;
+  mp_limb_t limb, ux;
+
+  us = u->_mp_size;
+  un = GMP_ABS (us);
+  i = starting_bit / GMP_LIMB_BITS;
+
+  /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
+     for u<0. Notice this test picks up any u==0 too. */
+  if (i >= un)
+    return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
+
+  up = u->_mp_d;
+  ux = 0;
+  limb = up[i];
+
+  if (starting_bit != 0)
+    {
+      if (us < 0)
+	{
+	  ux = mpn_zero_p (up, i);
+	  limb = ~ limb + ux;
+	  ux = - (mp_limb_t) (limb >= ux);
+	}
+
+      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+      limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
+    }
+
+  return mpn_common_scan (limb, i, up, un, ux);
+}
+
+mp_bitcnt_t
+mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+  mp_ptr up;
+  mp_size_t us, un, i;
+  mp_limb_t limb, ux;
+
+  us = u->_mp_size;
+  ux = - (mp_limb_t) (us >= 0);
+  un = GMP_ABS (us);
+  i = starting_bit / GMP_LIMB_BITS;
+
+  /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
+     u<0.  Notice this test picks up all cases of u==0 too. */
+  if (i >= un)
+    return (ux ? starting_bit : ~(mp_bitcnt_t) 0);
+
+  up = u->_mp_d;
+  limb = up[i] ^ ux;
+
+  if (ux == 0)
+    limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */
+
+  /* Mask all bits before starting_bit, thus ignoring them. */
+  limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
+
+  return mpn_common_scan (limb, i, up, un, ux);
+}
+
+
+/* MPZ base conversion. */
+
+size_t
+mpz_sizeinbase (const mpz_t u, int base)
+{
+  mp_size_t un, tn;
+  mp_srcptr up;
+  mp_ptr tp;
+  mp_bitcnt_t bits;
+  struct gmp_div_inverse bi;
+  size_t ndigits;
+
+  assert (base >= 2);
+  assert (base <= 62);
+
+  un = GMP_ABS (u->_mp_size);
+  if (un == 0)
+    return 1;
+
+  up = u->_mp_d;
+
+  bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
+  switch (base)
+    {
+    case 2:
+      return bits;
+    case 4:
+      return (bits + 1) / 2;
+    case 8:
+      return (bits + 2) / 3;
+    case 16:
+      return (bits + 3) / 4;
+    case 32:
+      return (bits + 4) / 5;
+      /* FIXME: Do something more clever for the common case of base
+	 10. */
+    }
+
+  tp = gmp_alloc_limbs (un);
+  mpn_copyi (tp, up, un);
+  mpn_div_qr_1_invert (&bi, base);
+
+  tn = un;
+  ndigits = 0;
+  do
+    {
+      ndigits++;
+      mpn_div_qr_1_preinv (tp, tp, tn, &bi);
+      tn -= (tp[tn-1] == 0);
+    }
+  while (tn > 0);
+
+  gmp_free_limbs (tp, un);
+  return ndigits;
+}
+
+char *
+mpz_get_str (char *sp, int base, const mpz_t u)
+{
+  unsigned bits;
+  const char *digits;
+  mp_size_t un;
+  size_t i, sn, osn;
+
+  digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (base > 62)
+	return NULL;
+    }
+  else if (base >= -1)
+    base = 10;
+  else
+    {
+      base = -base;
+      if (base > 36)
+	return NULL;
+    }
+
+  sn = 1 + mpz_sizeinbase (u, base);
+  if (!sp)
+    {
+      osn = 1 + sn;
+      sp = (char *) gmp_alloc (osn);
+    }
+  else
+    osn = 0;
+  un = GMP_ABS (u->_mp_size);
+
+  if (un == 0)
+    {
+      sp[0] = '0';
+      sn = 1;
+      goto ret;
+    }
+
+  i = 0;
+
+  if (u->_mp_size < 0)
+    sp[i++] = '-';
+
+  bits = mpn_base_power_of_two_p (base);
+
+  if (bits)
+    /* Not modified in this case. */
+    sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
+  else
+    {
+      struct mpn_base_info info;
+      mp_ptr tp;
+
+      mpn_get_base_info (&info, base);
+      tp = gmp_alloc_limbs (un);
+      mpn_copyi (tp, u->_mp_d, un);
+
+      sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
+      gmp_free_limbs (tp, un);
+    }
+
+  for (; i < sn; i++)
+    sp[i] = digits[(unsigned char) sp[i]];
+
+ret:
+  sp[sn] = '\0';
+  if (osn && osn != sn + 1)
+    sp = (char*) gmp_realloc (sp, osn, sn + 1);
+  return sp;
+}
+
+int
+mpz_set_str (mpz_t r, const char *sp, int base)
+{
+  unsigned bits, value_of_a;
+  mp_size_t rn, alloc;
+  mp_ptr rp;
+  size_t dn, sn;
+  int sign;
+  unsigned char *dp;
+
+  assert (base == 0 || (base >= 2 && base <= 62));
+
+  while (isspace( (unsigned char) *sp))
+    sp++;
+
+  sign = (*sp == '-');
+  sp += sign;
+
+  if (base == 0)
+    {
+      if (sp[0] == '0')
+	{
+	  if (sp[1] == 'x' || sp[1] == 'X')
+	    {
+	      base = 16;
+	      sp += 2;
+	    }
+	  else if (sp[1] == 'b' || sp[1] == 'B')
+	    {
+	      base = 2;
+	      sp += 2;
+	    }
+	  else
+	    base = 8;
+	}
+      else
+	base = 10;
+    }
+
+  if (!*sp)
+    {
+      r->_mp_size = 0;
+      return -1;
+    }
+  sn = strlen(sp);
+  dp = (unsigned char *) gmp_alloc (sn);
+
+  value_of_a = (base > 36) ? 36 : 10;
+  for (dn = 0; *sp; sp++)
+    {
+      unsigned digit;
+
+      if (isspace ((unsigned char) *sp))
+	continue;
+      else if (*sp >= '0' && *sp <= '9')
+	digit = *sp - '0';
+      else if (*sp >= 'a' && *sp <= 'z')
+	digit = *sp - 'a' + value_of_a;
+      else if (*sp >= 'A' && *sp <= 'Z')
+	digit = *sp - 'A' + 10;
+      else
+	digit = base; /* fail */
+
+      if (digit >= (unsigned) base)
+	{
+	  gmp_free (dp, sn);
+	  r->_mp_size = 0;
+	  return -1;
+	}
+
+      dp[dn++] = digit;
+    }
+
+  if (!dn)
+    {
+      gmp_free (dp, sn);
+      r->_mp_size = 0;
+      return -1;
+    }
+  bits = mpn_base_power_of_two_p (base);
+
+  if (bits > 0)
+    {
+      alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+      rp = MPZ_REALLOC (r, alloc);
+      rn = mpn_set_str_bits (rp, dp, dn, bits);
+    }
+  else
+    {
+      struct mpn_base_info info;
+      mpn_get_base_info (&info, base);
+      alloc = (dn + info.exp - 1) / info.exp;
+      rp = MPZ_REALLOC (r, alloc);
+      rn = mpn_set_str_other (rp, dp, dn, base, &info);
+      /* Normalization, needed for all-zero input. */
+      assert (rn > 0);
+      rn -= rp[rn-1] == 0;
+    }
+  assert (rn <= alloc);
+  gmp_free (dp, sn);
+
+  r->_mp_size = sign ? - rn : rn;
+
+  return 0;
+}
+
+int
+mpz_init_set_str (mpz_t r, const char *sp, int base)
+{
+  mpz_init (r);
+  return mpz_set_str (r, sp, base);
+}
+
+size_t
+mpz_out_str (FILE *stream, int base, const mpz_t x)
+{
+  char *str;
+  size_t len, n;
+
+  str = mpz_get_str (NULL, base, x);
+  if (!str)
+    return 0;
+  len = strlen (str);
+  n = fwrite (str, 1, len, stream);
+  gmp_free (str, len + 1);
+  return n;
+}
+
+
+static int
+gmp_detect_endian (void)
+{
+  static const int i = 2;
+  const unsigned char *p = (const unsigned char *) &i;
+  return 1 - *p;
+}
+
+/* Import and export. Does not support nails. */
+void
+mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
+	    size_t nails, const void *src)
+{
+  const unsigned char *p;
+  ptrdiff_t word_step;
+  mp_ptr rp;
+  mp_size_t rn;
+
+  /* The current (partial) limb. */
+  mp_limb_t limb;
+  /* The number of bytes already copied to this limb (starting from
+     the low end). */
+  size_t bytes;
+  /* The index where the limb should be stored, when completed. */
+  mp_size_t i;
+
+  if (nails != 0)
+    gmp_die ("mpz_import: Nails not supported.");
+
+  assert (order == 1 || order == -1);
+  assert (endian >= -1 && endian <= 1);
+
+  if (endian == 0)
+    endian = gmp_detect_endian ();
+
+  p = (unsigned char *) src;
+
+  word_step = (order != endian) ? 2 * size : 0;
+
+  /* Process bytes from the least significant end, so point p at the
+     least significant word. */
+  if (order == 1)
+    {
+      p += size * (count - 1);
+      word_step = - word_step;
+    }
+
+  /* And at least significant byte of that word. */
+  if (endian == 1)
+    p += (size - 1);
+
+  rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
+  rp = MPZ_REALLOC (r, rn);
+
+  for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
+    {
+      size_t j;
+      for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
+	{
+	  limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
+	  if (bytes == sizeof(mp_limb_t))
+	    {
+	      rp[i++] = limb;
+	      bytes = 0;
+	      limb = 0;
+	    }
+	}
+    }
+  assert (i + (bytes > 0) == rn);
+  if (limb != 0)
+    rp[i++] = limb;
+  else
+    i = mpn_normalized_size (rp, i);
+
+  r->_mp_size = i;
+}
+
+void *
+mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
+	    size_t nails, const mpz_t u)
+{
+  size_t count;
+  mp_size_t un;
+
+  if (nails != 0)
+    gmp_die ("mpz_export: Nails not supported.");
+
+  assert (order == 1 || order == -1);
+  assert (endian >= -1 && endian <= 1);
+  assert (size > 0 || u->_mp_size == 0);
+
+  un = u->_mp_size;
+  count = 0;
+  if (un != 0)
+    {
+      size_t k;
+      unsigned char *p;
+      ptrdiff_t word_step;
+      /* The current (partial) limb. */
+      mp_limb_t limb;
+      /* The number of bytes left to do in this limb. */
+      size_t bytes;
+      /* The index where the limb was read. */
+      mp_size_t i;
+
+      un = GMP_ABS (un);
+
+      /* Count bytes in top limb. */
+      limb = u->_mp_d[un-1];
+      assert (limb != 0);
+
+      k = (GMP_LIMB_BITS <= CHAR_BIT);
+      if (!k)
+	{
+	  do {
+	    int LOCAL_CHAR_BIT = CHAR_BIT;
+	    k++; limb >>= LOCAL_CHAR_BIT;
+	  } while (limb != 0);
+	}
+      /* else limb = 0; */
+
+      count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
+
+      if (!r)
+	r = gmp_alloc (count * size);
+
+      if (endian == 0)
+	endian = gmp_detect_endian ();
+
+      p = (unsigned char *) r;
+
+      word_step = (order != endian) ? 2 * size : 0;
+
+      /* Process bytes from the least significant end, so point p at the
+	 least significant word. */
+      if (order == 1)
+	{
+	  p += size * (count - 1);
+	  word_step = - word_step;
+	}
+
+      /* And at least significant byte of that word. */
+      if (endian == 1)
+	p += (size - 1);
+
+      for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
+	{
+	  size_t j;
+	  for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian)
+	    {
+	      if (sizeof (mp_limb_t) == 1)
+		{
+		  if (i < un)
+		    *p = u->_mp_d[i++];
+		  else
+		    *p = 0;
+		}
+	      else
+		{
+		  int LOCAL_CHAR_BIT = CHAR_BIT;
+		  if (bytes == 0)
+		    {
+		      if (i < un)
+			limb = u->_mp_d[i++];
+		      bytes = sizeof (mp_limb_t);
+		    }
+		  *p = limb;
+		  limb >>= LOCAL_CHAR_BIT;
+		  bytes--;
+		}
+	    }
+	}
+      assert (i == un);
+      assert (k == count);
+    }
+
+  if (countp)
+    *countp = count;
+
+  return r;
+}
diff --git a/mini-gmp/mini-gmp.h b/mini-gmp/mini-gmp.h
new file mode 100644
index 0000000..59c24cf
--- /dev/null
+++ b/mini-gmp/mini-gmp.h
@@ -0,0 +1,310 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+Copyright 2011-2015, 2017, 2019-2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* About mini-gmp: This is a minimal implementation of a subset of the
+   GMP interface. It is intended for inclusion into applications which
+   have modest bignums needs, as a fallback when the real GMP library
+   is not installed.
+
+   This file defines the public interface. */
+
+#ifndef __MINI_GMP_H__
+#define __MINI_GMP_H__
+
+/* For size_t */
+#include <stddef.h>
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+void mp_set_memory_functions (void *(*) (size_t),
+			      void *(*) (void *, size_t, size_t),
+			      void (*) (void *, size_t));
+
+void mp_get_memory_functions (void *(**) (size_t),
+			      void *(**) (void *, size_t, size_t),
+			      void (**) (void *, size_t));
+
+#ifndef MINI_GMP_LIMB_TYPE
+#define MINI_GMP_LIMB_TYPE long
+#endif
+
+typedef unsigned MINI_GMP_LIMB_TYPE mp_limb_t;
+typedef long mp_size_t;
+typedef unsigned long mp_bitcnt_t;
+
+typedef mp_limb_t *mp_ptr;
+typedef const mp_limb_t *mp_srcptr;
+
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+typedef __mpz_struct mpz_t[1];
+
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpz_struct *mpz_srcptr;
+
+extern const int mp_bits_per_limb;
+
+void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_zero (mp_ptr, mp_size_t);
+
+int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+int mpn_zero_p (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+int mpn_perfect_square_p (mp_srcptr, mp_size_t);
+mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
+mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);
+
+void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+
+mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
+#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)
+
+size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+void mpz_init (mpz_t);
+void mpz_init2 (mpz_t, mp_bitcnt_t);
+void mpz_clear (mpz_t);
+
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+int mpz_sgn (const mpz_t);
+int mpz_cmp_si (const mpz_t, long);
+int mpz_cmp_ui (const mpz_t, unsigned long);
+int mpz_cmp (const mpz_t, const mpz_t);
+int mpz_cmpabs_ui (const mpz_t, unsigned long);
+int mpz_cmpabs (const mpz_t, const mpz_t);
+int mpz_cmp_d (const mpz_t, double);
+int mpz_cmpabs_d (const mpz_t, double);
+
+void mpz_abs (mpz_t, const mpz_t);
+void mpz_neg (mpz_t, const mpz_t);
+void mpz_swap (mpz_t, mpz_t);
+
+void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_add (mpz_t, const mpz_t, const mpz_t);
+void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
+void mpz_sub (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_mul_si (mpz_t, const mpz_t, long int);
+void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_mul (mpz_t, const mpz_t, const mpz_t);
+void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_addmul (mpz_t, const mpz_t, const mpz_t);
+void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_submul (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+
+void mpz_mod (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_divexact (mpz_t, const mpz_t, const mpz_t);
+
+int mpz_divisible_p (const mpz_t, const mpz_t);
+int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t);
+
+unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);
+
+unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);
+
+void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);
+
+int mpz_divisible_ui_p (const mpz_t, unsigned long);
+
+unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
+void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
+int mpz_invert (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
+void mpz_sqrt (mpz_t, const mpz_t);
+int mpz_perfect_square_p (const mpz_t);
+
+void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
+void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
+void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);
+
+void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
+int mpz_root (mpz_t, const mpz_t, unsigned long);
+
+void mpz_fac_ui (mpz_t, unsigned long);
+void mpz_2fac_ui (mpz_t, unsigned long);
+void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long);
+void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);
+
+int mpz_probab_prime_p (const mpz_t, int);
+
+int mpz_tstbit (const mpz_t, mp_bitcnt_t);
+void mpz_setbit (mpz_t, mp_bitcnt_t);
+void mpz_clrbit (mpz_t, mp_bitcnt_t);
+void mpz_combit (mpz_t, mp_bitcnt_t);
+
+void mpz_com (mpz_t, const mpz_t);
+void mpz_and (mpz_t, const mpz_t, const mpz_t);
+void mpz_ior (mpz_t, const mpz_t, const mpz_t);
+void mpz_xor (mpz_t, const mpz_t, const mpz_t);
+
+mp_bitcnt_t mpz_popcount (const mpz_t);
+mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
+mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
+mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
+
+int mpz_fits_slong_p (const mpz_t);
+int mpz_fits_ulong_p (const mpz_t);
+int mpz_fits_sint_p (const mpz_t);
+int mpz_fits_uint_p (const mpz_t);
+int mpz_fits_sshort_p (const mpz_t);
+int mpz_fits_ushort_p (const mpz_t);
+long int mpz_get_si (const mpz_t);
+unsigned long int mpz_get_ui (const mpz_t);
+double mpz_get_d (const mpz_t);
+size_t mpz_size (const mpz_t);
+mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);
+
+void mpz_realloc2 (mpz_t, mp_bitcnt_t);
+mp_srcptr mpz_limbs_read (mpz_srcptr);
+mp_ptr mpz_limbs_modify (mpz_t, mp_size_t);
+mp_ptr mpz_limbs_write (mpz_t, mp_size_t);
+void mpz_limbs_finish (mpz_t, mp_size_t);
+mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+void mpz_set_si (mpz_t, signed long int);
+void mpz_set_ui (mpz_t, unsigned long int);
+void mpz_set (mpz_t, const mpz_t);
+void mpz_set_d (mpz_t, double);
+
+void mpz_init_set_si (mpz_t, signed long int);
+void mpz_init_set_ui (mpz_t, unsigned long int);
+void mpz_init_set (mpz_t, const mpz_t);
+void mpz_init_set_d (mpz_t, double);
+
+size_t mpz_sizeinbase (const mpz_t, int);
+char *mpz_get_str (char *, int, const mpz_t);
+int mpz_set_str (mpz_t, const char *, int);
+int mpz_init_set_str (mpz_t, const char *, int);
+
+/* This long list taken from gmp.h. */
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */			\
+  || defined (_STDIO)                 /* HPE NonStop */         \
+  || defined (__DEFINED_FILE)         /* musl */
+size_t mpz_out_str (FILE *, int, const mpz_t);
+#endif
+
+void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
+void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* __MINI_GMP_H__ */
diff --git a/mini-gmp/mini-mpq.c b/mini-gmp/mini-mpq.c
new file mode 100644
index 0000000..58ce37f
--- /dev/null
+++ b/mini-gmp/mini-mpq.c
@@ -0,0 +1,556 @@
+/* mini-mpq, a minimalistic implementation of a GNU GMP subset.
+
+   Contributed to the GNU project by Marco Bodrato
+
+   Acknowledgment: special thanks to Bradley Lucier for his comments
+   to the preliminary version of this code.
+
+Copyright 2018-2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mini-mpq.h"
+
+#ifndef GMP_LIMB_HIGHBIT
+/* Define macros and static functions already defined by mini-gmp.c */
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
+#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0)
+#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
+#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static mpz_srcptr
+mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+  x->_mp_alloc = 0;
+  x->_mp_d = (mp_ptr) xp;
+  x->_mp_size = xs;
+  return x;
+}
+
+static void
+gmp_die (const char *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+  abort();
+}
+#endif
+
+
+/* MPQ helper functions */
+static mpq_srcptr
+mpq_roinit_normal_nn (mpq_t x, mp_srcptr np, mp_size_t ns,
+		     mp_srcptr dp, mp_size_t ds)
+{
+  mpz_roinit_normal_n (mpq_numref(x), np, ns);
+  mpz_roinit_normal_n (mpq_denref(x), dp, ds);
+  return x;
+}
+
+static mpq_srcptr
+mpq_roinit_zz (mpq_t x, mpz_srcptr n, mpz_srcptr d)
+{
+  return mpq_roinit_normal_nn (x, n->_mp_d, n->_mp_size,
+			       d->_mp_d, d->_mp_size);
+}
+
+static void
+mpq_nan_init (mpq_t x)
+{
+  mpz_init (mpq_numref (x));
+  mpz_init (mpq_denref (x));
+}
+
+void
+mpq_init (mpq_t x)
+{
+  mpz_init (mpq_numref (x));
+  mpz_init_set_ui (mpq_denref (x), 1);
+}
+
+void
+mpq_clear (mpq_t x)
+{
+  mpz_clear (mpq_numref (x));
+  mpz_clear (mpq_denref (x));
+}
+
+static void
+mpq_canonical_sign (mpq_t r)
+{
+  mp_size_t ds = mpq_denref (r)->_mp_size;
+  if (ds <= 0)
+    {
+      if (ds == 0)
+	gmp_die("mpq: Fraction with zero denominator.");
+      mpz_neg (mpq_denref (r), mpq_denref (r));
+      mpz_neg (mpq_numref (r), mpq_numref (r));
+    }
+}
+
+static void
+mpq_helper_canonicalize (mpq_t r, const mpz_t num, const mpz_t den)
+{
+  if (num->_mp_size == 0)
+    mpq_set_ui (r, 0, 1);
+  else
+    {
+      mpz_t g;
+
+      mpz_init (g);
+      mpz_gcd (g, num, den);
+      mpz_tdiv_q (mpq_numref (r), num, g);
+      mpz_tdiv_q (mpq_denref (r), den, g);
+      mpz_clear (g);
+      mpq_canonical_sign (r);
+    }
+}
+
+void
+mpq_canonicalize (mpq_t r)
+{
+  mpq_helper_canonicalize (r, mpq_numref (r), mpq_denref (r));
+}
+
+void
+mpq_swap (mpq_t a, mpq_t b)
+{
+  mpz_swap (mpq_numref (a), mpq_numref (b));
+  mpz_swap (mpq_denref (a), mpq_denref (b));
+}
+
+
+/* MPQ assignment and conversions. */
+void
+mpz_set_q (mpz_t r, const mpq_t q)
+{
+  mpz_tdiv_q (r, mpq_numref (q), mpq_denref (q));
+}
+
+void
+mpq_set (mpq_t r, const mpq_t q)
+{
+  mpz_set (mpq_numref (r), mpq_numref (q));
+  mpz_set (mpq_denref (r), mpq_denref (q));
+}
+
+void
+mpq_set_ui (mpq_t r, unsigned long n, unsigned long d)
+{
+  mpz_set_ui (mpq_numref (r), n);
+  mpz_set_ui (mpq_denref (r), d);
+}
+
+void
+mpq_set_si (mpq_t r, signed long n, unsigned long d)
+{
+  mpz_set_si (mpq_numref (r), n);
+  mpz_set_ui (mpq_denref (r), d);
+}
+
+void
+mpq_set_z (mpq_t r, const mpz_t n)
+{
+  mpz_set_ui (mpq_denref (r), 1);
+  mpz_set (mpq_numref (r), n);
+}
+
+void
+mpq_set_num (mpq_t r, const mpz_t z)
+{
+  mpz_set (mpq_numref (r), z);
+}
+
+void
+mpq_set_den (mpq_t r, const mpz_t z)
+{
+  mpz_set (mpq_denref (r), z);
+}
+
+void
+mpq_get_num (mpz_t r, const mpq_t q)
+{
+  mpz_set (r, mpq_numref (q));
+}
+
+void
+mpq_get_den (mpz_t r, const mpq_t q)
+{
+  mpz_set (r, mpq_denref (q));
+}
+
+
+/* MPQ comparisons and the like. */
+int
+mpq_cmp (const mpq_t a, const mpq_t b)
+{
+  mpz_t t1, t2;
+  int res;
+
+  mpz_init (t1);
+  mpz_init (t2);
+  mpz_mul (t1, mpq_numref (a), mpq_denref (b));
+  mpz_mul (t2, mpq_numref (b), mpq_denref (a));
+  res = mpz_cmp (t1, t2);
+  mpz_clear (t1);
+  mpz_clear (t2);
+
+  return res;
+}
+
+int
+mpq_cmp_z (const mpq_t a, const mpz_t b)
+{
+  mpz_t t;
+  int res;
+
+  mpz_init (t);
+  mpz_mul (t, b, mpq_denref (a));
+  res = mpz_cmp (mpq_numref (a), t);
+  mpz_clear (t);
+
+  return res;
+}
+
+int
+mpq_equal (const mpq_t a, const mpq_t b)
+{
+  return (mpz_cmp (mpq_numref (a), mpq_numref (b)) == 0) &&
+    (mpz_cmp (mpq_denref (a), mpq_denref (b)) == 0);
+}
+
+int
+mpq_cmp_ui (const mpq_t q, unsigned long n, unsigned long d)
+{
+  mpq_t t;
+  assert (d != 0);
+  if (ULONG_MAX <= GMP_LIMB_MAX) {
+    mp_limb_t nl = n, dl = d;
+    return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, n != 0, &dl, 1));
+  } else {
+    int ret;
+
+    mpq_nan_init (t);
+    mpq_set_ui (t, n, d);
+    ret = mpq_cmp (q, t);
+    mpq_clear (t);
+
+    return ret;
+  }
+}
+
+int
+mpq_cmp_si (const mpq_t q, signed long n, unsigned long d)
+{
+  assert (d != 0);
+
+  if (n >= 0)
+    return mpq_cmp_ui (q, n, d);
+  else
+    {
+      mpq_t t;
+
+      if (ULONG_MAX <= GMP_LIMB_MAX)
+	{
+	  mp_limb_t nl = GMP_NEG_CAST (unsigned long, n), dl = d;
+	  return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, -1, &dl, 1));
+	}
+      else
+	{
+	  unsigned long l_n = GMP_NEG_CAST (unsigned long, n);
+
+	  mpq_roinit_normal_nn (t, mpq_numref (q)->_mp_d, - mpq_numref (q)->_mp_size,
+				mpq_denref (q)->_mp_d, mpq_denref (q)->_mp_size);
+	  return - mpq_cmp_ui (t, l_n, d);
+	}
+    }
+}
+
+int
+mpq_sgn (const mpq_t a)
+{
+  return mpz_sgn (mpq_numref (a));
+}
+
+
+/* MPQ arithmetic. */
+void
+mpq_abs (mpq_t r, const mpq_t q)
+{
+  mpz_abs (mpq_numref (r), mpq_numref (q));
+  mpz_set (mpq_denref (r), mpq_denref (q));
+}
+
+void
+mpq_neg (mpq_t r, const mpq_t q)
+{
+  mpz_neg (mpq_numref (r), mpq_numref (q));
+  mpz_set (mpq_denref (r), mpq_denref (q));
+}
+
+void
+mpq_add (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpz_gcd (t, mpq_denref (a), mpq_denref (b));
+  if (mpz_cmp_ui (t, 1) == 0)
+    {
+      mpz_mul (t, mpq_numref (a), mpq_denref (b));
+      mpz_addmul (t, mpq_numref (b), mpq_denref (a));
+      mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b));
+      mpz_swap (mpq_numref (r), t);
+    }
+  else
+    {
+      mpz_t x, y;
+      mpz_init (x);
+      mpz_init (y);
+
+      mpz_tdiv_q (x, mpq_denref (b), t);
+      mpz_tdiv_q (y, mpq_denref (a), t);
+      mpz_mul (x, mpq_numref (a), x);
+      mpz_addmul (x, mpq_numref (b), y);
+
+      mpz_gcd (t, x, t);
+      mpz_tdiv_q (mpq_numref (r), x, t);
+      mpz_tdiv_q (x, mpq_denref (b), t);
+      mpz_mul (mpq_denref (r), x, y);
+
+      mpz_clear (x);
+      mpz_clear (y);
+    }
+  mpz_clear (t);
+}
+
+void
+mpq_sub (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpq_t t;
+
+  mpq_roinit_normal_nn (t, mpq_numref (b)->_mp_d, - mpq_numref (b)->_mp_size,
+			mpq_denref (b)->_mp_d, mpq_denref (b)->_mp_size);
+  mpq_add (r, a, t);
+}
+
+void
+mpq_div (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpq_t t;
+  mpq_mul (r, a, mpq_roinit_zz (t, mpq_denref (b), mpq_numref (b)));
+}
+
+void
+mpq_mul (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpq_t t;
+  mpq_nan_init (t);
+
+  if (a != b) {
+    mpq_helper_canonicalize (t, mpq_numref (a), mpq_denref (b));
+    mpq_helper_canonicalize (r, mpq_numref (b), mpq_denref (a));
+
+    a = r;
+    b = t;
+  }
+
+  mpz_mul (mpq_numref (r), mpq_numref (a), mpq_numref (b));
+  mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b));
+  mpq_clear (t);
+}
+
+static void
+mpq_helper_2exp (mpz_t rn, mpz_t rd, const mpz_t qn, const mpz_t qd, mp_bitcnt_t e)
+{
+  mp_bitcnt_t z = mpz_scan1 (qd, 0);
+  z = GMP_MIN (z, e);
+  mpz_mul_2exp (rn, qn, e - z);
+  mpz_tdiv_q_2exp (rd, qd, z);
+}
+
+void
+mpq_div_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e)
+{
+  mpq_helper_2exp (mpq_denref (r), mpq_numref (r), mpq_denref (q), mpq_numref (q), e);
+}
+
+void
+mpq_mul_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e)
+{
+  mpq_helper_2exp (mpq_numref (r), mpq_denref (r), mpq_numref (q), mpq_denref (q), e);
+}
+
+void
+mpq_inv (mpq_t r, const mpq_t q)
+{
+  mpq_set (r, q);
+  mpz_swap (mpq_denref (r), mpq_numref (r));
+  mpq_canonical_sign (r);
+}
+
+
+/* MPQ to/from double. */
+void
+mpq_set_d (mpq_t r, double x)
+{
+  mpz_set_ui (mpq_denref (r), 1);
+
+  /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
+     zero or infinity. */
+  if (x == x * 0.5 || x != x)
+    mpq_numref (r)->_mp_size = 0;
+  else
+    {
+      double B;
+      mp_bitcnt_t e;
+
+      B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+      for (e = 0; x != x + 0.5; e += GMP_LIMB_BITS)
+	x *= B;
+
+      mpz_set_d (mpq_numref (r), x);
+      mpq_div_2exp (r, r, e);
+    }
+}
+
+double
+mpq_get_d (const mpq_t u)
+{
+  mp_bitcnt_t ne, de, ee;
+  mpz_t z;
+  double B, ret;
+
+  ne = mpz_sizeinbase (mpq_numref (u), 2);
+  de = mpz_sizeinbase (mpq_denref (u), 2);
+
+  ee = CHAR_BIT * sizeof (double);
+  if (de == 1 || ne > de + ee)
+    ee = 0;
+  else
+    ee = (ee + de - ne) / GMP_LIMB_BITS + 1;
+
+  mpz_init (z);
+  mpz_mul_2exp (z, mpq_numref (u), ee * GMP_LIMB_BITS);
+  mpz_tdiv_q (z, z, mpq_denref (u));
+  ret = mpz_get_d (z);
+  mpz_clear (z);
+
+  B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+  for (B = 1 / B; ee != 0; --ee)
+    ret *= B;
+
+  return ret;
+}
+
+
+/* MPQ and strings/streams. */
+char *
+mpq_get_str (char *sp, int base, const mpq_t q)
+{
+  char *res;
+  char *rden;
+  size_t len;
+
+  res = mpz_get_str (sp, base, mpq_numref (q));
+  if (res == NULL || mpz_cmp_ui (mpq_denref (q), 1) == 0)
+    return res;
+
+  len = strlen (res) + 1;
+  rden = sp ? sp + len : NULL;
+  rden = mpz_get_str (rden, base, mpq_denref (q));
+  assert (rden != NULL);
+
+  if (sp == NULL) {
+    void * (*gmp_reallocate_func) (void *, size_t, size_t);
+    void (*gmp_free_func) (void *, size_t);
+    size_t lden;
+
+    mp_get_memory_functions (NULL, &gmp_reallocate_func, &gmp_free_func);
+    lden = strlen (rden) + 1;
+    res = (char *) gmp_reallocate_func (res, len, (lden + len) * sizeof (char));
+    memcpy (res + len, rden, lden);
+    gmp_free_func (rden, lden);
+  }
+
+  res [len - 1] = '/';
+  return res;
+}
+
+size_t
+mpq_out_str (FILE *stream, int base, const mpq_t x)
+{
+  char * str;
+  size_t len, n;
+  void (*gmp_free_func) (void *, size_t);
+
+  str = mpq_get_str (NULL, base, x);
+  if (!str)
+    return 0;
+  len = strlen (str);
+  n = fwrite (str, 1, len, stream);
+  mp_get_memory_functions (NULL, NULL, &gmp_free_func);
+  gmp_free_func (str, len + 1);
+  return n;
+}
+
+int
+mpq_set_str (mpq_t r, const char *sp, int base)
+{
+  const char *slash;
+
+  slash = strchr (sp, '/');
+  if (slash == NULL) {
+    mpz_set_ui (mpq_denref(r), 1);
+    return mpz_set_str (mpq_numref(r), sp, base);
+  } else {
+    char *num;
+    size_t numlen;
+    int ret;
+    void * (*gmp_allocate_func) (size_t);
+    void (*gmp_free_func) (void *, size_t);
+
+    mp_get_memory_functions (&gmp_allocate_func, NULL, &gmp_free_func);
+    numlen = slash - sp;
+    num = (char *) gmp_allocate_func (numlen + 1);
+    memcpy (num, sp, numlen);
+    num[numlen] = '\0';
+    ret = mpz_set_str (mpq_numref(r), num, base);
+    gmp_free_func (num, numlen + 1);
+
+    if (ret != 0)
+      return ret;
+
+    return mpz_set_str (mpq_denref(r), slash + 1, base);
+  }
+}
diff --git a/mini-gmp/mini-mpq.h b/mini-gmp/mini-mpq.h
new file mode 100644
index 0000000..8eabcec
--- /dev/null
+++ b/mini-gmp/mini-mpq.h
@@ -0,0 +1,114 @@
+/* mini-mpq, a minimalistic implementation of a GNU GMP subset.
+
+Copyright 2018, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Header */
+
+#ifndef __MINI_MPQ_H__
+#define __MINI_MPQ_H__
+
+#include "mini-gmp.h"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct mpq_t[1];
+
+typedef const __mpq_struct *mpq_srcptr;
+typedef __mpq_struct *mpq_ptr;
+
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+void mpq_abs (mpq_t, const mpq_t);
+void mpq_add (mpq_t, const mpq_t, const mpq_t);
+void mpq_canonicalize (mpq_t);
+void mpq_clear (mpq_t);
+int mpq_cmp (const mpq_t, const mpq_t);
+int mpq_cmp_si (const mpq_t, signed long, unsigned long);
+int mpq_cmp_ui (const mpq_t, unsigned long, unsigned long);
+int mpq_cmp_z (const mpq_t, const mpz_t);
+void mpq_div (mpq_t, const mpq_t, const mpq_t);
+void mpq_div_2exp (mpq_t, const mpq_t, mp_bitcnt_t);
+int mpq_equal (const mpq_t, const mpq_t);
+double mpq_get_d (const mpq_t);
+void mpq_get_den (mpz_t, const mpq_t);
+void mpq_get_num (mpz_t, const mpq_t);
+char * mpq_get_str (char *, int, const mpq_t q);
+void mpq_init (mpq_t);
+void mpq_inv (mpq_t, const mpq_t);
+void mpq_mul (mpq_t, const mpq_t, const mpq_t);
+void mpq_mul_2exp (mpq_t, const mpq_t, mp_bitcnt_t);
+void mpq_neg (mpq_t, const mpq_t);
+void mpq_set (mpq_t, const mpq_t);
+void mpq_set_d (mpq_t, double);
+void mpq_set_den (mpq_t, const mpz_t);
+void mpq_set_num (mpq_t, const mpz_t);
+void mpq_set_si (mpq_t, signed long, unsigned long);
+int mpq_set_str (mpq_t, const char *, int);
+void mpq_set_ui (mpq_t, unsigned long, unsigned long);
+void mpq_set_z (mpq_t, const mpz_t);
+int mpq_sgn (const mpq_t);
+void mpq_sub (mpq_t, const mpq_t, const mpq_t);
+void mpq_swap (mpq_t, mpq_t);
+
+/* This long list taken from gmp.h. */
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */                \
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */             \
+  || defined (__STDIO_LOADED)         /* VMS */
+size_t mpq_out_str (FILE *, int, const mpq_t);
+#endif
+
+void mpz_set_q (mpz_t, const mpq_t);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* __MINI_MPQ_H__ */
diff --git a/mp_bpl.c b/mp_bpl.c
new file mode 100644
index 0000000..a13fb15
--- /dev/null
+++ b/mp_bpl.c
@@ -0,0 +1,34 @@
+/*
+Copyright 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+const int mp_bits_per_limb = GMP_LIMB_BITS;
+const int __gmp_0 = 0;
+int __gmp_junk;
diff --git a/mp_clz_tab.c b/mp_clz_tab.c
new file mode 100644
index 0000000..fc7cb0b
--- /dev/null
+++ b/mp_clz_tab.c
@@ -0,0 +1,48 @@
+/* __clz_tab -- support for longlong.h
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND MAY CHANGE
+   INCOMPATIBLY OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifdef COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+const
+unsigned char __clz_tab[129] =
+{
+  1,2,3,3,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  9
+};
+#endif
diff --git a/mp_dv_tab.c b/mp_dv_tab.c
new file mode 100644
index 0000000..cd09d5d
--- /dev/null
+++ b/mp_dv_tab.c
@@ -0,0 +1,77 @@
+/* __gmp_digit_value_tab -- support for mp*_set_str
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND MAY CHANGE
+   INCOMPATIBLY OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Table to be indexed by character, to get its numerical value.  Assumes ASCII
+   character set.
+
+   First part of table supports common usages, where 'A' and 'a' have the same
+   value; this supports bases 2..36
+
+   At offset 208, values for bases 37..62 start.  Here, 'A' has the value 10
+   (in decimal) and 'a' has the value 36.  */
+
+#define X 0xff
+const unsigned char __gmp_digit_value_tab[] =
+{
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, X, X, X, X, X, X,
+  X,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+  25,26,27,28,29,30,31,32,33,34,35,X, X, X, X, X,
+  X,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+  25,26,27,28,29,30,31,32,33,34,35,X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, X, X, X, X, X, X,
+  X,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+  25,26,27,28,29,30,31,32,33,34,35,X, X, X, X, X,
+  X,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,
+  51,52,53,54,55,56,57,58,59,60,61,X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X
+};
diff --git a/mp_get_fns.c b/mp_get_fns.c
new file mode 100644
index 0000000..70ed96d
--- /dev/null
+++ b/mp_get_fns.c
@@ -0,0 +1,47 @@
+/* mp_get_memory_functions -- Get the allocate, reallocate, and free functions.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+
+void
+mp_get_memory_functions (void *(**alloc_func) (size_t),
+			 void *(**realloc_func) (void *, size_t, size_t),
+			 void (**free_func) (void *, size_t)) __GMP_NOTHROW
+{
+  if (alloc_func != NULL)
+    *alloc_func = __gmp_allocate_func;
+
+  if (realloc_func != NULL)
+    *realloc_func = __gmp_reallocate_func;
+
+  if (free_func != NULL)
+    *free_func = __gmp_free_func;
+}
diff --git a/mp_minv_tab.c b/mp_minv_tab.c
new file mode 100644
index 0000000..833d4c1
--- /dev/null
+++ b/mp_minv_tab.c
@@ -0,0 +1,58 @@
+/* A table of data supporting binvert_limb().
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND MAY CHANGE
+   INCOMPATIBLY OR DISAPPEAR IN A FUTURE GNU MP RELEASE.  */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* binvert_limb_table[i] is the multiplicative inverse of 2*i+1 mod 256,
+   ie. (binvert_limb_table[i] * (2*i+1)) % 256 == 1 */
+
+const unsigned char  binvert_limb_table[128] = {
+  0x01, 0xAB, 0xCD, 0xB7, 0x39, 0xA3, 0xC5, 0xEF,
+  0xF1, 0x1B, 0x3D, 0xA7, 0x29, 0x13, 0x35, 0xDF,
+  0xE1, 0x8B, 0xAD, 0x97, 0x19, 0x83, 0xA5, 0xCF,
+  0xD1, 0xFB, 0x1D, 0x87, 0x09, 0xF3, 0x15, 0xBF,
+  0xC1, 0x6B, 0x8D, 0x77, 0xF9, 0x63, 0x85, 0xAF,
+  0xB1, 0xDB, 0xFD, 0x67, 0xE9, 0xD3, 0xF5, 0x9F,
+  0xA1, 0x4B, 0x6D, 0x57, 0xD9, 0x43, 0x65, 0x8F,
+  0x91, 0xBB, 0xDD, 0x47, 0xC9, 0xB3, 0xD5, 0x7F,
+  0x81, 0x2B, 0x4D, 0x37, 0xB9, 0x23, 0x45, 0x6F,
+  0x71, 0x9B, 0xBD, 0x27, 0xA9, 0x93, 0xB5, 0x5F,
+  0x61, 0x0B, 0x2D, 0x17, 0x99, 0x03, 0x25, 0x4F,
+  0x51, 0x7B, 0x9D, 0x07, 0x89, 0x73, 0x95, 0x3F,
+  0x41, 0xEB, 0x0D, 0xF7, 0x79, 0xE3, 0x05, 0x2F,
+  0x31, 0x5B, 0x7D, 0xE7, 0x69, 0x53, 0x75, 0x1F,
+  0x21, 0xCB, 0xED, 0xD7, 0x59, 0xC3, 0xE5, 0x0F,
+  0x11, 0x3B, 0x5D, 0xC7, 0x49, 0x33, 0x55, 0xFF
+};
diff --git a/mp_set_fns.c b/mp_set_fns.c
new file mode 100644
index 0000000..b7bcd5b
--- /dev/null
+++ b/mp_set_fns.c
@@ -0,0 +1,49 @@
+/* mp_set_memory_functions -- Set the allocate, reallocate, and free functions
+   for use by the mp package.
+
+Copyright 1991, 1993, 1994, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mp_set_memory_functions (void *(*alloc_func) (size_t),
+			 void *(*realloc_func) (void *, size_t, size_t),
+			 void (*free_func) (void *, size_t)) __GMP_NOTHROW
+{
+  if (alloc_func == 0)
+    alloc_func = __gmp_default_allocate;
+  if (realloc_func == 0)
+    realloc_func = __gmp_default_reallocate;
+  if (free_func == 0)
+    free_func = __gmp_default_free;
+
+  __gmp_allocate_func = alloc_func;
+  __gmp_reallocate_func = realloc_func;
+  __gmp_free_func = free_func;
+}
diff --git a/mpf/abs.c b/mpf/abs.c
new file mode 100644
index 0000000..1642a46
--- /dev/null
+++ b/mpf/abs.c
@@ -0,0 +1,58 @@
+/* mpf_abs -- Compute the absolute value of a float.
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_abs (mpf_ptr r, mpf_srcptr u)
+{
+  mp_size_t size;
+
+  size = ABS (u->_mp_size);
+  if (r != u)
+    {
+      mp_size_t prec;
+      mp_ptr rp, up;
+
+      prec = r->_mp_prec + 1;	/* lie not to lose precision in assignment */
+      rp = r->_mp_d;
+      up = u->_mp_d;
+
+      if (size > prec)
+	{
+	  up += size - prec;
+	  size = prec;
+	}
+
+      MPN_COPY (rp, up, size);
+      r->_mp_exp = u->_mp_exp;
+    }
+  r->_mp_size = size;
+}
diff --git a/mpf/add.c b/mpf/add.c
new file mode 100644
index 0000000..77a9e47
--- /dev/null
+++ b/mpf/add.c
@@ -0,0 +1,183 @@
+/* mpf_add -- Add two floats.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_add (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr rp, tp;
+  mp_size_t usize, vsize, rsize;
+  mp_size_t prec;
+  mp_exp_t uexp;
+  mp_size_t ediff;
+  mp_limb_t cy;
+  int negate;
+  TMP_DECL;
+
+  usize = u->_mp_size;
+  vsize = v->_mp_size;
+
+  /* Handle special cases that don't work in generic code below.  */
+  if (usize == 0)
+    {
+    set_r_v_maybe:
+      if (r != v)
+        mpf_set (r, v);
+      return;
+    }
+  if (vsize == 0)
+    {
+      v = u;
+      goto set_r_v_maybe;
+    }
+
+  /* If signs of U and V are different, perform subtraction.  */
+  if ((usize ^ vsize) < 0)
+    {
+      __mpf_struct v_negated;
+      v_negated._mp_size = -vsize;
+      v_negated._mp_exp = v->_mp_exp;
+      v_negated._mp_d = v->_mp_d;
+      mpf_sub (r, u, &v_negated);
+      return;
+    }
+
+  TMP_MARK;
+
+  /* Signs are now known to be the same.  */
+  negate = usize < 0;
+
+  /* Make U be the operand with the largest exponent.  */
+  if (u->_mp_exp < v->_mp_exp)
+    {
+      mpf_srcptr t;
+      t = u; u = v; v = t;
+      usize = u->_mp_size;
+      vsize = v->_mp_size;
+    }
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+  up = u->_mp_d;
+  vp = v->_mp_d;
+  rp = r->_mp_d;
+  prec = r->_mp_prec;
+  uexp = u->_mp_exp;
+  ediff = u->_mp_exp - v->_mp_exp;
+
+  /* If U extends beyond PREC, ignore the part that does.  */
+  if (usize > prec)
+    {
+      up += usize - prec;
+      usize = prec;
+    }
+
+  /* If V extends beyond PREC, ignore the part that does.
+     Note that this may make vsize negative.  */
+  if (vsize + ediff > prec)
+    {
+      vp += vsize + ediff - prec;
+      vsize = prec - ediff;
+    }
+
+#if 0
+  /* Locate the least significant non-zero limb in (the needed parts
+     of) U and V, to simplify the code below.  */
+  while (up[0] == 0)
+    up++, usize--;
+  while (vp[0] == 0)
+    vp++, vsize--;
+#endif
+
+  /* Allocate temp space for the result.  Allocate
+     just vsize + ediff later???  */
+  tp = TMP_ALLOC_LIMBS (prec);
+
+  if (ediff >= prec)
+    {
+      /* V completely cancelled.  */
+      if (rp != up)
+	MPN_COPY_INCR (rp, up, usize);
+      rsize = usize;
+    }
+  else
+    {
+      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
+      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
+
+      if (usize > ediff)
+	{
+	  /* U and V partially overlaps.  */
+	  if (vsize + ediff <= usize)
+	    {
+	      /* uuuu     */
+	      /*   v      */
+	      mp_size_t size;
+	      size = usize - ediff - vsize;
+	      MPN_COPY (tp, up, size);
+	      cy = mpn_add (tp + size, up + size, usize - size, vp, vsize);
+	      rsize = usize;
+	    }
+	  else
+	    {
+	      /* uuuu     */
+	      /*   vvvvv  */
+	      mp_size_t size;
+	      size = vsize + ediff - usize;
+	      MPN_COPY (tp, vp, size);
+	      cy = mpn_add (tp + size, up, usize, vp + size, usize - ediff);
+	      rsize = vsize + ediff;
+	    }
+	}
+      else
+	{
+	  /* uuuu     */
+	  /*      vv  */
+	  mp_size_t size;
+	  size = vsize + ediff - usize;
+	  MPN_COPY (tp, vp, vsize);
+	  MPN_ZERO (tp + vsize, ediff - usize);
+	  MPN_COPY (tp + size, up, usize);
+	  cy = 0;
+	  rsize = size + usize;
+	}
+
+      MPN_COPY (rp, tp, rsize);
+      rp[rsize] = cy;
+      rsize += cy;
+      uexp += cy;
+    }
+
+  r->_mp_size = negate ? -rsize : rsize;
+  r->_mp_exp = uexp;
+  TMP_FREE;
+}
diff --git a/mpf/add_ui.c b/mpf/add_ui.c
new file mode 100644
index 0000000..1e2a94b
--- /dev/null
+++ b/mpf/add_ui.c
@@ -0,0 +1,152 @@
+/* mpf_add_ui -- Add a float and an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_add_ui (mpf_ptr sum, mpf_srcptr u, unsigned long int v)
+{
+  mp_srcptr up = u->_mp_d;
+  mp_ptr sump = sum->_mp_d;
+  mp_size_t usize, sumsize;
+  mp_size_t prec = sum->_mp_prec;
+  mp_exp_t uexp = u->_mp_exp;
+
+  usize = u->_mp_size;
+  if (usize <= 0)
+    {
+      if (usize == 0)
+	{
+	  mpf_set_ui (sum, v);
+	  return;
+	}
+      else
+	{
+	  __mpf_struct u_negated;
+	  u_negated._mp_size = -usize;
+	  u_negated._mp_exp = u->_mp_exp;
+	  u_negated._mp_d = u->_mp_d;
+	  mpf_sub_ui (sum, &u_negated, v);
+	  sum->_mp_size = -(sum->_mp_size);
+	  return;
+	}
+    }
+
+  if (v == 0)
+    {
+    sum_is_u:
+      if (u != sum)
+	{
+	  sumsize = MIN (usize, prec + 1);
+	  MPN_COPY (sum->_mp_d, up + usize - sumsize, sumsize);
+	  sum->_mp_size = sumsize;
+	  sum->_mp_exp = u->_mp_exp;
+	}
+      return;
+    }
+
+  if (uexp > 0)
+    {
+      /* U >= 1.  */
+      if (uexp > prec)
+	{
+	  /* U >> V, V is not part of final result.  */
+	  goto sum_is_u;
+	}
+      else
+	{
+	  /* U's "limb point" is somewhere between the first limb
+	     and the PREC:th limb.
+	     Both U and V are part of the final result.  */
+	  if (uexp > usize)
+	    {
+	      /*   uuuuuu0000. */
+	      /* +          v. */
+	      /* We begin with moving U to the top of SUM, to handle
+		 samevar(U,SUM).  */
+	      MPN_COPY_DECR (sump + uexp - usize, up, usize);
+	      sump[0] = v;
+	      MPN_ZERO (sump + 1, uexp - usize - 1);
+#if 0 /* What is this??? */
+	      if (sum == u)
+		MPN_COPY (sum->_mp_d, sump, uexp);
+#endif
+	      sum->_mp_size = uexp;
+	      sum->_mp_exp = uexp;
+	    }
+	  else
+	    {
+	      /*   uuuuuu.uuuu */
+	      /* +      v.     */
+	      mp_limb_t cy_limb;
+	      if (usize > prec)
+		{
+		  /* Ignore excess limbs in U.  */
+		  up += usize - prec;
+		  usize -= usize - prec; /* Eq. usize = prec */
+		}
+	      if (sump != up)
+		MPN_COPY_INCR (sump, up, usize - uexp);
+	      cy_limb = mpn_add_1 (sump + usize - uexp, up + usize - uexp,
+				   uexp, (mp_limb_t) v);
+	      sump[usize] = cy_limb;
+	      sum->_mp_size = usize + cy_limb;
+	      sum->_mp_exp = uexp + cy_limb;
+	    }
+	}
+    }
+  else
+    {
+      /* U < 1, so V > U for sure.  */
+      /* v.         */
+      /*  .0000uuuu */
+      if ((-uexp) >= prec)
+	{
+	  sump[0] = v;
+	  sum->_mp_size = 1;
+	  sum->_mp_exp = 1;
+	}
+      else
+	{
+	  if (usize + (-uexp) + 1 > prec)
+	    {
+	      /* Ignore excess limbs in U.  */
+	      up += usize + (-uexp) + 1 - prec;
+	      usize -= usize + (-uexp) + 1 - prec;
+	    }
+	  if (sump != up)
+	    MPN_COPY_INCR (sump, up, usize);
+	  MPN_ZERO (sump + usize, -uexp);
+	  sump[usize + (-uexp)] = v;
+	  sum->_mp_size = usize + (-uexp) + 1;
+	  sum->_mp_exp = 1;
+	}
+    }
+}
diff --git a/mpf/ceilfloor.c b/mpf/ceilfloor.c
new file mode 100644
index 0000000..9bb6638
--- /dev/null
+++ b/mpf/ceilfloor.c
@@ -0,0 +1,125 @@
+/* mpf_ceil, mpf_floor -- round an mpf to an integer.
+
+Copyright 2001, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* dir==1 for ceil, dir==-1 for floor
+
+   Notice the use of prec+1 ensures mpf_ceil and mpf_floor are equivalent to
+   mpf_set if u is already an integer.  */
+
+static void __gmpf_ceil_or_floor (REGPARM_2_1 (mpf_ptr, mpf_srcptr, int)) REGPARM_ATTR (1);
+#define mpf_ceil_or_floor(r,u,dir)  __gmpf_ceil_or_floor (REGPARM_2_1 (r, u, dir))
+
+REGPARM_ATTR (1) static void
+mpf_ceil_or_floor (mpf_ptr r, mpf_srcptr u, int dir)
+{
+  mp_ptr     rp, up, p;
+  mp_size_t  size, asize, prec;
+  mp_exp_t   exp;
+
+  size = SIZ(u);
+  if (size == 0)
+    {
+    zero:
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+
+  rp = PTR(r);
+  exp = EXP(u);
+  if (exp <= 0)
+    {
+      /* u is only a fraction */
+      if ((size ^ dir) < 0)
+        goto zero;
+      rp[0] = 1;
+      EXP(r) = 1;
+      SIZ(r) = dir;
+      return;
+    }
+  EXP(r) = exp;
+
+  up = PTR(u);
+  asize = ABS (size);
+  up += asize;
+
+  /* skip fraction part of u */
+  asize = MIN (asize, exp);
+
+  /* don't lose precision in the copy */
+  prec = PREC (r) + 1;
+
+  /* skip excess over target precision */
+  asize = MIN (asize, prec);
+
+  up -= asize;
+
+  if ((size ^ dir) >= 0)
+    {
+      /* rounding direction matches sign, must increment if ignored part is
+         non-zero */
+      for (p = PTR(u); p != up; p++)
+        {
+          if (*p != 0)
+            {
+              if (mpn_add_1 (rp, up, asize, CNST_LIMB(1)))
+                {
+                  /* was all 0xFF..FFs, which have become zeros, giving just
+                     a carry */
+                  rp[0] = 1;
+                  asize = 1;
+                  EXP(r)++;
+                }
+              SIZ(r) = (size >= 0 ? asize : -asize);
+              return;
+            }
+        }
+    }
+
+  SIZ(r) = (size >= 0 ? asize : -asize);
+  if (rp != up)
+    MPN_COPY_INCR (rp, up, asize);
+}
+
+
+void
+mpf_ceil (mpf_ptr r, mpf_srcptr u)
+{
+  mpf_ceil_or_floor (r, u, 1);
+}
+
+void
+mpf_floor (mpf_ptr r, mpf_srcptr u)
+{
+  mpf_ceil_or_floor (r, u, -1);
+}
diff --git a/mpf/clear.c b/mpf/clear.c
new file mode 100644
index 0000000..0939e03
--- /dev/null
+++ b/mpf/clear.c
@@ -0,0 +1,38 @@
+/* mpf_clear -- de-allocate the space occupied by the dynamic digit space of
+   an integer.
+
+Copyright 1993-1995, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_clear (mpf_ptr x)
+{
+  __GMP_FREE_FUNC_LIMBS (PTR(x), PREC(x) + 1);
+}
diff --git a/mpf/clears.c b/mpf/clears.c
new file mode 100644
index 0000000..115fa19
--- /dev/null
+++ b/mpf/clears.c
@@ -0,0 +1,49 @@
+/* mpf_clears() -- Clear multiple mpf_t variables.
+
+Copyright 2009, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpf_clears (mpf_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      __GMP_FREE_FUNC_LIMBS (PTR(x), PREC(x) + 1);
+      x = va_arg (ap, mpf_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/mpf/cmp.c b/mpf/cmp.c
new file mode 100644
index 0000000..3518b51
--- /dev/null
+++ b/mpf/cmp.c
@@ -0,0 +1,113 @@
+/* mpf_cmp -- Compare two floats.
+
+Copyright 1993, 1994, 1996, 2001, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp (mpf_srcptr u, mpf_srcptr v) __GMP_NOTHROW
+{
+  mp_srcptr up, vp;
+  mp_size_t usize, vsize;
+  mp_exp_t uexp, vexp;
+  int cmp;
+  int usign;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+  usign = usize >= 0 ? 1 : -1;
+
+  /* 1. Are the signs different?  */
+  if ((usize ^ vsize) >= 0)
+    {
+      /* U and V are both non-negative or both negative.  */
+      if (usize == 0)
+	/* vsize >= 0 */
+	return -(vsize != 0);
+      if (vsize == 0)
+	/* usize >= 0 */
+	return usize != 0;
+      /* Fall out.  */
+    }
+  else
+    {
+      /* Either U or V is negative, but not both.  */
+      return usign;
+    }
+
+  /* U and V have the same sign and are both non-zero.  */
+
+  uexp = EXP(u);
+  vexp = EXP(v);
+
+  /* 2. Are the exponents different?  */
+  if (uexp > vexp)
+    return usign;
+  if (uexp < vexp)
+    return -usign;
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  up = PTR (u);
+  vp = PTR (v);
+
+#define STRICT_MPF_NORMALIZATION 0
+#if ! STRICT_MPF_NORMALIZATION
+  /* Ignore zeroes at the low end of U and V.  */
+  do {
+    mp_limb_t tl;
+    tl = up[0];
+    MPN_STRIP_LOW_ZEROS_NOT_ZERO (up, usize, tl);
+    tl = vp[0];
+    MPN_STRIP_LOW_ZEROS_NOT_ZERO (vp, vsize, tl);
+  } while (0);
+#endif
+
+  if (usize > vsize)
+    {
+      cmp = mpn_cmp (up + usize - vsize, vp, vsize);
+      /* if (cmp == 0) */
+      /*	return usign; */
+      ++cmp;
+    }
+  else if (vsize > usize)
+    {
+      cmp = mpn_cmp (up, vp + vsize - usize, usize);
+      /* if (cmp == 0) */
+      /*	return -usign; */
+    }
+  else
+    {
+      cmp = mpn_cmp (up, vp, usize);
+      if (cmp == 0)
+	return 0;
+    }
+  return cmp > 0 ? usign : -usign;
+}
diff --git a/mpf/cmp_d.c b/mpf/cmp_d.c
new file mode 100644
index 0000000..3fa099b
--- /dev/null
+++ b/mpf/cmp_d.c
@@ -0,0 +1,59 @@
+/* mpf_cmp_d -- compare mpf and double.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_d (mpf_srcptr f, double d)
+{
+  mp_limb_t  darray[LIMBS_PER_DOUBLE];
+  mpf_t      df;
+
+  /* d=NaN has no sensible return value, so raise an exception.
+     d=Inf or -Inf is always bigger than z.  */
+  DOUBLE_NAN_INF_ACTION (d,
+                         __gmp_invalid_operation (),
+                         return (d < 0.0 ? 1 : -1));
+
+  if (d == 0.0)
+    return SIZ(f);
+
+  PTR(df) = darray;
+  SIZ(df) = (d >= 0.0 ? LIMBS_PER_DOUBLE : -LIMBS_PER_DOUBLE);
+  EXP(df) = __gmp_extract_double (darray, ABS(d));
+
+  return mpf_cmp (f, df);
+}
diff --git a/mpf/cmp_si.c b/mpf/cmp_si.c
new file mode 100644
index 0000000..d8d9880
--- /dev/null
+++ b/mpf/cmp_si.c
@@ -0,0 +1,109 @@
+/* mpf_cmp_si -- Compare a float with a signed integer.
+
+Copyright 1993-1995, 1999-2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_si (mpf_srcptr u, long int vval) __GMP_NOTHROW
+{
+  mp_srcptr up;
+  mp_size_t usize;
+  mp_exp_t uexp;
+  mp_limb_t ulimb;
+  int usign;
+  unsigned long abs_vval;
+
+  usize = SIZ (u);
+
+  /* 1. Are the signs different?  */
+  if ((usize < 0) == (vval < 0)) /* don't use xor, type size may differ */
+    {
+      /* U and V are both non-negative or both negative.  */
+      if (usize == 0)
+	/* vval >= 0 */
+	return -(vval != 0);
+      if (vval == 0)
+	/* usize >= 0 */
+	return usize != 0;
+      /* Fall out.  */
+    }
+  else
+    {
+      /* Either U or V is negative, but not both.  */
+      return usize >= 0 ? 1 : -1;
+    }
+
+  /* U and V have the same sign and are both non-zero.  */
+
+  /* 2. Are the exponents different (V's exponent == 1)?  */
+  uexp = EXP (u);
+  usign = usize >= 0 ? 1 : -1;
+  usize = ABS (usize);
+  abs_vval = ABS_CAST (unsigned long, vval);
+
+#if GMP_NAIL_BITS != 0
+  if (uexp != 1 + (abs_vval > GMP_NUMB_MAX))
+    return (uexp < 1 + (abs_vval > GMP_NUMB_MAX)) ? -usign : usign;
+#else
+  if (uexp != 1)
+    return (uexp < 1) ? -usign : usign;
+#endif
+
+  up = PTR (u);
+
+  ASSERT (usize > 0);
+  ulimb = up[--usize];
+#if GMP_NAIL_BITS != 0
+  if (uexp == 2)
+    {
+      if ((ulimb >> GMP_NAIL_BITS) != 0)
+	return usign;
+      ulimb = (ulimb << GMP_NUMB_BITS);
+      if (usize != 0) ulimb |= up[--usize];
+    }
+#endif
+
+  /* 3. Compare the most significant mantissa limb with V.  */
+  if (ulimb != abs_vval)
+    return (ulimb < abs_vval) ? -usign : usign;
+
+  /* Ignore zeroes at the low end of U.  */
+  for (; *up == 0; ++up)
+    --usize;
+
+  /* 4. Now, if the number of limbs are different, we have a difference
+     since we have made sure the trailing limbs are not zero.  */
+  if (usize > 0)
+    return usign;
+
+  /* Wow, we got zero even if we tried hard to avoid it.  */
+  return 0;
+}
diff --git a/mpf/cmp_ui.c b/mpf/cmp_ui.c
new file mode 100644
index 0000000..a9a6036
--- /dev/null
+++ b/mpf/cmp_ui.c
@@ -0,0 +1,87 @@
+/* mpf_cmp_ui -- Compare a float with an unsigned integer.
+
+Copyright 1993-1995, 1999, 2001, 2002, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_ui (mpf_srcptr u, unsigned long int vval) __GMP_NOTHROW
+{
+  mp_srcptr up;
+  mp_size_t usize;
+  mp_exp_t uexp;
+  mp_limb_t ulimb;
+
+  usize = SIZ (u);
+
+  /* 1. Is U negative?  */
+  if (usize < 0)
+    return -1;
+  /* We rely on usize being non-negative in the code that follows.  */
+
+  if (vval == 0)
+    return usize != 0;
+
+  /* 2. Are the exponents different (V's exponent == 1)?  */
+  uexp = EXP (u);
+
+#if GMP_NAIL_BITS != 0
+  if (uexp != 1 + (vval > GMP_NUMB_MAX))
+    return (uexp < 1 + (vval > GMP_NUMB_MAX)) ? -1 : 1;
+#else
+  if (uexp != 1)
+    return (uexp < 1) ? -1 : 1;
+#endif
+
+  up = PTR (u);
+
+  ASSERT (usize > 0);
+  ulimb = up[--usize];
+#if GMP_NAIL_BITS != 0
+  if (uexp == 2)
+    {
+      if ((ulimb >> GMP_NAIL_BITS) != 0)
+	return 1;
+      ulimb = (ulimb << GMP_NUMB_BITS);
+      if (usize != 0) ulimb |= up[--usize];
+    }
+#endif
+
+  /* 3. Compare the most significant mantissa limb with V.  */
+  if (ulimb != vval)
+    return (ulimb < vval) ? -1 : 1;
+
+  /* Ignore zeroes at the low end of U.  */
+  for (; *up == 0; ++up)
+    --usize;
+
+  /* 4. Now, if the number of limbs are different, we have a difference
+     since we have made sure the trailing limbs are not zero.  */
+  return (usize > 0);
+}
diff --git a/mpf/cmp_z.c b/mpf/cmp_z.c
new file mode 100644
index 0000000..279980f
--- /dev/null
+++ b/mpf/cmp_z.c
@@ -0,0 +1,45 @@
+/* mpf_cmp_z -- Compare a float with an integer.
+
+Copyright 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_z (mpf_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mpf_t vf;
+  mp_size_t size;
+
+  SIZ (vf) = size = SIZ (v);
+  EXP (vf) = size = ABS (size);
+  /* PREC (vf) = size; */
+  PTR (vf) = PTR (v);
+
+  return mpf_cmp (u, vf);
+}
diff --git a/mpf/div.c b/mpf/div.c
new file mode 100644
index 0000000..d13af75
--- /dev/null
+++ b/mpf/div.c
@@ -0,0 +1,137 @@
+/* mpf_div -- Divide two floats.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004, 2005, 2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Not done:
+
+   No attempt is made to identify an overlap u==v.  The result will be
+   correct (1.0), but a full actual division is done whereas of course
+   x/x==1 needs no work.  Such a call is not a sensible thing to make, and
+   it's left to an application to notice and optimize if it might arise
+   somehow through pointer aliasing or whatever.
+
+   Enhancements:
+
+   The high quotient limb is non-zero when high{up,vsize} >= {vp,vsize}.  We
+   could make that comparison and use qsize==prec instead of qsize==prec+1,
+   to save one limb in the division.
+
+   If r==u but the size is enough bigger than prec that there won't be an
+   overlap between quotient and dividend in mpn_div_q, then we can avoid
+   copying up,usize.  This would only arise from a prec reduced with
+   mpf_set_prec_raw and will be pretty unusual, but might be worthwhile if
+   it could be worked into the copy_u decision cleanly.  */
+
+void
+mpf_div (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr rp, tp, new_vp;
+  mp_size_t usize, vsize, rsize, prospective_rsize, tsize, zeros;
+  mp_size_t sign_quotient, prec, high_zero, chop;
+  mp_exp_t rexp;
+  int copy_u;
+  TMP_DECL;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+
+  if (UNLIKELY (vsize == 0))
+    DIVIDE_BY_ZERO;
+
+  if (usize == 0)
+    {
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+
+  sign_quotient = usize ^ vsize;
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+  prec = PREC(r);
+
+  TMP_MARK;
+  rexp = EXP(u) - EXP(v) + 1;
+
+  rp = PTR(r);
+  up = PTR(u);
+  vp = PTR(v);
+
+  prospective_rsize = usize - vsize + 1; /* quot from using given u,v sizes */
+  rsize = prec + 1;			 /* desired quot */
+
+  zeros = rsize - prospective_rsize;	 /* padding u to give rsize */
+  copy_u = (zeros > 0 || rp == up);	 /* copy u if overlap or padding */
+
+  chop = MAX (-zeros, 0);		 /* negative zeros means shorten u */
+  up += chop;
+  usize -= chop;
+  zeros += chop;			 /* now zeros >= 0 */
+
+  tsize = usize + zeros;		 /* size for possible copy of u */
+
+  /* copy and possibly extend u if necessary */
+  if (copy_u)
+    {
+      tp = TMP_ALLOC_LIMBS (tsize + 1);	/* +1 for mpn_div_q's scratch needs */
+      MPN_ZERO (tp, zeros);
+      MPN_COPY (tp+zeros, up, usize);
+      up = tp;
+      usize = tsize;
+    }
+  else
+    {
+      tp = TMP_ALLOC_LIMBS (usize + 1);
+    }
+
+  /* ensure divisor doesn't overlap quotient */
+  if (rp == vp)
+    {
+      new_vp = TMP_ALLOC_LIMBS (vsize);
+      MPN_COPY (new_vp, vp, vsize);
+      vp = new_vp;
+    }
+
+  ASSERT (usize-vsize+1 == rsize);
+  mpn_div_q (rp, up, usize, vp, vsize, tp);
+
+  /* strip possible zero high limb */
+  high_zero = (rp[rsize-1] == 0);
+  rsize -= high_zero;
+  rexp -= high_zero;
+
+  SIZ(r) = sign_quotient >= 0 ? rsize : -rsize;
+  EXP(r) = rexp;
+  TMP_FREE;
+}
diff --git a/mpf/div_2exp.c b/mpf/div_2exp.c
new file mode 100644
index 0000000..ad552c1
--- /dev/null
+++ b/mpf/div_2exp.c
@@ -0,0 +1,138 @@
+/* mpf_div_2exp -- Divide a float by 2^n.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Multiples of GMP_NUMB_BITS in exp simply mean an amount subtracted from
+   EXP(u) to set EXP(r).  The remainder exp%GMP_NUMB_BITS is then a right
+   shift for the limb data.
+
+   If exp%GMP_NUMB_BITS == 0 then there's no shifting, we effectively just
+   do an mpz_set with changed EXP(r).  Like mpz_set we take prec+1 limbs in
+   this case.  Although just prec would suffice, it's nice to have
+   mpf_div_2exp with exp==0 come out the same as mpz_set.
+
+   When shifting we take up to prec many limbs from the input.  Our shift is
+   cy = mpn_rshift (PTR(r)+1, PTR(u)+k, ...), where k is the number of low
+   limbs dropped from u, and the carry out is stored to PTR(r)[0].  We don't
+   try to work extra bits from PTR(u)[k-1] (when k>=1 makes it available)
+   into that low carry limb.  Just prec limbs (with the high non-zero) from
+   the input is enough bits for the application requested precision, no need
+   to do extra work.
+
+   If r==u the shift will have overlapping operands.  When k>=1 (ie. when
+   usize > prec), the overlap is in the style supported by rshift (ie. dst
+   <= src).
+
+   But when r==u and k==0 (ie. usize <= prec), we would have an invalid
+   overlap (mpn_rshift (rp+1, rp, ...)).  In this case we must instead use
+   mpn_lshift (PTR(r), PTR(u), size, NUMB-shift).  An lshift by NUMB-shift
+   bits gives identical data of course, it's just its overlap restrictions
+   which differ.
+
+   In both shift cases, the resulting data is abs_usize+1 limbs.  "adj" is
+   used to add +1 to that size if the high is non-zero (it may of course
+   have become zero by the shifting).  EXP(u) is the exponent just above
+   those abs_usize+1 limbs, so it gets -1+adj, which means -1 if the high is
+   zero, or no change if the high is non-zero.
+
+   Enhancements:
+
+   The way mpn_lshift is used means successive mpf_div_2exp calls on the
+   same operand will accumulate low zero limbs, until prec+1 limbs is
+   reached.  This is wasteful for subsequent operations.  When abs_usize <=
+   prec, we should test the low exp%GMP_NUMB_BITS many bits of PTR(u)[0],
+   ie. those which would be shifted out by an mpn_rshift.  If they're zero
+   then use that mpn_rshift.  */
+
+void
+mpf_div_2exp (mpf_ptr r, mpf_srcptr u, mp_bitcnt_t exp)
+{
+  mp_srcptr up;
+  mp_ptr rp = r->_mp_d;
+  mp_size_t usize;
+  mp_size_t abs_usize;
+  mp_size_t prec = r->_mp_prec;
+  mp_exp_t uexp = u->_mp_exp;
+
+  usize = u->_mp_size;
+
+  if (UNLIKELY (usize == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  abs_usize = ABS (usize);
+  up = u->_mp_d;
+
+  if (exp % GMP_NUMB_BITS == 0)
+    {
+      prec++;			/* retain more precision here as we don't need
+				   to account for carry-out here */
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	}
+      if (rp != up)
+	MPN_COPY_INCR (rp, up, abs_usize);
+      r->_mp_exp = uexp - exp / GMP_NUMB_BITS;
+    }
+  else
+    {
+      mp_limb_t cy_limb;
+      mp_size_t adj;
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	  /* Use mpn_rshift since mpn_lshift operates downwards, and we
+	     therefore would clobber part of U before using that part, in case
+	     R is the same variable as U.  */
+	  cy_limb = mpn_rshift (rp + 1, up, abs_usize, exp % GMP_NUMB_BITS);
+	  rp[0] = cy_limb;
+	  adj = rp[abs_usize] != 0;
+	}
+      else
+	{
+	  cy_limb = mpn_lshift (rp, up, abs_usize,
+				GMP_NUMB_BITS - exp % GMP_NUMB_BITS);
+	  rp[abs_usize] = cy_limb;
+	  adj = cy_limb != 0;
+	}
+
+      abs_usize += adj;
+      r->_mp_exp = uexp - exp / GMP_NUMB_BITS - 1 + adj;
+    }
+  r->_mp_size = usize >= 0 ? abs_usize : -abs_usize;
+}
diff --git a/mpf/div_ui.c b/mpf/div_ui.c
new file mode 100644
index 0000000..e1b0112
--- /dev/null
+++ b/mpf/div_ui.c
@@ -0,0 +1,110 @@
+/* mpf_div_ui -- Divide a float with an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004, 2005, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpf_div_ui (mpf_ptr r, mpf_srcptr u, unsigned long int v)
+{
+  mp_srcptr up;
+  mp_ptr rp, tp, rtp;
+  mp_size_t usize;
+  mp_size_t rsize, tsize;
+  mp_size_t sign_quotient;
+  mp_size_t prec;
+  mp_limb_t q_limb;
+  mp_exp_t rexp;
+  TMP_DECL;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpf_t vf;
+      mp_limb_t vl[2];
+      SIZ(vf) = 2;
+      EXP(vf) = 2;
+      PTR(vf) = vl;
+      vl[0] = v & GMP_NUMB_MASK;
+      vl[1] = v >> GMP_NUMB_BITS;
+      mpf_div (r, u, vf);
+      return;
+    }
+#endif
+
+  if (UNLIKELY (v == 0))
+    DIVIDE_BY_ZERO;
+
+  usize = u->_mp_size;
+
+  if (usize == 0)
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  sign_quotient = usize;
+  usize = ABS (usize);
+  prec = r->_mp_prec;
+
+  TMP_MARK;
+
+  rp = r->_mp_d;
+  up = u->_mp_d;
+
+  tsize = 1 + prec;
+  tp = TMP_ALLOC_LIMBS (tsize + 1);
+
+  if (usize > tsize)
+    {
+      up += usize - tsize;
+      usize = tsize;
+      rtp = tp;
+    }
+  else
+    {
+      MPN_ZERO (tp, tsize - usize);
+      rtp = tp + (tsize - usize);
+    }
+
+  /* Move the dividend to the remainder.  */
+  MPN_COPY (rtp, up, usize);
+
+  mpn_divmod_1 (rp, tp, tsize, (mp_limb_t) v);
+  q_limb = rp[tsize - 1];
+
+  rsize = tsize - (q_limb == 0);
+  rexp = u->_mp_exp - (q_limb == 0);
+  r->_mp_size = sign_quotient >= 0 ? rsize : -rsize;
+  r->_mp_exp = rexp;
+  TMP_FREE;
+}
diff --git a/mpf/dump.c b/mpf/dump.c
new file mode 100644
index 0000000..cd37dab
--- /dev/null
+++ b/mpf/dump.c
@@ -0,0 +1,52 @@
+/* mpf_dump -- Dump a float to stdout.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS NOT SAFE TO
+   CALL THIS FUNCTION DIRECTLY.  IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+   FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1995, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h> /* for strlen */
+#include "gmp-impl.h"
+
+void
+mpf_dump (mpf_srcptr u)
+{
+  mp_exp_t exp;
+  char *str;
+
+  str = mpf_get_str (0, &exp, 10, 0, u);
+  if (str[0] == '-')
+    printf ("-0.%se%ld\n", str + 1, exp);
+  else
+    printf ("0.%se%ld\n", str, exp);
+  (*__gmp_free_func) (str, strlen (str) + 1);
+}
diff --git a/mpf/eq.c b/mpf/eq.c
new file mode 100644
index 0000000..cddb9d5
--- /dev/null
+++ b/mpf/eq.c
@@ -0,0 +1,149 @@
+/* mpf_eq -- Compare two floats up to a specified bit #.
+
+Copyright 1993, 1995, 1996, 2001, 2002, 2008, 2009, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+int
+mpf_eq (mpf_srcptr u, mpf_srcptr v, mp_bitcnt_t n_bits)
+{
+  mp_srcptr up, vp, p;
+  mp_size_t usize, vsize, minsize, maxsize, n_limbs, i, size;
+  mp_exp_t uexp, vexp;
+  mp_limb_t diff;
+  int cnt;
+
+  uexp = u->_mp_exp;
+  vexp = v->_mp_exp;
+
+  usize = u->_mp_size;
+  vsize = v->_mp_size;
+
+  /* 1. Are the signs different?  */
+  if ((usize ^ vsize) >= 0)
+    {
+      /* U and V are both non-negative or both negative.  */
+      if (usize == 0)
+	return vsize == 0;
+      if (vsize == 0)
+	return 0;
+
+      /* Fall out.  */
+    }
+  else
+    {
+      /* Either U or V is negative, but not both.  */
+      return 0;
+    }
+
+  /* U and V have the same sign and are both non-zero.  */
+
+  /* 2. Are the exponents different?  */
+  if (uexp != vexp)
+    return 0;
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  up += usize;			/* point just above most significant limb */
+  vp += vsize;			/* point just above most significant limb */
+
+  count_leading_zeros (cnt, up[-1]);
+  if ((vp[-1] >> (GMP_LIMB_BITS - 1 - cnt)) != 1)
+    return 0;			/* msb positions different */
+
+  n_bits += cnt - GMP_NAIL_BITS;
+  n_limbs = (n_bits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
+
+  usize = MIN (usize, n_limbs);
+  vsize = MIN (vsize, n_limbs);
+
+#if 0
+  /* Ignore zeros at the low end of U and V.  */
+  while (up[0] == 0)
+    up++, usize--;
+  while (vp[0] == 0)
+    vp++, vsize--;
+#endif
+
+  minsize = MIN (usize, vsize);
+  maxsize = usize + vsize - minsize;
+
+  up -= minsize;		/* point at most significant common limb */
+  vp -= minsize;		/* point at most significant common limb */
+
+  /* Compare the most significant part which has explicit limbs for U and V. */
+  for (i = minsize - 1; i > 0; i--)
+    {
+      if (up[i] != vp[i])
+	return 0;
+    }
+
+  n_bits -= (maxsize - 1) * GMP_NUMB_BITS;
+
+  size = maxsize - minsize;
+  if (size != 0)
+    {
+      if (up[0] != vp[0])
+	return 0;
+
+      /* Now either U or V has its limbs consumed, i.e, continues with an
+	 infinite number of implicit zero limbs.  Check that the other operand
+	 has just zeros in the corresponding, relevant part.  */
+
+      if (usize > vsize)
+	p = up - size;
+      else
+	p = vp - size;
+
+      for (i = size - 1; i > 0; i--)
+	{
+	  if (p[i] != 0)
+	    return 0;
+	}
+
+      diff = p[0];
+    }
+  else
+    {
+      /* Both U or V has its limbs consumed.  */
+
+      diff = up[0] ^ vp[0];
+    }
+
+  if (n_bits < GMP_NUMB_BITS)
+    diff >>= GMP_NUMB_BITS - n_bits;
+
+  return diff == 0;
+}
diff --git a/mpf/fits_s.h b/mpf/fits_s.h
new file mode 100644
index 0000000..80e74be
--- /dev/null
+++ b/mpf/fits_s.h
@@ -0,0 +1,71 @@
+/* mpf_fits_s*_p -- test whether an mpf fits a C signed type.
+
+Copyright 2001, 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Notice this is equivalent to mpz_set_f + mpz_fits_s*_p.  */
+
+int
+FUNCTION (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_size_t  fs, fn;
+  mp_srcptr  fp;
+  mp_exp_t   exp;
+  mp_limb_t  fl;
+
+  exp = EXP(f);
+  if (exp < 1)
+    return 1;  /* -1 < f < 1 truncates to zero, so fits */
+
+  fs = SIZ (f);
+  fp = PTR(f);
+  fn = ABS (fs);
+
+  if (exp == 1)
+    {
+      fl = fp[fn-1];
+    }
+#if GMP_NAIL_BITS != 0
+  else if (exp == 2 && MAXIMUM > GMP_NUMB_MAX)
+    {
+      fl = fp[fn-1];
+      if ((fl >> GMP_NAIL_BITS) != 0)
+	return 0;
+      fl = (fl << GMP_NUMB_BITS);
+      if (fn >= 2)
+        fl |= fp[fn-2];
+    }
+#endif
+  else
+    return 0;
+
+  return fl <= (fs >= 0 ? (mp_limb_t) MAXIMUM : NEG_CAST (mp_limb_t, MINIMUM));
+}
diff --git a/mpf/fits_sint.c b/mpf/fits_sint.c
new file mode 100644
index 0000000..26ace07
--- /dev/null
+++ b/mpf/fits_sint.c
@@ -0,0 +1,36 @@
+/* mpf_fits_sint_p -- test whether an mpf fits an int.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION   mpf_fits_sint_p
+#define MAXIMUM    INT_MAX
+#define MINIMUM    INT_MIN
+
+#include "fits_s.h"
diff --git a/mpf/fits_slong.c b/mpf/fits_slong.c
new file mode 100644
index 0000000..25db68c
--- /dev/null
+++ b/mpf/fits_slong.c
@@ -0,0 +1,36 @@
+/* mpf_fits_slong_p -- test whether an mpf fits a long.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION   mpf_fits_slong_p
+#define MAXIMUM    LONG_MAX
+#define MINIMUM    LONG_MIN
+
+#include "fits_s.h"
diff --git a/mpf/fits_sshort.c b/mpf/fits_sshort.c
new file mode 100644
index 0000000..3bfc5a4
--- /dev/null
+++ b/mpf/fits_sshort.c
@@ -0,0 +1,36 @@
+/* mpf_fits_sshort_p -- test whether an mpf fits a short.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION   mpf_fits_sshort_p
+#define MAXIMUM    SHRT_MAX
+#define MINIMUM    SHRT_MIN
+
+#include "fits_s.h"
diff --git a/mpf/fits_u.h b/mpf/fits_u.h
new file mode 100644
index 0000000..bd7ca78
--- /dev/null
+++ b/mpf/fits_u.h
@@ -0,0 +1,73 @@
+/* mpf_fits_u*_p -- test whether an mpf fits a C unsigned type.
+
+Copyright 2001, 2002, 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Notice this is equivalent to mpz_set_f + mpz_fits_u*_p.  */
+
+int
+FUNCTION (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_size_t  fn;
+  mp_srcptr  fp;
+  mp_exp_t   exp;
+  mp_limb_t  fl;
+
+  exp = EXP(f);
+  if (exp < 1)
+    return 1;  /* -1 < f < 1 truncates to zero, so fits */
+
+  fn = SIZ(f);
+  if (fn < 0) /* zero catched by exp == 0 */
+    return 0; /* negatives don't fit */
+
+  fp = PTR(f);
+
+  if (exp == 1)
+    {
+      fl = fp[fn-1];
+    }
+#if GMP_NAIL_BITS != 0
+  else if (exp == 2 && MAXIMUM > GMP_NUMB_MAX)
+    {
+      fl = fp[fn-1];
+      if ((fl >> GMP_NAIL_BITS) != 0)
+	return 0;
+      fl = (fl << GMP_NUMB_BITS);
+      if (fn >= 2)
+        fl |= fp[fn-2];
+    }
+#endif
+  else
+    return 0;
+
+  return fl <= MAXIMUM;
+}
diff --git a/mpf/fits_uint.c b/mpf/fits_uint.c
new file mode 100644
index 0000000..4b107b0
--- /dev/null
+++ b/mpf/fits_uint.c
@@ -0,0 +1,35 @@
+/* mpf_fits_uint_p -- test whether an mpf fits an unsigned int.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpf_fits_uint_p
+#define MAXIMUM   UINT_MAX
+
+#include "fits_u.h"
diff --git a/mpf/fits_ulong.c b/mpf/fits_ulong.c
new file mode 100644
index 0000000..1db688c
--- /dev/null
+++ b/mpf/fits_ulong.c
@@ -0,0 +1,35 @@
+/* mpf_fits_ulong_p -- test whether an mpf fits an unsigned long.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpf_fits_ulong_p
+#define MAXIMUM   ULONG_MAX
+
+#include "fits_u.h"
diff --git a/mpf/fits_ushort.c b/mpf/fits_ushort.c
new file mode 100644
index 0000000..76a3fd9
--- /dev/null
+++ b/mpf/fits_ushort.c
@@ -0,0 +1,35 @@
+/* mpf_fits_ushort_p -- test whether an mpf fits an unsigned short.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpf_fits_ushort_p
+#define MAXIMUM   USHRT_MAX
+
+#include "fits_u.h"
diff --git a/mpf/get_d.c b/mpf/get_d.c
new file mode 100644
index 0000000..34826fb
--- /dev/null
+++ b/mpf/get_d.c
@@ -0,0 +1,46 @@
+/* double mpf_get_d (mpf_t src) -- return SRC truncated to a double.
+
+Copyright 1996, 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+double
+mpf_get_d (mpf_srcptr src)
+{
+  mp_size_t  size, abs_size;
+  long       exp;
+
+  size = SIZ (src);
+  if (UNLIKELY (size == 0))
+    return 0.0;
+
+  abs_size = ABS (size);
+  exp = (EXP (src) - abs_size) * GMP_NUMB_BITS;
+  return mpn_get_d (PTR (src), abs_size, size, exp);
+}
diff --git a/mpf/get_d_2exp.c b/mpf/get_d_2exp.c
new file mode 100644
index 0000000..440a753
--- /dev/null
+++ b/mpf/get_d_2exp.c
@@ -0,0 +1,56 @@
+/* double mpf_get_d_2exp (signed long int *exp, mpf_t src).
+
+Copyright 2001-2004, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+double
+mpf_get_d_2exp (signed long int *expptr, mpf_srcptr src)
+{
+  mp_size_t size, abs_size;
+  mp_srcptr ptr;
+  int cnt;
+
+  size = SIZ(src);
+  if (UNLIKELY (size == 0))
+    {
+      *expptr = 0;
+      return 0.0;
+    }
+
+  ptr = PTR(src);
+  abs_size = ABS (size);
+  count_leading_zeros (cnt, ptr[abs_size - 1]);
+  cnt -= GMP_NAIL_BITS;
+
+  *expptr = EXP(src) * GMP_NUMB_BITS - cnt;
+  return mpn_get_d (ptr, abs_size, size, -(abs_size * GMP_NUMB_BITS - cnt));
+}
diff --git a/mpf/get_dfl_prec.c b/mpf/get_dfl_prec.c
new file mode 100644
index 0000000..13fc514
--- /dev/null
+++ b/mpf/get_dfl_prec.c
@@ -0,0 +1,38 @@
+/* mpf_get_default_prec -- return default precision in bits.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+mp_bitcnt_t
+mpf_get_default_prec (void) __GMP_NOTHROW
+{
+  return __GMPF_PREC_TO_BITS (__gmp_default_fp_limb_precision);
+}
diff --git a/mpf/get_prc.c b/mpf/get_prc.c
new file mode 100644
index 0000000..8dee99e
--- /dev/null
+++ b/mpf/get_prc.c
@@ -0,0 +1,37 @@
+/* mpf_get_prec(x) -- Return the precision in bits of x.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_bitcnt_t
+mpf_get_prec (mpf_srcptr x) __GMP_NOTHROW
+{
+  return __GMPF_PREC_TO_BITS (x->_mp_prec);
+}
diff --git a/mpf/get_si.c b/mpf/get_si.c
new file mode 100644
index 0000000..6ac4d44
--- /dev/null
+++ b/mpf/get_si.c
@@ -0,0 +1,86 @@
+/* mpf_get_si -- mpf to long conversion
+
+Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Any fraction bits are truncated, meaning simply discarded.
+
+   For values bigger than a long, the low bits are returned, like
+   mpz_get_si, but this isn't documented.
+
+   Notice this is equivalent to mpz_set_f + mpz_get_si.
+
+
+   Implementation:
+
+   fl is established in basically the same way as for mpf_get_ui, see that
+   code for explanations of the conditions.
+
+   However unlike mpf_get_ui we need an explicit return 0 for exp<=0.  When
+   f is a negative fraction (ie. size<0 and exp<=0) we can't let fl==0 go
+   through to the zany final "~ ((fl - 1) & LONG_MAX)", that would give
+   -0x80000000 instead of the desired 0.  */
+
+long
+mpf_get_si (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_exp_t exp;
+  mp_size_t size, abs_size;
+  mp_srcptr fp;
+  mp_limb_t fl;
+
+  exp = EXP (f);
+  size = SIZ (f);
+  fp = PTR (f);
+
+  /* fraction alone truncates to zero
+     this also covers zero, since we have exp==0 for zero */
+  if (exp <= 0)
+    return 0L;
+
+  /* there are some limbs above the radix point */
+
+  fl = 0;
+  abs_size = ABS (size);
+  if (abs_size >= exp)
+    fl = fp[abs_size-exp];
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (exp > 1 && abs_size+1 >= exp)
+    fl |= fp[abs_size - exp + 1] << GMP_NUMB_BITS;
+#endif
+
+  if (size > 0)
+    return fl & LONG_MAX;
+  else
+    /* this form necessary to correctly handle -0x80..00 */
+    return -1 - (long) ((fl - 1) & LONG_MAX);
+}
diff --git a/mpf/get_str.c b/mpf/get_str.c
new file mode 100644
index 0000000..946c4ae
--- /dev/null
+++ b/mpf/get_str.c
@@ -0,0 +1,320 @@
+/* mpf_get_str (digit_ptr, exp, base, n_digits, a) -- Convert the floating
+   point number A to a base BASE number and store N_DIGITS raw digits at
+   DIGIT_PTR, and the base BASE exponent in the word pointed to by EXP.  For
+   example, the number 3.1416 would be returned as "31416" in DIGIT_PTR and
+   1 in EXP.
+
+Copyright 1993-1997, 2000-2003, 2005, 2006, 2011, 2015, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"		/* for count_leading_zeros */
+
+/* Could use some more work.
+
+   1. Allocation is excessive.  Try to combine areas.  Perhaps use result
+      string area for temp limb space?
+   2. We generate up to two limbs of extra digits.  This is because we don't
+      check the exact number of bits in the input operand, and from that
+      compute an accurate exponent (variable e in the code).  It would be
+      cleaner and probably somewhat faster to change this.
+*/
+
+/* Compute base^exp and return the most significant prec limbs in rp[].
+   Put the count of omitted low limbs in *ign.
+   Return the actual size (which might be less than prec).
+   Allocation of rp[] and the temporary tp[] should be 2*prec+2 limbs.  */
+static mp_size_t
+mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
+		    mp_limb_t base, unsigned long exp,
+		    mp_size_t prec, mp_ptr tp)
+{
+  mp_size_t ign;		/* counts number of ignored low limbs in r */
+  mp_size_t off;		/* keeps track of offset where value starts */
+  mp_ptr passed_rp = rp;
+  mp_size_t rn;
+  int cnt;
+  int i;
+
+  if (exp == 0)
+    {
+      rp[0] = 1;
+      *ignp = 0;
+      return 1;
+    }
+
+  rp[0] = base;
+  rn = 1;
+  off = 0;
+  ign = 0;
+  count_leading_zeros (cnt, exp);
+  for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
+    {
+      mpn_sqr (tp, rp + off, rn);
+      rn = 2 * rn;
+      rn -= tp[rn - 1] == 0;
+      ign <<= 1;
+
+      off = 0;
+      if (rn > prec)
+	{
+	  ign += rn - prec;
+	  off = rn - prec;
+	  rn = prec;
+	}
+      MP_PTR_SWAP (rp, tp);
+
+      if (((exp >> i) & 1) != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_mul_1 (rp, rp + off, rn, base);
+	  rp[rn] = cy;
+	  rn += cy != 0;
+	  off = 0;
+	}
+    }
+
+  if (rn > prec)
+    {
+      ASSERT (rn == prec + 1);
+
+      ign += rn - prec;
+      rp += rn - prec;
+      rn = prec;
+    }
+
+  /* With somewhat less than 50% probability, we can skip this copy.  */
+  if (passed_rp != rp + off)
+    MPN_COPY_INCR (passed_rp, rp + off, rn);
+  *ignp = ign;
+  return rn;
+}
+
+char *
+mpf_get_str (char *dbuf, mp_exp_t *exp, int base, size_t n_digits, mpf_srcptr u)
+{
+  mp_exp_t ue;
+  mp_size_t n_limbs_needed;
+  size_t max_digits;
+  mp_ptr up, pp, tp;
+  mp_size_t un, pn, tn;
+  unsigned char *tstr;
+  mp_exp_t exp_in_base;
+  size_t n_digits_computed;
+  mp_size_t i;
+  const char *num_to_text;
+  size_t alloc_size = 0;
+  char *dp;
+  TMP_DECL;
+
+  up = PTR(u);
+  un = ABSIZ(u);
+  ue = EXP(u);
+
+  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (UNLIKELY (base > 62))
+	    return NULL;
+    }
+  else if (base > -2)
+    {
+      base = 10;
+    }
+  else
+    {
+      base = -base;
+      if (UNLIKELY (base > 36))
+	return NULL;
+    }
+
+  MPF_SIGNIFICANT_DIGITS (max_digits, base, PREC(u));
+  if (n_digits == 0 || n_digits > max_digits)
+    n_digits = max_digits;
+
+  if (dbuf == 0)
+    {
+      /* We didn't get a string from the user.  Allocate one (and return
+	 a pointer to it) with space for `-' and terminating null.  */
+      alloc_size = n_digits + 2;
+      dbuf = __GMP_ALLOCATE_FUNC_TYPE (n_digits + 2, char);
+    }
+
+  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);
+
+  LIMBS_PER_DIGIT_IN_BASE (n_limbs_needed, n_digits, base);
+
+  if (un > n_limbs_needed)
+    {
+      up += un - n_limbs_needed;
+      un = n_limbs_needed;
+    }
+
+  TMP_ALLOC_LIMBS_2 (pp, 2 * n_limbs_needed + 4,
+		     tp, 2 * n_limbs_needed + 4);
+
+  if (ue <= n_limbs_needed)
+    {
+      /* We need to multiply number by base^n to get an n_digits integer part.  */
+      mp_size_t n_more_limbs_needed, ign, off;
+      unsigned long e;
+
+      n_more_limbs_needed = n_limbs_needed - ue;
+      DIGITS_IN_BASE_PER_LIMB (e, n_more_limbs_needed, base);
+
+      pn = mpn_pow_1_highpart (pp, &ign, (mp_limb_t) base, e, n_limbs_needed + 1, tp);
+      if (un > pn)
+	mpn_mul (tp, up, un, pp, pn);	/* FIXME: mpn_mul_highpart */
+      else
+	mpn_mul (tp, pp, pn, up, un);	/* FIXME: mpn_mul_highpart */
+      tn = un + pn;
+      tn -= tp[tn - 1] == 0;
+      off = un - ue - ign;
+      if (off < 0)
+	{
+	  MPN_COPY_DECR (tp - off, tp, tn);
+	  MPN_ZERO (tp, -off);
+	  tn -= off;
+	  off = 0;
+	}
+      n_digits_computed = mpn_get_str (tstr, base, tp + off, tn - off);
+
+      exp_in_base = n_digits_computed - e;
+    }
+  else
+    {
+      /* We need to divide number by base^n to get an n_digits integer part.  */
+      mp_size_t n_less_limbs_needed, ign, off, xn;
+      unsigned long e;
+      mp_ptr dummyp, xp;
+
+      n_less_limbs_needed = ue - n_limbs_needed;
+      DIGITS_IN_BASE_PER_LIMB (e, n_less_limbs_needed, base);
+
+      pn = mpn_pow_1_highpart (pp, &ign, (mp_limb_t) base, e, n_limbs_needed + 1, tp);
+
+      xn = n_limbs_needed + (n_less_limbs_needed-ign);
+      xp = TMP_ALLOC_LIMBS (xn);
+      off = xn - un;
+      MPN_ZERO (xp, off);
+      MPN_COPY (xp + off, up, un);
+
+      dummyp = TMP_ALLOC_LIMBS (pn);
+      mpn_tdiv_qr (tp, dummyp, (mp_size_t) 0, xp, xn, pp, pn);
+      tn = xn - pn + 1;
+      tn -= tp[tn - 1] == 0;
+      n_digits_computed = mpn_get_str (tstr, base, tp, tn);
+
+      exp_in_base = n_digits_computed + e;
+    }
+
+  /* We should normally have computed too many digits.  Round the result
+     at the point indicated by n_digits.  */
+  if (n_digits_computed > n_digits)
+    {
+      size_t i;
+      /* Round the result.  */
+      if (tstr[n_digits] * 2 >= base)
+	{
+	  n_digits_computed = n_digits;
+	  for (i = n_digits - 1;; i--)
+	    {
+	      unsigned int x;
+	      x = ++(tstr[i]);
+	      if (x != base)
+		break;
+	      n_digits_computed--;
+	      if (i == 0)
+		{
+		  /* We had something like `bbbbbbb...bd', where 2*d >= base
+		     and `b' denotes digit with significance base - 1.
+		     This rounds up to `1', increasing the exponent.  */
+		  tstr[0] = 1;
+		  n_digits_computed = 1;
+		  exp_in_base++;
+		  break;
+		}
+	    }
+	}
+    }
+
+  /* We might have fewer digits than requested as a result of rounding above,
+     (i.e. 0.999999 => 1.0) or because we have a number that simply doesn't
+     need many digits in this base (e.g., 0.125 in base 10).  */
+  if (n_digits > n_digits_computed)
+    n_digits = n_digits_computed;
+
+  /* Remove trailing 0.  There can be many zeros.  */
+  while (n_digits != 0 && tstr[n_digits - 1] == 0)
+    n_digits--;
+
+  dp = dbuf + (SIZ(u) < 0);
+
+  /* Translate to ASCII and copy to result string.  */
+  for (i = 0; i < n_digits; i++)
+    dp[i] = num_to_text[tstr[i]];
+  dp[n_digits] = 0;
+
+  *exp = exp_in_base;
+
+  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);
+    }
+
+  return dbuf;
+}
diff --git a/mpf/get_ui.c b/mpf/get_ui.c
new file mode 100644
index 0000000..e7b9333
--- /dev/null
+++ b/mpf/get_ui.c
@@ -0,0 +1,101 @@
+/* mpf_get_ui -- mpf to ulong conversion
+
+Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Any fraction bits are truncated, meaning simply discarded.
+
+   For values bigger than a ulong, the low bits are returned (the low
+   absolute value bits actually), like mpz_get_ui, but this isn't
+   documented.
+
+   Notice this is equivalent to mpz_set_f + mpz_get_ui.
+
+
+   Implementation:
+
+   The limb just above the radix point for us to extract is ptr[size-exp].
+
+   We need to check that the size-exp index falls in our available data
+   range, 0 to size-1 inclusive.  We test this without risk of an overflow
+   involving exp by requiring size>=exp (giving size-exp >= 0) and exp>0
+   (giving size-exp <= size-1).
+
+   Notice if size==0 there's no fetch, since of course size>=exp and exp>0
+   can only be true if size>0.  So there's no special handling for size==0,
+   it comes out as 0 the same as any other time we have no data at our
+   target index.
+
+   For nails, the second limb above the radix point is also required, this
+   is ptr[size-exp+1].
+
+   Again we need to check that size-exp+1 falls in our data range, 0 to
+   size-1 inclusive.  We test without risk of overflow by requiring
+   size+1>=exp (giving size-exp+1 >= 0) and exp>1 (giving size-exp+1 <=
+   size-1).
+
+   And again if size==0 these second fetch conditions are not satisfied
+   either since size+1>=exp and exp>1 are only true if size>0.
+
+   The code is arranged with exp>0 wrapping the exp>1 test since exp>1 is
+   mis-compiled by alpha gcc prior to version 3.4.  It re-writes it as
+   exp-1>0, which is incorrect when exp==MP_EXP_T_MIN.  By having exp>0
+   tested first we ensure MP_EXP_T_MIN doesn't reach exp>1.  */
+
+unsigned long
+mpf_get_ui (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  mp_srcptr fp;
+  mp_limb_t fl;
+
+  exp = EXP (f);
+  size = SIZ (f);
+  fp = PTR (f);
+
+  fl = 0;
+  if (exp > 0)
+    {
+      /* there are some limbs above the radix point */
+
+      size = ABS (size);
+      if (size >= exp)
+        fl = fp[size-exp];
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+      if (exp > 1 && size+1 >= exp)
+        fl += (fp[size-exp+1] << GMP_NUMB_BITS);
+#endif
+    }
+
+  return (unsigned long) fl;
+}
diff --git a/mpf/init.c b/mpf/init.c
new file mode 100644
index 0000000..26ab262
--- /dev/null
+++ b/mpf/init.c
@@ -0,0 +1,41 @@
+/* mpf_init() -- Make a new multiple precision number with value 0.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init (mpf_ptr r)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  r->_mp_size = 0;
+  r->_mp_exp = 0;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+}
diff --git a/mpf/init2.c b/mpf/init2.c
new file mode 100644
index 0000000..b90a08a
--- /dev/null
+++ b/mpf/init2.c
@@ -0,0 +1,43 @@
+/* mpf_init2() -- Make a new multiple precision number with value 0.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init2 (mpf_ptr r, mp_bitcnt_t prec_in_bits)
+{
+  mp_size_t prec;
+
+  prec = __GMPF_BITS_TO_PREC (prec_in_bits);
+  r->_mp_size = 0;
+  r->_mp_exp = 0;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+}
diff --git a/mpf/inits.c b/mpf/inits.c
new file mode 100644
index 0000000..b6d054f
--- /dev/null
+++ b/mpf/inits.c
@@ -0,0 +1,49 @@
+/* mpf_inits() -- Initialize multiple mpf_t variables and set them to 0.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpf_inits (mpf_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      mpf_init (x);
+      x = va_arg (ap, mpf_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/mpf/inp_str.c b/mpf/inp_str.c
new file mode 100644
index 0000000..c661a79
--- /dev/null
+++ b/mpf/inp_str.c
@@ -0,0 +1,92 @@
+/* mpf_inp_str(dest_float, stream, base) -- Input a number in base
+   BASE from stdio stream STREAM and store the result in DEST_FLOAT.
+
+Copyright 1996, 2000-2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+
+size_t
+mpf_inp_str (mpf_ptr rop, FILE *stream, int base)
+{
+  char *str;
+  size_t alloc_size, str_size;
+  int c;
+  int res;
+  size_t nread;
+
+  if (stream == 0)
+    stream = stdin;
+
+  alloc_size = 100;
+  str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
+  str_size = 0;
+  nread = 0;
+
+  /* Skip whitespace.  */
+  do
+    {
+      c = getc (stream);
+      nread++;
+    }
+  while (isspace (c));
+
+  for (;;)
+    {
+      if (str_size >= alloc_size)
+	{
+	  size_t old_alloc_size = alloc_size;
+	  alloc_size = alloc_size * 3 / 2;
+	  str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
+	}
+      if (c == EOF || isspace (c))
+	break;
+      str[str_size++] = c;
+      c = getc (stream);
+    }
+  ungetc (c, stream);
+  nread--;
+
+  if (str_size >= alloc_size)
+    {
+      size_t old_alloc_size = alloc_size;
+      alloc_size = alloc_size * 3 / 2;
+      str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
+    }
+  str[str_size] = 0;
+
+  res = mpf_set_str (rop, str, base);
+  (*__gmp_free_func) (str, alloc_size);
+
+  if (res == -1)
+    return 0;			/* error */
+
+  return str_size + nread;
+}
diff --git a/mpf/int_p.c b/mpf/int_p.c
new file mode 100644
index 0000000..024cfb5
--- /dev/null
+++ b/mpf/int_p.c
@@ -0,0 +1,55 @@
+/* mpf_integer_p -- test whether an mpf is an integer */
+
+/*
+Copyright 2001, 2002, 2014-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpf_integer_p (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_srcptr fp;
+  mp_exp_t exp;
+  mp_size_t size;
+
+  size = SIZ (f);
+  exp = EXP (f);
+  if (exp <= 0)
+    return (size == 0);  /* zero is an integer,
+			    others have only fraction limbs */
+  size = ABS (size);
+
+  /* Ignore zeroes at the low end of F.  */
+  for (fp = PTR (f); *fp == 0; ++fp)
+    --size;
+
+  /* no fraction limbs */
+  return size <= exp;
+}
diff --git a/mpf/iset.c b/mpf/iset.c
new file mode 100644
index 0000000..07f9006
--- /dev/null
+++ b/mpf/iset.c
@@ -0,0 +1,61 @@
+/* mpf_init_set -- Initialize a float and assign it from another float.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set (mpf_ptr r, mpf_srcptr s)
+{
+  mp_ptr rp, sp;
+  mp_size_t ssize, size;
+  mp_size_t prec;
+
+  prec = __gmp_default_fp_limb_precision;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+  r->_mp_prec = prec;
+
+  prec++;		/* lie not to lose precision in assignment */
+  ssize = s->_mp_size;
+  size = ABS (ssize);
+
+  rp = r->_mp_d;
+  sp = s->_mp_d;
+
+  if (size > prec)
+    {
+      sp += size - prec;
+      size = prec;
+    }
+
+  r->_mp_exp = s->_mp_exp;
+  r->_mp_size = ssize >= 0 ? size : -size;
+
+  MPN_COPY (rp, sp, size);
+}
diff --git a/mpf/iset_d.c b/mpf/iset_d.c
new file mode 100644
index 0000000..2f36240
--- /dev/null
+++ b/mpf/iset_d.c
@@ -0,0 +1,41 @@
+/* mpf_init_set_d -- Initialize a float and assign it from a double.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set_d (mpf_ptr r, double val)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+
+  mpf_set_d (r, val);
+}
diff --git a/mpf/iset_si.c b/mpf/iset_si.c
new file mode 100644
index 0000000..65abb9a
--- /dev/null
+++ b/mpf/iset_si.c
@@ -0,0 +1,57 @@
+/* mpf_init_set_si() -- Initialize a float and assign it from a signed int.
+
+Copyright 1993-1995, 2000, 2001, 2003, 2004, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set_si (mpf_ptr r, long int val)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  mp_size_t size;
+  mp_limb_t vl;
+
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  r->_mp_d[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  vl >>= GMP_NUMB_BITS;
+  r->_mp_d[1] = vl;
+  size += (vl != 0);
+#endif
+
+  r->_mp_exp = size;
+  r->_mp_size = val >= 0 ? size : -size;
+}
diff --git a/mpf/iset_str.c b/mpf/iset_str.c
new file mode 100644
index 0000000..10acda9
--- /dev/null
+++ b/mpf/iset_str.c
@@ -0,0 +1,43 @@
+/* mpf_init_set_str -- Initialize a float and assign it from a string.
+
+Copyright 1995, 1996, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_init_set_str (mpf_ptr r, const char *s, int base)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  r->_mp_size = 0;
+  r->_mp_exp = 0;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+
+  return mpf_set_str (r, s, base);
+}
diff --git a/mpf/iset_ui.c b/mpf/iset_ui.c
new file mode 100644
index 0000000..2c426bf
--- /dev/null
+++ b/mpf/iset_ui.c
@@ -0,0 +1,52 @@
+/* mpf_init_set_ui() -- Initialize a float and assign it from an unsigned int.
+
+Copyright 1993-1995, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set_ui (mpf_ptr r, unsigned long int val)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  mp_size_t size;
+
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+  r->_mp_d[0] = val & GMP_NUMB_MASK;
+  size = (val != 0);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  val >>= GMP_NUMB_BITS;
+  r->_mp_d[1] = val;
+  size += (val != 0);
+#endif
+
+  r->_mp_size = size;
+  r->_mp_exp = size;
+}
diff --git a/mpf/mul.c b/mpf/mul.c
new file mode 100644
index 0000000..518c060
--- /dev/null
+++ b/mpf/mul.c
@@ -0,0 +1,134 @@
+/* mpf_mul -- Multiply two floats.
+
+Copyright 1993, 1994, 1996, 2001, 2005, 2019, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_mul (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_size_t sign_product;
+  mp_size_t prec = PREC (r);
+  mp_size_t rsize;
+  mp_limb_t cy_limb;
+  mp_ptr rp, tp;
+  mp_size_t adj;
+  TMP_DECL;
+
+  if (u == v)
+    {
+      mp_srcptr up;
+      mp_size_t usize;
+
+      sign_product = 0;
+
+      usize = ABSIZ (u);
+
+      up = PTR (u);
+      if (usize > prec)
+	{
+	  up += usize - prec;
+	  usize = prec;
+	}
+
+      if (usize == 0)
+	{
+	  SIZ (r) = 0;
+	  EXP (r) = 0;		/* ??? */
+	  return;
+	}
+      else
+	{
+	  TMP_MARK;
+	  rsize = 2 * usize;
+	  tp = TMP_ALLOC_LIMBS (rsize);
+
+	  mpn_sqr (tp, up, usize);
+	  cy_limb = tp[rsize - 1];
+	}
+    }
+  else
+    {
+      mp_srcptr up, vp;
+      mp_size_t usize, vsize;
+
+      usize = SIZ (u);
+      vsize = SIZ (v);
+      sign_product = usize ^ vsize;
+
+      usize = ABS (usize);
+      vsize = ABS (vsize);
+
+      up = PTR (u);
+      vp = PTR (v);
+      if (usize > prec)
+	{
+	  up += usize - prec;
+	  usize = prec;
+	}
+      if (vsize > prec)
+	{
+	  vp += vsize - prec;
+	  vsize = prec;
+	}
+
+      if (usize == 0 || vsize == 0)
+	{
+	  SIZ (r) = 0;
+	  EXP (r) = 0;
+	  return;
+	}
+      else
+	{
+	  TMP_MARK;
+	  rsize = usize + vsize;
+	  tp = TMP_ALLOC_LIMBS (rsize);
+	  cy_limb = (usize >= vsize
+		     ? mpn_mul (tp, up, usize, vp, vsize)
+		     : mpn_mul (tp, vp, vsize, up, usize));
+
+	}
+    }
+
+  adj = cy_limb == 0;
+  rsize -= adj;
+  prec++;
+  if (rsize > prec)
+    {
+      tp += rsize - prec;
+      rsize = prec;
+    }
+  rp = PTR (r);
+  MPN_COPY (rp, tp, rsize);
+  EXP (r) = EXP (u) + EXP (v) - adj;
+  SIZ (r) = sign_product >= 0 ? rsize : -rsize;
+
+  TMP_FREE;
+}
diff --git a/mpf/mul_2exp.c b/mpf/mul_2exp.c
new file mode 100644
index 0000000..5de7363
--- /dev/null
+++ b/mpf/mul_2exp.c
@@ -0,0 +1,132 @@
+/* mpf_mul_2exp -- Multiply a float by 2^n.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Multiples of GMP_NUMB_BITS in exp simply mean an amount added to EXP(u)
+   to set EXP(r).  The remainder exp%GMP_NUMB_BITS is then a left shift for
+   the limb data.
+
+   If exp%GMP_NUMB_BITS == 0 then there's no shifting, we effectively just
+   do an mpz_set with changed EXP(r).  Like mpz_set we take prec+1 limbs in
+   this case.  Although just prec would suffice, it's nice to have
+   mpf_mul_2exp with exp==0 come out the same as mpz_set.
+
+   When shifting we take up to prec many limbs from the input.  Our shift is
+   cy = mpn_lshift (PTR(r), PTR(u)+k, size, ...), where k is the number of
+   low limbs dropped from u, and the carry out is stored to PTR(r)[size].
+
+   It may be noted that the low limb PTR(r)[0] doesn't incorporate bits from
+   PTR(u)[k-1] (when k>=1 makes that limb available).  Taking just prec
+   limbs from the input (with the high non-zero) is enough bits for the
+   application requested precision, there's no need for extra work.
+
+   If r==u the shift will have overlapping operands.  When k==0 (ie. when
+   usize <= prec), the overlap is supported by lshift (ie. dst == src).
+
+   But when r==u and k>=1 (ie. usize > prec), we would have an invalid
+   overlap (ie. mpn_lshift (rp, rp+k, ...)).  In this case we must instead
+   use mpn_rshift (PTR(r)+1, PTR(u)+k, size, NUMB-shift) with the carry out
+   stored to PTR(r)[0].  An rshift by NUMB-shift bits like this gives
+   identical data, it's just its overlap restrictions which differ.
+
+   Enhancements:
+
+   The way mpn_lshift is used means successive mpf_mul_2exp calls on the
+   same operand will accumulate low zero limbs, until prec+1 limbs is
+   reached.  This is wasteful for subsequent operations.  When abs_usize <=
+   prec, we should test the low exp%GMP_NUMB_BITS many bits of PTR(u)[0],
+   ie. those which would be shifted out by an mpn_rshift.  If they're zero
+   then use that mpn_rshift.  */
+
+void
+mpf_mul_2exp (mpf_ptr r, mpf_srcptr u, mp_bitcnt_t exp)
+{
+  mp_srcptr up;
+  mp_ptr rp = r->_mp_d;
+  mp_size_t usize;
+  mp_size_t abs_usize;
+  mp_size_t prec = r->_mp_prec;
+  mp_exp_t uexp = u->_mp_exp;
+
+  usize = u->_mp_size;
+
+  if (UNLIKELY (usize == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  abs_usize = ABS (usize);
+  up = u->_mp_d;
+
+  if (exp % GMP_NUMB_BITS == 0)
+    {
+      prec++;			/* retain more precision here as we don't need
+				   to account for carry-out here */
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	}
+      if (rp != up)
+	MPN_COPY_INCR (rp, up, abs_usize);
+      r->_mp_exp = uexp + exp / GMP_NUMB_BITS;
+    }
+  else
+    {
+      mp_limb_t cy_limb;
+      mp_size_t adj;
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	  /* Use mpn_rshift since mpn_lshift operates downwards, and we
+	     therefore would clobber part of U before using that part, in case
+	     R is the same variable as U.  */
+	  cy_limb = mpn_rshift (rp + 1, up, abs_usize,
+				GMP_NUMB_BITS - exp % GMP_NUMB_BITS);
+	  rp[0] = cy_limb;
+	  adj = rp[abs_usize] != 0;
+	}
+      else
+	{
+	  cy_limb = mpn_lshift (rp, up, abs_usize, exp % GMP_NUMB_BITS);
+	  rp[abs_usize] = cy_limb;
+	  adj = cy_limb != 0;
+	}
+
+      abs_usize += adj;
+      r->_mp_exp = uexp + exp / GMP_NUMB_BITS + adj;
+    }
+  r->_mp_size = usize >= 0 ? abs_usize : -abs_usize;
+}
diff --git a/mpf/mul_ui.c b/mpf/mul_ui.c
new file mode 100644
index 0000000..30da6ae
--- /dev/null
+++ b/mpf/mul_ui.c
@@ -0,0 +1,181 @@
+/* mpf_mul_ui -- Multiply a float and an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The core operation is a multiply of PREC(r) limbs from u by v, producing
+   either PREC(r) or PREC(r)+1 result limbs.  If u is shorter than PREC(r),
+   then we take only as much as it has.  If u is longer we incorporate a
+   carry from the lower limbs.
+
+   If u has just 1 extra limb, then the carry to add is high(up[0]*v).  That
+   is of course what mpn_mul_1 would do if it was called with PREC(r)+1
+   limbs of input.
+
+   If u has more than 1 extra limb, then there can be a further carry bit
+   out of lower uncalculated limbs (the way the low of one product adds to
+   the high of the product below it).  This is of course what an mpn_mul_1
+   would do if it was called with the full u operand.  But we instead work
+   downwards explicitly, until a carry occurs or until a value other than
+   GMP_NUMB_MAX occurs (that being the only value a carry bit can propagate
+   across).
+
+   The carry determination normally requires two umul_ppmm's, only rarely
+   will GMP_NUMB_MAX occur and require further products.
+
+   The carry limb is conveniently added into the mul_1 using mpn_mul_1c when
+   that function exists, otherwise a subsequent mpn_add_1 is needed.
+
+   Clearly when mpn_mul_1c is used the carry must be calculated first.  But
+   this is also the case when add_1 is used, since if r==u and ABSIZ(r) >
+   PREC(r) then the mpn_mul_1 overwrites the low part of the input.
+
+   A reuse r==u with size > prec can occur from a size PREC(r)+1 in the
+   usual way, or it can occur from an mpf_set_prec_raw leaving a bigger
+   sized value.  In both cases we can end up calling mpn_mul_1 with
+   overlapping src and dst regions, but this will be with dst < src and such
+   an overlap is permitted.
+
+   Not done:
+
+   No attempt is made to determine in advance whether the result will be
+   PREC(r) or PREC(r)+1 limbs.  If it's going to be PREC(r)+1 then we could
+   take one less limb from u and generate just PREC(r), that of course
+   satisfying application requested precision.  But any test counting bits
+   or forming the high product would almost certainly take longer than the
+   incremental cost of an extra limb in mpn_mul_1.
+
+   Enhancements:
+
+   Repeated mpf_mul_ui's with an even v will accumulate low zero bits on the
+   result, leaving low zero limbs after a while, which it might be nice to
+   strip to save work in subsequent operations.  Calculating the low limb
+   explicitly would let us direct mpn_mul_1 to put the balance at rp when
+   the low is zero (instead of normally rp+1).  But it's not clear whether
+   this would be worthwhile.  Explicit code for the low limb will probably
+   be slower than having it done in mpn_mul_1, so we need to consider how
+   often a zero will be stripped and how much that's likely to save
+   later.  */
+
+void
+mpf_mul_ui (mpf_ptr r, mpf_srcptr u, unsigned long int v)
+{
+  mp_srcptr up;
+  mp_size_t usize;
+  mp_size_t size;
+  mp_size_t prec, excess;
+  mp_limb_t cy_limb, vl, cbit, cin;
+  mp_ptr rp;
+
+  usize = u->_mp_size;
+  if (UNLIKELY (v == 0) || UNLIKELY (usize == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpf_t     vf;
+      mp_limb_t vp[2];
+      vp[0] = v & GMP_NUMB_MASK;
+      vp[1] = v >> GMP_NUMB_BITS;
+      PTR(vf) = vp;
+      SIZ(vf) = 2;
+      ASSERT_CODE (PREC(vf) = 2);
+      EXP(vf) = 2;
+      mpf_mul (r, u, vf);
+      return;
+    }
+#endif
+
+  size = ABS (usize);
+  prec = r->_mp_prec;
+  up = u->_mp_d;
+  vl = v;
+  excess = size - prec;
+  cin = 0;
+
+  if (excess > 0)
+    {
+      /* up is bigger than desired rp, shorten it to prec limbs and
+         determine a carry-in */
+
+      mp_limb_t  vl_shifted = vl << GMP_NAIL_BITS;
+      mp_limb_t  hi, lo, next_lo, sum;
+      mp_size_t  i;
+
+      /* high limb of top product */
+      i = excess - 1;
+      umul_ppmm (cin, lo, up[i], vl_shifted);
+
+      /* and carry bit out of products below that, if any */
+      for (;;)
+        {
+          i--;
+          if (i < 0)
+            break;
+
+          umul_ppmm (hi, next_lo, up[i], vl_shifted);
+          lo >>= GMP_NAIL_BITS;
+          ADDC_LIMB (cbit, sum, hi, lo);
+          cin += cbit;
+          lo = next_lo;
+
+          /* Continue only if the sum is GMP_NUMB_MAX.  GMP_NUMB_MAX is the
+             only value a carry from below can propagate across.  If we've
+             just seen the carry out (ie. cbit!=0) then sum!=GMP_NUMB_MAX,
+             so this test stops us for that case too.  */
+          if (LIKELY (sum != GMP_NUMB_MAX))
+            break;
+        }
+
+      up += excess;
+      size = prec;
+    }
+
+  rp = r->_mp_d;
+#if HAVE_NATIVE_mpn_mul_1c
+  cy_limb = mpn_mul_1c (rp, up, size, vl, cin);
+#else
+  cy_limb = mpn_mul_1 (rp, up, size, vl);
+  __GMPN_ADD_1 (cbit, rp, rp, size, cin);
+  cy_limb += cbit;
+#endif
+  rp[size] = cy_limb;
+  cy_limb = cy_limb != 0;
+  r->_mp_exp = u->_mp_exp + cy_limb;
+  size += cy_limb;
+  r->_mp_size = usize >= 0 ? size : -size;
+}
diff --git a/mpf/neg.c b/mpf/neg.c
new file mode 100644
index 0000000..d294815
--- /dev/null
+++ b/mpf/neg.c
@@ -0,0 +1,61 @@
+/* mpf_neg -- Negate a float.
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_neg (mpf_ptr r, mpf_srcptr u)
+{
+  mp_size_t size;
+
+  size = -u->_mp_size;
+  if (r != u)
+    {
+      mp_size_t prec;
+      mp_size_t asize;
+      mp_ptr rp, up;
+
+      prec = r->_mp_prec + 1;	/* lie not to lose precision in assignment */
+      asize = ABS (size);
+      rp = r->_mp_d;
+      up = u->_mp_d;
+
+      if (asize > prec)
+	{
+	  up += asize - prec;
+	  asize = prec;
+	}
+
+      MPN_COPY (rp, up, asize);
+      r->_mp_exp = u->_mp_exp;
+      size = size >= 0 ? asize : -asize;
+    }
+  r->_mp_size = size;
+}
diff --git a/mpf/out_str.c b/mpf/out_str.c
new file mode 100644
index 0000000..1802d0f
--- /dev/null
+++ b/mpf/out_str.c
@@ -0,0 +1,116 @@
+/* mpf_out_str (stream, base, n_digits, op) -- Print N_DIGITS digits from
+   the float OP to STREAM in base BASE.  Return the number of characters
+   written, or 0 if an error occurred.
+
+Copyright 1996, 1997, 2001, 2002, 2005, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+size_t
+mpf_out_str (FILE *stream, int base, size_t n_digits, mpf_srcptr op)
+{
+  char *str;
+  mp_exp_t exp;
+  size_t written;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (base == 0)
+    base = 10;
+  if (n_digits == 0)
+    MPF_SIGNIFICANT_DIGITS (n_digits, base, op->_mp_prec);
+
+  if (stream == 0)
+    stream = stdout;
+
+  /* Consider these changes:
+     * Don't allocate memory here for huge n_digits; pass NULL to mpf_get_str.
+     * Make mpf_get_str allocate extra space when passed NULL, to avoid
+       allocating two huge string buffers.
+     * Implement more/other allocation reductions tricks.  */
+
+  str = (char *) TMP_ALLOC (n_digits + 2); /* extra for minus sign and \0 */
+
+  mpf_get_str (str, &exp, base, n_digits, op);
+  n_digits = strlen (str);
+
+  written = 0;
+
+  /* Write sign */
+  if (str[0] == '-')
+    {
+      str++;
+      fputc ('-', stream);
+      written = 1;
+      n_digits--;
+    }
+
+  {
+    const char  *point = GMP_DECIMAL_POINT;
+    size_t      pointlen = strlen (point);
+    putc ('0', stream);
+    fwrite (point, 1, pointlen, stream);
+    written += pointlen + 1;
+  }
+
+  /* Write mantissa */
+  {
+    size_t fwret;
+    fwret = fwrite (str, 1, n_digits, stream);
+    written += fwret;
+  }
+
+  /* Write exponent */
+  {
+    int fpret;
+    fpret = fprintf (stream, (base <= 10 ? "e%ld" : "@%ld"), exp);
+    written += fpret;
+  }
+
+  TMP_FREE;
+  return ferror (stream) ? 0 : written;
+}
diff --git a/mpf/pow_ui.c b/mpf/pow_ui.c
new file mode 100644
index 0000000..8d54dc0
--- /dev/null
+++ b/mpf/pow_ui.c
@@ -0,0 +1,83 @@
+/* mpf_pow_ui -- Compute b^e.
+
+Copyright 1998, 1999, 2001, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* This uses a plain right-to-left square-and-multiply algorithm.
+
+   FIXME: When popcount(e) is not too small, it would probably speed things up
+   to use a k-ary sliding window algorithm.  */
+
+void
+mpf_pow_ui (mpf_ptr r, mpf_srcptr b, unsigned long int e)
+{
+  mpf_t t;
+  int cnt;
+
+  if (e <= 1)
+    {
+      if (e == 0)
+	mpf_set_ui (r, 1);
+      else
+	mpf_set (r, b);
+      return;
+    }
+
+  count_leading_zeros (cnt, (mp_limb_t) e);
+  cnt = GMP_LIMB_BITS - 1 - cnt;
+
+  /* Increase computation precision as a function of the exponent.  Adding
+     log2(popcount(e) + log2(e)) bits should be sufficient, but we add log2(e),
+     i.e. much more.  With mpf's rounding of precision to whole limbs, this
+     will be excessive only when limbs are artificially small.  */
+  mpf_init2 (t, mpf_get_prec (r) + cnt);
+
+  mpf_set (t, b);		/* consume most significant bit */
+  while (--cnt > 0)
+    {
+      mpf_mul (t, t, t);
+      if ((e >> cnt) & 1)
+	mpf_mul (t, t, b);
+    }
+
+  /* Do the last iteration specially in order to save a copy operation.  */
+  if (e & 1)
+    {
+      mpf_mul (t, t, t);
+      mpf_mul (r, t, b);
+    }
+  else
+    {
+      mpf_mul (r, t, t);
+    }
+
+  mpf_clear (t);
+}
diff --git a/mpf/random2.c b/mpf/random2.c
new file mode 100644
index 0000000..2e0163c
--- /dev/null
+++ b/mpf/random2.c
@@ -0,0 +1,66 @@
+/* mpf_random2 -- Generate a positive random mpf_t of specified size, with
+   long runs of consecutive ones and zeros in the binary representation.
+   Intended for testing of other MP routines.
+
+Copyright 1995, 1996, 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpf_random2 (mpf_ptr x, mp_size_t xs, mp_exp_t exp)
+{
+  mp_size_t xn;
+  mp_size_t prec;
+  mp_limb_t elimb;
+
+  xn = ABS (xs);
+  prec = PREC(x);
+
+  if (xn == 0)
+    {
+      EXP(x) = 0;
+      SIZ(x) = 0;
+      return;
+    }
+
+  if (xn > prec + 1)
+    xn = prec + 1;
+
+  /* General random mantissa.  */
+  mpn_random2 (PTR(x), xn);
+
+  /* Generate random exponent.  */
+  _gmp_rand (&elimb, RANDS, GMP_NUMB_BITS);
+  exp = ABS (exp);
+  exp = elimb % (2 * exp + 1) - exp;
+
+  EXP(x) = exp;
+  SIZ(x) = xs < 0 ? -xn : xn;
+}
diff --git a/mpf/reldiff.c b/mpf/reldiff.c
new file mode 100644
index 0000000..3fe6590
--- /dev/null
+++ b/mpf/reldiff.c
@@ -0,0 +1,64 @@
+/* mpf_reldiff -- Generate the relative difference of two floats.
+
+Copyright 1996, 2001, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* The precision we use for d = x-y is based on what mpf_div will want from
+   the dividend.  It calls mpn_div_q to produce a quotient of rprec+1 limbs.
+   So rprec+1 == dsize - xsize + 1, hence dprec = rprec+xsize.  */
+
+void
+mpf_reldiff (mpf_ptr rdiff, mpf_srcptr x, mpf_srcptr y)
+{
+  if (UNLIKELY (SIZ(x) == 0))
+    {
+      mpf_set_ui (rdiff, (unsigned long int) (mpf_sgn (y) != 0));
+    }
+  else
+    {
+      mp_size_t dprec;
+      mpf_t d;
+      TMP_DECL;
+
+      TMP_MARK;
+      dprec = PREC(rdiff) + ABSIZ(x);
+      ASSERT (PREC(rdiff)+1 == dprec - ABSIZ(x) + 1);
+
+      PREC(d) = dprec;
+      PTR(d) = TMP_ALLOC_LIMBS (dprec + 1);
+
+      mpf_sub (d, x, y);
+      SIZ(d) = ABSIZ(d);
+      mpf_div (rdiff, d, x);
+
+      TMP_FREE;
+    }
+}
diff --git a/mpf/set.c b/mpf/set.c
new file mode 100644
index 0000000..382fe86
--- /dev/null
+++ b/mpf/set.c
@@ -0,0 +1,55 @@
+/* mpf_set -- Assign a float from another float.
+
+Copyright 1993-1995, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set (mpf_ptr r, mpf_srcptr u)
+{
+  mp_ptr rp, up;
+  mp_size_t size, asize;
+  mp_size_t prec;
+
+  prec = r->_mp_prec + 1;		/* lie not to lose precision in assignment */
+  size = u->_mp_size;
+  asize = ABS (size);
+  rp = r->_mp_d;
+  up = u->_mp_d;
+
+  if (asize > prec)
+    {
+      up += asize - prec;
+      asize = prec;
+    }
+
+  r->_mp_exp = u->_mp_exp;
+  r->_mp_size = size >= 0 ? asize : -asize;
+  MPN_COPY_INCR (rp, up, asize);
+}
diff --git a/mpf/set_d.c b/mpf/set_d.c
new file mode 100644
index 0000000..0442f2f
--- /dev/null
+++ b/mpf/set_d.c
@@ -0,0 +1,59 @@
+/* mpf_set_d -- Assign a float from a double.
+
+Copyright 1993-1996, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+void
+mpf_set_d (mpf_ptr r, double d)
+{
+  int negative;
+
+  DOUBLE_NAN_INF_ACTION (d,
+                         __gmp_invalid_operation (),
+                         __gmp_invalid_operation ());
+
+  if (UNLIKELY (d == 0))
+    {
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+  negative = d < 0;
+  d = ABS (d);
+
+  SIZ(r) = negative ? -LIMBS_PER_DOUBLE : LIMBS_PER_DOUBLE;
+  EXP(r) = __gmp_extract_double (PTR(r), d);
+}
diff --git a/mpf/set_dfl_prec.c b/mpf/set_dfl_prec.c
new file mode 100644
index 0000000..9be71c0
--- /dev/null
+++ b/mpf/set_dfl_prec.c
@@ -0,0 +1,39 @@
+/* mpf_set_default_prec --
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_size_t __gmp_default_fp_limb_precision = __GMPF_BITS_TO_PREC (53);
+
+void
+mpf_set_default_prec (mp_bitcnt_t prec_in_bits) __GMP_NOTHROW
+{
+  __gmp_default_fp_limb_precision = __GMPF_BITS_TO_PREC (prec_in_bits);
+}
diff --git a/mpf/set_prc.c b/mpf/set_prc.c
new file mode 100644
index 0000000..40c3f0e
--- /dev/null
+++ b/mpf/set_prc.c
@@ -0,0 +1,68 @@
+/* mpf_set_prec(x) -- Change the precision of x.
+
+Copyright 1993-1995, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* A full new_prec+1 limbs are always retained, even though just new_prec
+   would satisfy the requested precision.  If size==new_prec+1 then
+   certainly new_prec+1 should be kept since no copying is needed in that
+   case.  If just new_prec was kept for size>new_prec+1 it'd be a bit
+   inconsistent.  */
+
+void
+mpf_set_prec (mpf_ptr x, mp_bitcnt_t new_prec_in_bits)
+{
+  mp_size_t  old_prec, new_prec, new_prec_plus1;
+  mp_size_t  size, sign;
+  mp_ptr     xp;
+
+  new_prec = __GMPF_BITS_TO_PREC (new_prec_in_bits);
+  old_prec = PREC(x);
+
+  /* do nothing if already the right precision */
+  if (new_prec == old_prec)
+    return;
+
+  PREC(x) = new_prec;
+  new_prec_plus1 = new_prec + 1;
+
+  /* retain most significant limbs */
+  sign = SIZ(x);
+  size = ABS (sign);
+  xp = PTR(x);
+  if (size > new_prec_plus1)
+    {
+      SIZ(x) = (sign >= 0 ? new_prec_plus1 : -new_prec_plus1);
+      MPN_COPY_INCR (xp, xp + size - new_prec_plus1, new_prec_plus1);
+    }
+
+  PTR(x) = __GMP_REALLOCATE_FUNC_LIMBS (xp, old_prec+1, new_prec_plus1);
+}
diff --git a/mpf/set_prc_raw.c b/mpf/set_prc_raw.c
new file mode 100644
index 0000000..e5c52cc
--- /dev/null
+++ b/mpf/set_prc_raw.c
@@ -0,0 +1,39 @@
+/* mpf_set_prec_raw(x,bits) -- Change the precision of x without changing
+   allocation.  For proper operation, the original precision need to be reset
+   sooner or later.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_prec_raw (mpf_ptr x, mp_bitcnt_t prec_in_bits) __GMP_NOTHROW
+{
+  x->_mp_prec = __GMPF_BITS_TO_PREC (prec_in_bits);
+}
diff --git a/mpf/set_q.c b/mpf/set_q.c
new file mode 100644
index 0000000..b721e3a
--- /dev/null
+++ b/mpf/set_q.c
@@ -0,0 +1,118 @@
+/* mpf_set_q (mpf_t rop, mpq_t op) -- Convert the rational op to the float rop.
+
+Copyright 1996, 1999, 2001, 2002, 2004, 2005, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* As usual the aim is to produce PREC(r) limbs, with the high non-zero.  The
+   basic mpn_div_q produces a quotient of nsize-dsize+1 limbs, with either the
+   high or second highest limb non-zero.  We arrange for nsize-dsize+1 to equal
+   prec+1, hence giving either prec or prec+1 result limbs at PTR(r).
+
+   nsize-dsize+1 == prec+1 is achieved by adjusting num(q), either dropping low
+   limbs if it's too big, or padding with low zeros if it's too small.  The
+   full given den(q) is always used.
+
+   We cannot truncate den(q), because even when it's much bigger than prec the
+   last limbs can still influence the final quotient.  Often they don't, but we
+   leave optimization of that to mpn_div_q.
+
+   Enhancements:
+
+   The high quotient limb is non-zero when high{np,dsize} > {dp,dsize}.  We
+   could make that comparison and use qsize==prec instead of qsize==prec+1,
+   to save one limb in the division.  */
+
+void
+mpf_set_q (mpf_ptr r, mpq_srcptr q)
+{
+  mp_srcptr np, dp;
+  mp_size_t prec, nsize, dsize, qsize, prospective_qsize, tsize, zeros;
+  mp_size_t sign_quotient, high_zero;
+  mp_ptr qp, tp;
+  mp_exp_t exp;
+  TMP_DECL;
+
+  ASSERT (SIZ(&q->_mp_den) > 0);  /* canonical q */
+
+  nsize = SIZ (&q->_mp_num);
+  dsize = SIZ (&q->_mp_den);
+
+  if (UNLIKELY (nsize == 0))
+    {
+      SIZ (r) = 0;
+      EXP (r) = 0;
+      return;
+    }
+
+  TMP_MARK;
+
+  prec = PREC (r);
+  qp = PTR (r);
+
+  sign_quotient = nsize;
+  nsize = ABS (nsize);
+  np = PTR (&q->_mp_num);
+  dp = PTR (&q->_mp_den);
+
+  prospective_qsize = nsize - dsize + 1;  /* q from using given n,d sizes */
+  exp = prospective_qsize;                /* ie. number of integer limbs */
+  qsize = prec + 1;                       /* desired q */
+
+  zeros = qsize - prospective_qsize;      /* n zeros to get desired qsize */
+  tsize = nsize + zeros;                  /* size of intermediate numerator */
+  tp = TMP_ALLOC_LIMBS (tsize + 1);       /* +1 for mpn_div_q's scratch */
+
+  if (zeros > 0)
+    {
+      /* pad n with zeros into temporary space */
+      MPN_ZERO (tp, zeros);
+      MPN_COPY (tp+zeros, np, nsize);
+      np = tp;                            /* mpn_div_q allows this overlap */
+    }
+  else
+    {
+      /* shorten n to get desired qsize */
+      np -= zeros;
+    }
+
+  ASSERT (tsize-dsize+1 == qsize);
+  mpn_div_q (qp, np, tsize, dp, dsize, tp);
+
+  /* strip possible zero high limb */
+  high_zero = (qp[qsize-1] == 0);
+  qsize -= high_zero;
+  exp -= high_zero;
+
+  EXP (r) = exp;
+  SIZ (r) = sign_quotient >= 0 ? qsize : -qsize;
+
+  TMP_FREE;
+}
diff --git a/mpf/set_si.c b/mpf/set_si.c
new file mode 100644
index 0000000..23f713d
--- /dev/null
+++ b/mpf/set_si.c
@@ -0,0 +1,52 @@
+/* mpf_set_si() -- Assign a float from a signed int.
+
+Copyright 1993-1995, 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_si (mpf_ptr dest, long val)
+{
+  mp_size_t size;
+  mp_limb_t vl;
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  dest->_mp_d[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  vl >>= GMP_NUMB_BITS;
+  dest->_mp_d[1] = vl;
+  size += (vl != 0);
+#endif
+
+  dest->_mp_exp = size;
+  dest->_mp_size = val >= 0 ? size : -size;
+}
diff --git a/mpf/set_str.c b/mpf/set_str.c
new file mode 100644
index 0000000..c7bfe0b
--- /dev/null
+++ b/mpf/set_str.c
@@ -0,0 +1,412 @@
+/* mpf_set_str (dest, string, base) -- Convert the string STRING
+   in base BASE to a float in dest.  If BASE is zero, the leading characters
+   of STRING is used to figure out the base.
+
+Copyright 1993-1997, 2000-2003, 2005, 2007, 2008, 2011, 2013, 2019 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  This still needs work, as suggested by some FIXME comments.
+  1. Don't depend on superfluous mantissa digits.
+  2. Allocate temp space more cleverly.
+  3. Use mpn_div_q instead of mpn_lshift+mpn_divrem.
+*/
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#define digit_value_tab __gmp_digit_value_tab
+
+/* Compute base^exp and return the most significant prec limbs in rp[].
+   Put the count of omitted low limbs in *ign.
+   Return the actual size (which might be less than prec).  */
+static mp_size_t
+mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
+		    mp_limb_t base, mp_exp_t exp,
+		    mp_size_t prec, mp_ptr tp)
+{
+  mp_size_t ign;		/* counts number of ignored low limbs in r */
+  mp_size_t off;		/* keeps track of offset where value starts */
+  mp_ptr passed_rp = rp;
+  mp_size_t rn;
+  int cnt;
+  int i;
+
+  rp[0] = base;
+  rn = 1;
+  off = 0;
+  ign = 0;
+  count_leading_zeros (cnt, exp);
+  for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
+    {
+      mpn_sqr (tp, rp + off, rn);
+      rn = 2 * rn;
+      rn -= tp[rn - 1] == 0;
+      ign <<= 1;
+
+      off = 0;
+      if (rn > prec)
+	{
+	  ign += rn - prec;
+	  off = rn - prec;
+	  rn = prec;
+	}
+      MP_PTR_SWAP (rp, tp);
+
+      if (((exp >> i) & 1) != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_mul_1 (rp, rp + off, rn, base);
+	  rp[rn] = cy;
+	  rn += cy != 0;
+	  off = 0;
+	}
+    }
+
+  if (rn > prec)
+    {
+      ign += rn - prec;
+      rp += rn - prec;
+      rn = prec;
+    }
+
+  MPN_COPY_INCR (passed_rp, rp + off, rn);
+  *ignp = ign;
+  return rn;
+}
+
+int
+mpf_set_str (mpf_ptr x, const char *str, int base)
+{
+  size_t str_size;
+  char *s, *begs;
+  size_t i, j;
+  int c;
+  int negative;
+  char *dotpos;
+  const char *expptr;
+  int exp_base;
+  const char  *point = GMP_DECIMAL_POINT;
+  size_t      pointlen = strlen (point);
+  const unsigned char *digit_value;
+  int incr;
+  size_t n_zeros_skipped;
+
+  TMP_DECL;
+
+  c = (unsigned char) *str;
+
+  /* Skip whitespace.  */
+  while (isspace (c))
+    c = (unsigned char) *++str;
+
+  negative = 0;
+  if (c == '-')
+    {
+      negative = 1;
+      c = (unsigned char) *++str;
+    }
+
+  /* Default base to decimal.  */
+  if (base == 0)
+    base = 10;
+
+  exp_base = base;
+
+  if (base < 0)
+    {
+      exp_base = 10;
+      base = -base;
+    }
+
+  digit_value = digit_value_tab;
+  if (base > 36)
+    {
+      /* For bases > 36, use the collating sequence
+	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
+      digit_value += 208;
+      if (base > 62)
+	return -1;		/* too large base */
+    }
+
+  /* Require at least one digit, possibly after an initial decimal point.  */
+  if (digit_value[c] >= base)
+    {
+      /* not a digit, must be a decimal point */
+      for (i = 0; i < pointlen; i++)
+	if (str[i] != point[i])
+	  return -1;
+      if (digit_value[(unsigned char) str[pointlen]] >= base)
+	return -1;
+    }
+
+  /* Locate exponent part of the input.  Look from the right of the string,
+     since the exponent is usually a lot shorter than the mantissa.  */
+  expptr = NULL;
+  str_size = strlen (str);
+  for (i = str_size - 1; i > 0; i--)
+    {
+      c = (unsigned char) str[i];
+      if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
+	{
+	  expptr = str + i + 1;
+	  str_size = i;
+	  break;
+	}
+    }
+
+  TMP_MARK;
+  s = begs = (char *) TMP_ALLOC (str_size + 1);
+
+  incr = 0;
+  n_zeros_skipped = 0;
+  dotpos = NULL;
+
+  /* Loop through mantissa, converting it from ASCII to raw byte values.  */
+  for (i = 0; i < str_size; i++)
+    {
+      c = (unsigned char) *str;
+      if (!isspace (c))
+	{
+	  int dig;
+
+	  for (j = 0; j < pointlen; j++)
+	    if (str[j] != point[j])
+	      goto not_point;
+	  if (1)
+	    {
+	      if (dotpos != 0)
+		{
+		  /* already saw a decimal point, another is invalid */
+		  TMP_FREE;
+		  return -1;
+		}
+	      dotpos = s;
+	      str += pointlen - 1;
+	      i += pointlen - 1;
+	    }
+	  else
+	    {
+	    not_point:
+	      dig = digit_value[c];
+	      if (dig >= base)
+		{
+		  TMP_FREE;
+		  return -1;
+		}
+	      *s = dig;
+	      incr |= dig != 0;
+	      s += incr;	/* Increment after first non-0 digit seen. */
+	      if (dotpos != NULL)
+		/* Count skipped zeros between radix point and first non-0
+		   digit. */
+		n_zeros_skipped += 1 - incr;
+	    }
+	}
+      c = (unsigned char) *++str;
+    }
+
+  str_size = s - begs;
+
+  {
+    long exp_in_base;
+    mp_size_t ra, ma, rn, mn;
+    int cnt;
+    mp_ptr mp, tp, rp;
+    mp_exp_t exp_in_limbs;
+    mp_size_t prec = PREC(x) + 1;
+    int divflag;
+    mp_size_t madj, radj;
+
+#if 0
+    size_t n_chars_needed;
+
+    /* This needs careful testing.  Leave disabled for now.  */
+    /* Just consider the relevant leading digits of the mantissa.  */
+    LIMBS_PER_DIGIT_IN_BASE (n_chars_needed, prec, base);
+    if (str_size > n_chars_needed)
+      str_size = n_chars_needed;
+#endif
+
+    if (str_size == 0)
+      {
+	SIZ(x) = 0;
+	EXP(x) = 0;
+	TMP_FREE;
+	return 0;
+      }
+
+    LIMBS_PER_DIGIT_IN_BASE (ma, str_size, base);
+    mp = TMP_ALLOC_LIMBS (ma);
+    mn = mpn_set_str (mp, (unsigned char *) begs, str_size, base);
+
+    madj = 0;
+    /* Ignore excess limbs in MP,MSIZE.  */
+    if (mn > prec)
+      {
+	madj = mn - prec;
+	mp += mn - prec;
+	mn = prec;
+      }
+
+    if (expptr != 0)
+      {
+	/* Scan and convert the exponent, in base exp_base.  */
+	long dig, minus, plusminus;
+	c = (unsigned char) *expptr;
+	minus = -(long) (c == '-');
+	plusminus = minus | -(long) (c == '+');
+	expptr -= plusminus;			/* conditional increment */
+	c = (unsigned char) *expptr++;
+	dig = digit_value[c];
+	if (dig >= exp_base)
+	  {
+	    TMP_FREE;
+	    return -1;
+	  }
+	exp_in_base = dig;
+	c = (unsigned char) *expptr++;
+	dig = digit_value[c];
+	while (dig < exp_base)
+	  {
+	    exp_in_base = exp_in_base * exp_base;
+	    exp_in_base += dig;
+	    c = (unsigned char) *expptr++;
+	    dig = digit_value[c];
+	  }
+	exp_in_base = (exp_in_base ^ minus) - minus; /* conditional negation */
+      }
+    else
+      exp_in_base = 0;
+    if (dotpos != 0)
+      exp_in_base -= s - dotpos + n_zeros_skipped;
+    divflag = exp_in_base < 0;
+    exp_in_base = ABS (exp_in_base);
+
+    if (exp_in_base == 0)
+      {
+	MPN_COPY (PTR(x), mp, mn);
+	SIZ(x) = negative ? -mn : mn;
+	EXP(x) = mn + madj;
+	TMP_FREE;
+	return 0;
+      }
+
+    ra = 2 * (prec + 1);
+    TMP_ALLOC_LIMBS_2 (rp, ra, tp, ra);
+    rn = mpn_pow_1_highpart (rp, &radj, (mp_limb_t) base, exp_in_base, prec, tp);
+
+    if (divflag)
+      {
+#if 0
+	/* FIXME: Should use mpn_div_q here.  */
+	...
+	mpn_div_q (tp, mp, mn, rp, rn, scratch);
+	...
+#else
+	mp_ptr qp;
+	mp_limb_t qlimb;
+	if (mn < rn)
+	  {
+	    /* Pad out MP,MSIZE for current divrem semantics.  */
+	    mp_ptr tmp = TMP_ALLOC_LIMBS (rn + 1);
+	    MPN_ZERO (tmp, rn - mn);
+	    MPN_COPY (tmp + rn - mn, mp, mn);
+	    mp = tmp;
+	    madj -= rn - mn;
+	    mn = rn;
+	  }
+	if ((rp[rn - 1] & GMP_NUMB_HIGHBIT) == 0)
+	  {
+	    mp_limb_t cy;
+	    count_leading_zeros (cnt, rp[rn - 1]);
+	    cnt -= GMP_NAIL_BITS;
+	    mpn_lshift (rp, rp, rn, cnt);
+	    cy = mpn_lshift (mp, mp, mn, cnt);
+	    if (cy)
+	      mp[mn++] = cy;
+	  }
+
+	qp = TMP_ALLOC_LIMBS (prec + 1);
+	qlimb = mpn_divrem (qp, prec - (mn - rn), mp, mn, rp, rn);
+	tp = qp;
+	exp_in_limbs = qlimb + (mn - rn) + (madj - radj);
+	rn = prec;
+	if (qlimb != 0)
+	  {
+	    tp[prec] = qlimb;
+	    /* Skip the least significant limb not to overrun the destination
+	       variable.  */
+	    tp++;
+	  }
+#endif
+      }
+    else
+      {
+	tp = TMP_ALLOC_LIMBS (rn + mn);
+	if (rn > mn)
+	  mpn_mul (tp, rp, rn, mp, mn);
+	else
+	  mpn_mul (tp, mp, mn, rp, rn);
+	rn += mn;
+	rn -= tp[rn - 1] == 0;
+	exp_in_limbs = rn + madj + radj;
+
+	if (rn > prec)
+	  {
+	    tp += rn - prec;
+	    rn = prec;
+	    exp_in_limbs += 0;
+	  }
+      }
+
+    MPN_COPY (PTR(x), tp, rn);
+    SIZ(x) = negative ? -rn : rn;
+    EXP(x) = exp_in_limbs;
+    TMP_FREE;
+    return 0;
+  }
+}
diff --git a/mpf/set_ui.c b/mpf/set_ui.c
new file mode 100644
index 0000000..bd4ba26
--- /dev/null
+++ b/mpf/set_ui.c
@@ -0,0 +1,48 @@
+/* mpf_set_ui() -- Assign a float from an unsigned int.
+
+Copyright 1993-1995, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_ui (mpf_ptr f, unsigned long val)
+{
+  mp_size_t size;
+
+  f->_mp_d[0] = val & GMP_NUMB_MASK;
+  size = val != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  val >>= GMP_NUMB_BITS;
+  f->_mp_d[1] = val;
+  size += (val != 0);
+#endif
+
+  f->_mp_exp = f->_mp_size = size;
+}
diff --git a/mpf/set_z.c b/mpf/set_z.c
new file mode 100644
index 0000000..f762633
--- /dev/null
+++ b/mpf/set_z.c
@@ -0,0 +1,56 @@
+/* mpf_set_z -- Assign a float from an integer.
+
+Copyright 1996, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_z (mpf_ptr r, mpz_srcptr u)
+{
+  mp_ptr rp, up;
+  mp_size_t size, asize;
+  mp_size_t prec;
+
+  prec = PREC (r) + 1;
+  size = SIZ (u);
+  asize = ABS (size);
+  rp = PTR (r);
+  up = PTR (u);
+
+  EXP (r) = asize;
+
+  if (asize > prec)
+    {
+      up += asize - prec;
+      asize = prec;
+    }
+
+  SIZ (r) = size >= 0 ? asize : -asize;
+  MPN_COPY (rp, up, asize);
+}
diff --git a/mpf/size.c b/mpf/size.c
new file mode 100644
index 0000000..f7a9dbd
--- /dev/null
+++ b/mpf/size.c
@@ -0,0 +1,38 @@
+/* mpf_size(x) -- return the number of limbs currently used by the
+   value of the float X.
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+size_t
+mpf_size (mpf_srcptr f) __GMP_NOTHROW
+{
+  return __GMP_ABS (f->_mp_size);
+}
diff --git a/mpf/sqrt.c b/mpf/sqrt.c
new file mode 100644
index 0000000..ffb7c10
--- /dev/null
+++ b/mpf/sqrt.c
@@ -0,0 +1,112 @@
+/* mpf_sqrt -- Compute the square root of a float.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2004, 2005, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+/* As usual, the aim is to produce PREC(r) limbs of result, with the high
+   limb non-zero.  This is accomplished by applying mpn_sqrtrem to either
+   2*prec or 2*prec-1 limbs, both such sizes resulting in prec limbs.
+
+   The choice between 2*prec or 2*prec-1 limbs is based on the input
+   exponent.  With b=2^GMP_NUMB_BITS the limb base then we can think of
+   effectively taking out a factor b^(2k), for suitable k, to get to an
+   integer input of the desired size ready for mpn_sqrtrem.  It must be an
+   even power taken out, ie. an even number of limbs, so the square root
+   gives factor b^k and the radix point is still on a limb boundary.  So if
+   EXP(r) is even we'll get an even number of input limbs 2*prec, or if
+   EXP(r) is odd we get an odd number 2*prec-1.
+
+   Further limbs below the 2*prec or 2*prec-1 used don't affect the result
+   and are simply truncated.  This can be seen by considering an integer x,
+   with s=floor(sqrt(x)).  s is the unique integer satisfying s^2 <= x <
+   (s+1)^2.  Notice that adding a fraction part to x (ie. some further bits)
+   doesn't change the inequality, s remains the unique solution.  Working
+   suitable factors of 2 into this argument lets it apply to an intended
+   precision at any position for any x, not just the integer binary point.
+
+   If the input is smaller than 2*prec or 2*prec-1, then we just pad with
+   zeros, that of course being our usual interpretation of short inputs.
+   The effect is to extend the root beyond the size of the input (for
+   instance into fractional limbs if u is an integer).  */
+
+void
+mpf_sqrt (mpf_ptr r, mpf_srcptr u)
+{
+  mp_size_t usize;
+  mp_ptr up, tp;
+  mp_size_t prec, tsize;
+  mp_exp_t uexp, expodd;
+  TMP_DECL;
+
+  usize = u->_mp_size;
+  if (UNLIKELY (usize <= 0))
+    {
+      if (usize < 0)
+        SQRT_OF_NEGATIVE;
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  TMP_MARK;
+
+  uexp = u->_mp_exp;
+  prec = r->_mp_prec;
+  up = u->_mp_d;
+
+  expodd = (uexp & 1);
+  tsize = 2 * prec - expodd;
+  r->_mp_size = prec;
+  r->_mp_exp = (uexp + expodd) / 2;    /* ceil(uexp/2) */
+
+  /* root size is ceil(tsize/2), this will be our desired "prec" limbs */
+  ASSERT ((tsize + 1) / 2 == prec);
+
+  tp = TMP_ALLOC_LIMBS (tsize);
+
+  if (usize > tsize)
+    {
+      up += usize - tsize;
+      usize = tsize;
+      MPN_COPY (tp, up, tsize);
+    }
+  else
+    {
+      MPN_ZERO (tp, tsize - usize);
+      MPN_COPY (tp + (tsize - usize), up, usize);
+    }
+
+  mpn_sqrtrem (r->_mp_d, NULL, tp, tsize);
+
+  TMP_FREE;
+}
diff --git a/mpf/sqrt_ui.c b/mpf/sqrt_ui.c
new file mode 100644
index 0000000..9f91f99
--- /dev/null
+++ b/mpf/sqrt_ui.c
@@ -0,0 +1,108 @@
+/* mpf_sqrt_ui -- Compute the square root of an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2004, 2005, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+/* As usual the aim is to produce PREC(r) limbs of result with the high limb
+   non-zero.  That high limb will end up floor(sqrt(u)), and limbs below are
+   produced by padding the input with zeros, two for each desired result
+   limb, being 2*(prec-1) for a total 2*prec-1 limbs passed to mpn_sqrtrem.
+   The way mpn_sqrtrem calculates floor(sqrt(x)) ensures the root is correct
+   to the intended accuracy, ie. truncated to prec limbs.
+
+   With nails, u might be two limbs, in which case a total 2*prec limbs is
+   passed to mpn_sqrtrem (still giving a prec limb result).  If uhigh is
+   zero we adjust back to 2*prec-1, since mpn_sqrtrem requires the high
+   non-zero.  2*prec limbs are always allocated, even when uhigh is zero, so
+   the store of uhigh can be done without a conditional.
+
+   u==0 is a special case so the rest of the code can assume the result is
+   non-zero (ie. will have a non-zero high limb on the result).
+
+   Not done:
+
+   No attempt is made to identify perfect squares.  It's considered this can
+   be left to an application if it might occur with any frequency.  As it
+   stands, mpn_sqrtrem does its normal amount of work on a perfect square
+   followed by zero limbs, though of course only an mpn_sqrtrem1 would be
+   actually needed.  We also end up leaving our mpf result with lots of low
+   trailing zeros, slowing down subsequent operations.
+
+   We're not aware of any optimizations that can be made using the fact the
+   input has lots of trailing zeros (apart from the perfect square
+   case).  */
+
+
+/* 1 if we (might) need two limbs for u */
+#define U2   (GMP_NUMB_BITS < BITS_PER_ULONG)
+
+void
+mpf_sqrt_ui (mpf_ptr r, unsigned long int u)
+{
+  mp_size_t rsize, zeros;
+  mp_ptr tp;
+  mp_size_t prec;
+  TMP_DECL;
+
+  if (UNLIKELY (u <= 1))
+    {
+      SIZ (r) = EXP (r) = u;
+      *PTR (r) = u;
+      return;
+    }
+
+  TMP_MARK;
+
+  prec = PREC (r);
+  zeros = 2 * prec - 2;
+  rsize = zeros + 1 + U2;
+
+  tp = TMP_ALLOC_LIMBS (rsize);
+
+  MPN_ZERO (tp, zeros);
+  tp[zeros] = u & GMP_NUMB_MASK;
+
+#if U2
+  {
+    mp_limb_t uhigh = u >> GMP_NUMB_BITS;
+    tp[zeros + 1] = uhigh;
+    rsize -= (uhigh == 0);
+  }
+#endif
+
+  mpn_sqrtrem (PTR (r), NULL, tp, rsize);
+
+  SIZ (r) = prec;
+  EXP (r) = 1;
+  TMP_FREE;
+}
diff --git a/mpf/sub.c b/mpf/sub.c
new file mode 100644
index 0000000..56f26f6
--- /dev/null
+++ b/mpf/sub.c
@@ -0,0 +1,395 @@
+/* mpf_sub -- Subtract two floats.
+
+Copyright 1993-1996, 1999-2002, 2004, 2005, 2011, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr rp, tp;
+  mp_size_t usize, vsize, rsize;
+  mp_size_t prec;
+  mp_exp_t exp;
+  mp_size_t ediff;
+  int negate;
+  TMP_DECL;
+
+  usize = SIZ (u);
+  vsize = SIZ (v);
+
+  /* Handle special cases that don't work in generic code below.  */
+  if (usize == 0)
+    {
+      mpf_neg (r, v);
+      return;
+    }
+  if (vsize == 0)
+    {
+      if (r != u)
+        mpf_set (r, u);
+      return;
+    }
+
+  /* If signs of U and V are different, perform addition.  */
+  if ((usize ^ vsize) < 0)
+    {
+      __mpf_struct v_negated;
+      v_negated._mp_size = -vsize;
+      v_negated._mp_exp = EXP (v);
+      v_negated._mp_d = PTR (v);
+      mpf_add (r, u, &v_negated);
+      return;
+    }
+
+  TMP_MARK;
+
+  /* Signs are now known to be the same.  */
+  negate = usize < 0;
+
+  /* Make U be the operand with the largest exponent.  */
+  if (EXP (u) < EXP (v))
+    {
+      mpf_srcptr t;
+      t = u; u = v; v = t;
+      negate ^= 1;
+      usize = SIZ (u);
+      vsize = SIZ (v);
+    }
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+  up = PTR (u);
+  vp = PTR (v);
+  rp = PTR (r);
+  prec = PREC (r) + 1;
+  exp = EXP (u);
+  ediff = exp - EXP (v);
+
+  /* If ediff is 0 or 1, we might have a situation where the operands are
+     extremely close.  We need to scan the operands from the most significant
+     end ignore the initial parts that are equal.  */
+  if (ediff <= 1)
+    {
+      if (ediff == 0)
+	{
+	  /* Skip leading limbs in U and V that are equal.  */
+	      /* This loop normally exits immediately.  Optimize for that.  */
+	      while (up[usize - 1] == vp[vsize - 1])
+		{
+		  usize--;
+		  vsize--;
+		  exp--;
+
+		  if (usize == 0)
+		    {
+                      /* u cancels high limbs of v, result is rest of v */
+		      negate ^= 1;
+                    cancellation:
+                      /* strip high zeros before truncating to prec */
+                      while (vsize != 0 && vp[vsize - 1] == 0)
+                        {
+                          vsize--;
+                          exp--;
+                        }
+		      if (vsize > prec)
+			{
+			  vp += vsize - prec;
+			  vsize = prec;
+			}
+                      MPN_COPY_INCR (rp, vp, vsize);
+                      rsize = vsize;
+                      goto done;
+		    }
+		  if (vsize == 0)
+		    {
+                      vp = up;
+                      vsize = usize;
+                      goto cancellation;
+		    }
+		}
+
+	  if (up[usize - 1] < vp[vsize - 1])
+	    {
+	      /* For simplicity, swap U and V.  Note that since the loop above
+		 wouldn't have exited unless up[usize - 1] and vp[vsize - 1]
+		 were non-equal, this if-statement catches all cases where U
+		 is smaller than V.  */
+	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
+	      negate ^= 1;
+	      /* negating ediff not necessary since it is 0.  */
+	    }
+
+	  /* Check for
+	     x+1 00000000 ...
+	      x  ffffffff ... */
+	  if (up[usize - 1] != vp[vsize - 1] + 1)
+	    goto general_case;
+	  usize--;
+	  vsize--;
+	  exp--;
+	}
+      else /* ediff == 1 */
+	{
+	  /* Check for
+	     1 00000000 ...
+	     0 ffffffff ... */
+
+	  if (up[usize - 1] != 1 || vp[vsize - 1] != GMP_NUMB_MAX
+	      || (usize >= 2 && up[usize - 2] != 0))
+	    goto general_case;
+
+	  usize--;
+	  exp--;
+	}
+
+      /* Skip sequences of 00000000/ffffffff */
+      while (vsize != 0 && usize != 0 && up[usize - 1] == 0
+	     && vp[vsize - 1] == GMP_NUMB_MAX)
+	{
+	  usize--;
+	  vsize--;
+	  exp--;
+	}
+
+      if (usize == 0)
+	{
+	  while (vsize != 0 && vp[vsize - 1] == GMP_NUMB_MAX)
+	    {
+	      vsize--;
+	      exp--;
+	    }
+	}
+      else if (usize > prec - 1)
+	{
+	  up += usize - (prec - 1);
+	  usize = prec - 1;
+	}
+      if (vsize > prec - 1)
+	{
+	  vp += vsize - (prec - 1);
+	  vsize = prec - 1;
+	}
+
+      tp = TMP_ALLOC_LIMBS (prec);
+      {
+	mp_limb_t cy_limb;
+	if (vsize == 0)
+	  {
+	    MPN_COPY (tp, up, usize);
+	    tp[usize] = 1;
+	    rsize = usize + 1;
+	    exp++;
+	    goto normalized;
+	  }
+	if (usize == 0)
+	  {
+	    cy_limb = mpn_neg (tp, vp, vsize);
+	    rsize = vsize;
+	  }
+	else if (usize >= vsize)
+	  {
+	    /* uuuu     */
+	    /* vv       */
+	    mp_size_t size;
+	    size = usize - vsize;
+	    MPN_COPY (tp, up, size);
+	    cy_limb = mpn_sub_n (tp + size, up + size, vp, vsize);
+	    rsize = usize;
+	  }
+	else /* (usize < vsize) */
+	  {
+	    /* uuuu     */
+	    /* vvvvvvv  */
+	    mp_size_t size;
+	    size = vsize - usize;
+	    cy_limb = mpn_neg (tp, vp, size);
+	    cy_limb = mpn_sub_nc (tp + size, up, vp + size, usize, cy_limb);
+	    rsize = vsize;
+	  }
+	if (cy_limb == 0)
+	  {
+	    tp[rsize] = 1;
+	    rsize++;
+	    exp++;
+	    goto normalized;
+	  }
+	goto normalize;
+      }
+    }
+
+general_case:
+  /* If U extends beyond PREC, ignore the part that does.  */
+  if (usize > prec)
+    {
+      up += usize - prec;
+      usize = prec;
+    }
+
+  /* If V extends beyond PREC, ignore the part that does.
+     Note that this may make vsize negative.  */
+  if (vsize + ediff > prec)
+    {
+      vp += vsize + ediff - prec;
+      vsize = prec - ediff;
+    }
+
+  if (ediff >= prec)
+    {
+      /* V completely cancelled.  */
+      if (rp != up)
+	MPN_COPY (rp, up, usize);
+      rsize = usize;
+    }
+  else
+    {
+      /* Allocate temp space for the result.  Allocate
+	 just vsize + ediff later???  */
+      tp = TMP_ALLOC_LIMBS (prec);
+
+      /* Locate the least significant non-zero limb in (the needed
+	 parts of) U and V, to simplify the code below.  */
+      for (;;)
+	{
+	  if (vsize == 0)
+	    {
+	      MPN_COPY (rp, up, usize);
+	      rsize = usize;
+	      goto done;
+	    }
+	  if (vp[0] != 0)
+	    break;
+	  vp++, vsize--;
+	}
+      for (;;)
+	{
+	  if (usize == 0)
+	    {
+	      MPN_COPY (rp, vp, vsize);
+	      rsize = vsize;
+	      negate ^= 1;
+	      goto done;
+	    }
+	  if (up[0] != 0)
+	    break;
+	  up++, usize--;
+	}
+
+      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
+      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
+
+      if (usize > ediff)
+	{
+	  /* U and V partially overlaps.  */
+	  if (ediff == 0)
+	    {
+	      /* Have to compare the leading limbs of u and v
+		 to determine whether to compute u - v or v - u.  */
+	      if (usize >= vsize)
+		{
+		  /* uuuu     */
+		  /* vv       */
+		  mp_size_t size;
+		  size = usize - vsize;
+		  MPN_COPY (tp, up, size);
+		  mpn_sub_n (tp + size, up + size, vp, vsize);
+		  rsize = usize;
+		}
+	      else /* (usize < vsize) */
+		{
+		  /* uuuu     */
+		  /* vvvvvvv  */
+		  mp_size_t size;
+		  size = vsize - usize;
+		  ASSERT_CARRY (mpn_neg (tp, vp, size));
+		  mpn_sub_nc (tp + size, up, vp + size, usize, CNST_LIMB (1));
+		  rsize = vsize;
+		}
+	    }
+	  else
+	    {
+	      if (vsize + ediff <= usize)
+		{
+		  /* uuuu     */
+		  /*   v      */
+		  mp_size_t size;
+		  size = usize - ediff - vsize;
+		  MPN_COPY (tp, up, size);
+		  mpn_sub (tp + size, up + size, usize - size, vp, vsize);
+		  rsize = usize;
+		}
+	      else
+		{
+		  /* uuuu     */
+		  /*   vvvvv  */
+		  mp_size_t size;
+		  rsize = vsize + ediff;
+		  size = rsize - usize;
+		  ASSERT_CARRY (mpn_neg (tp, vp, size));
+		  mpn_sub (tp + size, up, usize, vp + size, usize - ediff);
+		  /* Should we use sub_nc then sub_1? */
+		  MPN_DECR_U (tp + size, usize, CNST_LIMB (1));
+		}
+	    }
+	}
+      else
+	{
+	  /* uuuu     */
+	  /*      vv  */
+	  mp_size_t size, i;
+	  size = vsize + ediff - usize;
+	  ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+	  for (i = vsize; i < size; i++)
+	    tp[i] = GMP_NUMB_MAX;
+	  mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1);
+	  rsize = size + usize;
+	}
+
+    normalize:
+      /* Full normalize.  Optimize later.  */
+      while (rsize != 0 && tp[rsize - 1] == 0)
+	{
+	  rsize--;
+	  exp--;
+	}
+    normalized:
+      MPN_COPY (rp, tp, rsize);
+    }
+
+ done:
+  TMP_FREE;
+  if (rsize == 0) {
+    SIZ (r) = 0;
+    EXP (r) = 0;
+  } else {
+    SIZ (r) = negate ? -rsize : rsize;
+    EXP (r) = exp;
+  }
+}
diff --git a/mpf/sub_ui.c b/mpf/sub_ui.c
new file mode 100644
index 0000000..a23d2a8
--- /dev/null
+++ b/mpf/sub_ui.c
@@ -0,0 +1,50 @@
+/* mpf_sub_ui -- Subtract an unsigned integer from a float.
+
+Copyright 1993, 1994, 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_sub_ui (mpf_ptr sum, mpf_srcptr u, unsigned long int v)
+{
+  __mpf_struct vv;
+  mp_limb_t vl;
+
+  if (v == 0)
+    {
+      mpf_set (sum, u);
+      return;
+    }
+
+  vl = v;
+  vv._mp_size = 1;
+  vv._mp_d = &vl;
+  vv._mp_exp = 1;
+  mpf_sub (sum, u, &vv);
+}
diff --git a/mpf/swap.c b/mpf/swap.c
new file mode 100644
index 0000000..80b2e9b
--- /dev/null
+++ b/mpf/swap.c
@@ -0,0 +1,56 @@
+/* mpf_swap (U, V) -- Swap U and V.
+
+Copyright 1997, 1998, 2000, 2001, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_swap (mpf_ptr u, mpf_ptr v) __GMP_NOTHROW
+{
+  mp_ptr tptr;
+  mp_size_t tprec;
+  mp_size_t tsiz;
+  mp_exp_t  texp;
+
+  tprec = PREC(u);
+  PREC(u) = PREC(v);
+  PREC(v) = tprec;
+
+  tsiz = SIZ(u);
+  SIZ(u) = SIZ(v);
+  SIZ(v) = tsiz;
+
+  texp = EXP(u);
+  EXP(u) = EXP(v);
+  EXP(v) = texp;
+
+  tptr = PTR(u);
+  PTR(u) = PTR(v);
+  PTR(v) = tptr;
+}
diff --git a/mpf/trunc.c b/mpf/trunc.c
new file mode 100644
index 0000000..e9af4a7
--- /dev/null
+++ b/mpf/trunc.c
@@ -0,0 +1,74 @@
+/* mpf_trunc -- truncate an mpf to an integer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Notice the use of prec+1 ensures mpf_trunc is equivalent to mpf_set if u
+   is already an integer.  */
+
+void
+mpf_trunc (mpf_ptr r, mpf_srcptr u)
+{
+  mp_ptr     rp;
+  mp_srcptr  up;
+  mp_size_t  size, asize, prec;
+  mp_exp_t   exp;
+
+  exp = EXP(u);
+  size = SIZ(u);
+  if (size == 0 || exp <= 0)
+    {
+      /* u is only a fraction */
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+
+  up = PTR(u);
+  EXP(r) = exp;
+  asize = ABS (size);
+  up += asize;
+
+  /* skip fraction part of u */
+  asize = MIN (asize, exp);
+
+  /* don't lose precision in the copy */
+  prec = PREC(r) + 1;
+
+  /* skip excess over target precision */
+  asize = MIN (asize, prec);
+
+  up -= asize;
+  rp = PTR(r);
+  SIZ(r) = (size >= 0 ? asize : -asize);
+  if (rp != up)
+    MPN_COPY_INCR (rp, up, asize);
+}
diff --git a/mpf/ui_div.c b/mpf/ui_div.c
new file mode 100644
index 0000000..d228bd4
--- /dev/null
+++ b/mpf/ui_div.c
@@ -0,0 +1,127 @@
+/* mpf_ui_div -- Divide an unsigned integer with a float.
+
+Copyright 1993-1996, 2000-2002, 2004, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpf_ui_div (mpf_ptr r, unsigned long int u, mpf_srcptr v)
+{
+  mp_srcptr vp;
+  mp_ptr rp, tp, remp, new_vp;
+  mp_size_t vsize;
+  mp_size_t rsize, prospective_rsize, zeros, tsize, high_zero;
+  mp_size_t sign_quotient;
+  mp_size_t prec;
+  mp_exp_t rexp;
+  TMP_DECL;
+
+  vsize = v->_mp_size;
+  sign_quotient = vsize;
+
+  if (UNLIKELY (vsize == 0))
+    DIVIDE_BY_ZERO;
+
+  if (UNLIKELY (u == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  vsize = ABS (vsize);
+  prec = r->_mp_prec;
+
+  TMP_MARK;
+  rexp = 1 - v->_mp_exp + 1;
+
+  rp = r->_mp_d;
+  vp = v->_mp_d;
+
+  prospective_rsize = 1 - vsize + 1;    /* quot from using given u,v sizes */
+  rsize = prec + 1;                     /* desired quot size */
+
+  zeros = rsize - prospective_rsize;    /* padding u to give rsize */
+  tsize = 1 + zeros;                    /* u with zeros */
+
+  if (WANT_TMP_DEBUG)
+    {
+      /* separate alloc blocks, for malloc debugging */
+      remp = TMP_ALLOC_LIMBS (vsize);
+      tp = TMP_ALLOC_LIMBS (tsize);
+      new_vp = NULL;
+      if (rp == vp)
+        new_vp = TMP_ALLOC_LIMBS (vsize);
+    }
+  else
+    {
+      /* one alloc with calculated size, for efficiency */
+      mp_size_t size = vsize + tsize + (rp == vp ? vsize : 0);
+      remp = TMP_ALLOC_LIMBS (size);
+      tp = remp + vsize;
+      new_vp = tp + tsize;
+    }
+
+  /* ensure divisor doesn't overlap quotient */
+  if (rp == vp)
+    {
+      MPN_COPY (new_vp, vp, vsize);
+      vp = new_vp;
+    }
+
+  MPN_ZERO (tp, tsize-1);
+
+  tp[tsize - 1] = u & GMP_NUMB_MASK;
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (u > GMP_NUMB_MAX)
+    {
+      /* tsize-vsize+1 == rsize, so tsize >= rsize.  rsize == prec+1 >= 2,
+         so tsize >= 2, hence there's room for 2-limb u with nails */
+      ASSERT (tsize >= 2);
+      tp[tsize - 1] = u >> GMP_NUMB_BITS;
+      tp[tsize - 2] = u & GMP_NUMB_MASK;
+      rexp++;
+    }
+#endif
+
+  ASSERT (tsize-vsize+1 == rsize);
+  mpn_tdiv_qr (rp, remp, (mp_size_t) 0, tp, tsize, vp, vsize);
+
+  /* strip possible zero high limb */
+  high_zero = (rp[rsize-1] == 0);
+  rsize -= high_zero;
+  rexp -= high_zero;
+
+  r->_mp_size = sign_quotient >= 0 ? rsize : -rsize;
+  r->_mp_exp = rexp;
+  TMP_FREE;
+}
diff --git a/mpf/ui_sub.c b/mpf/ui_sub.c
new file mode 100644
index 0000000..58da56b
--- /dev/null
+++ b/mpf/ui_sub.c
@@ -0,0 +1,281 @@
+/* mpf_ui_sub -- Subtract a float from an unsigned long int.
+
+Copyright 1993-1996, 2001, 2002, 2005, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
+{
+#if 1
+  __mpf_struct uu;
+  mp_limb_t ul;
+
+  if (u == 0)
+    {
+      mpf_neg (r, v);
+      return;
+    }
+
+  ul = u;
+  uu._mp_size = 1;
+  uu._mp_d = &ul;
+  uu._mp_exp = 1;
+  mpf_sub (r, &uu, v);
+
+#else
+  mp_srcptr up, vp;
+  mp_ptr rp, tp;
+  mp_size_t usize, vsize, rsize;
+  mp_size_t prec;
+  mp_exp_t uexp;
+  mp_size_t ediff;
+  int negate;
+  mp_limb_t ulimb;
+  TMP_DECL;
+
+  vsize = v->_mp_size;
+
+  /* Handle special cases that don't work in generic code below.  */
+  if (u == 0)
+    {
+      mpf_neg (r, v);
+      return;
+    }
+  if (vsize == 0)
+    {
+      mpf_set_ui (r, u);
+      return;
+    }
+
+  /* If signs of U and V are different, perform addition.  */
+  if (vsize < 0)
+    {
+      __mpf_struct v_negated;
+      v_negated._mp_size = -vsize;
+      v_negated._mp_exp = v->_mp_exp;
+      v_negated._mp_d = v->_mp_d;
+      mpf_add_ui (r, &v_negated, u);
+      return;
+    }
+
+  /* Signs are now known to be the same.  */
+  ASSERT (vsize > 0);
+  ulimb = u;
+  /* Make U be the operand with the largest exponent.  */
+  negate = 1 < v->_mp_exp;
+  prec = r->_mp_prec + negate;
+  rp = r->_mp_d;
+  if (negate)
+    {
+      usize = vsize;
+      vsize = 1;
+      up = v->_mp_d;
+      vp = &ulimb;
+      uexp = v->_mp_exp;
+      ediff = uexp - 1;
+
+      /* If U extends beyond PREC, ignore the part that does.  */
+      if (usize > prec)
+	{
+	  up += usize - prec;
+	  usize = prec;
+	}
+      ASSERT (ediff > 0);
+    }
+  else
+    {
+      vp = v->_mp_d;
+      ediff = 1 - v->_mp_exp;
+  /* Ignore leading limbs in U and V that are equal.  Doing
+     this helps increase the precision of the result.  */
+      if (ediff == 0 && ulimb == vp[vsize - 1])
+	{
+	  usize = 0;
+	  vsize--;
+	  uexp = 0;
+	  /* Note that V might now have leading zero limbs.
+	     In that case we have to adjust uexp.  */
+	  for (;;)
+	    {
+	      if (vsize == 0) {
+		rsize = 0;
+		uexp = 0;
+		goto done;
+	      }
+	      if ( vp[vsize - 1] != 0)
+		break;
+	      vsize--, uexp--;
+	    }
+	}
+      else
+	{
+	  usize = 1;
+	  uexp = 1;
+	  up = &ulimb;
+	}
+      ASSERT (usize <= prec);
+    }
+
+  if (ediff >= prec)
+    {
+      /* V completely cancelled.  */
+      if (rp != up)
+	MPN_COPY (rp, up, usize);
+      rsize = usize;
+    }
+  else
+    {
+  /* If V extends beyond PREC, ignore the part that does.
+     Note that this can make vsize neither zero nor negative.  */
+  if (vsize + ediff > prec)
+    {
+      vp += vsize + ediff - prec;
+      vsize = prec - ediff;
+    }
+
+      /* Locate the least significant non-zero limb in (the needed
+	 parts of) U and V, to simplify the code below.  */
+      ASSERT (vsize > 0);
+      for (;;)
+	{
+	  if (vp[0] != 0)
+	    break;
+	  vp++, vsize--;
+	  if (vsize == 0)
+	    {
+	      MPN_COPY (rp, up, usize);
+	      rsize = usize;
+	      goto done;
+	    }
+	}
+      for (;;)
+	{
+	  if (usize == 0)
+	    {
+	      MPN_COPY (rp, vp, vsize);
+	      rsize = vsize;
+	      negate ^= 1;
+	      goto done;
+	    }
+	  if (up[0] != 0)
+	    break;
+	  up++, usize--;
+	}
+
+      ASSERT (usize > 0 && vsize > 0);
+      TMP_MARK;
+
+      tp = TMP_ALLOC_LIMBS (prec);
+
+      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
+      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
+
+      if (usize > ediff)
+	{
+	  /* U and V partially overlaps.  */
+	  if (ediff == 0)
+	    {
+	      ASSERT (usize == 1 && vsize >= 1 && ulimb == *up); /* usize is 1>ediff, vsize >= 1 */
+	      if (1 < vsize)
+		{
+		  /* u        */
+		  /* vvvvvvv  */
+		  rsize = vsize;
+		  vsize -= 1;
+		  /* mpn_cmp (up, vp + vsize - usize, usize) > 0 */
+		  if (ulimb > vp[vsize])
+		    {
+		      tp[vsize] = ulimb - vp[vsize] - 1;
+		      ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+		    }
+		  else
+		    {
+		      /* vvvvvvv  */  /* Swap U and V. */
+		      /* u        */
+		      MPN_COPY (tp, vp, vsize);
+		      tp[vsize] = vp[vsize] - ulimb;
+		      negate = 1;
+		    }
+		}
+	      else /* vsize == usize == 1 */
+		{
+		  /* u     */
+		  /* v     */
+		  rsize = 1;
+		  negate = ulimb < vp[0];
+		  tp[0] = negate ? vp[0] - ulimb: ulimb - vp[0];
+		}
+	    }
+	  else
+	    {
+	      ASSERT (vsize + ediff <= usize);
+	      ASSERT (vsize == 1 && usize >= 2 && ulimb == *vp);
+		{
+		  /* uuuu     */
+		  /*   v      */
+		  mp_size_t size;
+		  size = usize - ediff - 1;
+		  MPN_COPY (tp, up, size);
+		  ASSERT_NOCARRY (mpn_sub_1 (tp + size, up + size, usize - size, ulimb));
+		  rsize = usize;
+		}
+		/* Other cases are not possible */
+		/* uuuu     */
+		/*   vvvvv  */
+	    }
+	}
+      else
+	{
+	  /* uuuu     */
+	  /*      vv  */
+	  mp_size_t size, i;
+	  ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+	  rsize = vsize + ediff;
+	  size = rsize - usize;
+	  for (i = vsize; i < size; i++)
+	    tp[i] = GMP_NUMB_MAX;
+	  ASSERT_NOCARRY (mpn_sub_1 (tp + size, up, usize, CNST_LIMB (1)));
+	}
+
+      /* Full normalize.  Optimize later.  */
+      while (rsize != 0 && tp[rsize - 1] == 0)
+	{
+	  rsize--;
+	  uexp--;
+	}
+      MPN_COPY (rp, tp, rsize);
+      TMP_FREE;
+    }
+
+ done:
+  r->_mp_size = negate ? -rsize : rsize;
+  r->_mp_exp = uexp;
+#endif
+}
diff --git a/mpf/urandomb.c b/mpf/urandomb.c
new file mode 100644
index 0000000..7939901
--- /dev/null
+++ b/mpf/urandomb.c
@@ -0,0 +1,68 @@
+/* mpf_urandomb (rop, state, nbits) -- Generate a uniform pseudorandom
+   real number between 0 (inclusive) and 1 (exclusive) of size NBITS,
+   using STATE as the random state previously initialized by a call to
+   gmp_randinit().
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_urandomb (mpf_ptr rop, gmp_randstate_ptr rstate, mp_bitcnt_t nbits)
+{
+  mp_ptr rp;
+  mp_size_t nlimbs;
+  mp_exp_t exp;
+  mp_size_t prec;
+
+  rp = PTR (rop);
+  nlimbs = BITS_TO_LIMBS (nbits);
+  prec = PREC (rop);
+
+  if (nlimbs > prec + 1 || nlimbs == 0)
+    {
+      nlimbs = prec + 1;
+      nbits = nlimbs * GMP_NUMB_BITS;
+    }
+
+  _gmp_rand (rp, rstate, nbits);
+
+  /* If nbits isn't a multiple of GMP_NUMB_BITS, shift up.  */
+  if (nbits % GMP_NUMB_BITS != 0)
+    mpn_lshift (rp, rp, nlimbs, GMP_NUMB_BITS - nbits % GMP_NUMB_BITS);
+
+  exp = 0;
+  while (nlimbs != 0 && rp[nlimbs - 1] == 0)
+    {
+      nlimbs--;
+      exp--;
+    }
+  EXP (rop) = exp;
+  SIZ (rop) = nlimbs;
+}
diff --git a/mpn/arm/aors_n.asm b/mpn/arm/aors_n.asm
new file mode 100644
index 0000000..b055ed5
--- /dev/null
+++ b/mpn/arm/aors_n.asm
@@ -0,0 +1,112 @@
+dnl  ARM mpn_add_n and mpn_sub_n
+
+dnl  Contributed to the GNU project by Robert Harley.
+
+dnl  Copyright 1997, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.5	slightly fluctuating
+C Cortex-A15	 2.25
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	r0, #0')
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`adc	r0, n, #0')
+  define(`func',	mpn_add_n)
+  define(`func_nc',	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	r0, r0')
+  define(`SETCY',	`rsbs	$1, $1, #0')
+  define(`RETVAL',	`sbc	r0, r0, r0
+			and	r0, r0, #1')
+  define(`func',	mpn_sub_n)
+  define(`func_nc',	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	ldr	r12, [sp, #0]
+	stmfd	sp!, { r8, r9, lr }
+	SETCY(	r12)
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(func)
+	stmfd	sp!, { r8, r9, lr }
+	CLRCY(	r12)
+L(ent):	tst	n, #1
+	beq	L(skip1)
+	ldr	r12, [up], #4
+	ldr	lr, [vp], #4
+	ADDSUBC	r12, r12, lr
+	str	r12, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	up!, { r8, r9 }
+	ldmia	vp!, { r12, lr }
+	ADDSUBC	r8, r8, r12
+	ADDSUBC	r9, r9, lr
+	stmia	rp!, { r8, r9 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+L(top):	ldmia	up!, { r4, r5, r6, r7 }
+	ldmia	vp!, { r8, r9, r12, lr }
+	ADDSUBC	r4, r4, r8
+	sub	n, n, #4
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r12
+	ADDSUBC	r7, r7, lr
+	stmia	rp!, { r4, r5, r6, r7 }
+	teq	n, #0
+	bne	L(top)
+
+	ldmfd	sp!, { r4, r5, r6, r7 }
+
+L(rtn):	RETVAL
+	ldmfd	sp!, { r8, r9, pc }
+EPILOGUE()
diff --git a/mpn/arm/aorslsh1_n.asm b/mpn/arm/aorslsh1_n.asm
new file mode 100644
index 0000000..8d3a733
--- /dev/null
+++ b/mpn/arm/aorslsh1_n.asm
@@ -0,0 +1,167 @@
+dnl  ARM mpn_addlsh1_n and mpn_sublsh1_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	      addlsh1_n       sublsh1_n
+C	     cycles/limb     cycles/limb
+C StrongARM	 ?		 ?
+C XScale	 ?		 ?
+C Cortex-A7	 ?		 ?
+C Cortex-A8	 ?		 ?
+C Cortex-A9	 3.12		 3.7
+C Cortex-A15	 ?		 ?
+
+C TODO
+C  * The addlsh1_n code runs well, but is only barely faster than mpn_addmul_1.
+C    The sublsh1_n code could surely be tweaked, its REVCY slows down things
+C    very much.  If two insns are really needed, it might help to separate them
+C    for better micro-parallelism.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_addlsh1_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`adc	r0, $1, #2')
+  define(`SAVECY',	`sbc	$1, $2, #0')
+  define(`RESTCY',	`cmn	$1, #1')
+  define(`REVCY',	`')
+  define(`INICYR',	`mov	$1, #0')
+  define(`r10r11',	`r11')
+  define(`func',	mpn_addlsh1_n)
+  define(`func_nc',	mpn_addlsh1_nc)')
+ifdef(`OPERATION_sublsh1_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`SETCY',	`rsbs	$1, $1, #0')
+  define(`RETVAL',	`adc	r0, $1, #1')
+  define(`SAVECY',	`sbc	$1, $1, $1')
+  define(`RESTCY',	`cmn	$1, #1')
+  define(`REVCY',	`sbc	$1, $1, $1
+			cmn	$1, #1')
+  define(`INICYR',	`mvn	$1, #0')
+  define(`r10r11',	`r10')
+  define(`func',	mpn_sublsh1_n)
+  define(`func_nc',	mpn_sublsh1_nc)')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{r4-r10r11, r14}
+
+ifdef(`OPERATION_addlsh1_n', `
+	mvn	r11, #0
+')
+	INICYR(	r14)
+	subs	n, n, #3
+	blt	L(le2)			C carry clear on branch path
+
+	cmn	r0, #0			C clear carry
+	ldmia	vp!, {r8, r9, r10}
+	b	L(mid)
+
+L(top):	RESTCY(	r14)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r10
+	ldmia	vp!, {r8, r9, r10}
+	stmia	rp!, {r4, r5, r6}
+	REVCY(r14)
+	adcs	r8, r8, r8
+	adcs	r9, r9, r9
+	adcs	r10, r10, r10
+	ldmia	up!, {r4, r5, r6}
+	SAVECY(	r14, r11)
+	subs	n, n, #3
+	blt	L(exi)
+	RESTCY(	r12)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r10
+	ldmia	vp!, {r8, r9, r10}
+	stmia	rp!, {r4, r5, r6}
+	REVCY(r12)
+L(mid):	adcs	r8, r8, r8
+	adcs	r9, r9, r9
+	adcs	r10, r10, r10
+	ldmia	up!, {r4, r5, r6}
+	SAVECY(	r12, r11)
+	subs	n, n, #3
+	bge	L(top)
+
+	mov	r7, r12			C swap alternating...
+	mov	r12, r14		C ...carry-save...
+	mov	r14, r7			C ...registers
+
+L(exi):	RESTCY(	r12)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r10
+	stmia	rp!, {r4, r5, r6}
+
+	REVCY(r12)
+L(le2):	tst	n, #1			C n = {-1,-2,-3} map to [2], [1], [0]
+	beq	L(e1)
+
+L(e02):	tst	n, #2
+	beq	L(rt0)
+	ldm	vp, {r8, r9}
+	adcs	r8, r8, r8
+	adcs	r9, r9, r9
+	ldm	up, {r4, r5}
+	SAVECY(	r12, r11)
+	RESTCY(	r14)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	stm	rp, {r4, r5}
+	b	L(rt1)
+
+L(e1):	ldr	r8, [vp]
+	adcs	r8, r8, r8
+	ldr	r4, [up]
+	SAVECY(	r12, r11)
+	RESTCY(	r14)
+	ADDSUBC	r4, r4, r8
+	str	r4, [rp]
+
+L(rt1):	mov	r14, r12
+	REVCY(r12)
+L(rt0):	RETVAL(	r14)
+	pop	{r4-r10r11, r14}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/aorsmul_1.asm b/mpn/arm/aorsmul_1.asm
new file mode 100644
index 0000000..15d4d42
--- /dev/null
+++ b/mpn/arm/aorsmul_1.asm
@@ -0,0 +1,135 @@
+dnl  ARM mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 1998, 2000, 2001, 2003, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:     ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 5.25
+C Cortex-A15	 4
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`vl', `r3')
+define(`rl', `r12')
+define(`ul', `r6')
+define(`r',  `lr')
+
+ifdef(`OPERATION_addmul_1', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`CLRRCY',	`mov	$1, #0
+			adds	r0, r0, #0')
+  define(`RETVAL',	`adc	r0, r4, #0')
+  define(`func',	mpn_addmul_1)')
+ifdef(`OPERATION_submul_1', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`CLRRCY',	`subs	$1, r0, r0')
+  define(`RETVAL',	`sbc	r0, r0, r0
+			sub	r0, $1, r0')
+  define(`func',	mpn_submul_1)')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	stmfd	sp!, { r4-r6, lr }
+	CLRRCY(	r4)
+	tst	n, #1
+	beq	L(skip1)
+	ldr	ul, [up], #4
+	ldr	rl, [rp, #0]
+	umull	r5, r4, ul, vl
+	ADDSUB	r, rl, r5
+	str	r, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldr	ul, [up], #4
+	ldr	rl, [rp, #0]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r4
+	ldr	rl, [rp, #4]
+	mov	r4, #0
+	umlal	r5, r4, ul, vl
+	str	r, [rp], #4
+	ADDSUBC	r, rl, r5
+	str	r, [rp], #4
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+
+	ldr	ul, [up], #4
+	ldr	rl, [rp, #0]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	b	L(in)
+
+L(top):	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r5
+	ldr	rl, [rp, #4]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	str	r, [rp], #4
+L(in):	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r4
+	ldr	rl, [rp, #4]
+	mov	r4, #0
+	umlal	r5, r4, ul, vl
+	str	r, [rp], #4
+	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r5
+	ldr	rl, [rp, #4]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	str	r, [rp], #4
+	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r4
+	ldr	rl, [rp, #4]
+	mov	r4, #0
+	umlal	r5, r4, ul, vl
+	sub	n, n, #4
+	tst	n, n
+	str	r, [rp], #4
+	bne	L(top)
+
+	ADDSUBC	r, rl, r5
+	str	r, [rp]
+
+L(rtn):	RETVAL(	r4)
+	ldmfd	sp!, { r4-r6, pc }
+EPILOGUE()
diff --git a/mpn/arm/arm-defs.m4 b/mpn/arm/arm-defs.m4
new file mode 100644
index 0000000..4b4fa0b
--- /dev/null
+++ b/mpn/arm/arm-defs.m4
@@ -0,0 +1,100 @@
+divert(-1)
+
+dnl  m4 macros for ARM assembler.
+
+dnl  Copyright 2001, 2012-2016, 2018-2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Standard commenting is with @, the default m4 # is for constants and we
+dnl  don't want to disable macro expansions in or after them.
+
+changecom(@&*$)
+
+define(`ASM_START',
+m4_assert_numargs_range(0,1)
+`ifelse($1,`neon',`.fpu	neon',
+        $1,,`',
+        1,1,`m4_error(`$0 got invalid argument $1')')')
+
+dnl  APCS register names.
+
+deflit(a1,r0)
+deflit(a2,r1)
+deflit(a3,r2)
+deflit(a4,r3)
+dnl deflit(v1,r4)
+dnl deflit(v2,r5)
+dnl deflit(v3,r6)
+dnl deflit(v4,r7)
+dnl deflit(v5,r8)
+dnl deflit(v6,r9)
+deflit(sb,r9)
+dnl deflit(v7,r10)
+deflit(sl,r10)
+deflit(fp,r11)
+deflit(ip,r12)
+dnl deflit(sp,r13)
+deflit(lr,r14)
+deflit(pc,r15)
+
+
+define(`lea_list', `')
+define(`lea_num',0)
+
+dnl  LEA(reg,gmp_symbol)
+dnl
+dnl  Load the address of gmp_symbol into a register.  The gmp_symbol must be
+dnl  either local or protected/hidden, since we assume it has a fixed distance
+dnl  from the point of use.
+
+define(`LEA',`dnl
+ldr	$1, L(ptr`'lea_num)
+ifdef(`PIC',dnl
+`dnl
+L(bas`'lea_num):dnl
+	add	$1, $1, pc`'dnl
+	m4append(`lea_list',`
+L(ptr'lea_num`):	.word	GSYM_PREFIX`'$2-L(bas'lea_num`)-8')
+	define(`lea_num', eval(lea_num+1))dnl
+',`dnl
+	m4append(`lea_list',`
+L(ptr'lea_num`):	.word	GSYM_PREFIX`'$2')
+	define(`lea_num', eval(lea_num+1))dnl
+')dnl
+')
+
+define(`return',`ifdef(`NOTHUMB',`mov	pc, ',`bx')')
+
+
+define(`EPILOGUE_cpu',
+`lea_list
+	SIZE(`$1',.-`$1')'
+`define(`lea_list', `')')
+
+divert
diff --git a/mpn/arm/bdiv_dbm1c.asm b/mpn/arm/bdiv_dbm1c.asm
new file mode 100644
index 0000000..efc1cb9
--- /dev/null
+++ b/mpn/arm/bdiv_dbm1c.asm
@@ -0,0 +1,113 @@
+dnl  ARM mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.25
+C Cortex-A15	 2.5
+
+C TODO
+C  * Try using umlal or umaal.
+C  * Try using ldm/stm.
+
+define(`qp',	  `r0')
+define(`up',	  `r1')
+define(`n',	  `r2')
+define(`bd',	  `r3')
+define(`cy',	  `sp,#0')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	push	{r4, r5, r6, r7, r8}
+	ldr	r4, [up], #4
+	ldr	r5, [sp, #20]
+	ands	r12, n, #3
+	beq	L(fi0)
+	cmp	r12, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	umull	r8, r12, r4, bd
+	ldr	r4, [up], #4
+	b	L(lo3)
+
+L(fi0):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	b	L(lo0)
+
+L(fi1):	subs	n, n, #1
+	umull	r8, r12, r4, bd
+	bls	L(wd1)
+	ldr	r4, [up], #4
+	b	L(lo1)
+
+L(fi2):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	b	L(lo2)
+
+L(top):	ldr	r4, [up], #4
+	subs	r5, r5, r6
+	str	r5, [qp], #4
+	sbc	r5, r5, r7
+L(lo1):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	subs	r5, r5, r8
+	str	r5, [qp], #4
+	sbc	r5, r5, r12
+L(lo0):	umull	r8, r12, r4, bd
+	ldr	r4, [up], #4
+	subs	r5, r5, r6
+	str	r5, [qp], #4
+	sbc	r5, r5, r7
+L(lo3):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	subs	r5, r5, r8
+	str	r5, [qp], #4
+	sbc	r5, r5, r12
+L(lo2):	subs	n, n, #4
+	umull	r8, r12, r4, bd
+	bhi	L(top)
+
+L(wd2):	subs	r5, r5, r6
+	str	r5, [qp], #4
+	sbc	r5, r5, r7
+L(wd1):	subs	r5, r5, r8
+	str	r5, [qp]
+	sbc	r0, r5, r12
+	pop	{r4, r5, r6, r7, r8}
+	return	lr
+EPILOGUE()
diff --git a/mpn/arm/bdiv_q_1.asm b/mpn/arm/bdiv_q_1.asm
new file mode 100644
index 0000000..5a89cd8
--- /dev/null
+++ b/mpn/arm/bdiv_q_1.asm
@@ -0,0 +1,162 @@
+dnl  ARM v4 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C               cycles/limb
+C               norm   unorm
+C 1176		13	18
+C Cortex-A5	 8	12
+C Cortex-A7	10.5	18
+C Cortex-A8	14	15
+C Cortex-A9	10	12		not measured since latest edits
+C Cortex-A15	 9	 9
+C Cortex-A53	14	20
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	-
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`d',   `r3')
+define(`di_arg',  `sp[0]')		C	just mpn_pi1_bdiv_q_1
+define(`cnt_arg', `sp[4]')		C	just mpn_pi1_bdiv_q_1
+
+define(`cy',  `r7')
+define(`cnt', `r6')
+define(`tnc', `r8')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_q_1)
+	tst	d, #1
+	push	{r6-r11}
+	mov	cnt, #0
+	bne	L(inv)
+
+C count trailing zeros
+	movs	r10, d, lsl #16
+	moveq	d, d, lsr #16
+	moveq	cnt, #16
+	tst	d, #0xff
+	moveq	d, d, lsr #8
+	addeq	cnt, cnt, #8
+	LEA(	r10, ctz_tab)
+	and	r11, d, #0xff
+	ldrb	r10, [r10, r11]
+	mov	d, d, lsr r10
+	add	cnt, cnt, r10
+
+C binvert limb
+L(inv):	LEA(	r10, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r10, [r10, r12, lsr #1]
+	mul	r12, r10, r10
+	mul	r12, d, r12
+	rsb	r12, r12, r10, lsl #1
+	mul	r10, r12, r12
+	mul	r10, d, r10
+	rsb	r10, r10, r12, lsl #1	C r10 = inverse
+	b	L(pi1)
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	push	{r6-r11}
+
+	ldr	cnt, [sp, #28]
+	ldr	r10, [sp, #24]
+
+L(pi1):	ldr	r11, [up], #4		C up[0]
+	cmp	cnt, #0
+	mov	cy, #0
+	bne	L(unorm)
+
+L(norm):
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edn)
+
+	ALIGN(16)
+L(tpn):	sbcs	cy, r11, cy
+	ldr	r11, [up], #4
+	sub	n, n, #1
+	mul	r9, r10, cy
+	tst	n, n
+	umull	r12, cy, d, r9
+	str	r9, [rp], #4
+	bne	L(tpn)
+
+L(edn):	sbc	cy, r11, cy
+	mul	r9, r10, cy
+	str	r9, [rp]
+	pop	{r6-r11}
+	return	r14
+
+L(unorm):
+	rsb	tnc, cnt, #32
+	mov	r11, r11, lsr cnt
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r11, r12, lsl tnc
+	mov	r11, r12, lsr cnt
+	sbcs	cy, r9, cy		C critical path ->cy->cy->
+	sub	n, n, #1
+	mul	r9, r10, cy		C critical path ->cy->r9->
+	tst	n, n
+	umull	r12, cy, d, r9		C critical path ->r9->cy->
+	str	r9, [rp], #4
+	bne	L(tpu)
+
+L(edu):	sbc	cy, r11, cy
+	mul	r9, r10, cy
+	str	r9, [rp]
+	pop	{r6-r11}
+	return	r14
+EPILOGUE()
+
+	RODATA
+ctz_tab:
+	.byte	8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
diff --git a/mpn/arm/cnd_aors_n.asm b/mpn/arm/cnd_aors_n.asm
new file mode 100644
index 0000000..603d1fa
--- /dev/null
+++ b/mpn/arm/cnd_aors_n.asm
@@ -0,0 +1,134 @@
+dnl  ARM mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3
+C Cortex-A15	 2.5
+
+define(`cnd',	`r0')
+define(`rp',	`r1')
+define(`up',	`r2')
+define(`vp',	`r3')
+
+define(`n',	`r12')
+
+
+ifdef(`OPERATION_cnd_add_n', `
+	define(`ADDSUB',      adds)
+	define(`ADDSUBC',      adcs)
+	define(`INITCY',      `cmn	r0, #0')
+	define(`RETVAL',      `adc	r0, n, #0')
+	define(func,	      mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+	define(`ADDSUB',      subs)
+	define(`ADDSUBC',      sbcs)
+	define(`INITCY',      `cmp	r0, #0')
+	define(`RETVAL',      `adc	r0, n, #0
+			      rsb	r0, r0, #1')
+	define(func,	      mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{r4-r11}
+	ldr	n, [sp, #32]
+
+	cmp	cnd, #1
+	sbc	cnd, cnd, cnd		C conditionally set to 0xffffffff
+
+	INITCY				C really only needed for n = 0 (mod 4)
+
+	ands	r4, n, #3
+	beq	L(top)
+	cmp	r4, #2
+	bcc	L(b1)
+	beq	L(b2)
+
+L(b3):	ldm	vp!, {r4,r5,r6}
+	ldm	up!, {r8,r9,r10}
+	bic	r4, r4, cnd
+	bic	r5, r5, cnd
+	bic	r6, r6, cnd
+	ADDSUB	r8, r8, r4
+	ADDSUBC	r9, r9, r5
+	ADDSUBC	r10, r10, r6
+	stm	rp!, {r8,r9,r10}
+	sub	n, n, #3
+	teq	n, #0
+	bne	L(top)
+	b	L(end)
+
+L(b2):	ldm	vp!, {r4,r5}
+	ldm	up!, {r8,r9}
+	bic	r4, r4, cnd
+	bic	r5, r5, cnd
+	ADDSUB	r8, r8, r4
+	ADDSUBC	r9, r9, r5
+	stm	rp!, {r8,r9}
+	sub	n, n, #2
+	teq	n, #0
+	bne	L(top)
+	b	L(end)
+
+L(b1):	ldr	r4, [vp], #4
+	ldr	r8, [up], #4
+	bic	r4, r4, cnd
+	ADDSUB	r8, r8, r4
+	str	r8, [rp], #4
+	sub	n, n, #1
+	teq	n, #0
+	beq	L(end)
+
+L(top):	ldm	vp!, {r4,r5,r6,r7}
+	ldm	up!, {r8,r9,r10,r11}
+	bic	r4, r4, cnd
+	bic	r5, r5, cnd
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	ADDSUBC	r8, r8, r4
+	ADDSUBC	r9, r9, r5
+	ADDSUBC	r10, r10, r6
+	ADDSUBC	r11, r11, r7
+	sub	n, n, #4
+	stm	rp!, {r8,r9,r10,r11}
+	teq	n, #0
+	bne	L(top)
+
+L(end):	RETVAL
+	pop	{r4-r11}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/com.asm b/mpn/arm/com.asm
new file mode 100644
index 0000000..f89033f
--- /dev/null
+++ b/mpn/arm/com.asm
@@ -0,0 +1,75 @@
+dnl  ARM mpn_com.
+
+dnl  Copyright 2003, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.0
+C Cortex-A15	 1.75
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_com)
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r3, [up], #4
+	mvn	r3, r3
+	str	r3, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	up!, { r3, r12 }		C load 2 limbs
+	mvn	r3, r3
+	mvn	r12, r12
+	stmia	rp!, { r3, r12 }		C store 2 limbs
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	stmfd	sp!, { r7, r8, r9 }		C save regs on stack
+
+L(top):	ldmia	up!, { r3, r8, r9, r12 }	C load 4 limbs
+	subs	n, n, #4
+	mvn	r3, r3
+	mvn	r8, r8
+	mvn	r9, r9
+	mvn	r12, r12
+	stmia	rp!, { r3, r8, r9, r12 }	C store 4 limbs
+	bne	L(top)
+
+	ldmfd	sp!, { r7, r8, r9 }		C restore regs from stack
+L(rtn):	return	lr
+EPILOGUE()
diff --git a/mpn/arm/copyd.asm b/mpn/arm/copyd.asm
new file mode 100644
index 0000000..c23c864
--- /dev/null
+++ b/mpn/arm/copyd.asm
@@ -0,0 +1,84 @@
+dnl  ARM mpn_copyd.
+
+dnl  Contributed to the GNU project by Robert Harley and Torbjörn Granlund.
+
+dnl  Copyright 2003, 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.25-1.5
+C Cortex-A15	 1.25
+
+C TODO
+C  * Consider wider unrolling.  Analogous 8-way code runs 10% faster on both A9
+C    and A15.  But it probably slows things down for 8 <= n < a few dozen.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	mov	r12, n, lsl #2
+	sub	r12, r12, #4
+	add	rp, rp, r12
+	add	up, up, r12
+
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r3, [up], #-4
+	str	r3, [rp], #-4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmda	up!, { r3,r12 }
+	stmda	rp!, { r3,r12 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+
+	push	{ r4-r5 }
+	subs	n, n, #4
+	ldmda	up!, { r3,r4,r5,r12 }
+	beq	L(end)
+
+L(top):	subs	n, n, #4
+	stmda	rp!, { r3,r4,r5,r12 }
+	ldmda	up!, { r3,r4,r5,r12 }
+	bne	L(top)
+
+L(end):	stmda	rp, { r3,r4,r5,r12 }
+	pop	{ r4-r5 }
+L(rtn):	return	lr
+EPILOGUE()
diff --git a/mpn/arm/copyi.asm b/mpn/arm/copyi.asm
new file mode 100644
index 0000000..9970594
--- /dev/null
+++ b/mpn/arm/copyi.asm
@@ -0,0 +1,79 @@
+dnl  ARM mpn_copyi.
+
+dnl  Contributed to the GNU project by Robert Harley and Torbjörn Granlund.
+
+dnl  Copyright 2003, 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.25-1.5
+C Cortex-A15	 1.25
+
+C TODO
+C  * Consider wider unrolling.  Analogous 8-way code runs 10% faster on both A9
+C    and A15.  But it probably slows things down for 8 <= n < a few dozen.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r3, [up], #4
+	str	r3, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	up!, { r3,r12 }
+	stmia	rp!, { r3,r12 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+
+	push	{ r4-r5 }
+	subs	n, n, #4
+	ldmia	up!, { r3,r4,r5,r12 }
+	beq	L(end)
+
+L(top):	subs	n, n, #4
+	stmia	rp!, { r3,r4,r5,r12 }
+	ldmia	up!, { r3,r4,r5,r12 }
+	bne	L(top)
+
+L(end):	stm	rp, { r3,r4,r5,r12 }
+	pop	{ r4-r5 }
+L(rtn):	return	lr
+EPILOGUE()
diff --git a/mpn/arm/dive_1.asm b/mpn/arm/dive_1.asm
new file mode 100644
index 0000000..5eefb1a
--- /dev/null
+++ b/mpn/arm/dive_1.asm
@@ -0,0 +1,151 @@
+dnl  ARM v4 mpn_divexact_1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C               cycles/limb       cycles/limb
+C               norm    unorm    modexact_1c_odd
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	10	12
+C Cortex-A15	 9	 9
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	-
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`d',  `r3')
+
+define(`cy', `r7')
+define(`cnt', `r6')
+define(`tnc', `r8')
+
+ASM_START()
+PROLOGUE(mpn_divexact_1)
+	tst	d, #1
+	push	{r4-r9}
+	mov	cnt, #0
+	bne	L(inv)
+
+C count trailing zeros
+	movs	r4, d, lsl #16
+	moveq	d, d, lsr #16
+	moveq	cnt, #16
+	tst	d, #0xff
+	moveq	d, d, lsr #8
+	addeq	cnt, cnt, #8
+	LEA(	r4, ctz_tab)
+	and	r5, d, #0xff
+	ldrb	r4, [r4, r5]
+	mov	d, d, lsr r4
+	add	cnt, cnt, r4
+
+C binvert limb
+L(inv):	LEA(	r4, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	mul	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, lsl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, lsl #1	C r4 = inverse
+
+	tst	cnt, cnt
+	ldr	r5, [up], #4		C up[0]
+	mov	cy, #0
+	bne	L(unnorm)
+
+L(norm):
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edn)
+
+	ALIGN(16)
+L(tpn):	sbcs	cy, r5, cy
+	ldr	r5, [up], #4
+	sub	n, n, #1
+	mul	r9, r4, cy
+	tst	n, n
+	umull	r12, cy, d, r9
+	str	r9, [rp], #4
+	bne	L(tpn)
+
+L(edn):	sbc	cy, r5, cy
+	mul	r9, r4, cy
+	str	r9, [rp]
+	pop	{r4-r9}
+	return	r14
+
+L(unnorm):
+	rsb	tnc, cnt, #32
+	mov	r5, r5, lsr cnt
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r5, r12, lsl tnc
+	mov	r5, r12, lsr cnt
+	sbcs	cy, r9, cy		C critical path ->cy->cy->
+	sub	n, n, #1
+	mul	r9, r4, cy		C critical path ->cy->r9->
+	tst	n, n
+	umull	r12, cy, d, r9		C critical path ->r9->cy->
+	str	r9, [rp], #4
+	bne	L(tpu)
+
+L(edu):	sbc	cy, r5, cy
+	mul	r9, r4, cy
+	str	r9, [rp]
+	pop	{r4-r9}
+	return	r14
+EPILOGUE()
+
+	RODATA
+ctz_tab:
+	.byte	8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
diff --git a/mpn/arm/gmp-mparam.h b/mpn/arm/gmp-mparam.h
new file mode 100644
index 0000000..87eec3a
--- /dev/null
+++ b/mpn/arm/gmp-mparam.h
@@ -0,0 +1,127 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2009, 2010 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1193MHz ARM (gcc55.fsffrance.org) */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         56
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         11
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     71
+#define USE_PREINV_DIVREM_1                  1  /* preinv always */
+#define DIVREM_2_THRESHOLD                   0  /* preinv always */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           41
+
+#define MUL_TOOM22_THRESHOLD                36
+#define MUL_TOOM33_THRESHOLD               125
+#define MUL_TOOM44_THRESHOLD               193
+#define MUL_TOOM6H_THRESHOLD               303
+#define MUL_TOOM8H_THRESHOLD               418
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     125
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     176
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     129
+
+#define SQR_BASECASE_THRESHOLD              12
+#define SQR_TOOM2_THRESHOLD                 78
+#define SQR_TOOM3_THRESHOLD                137
+#define SQR_TOOM4_THRESHOLD                212
+#define SQR_TOOM6_THRESHOLD                306
+#define SQR_TOOM8_THRESHOLD                422
+
+#define MULMOD_BNM1_THRESHOLD               20
+#define SQRMOD_BNM1_THRESHOLD               26
+
+#define MUL_FFT_MODF_THRESHOLD             436  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    436, 5}, {     27, 6}, {     28, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {    256, 9}, {    512,10}, {   1024,11}, {   2048,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 28
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    404, 5}, {     13, 4}, {     27, 5}, {     27, 6}, \
+    {     28, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {    512,10}, \
+    {   1024,11}, {   2048,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 26
+#define SQR_FFT_THRESHOLD                 3776
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                 137
+#define MULLO_MUL_N_THRESHOLD            11479
+
+#define DC_DIV_QR_THRESHOLD                150
+#define DC_DIVAPPR_Q_THRESHOLD             494
+#define DC_BDIV_QR_THRESHOLD               148
+#define DC_BDIV_Q_THRESHOLD                345
+
+#define INV_MULMOD_BNM1_THRESHOLD           70
+#define INV_NEWTON_THRESHOLD               474
+#define INV_APPR_THRESHOLD                 478
+
+#define BINV_NEWTON_THRESHOLD              542
+#define REDC_1_TO_REDC_N_THRESHOLD         117
+
+#define MU_DIV_QR_THRESHOLD               2089
+#define MU_DIVAPPR_Q_THRESHOLD            2172
+#define MUPI_DIV_QR_THRESHOLD              225
+#define MU_BDIV_QR_THRESHOLD              1528
+#define MU_BDIV_Q_THRESHOLD               2089
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD_THRESHOLD                     197
+#define GCD_DC_THRESHOLD                   902
+#define GCDEXT_DC_THRESHOLD                650
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                20
+#define GET_STR_PRECOMPUTE_THRESHOLD        39
+#define SET_STR_DC_THRESHOLD              1045
+#define SET_STR_PRECOMPUTE_THRESHOLD      2147
diff --git a/mpn/arm/invert_limb.asm b/mpn/arm/invert_limb.asm
new file mode 100644
index 0000000..bb55a60
--- /dev/null
+++ b/mpn/arm/invert_limb.asm
@@ -0,0 +1,93 @@
+dnl  ARM mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Copyright 2001, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+ASM_START()
+PROLOGUE(mpn_invert_limb)
+	LEA(	r2, approx_tab-512)
+	mov	r3, r0, lsr #23
+	mov	r3, r3, asl #1
+	ldrh	r3, [r3, r2]
+	mov	r1, r3, asl #17
+	mul	r12, r3, r3
+	umull	r3, r2, r12, r0
+	sub	r1, r1, r2, asl #1
+	umull	r3, r2, r1, r1
+	umull	r12, r3, r0, r3
+	umull	r2, r12, r0, r2
+	adds	r2, r2, r3
+	adc	r12, r12, #0
+	rsb	r1, r12, r1
+	mvn	r2, r2, lsr #30
+	add	r2, r2, r1, asl #2
+	umull	r12, r3, r0, r2
+	adds	r1, r12, r0
+	adc	r3, r3, r0
+	rsb	r0, r3, r2
+	return	lr
+EPILOGUE()
+
+	RODATA
+	ALIGN(2)
+approx_tab:
+	.short    0xffc0,0xfec0,0xfdc0,0xfcc0,0xfbc0,0xfac0,0xfa00,0xf900
+	.short    0xf800,0xf700,0xf640,0xf540,0xf440,0xf380,0xf280,0xf180
+	.short    0xf0c0,0xefc0,0xef00,0xee00,0xed40,0xec40,0xeb80,0xeac0
+	.short    0xe9c0,0xe900,0xe840,0xe740,0xe680,0xe5c0,0xe500,0xe400
+	.short    0xe340,0xe280,0xe1c0,0xe100,0xe040,0xdf80,0xdec0,0xde00
+	.short    0xdd40,0xdc80,0xdbc0,0xdb00,0xda40,0xd980,0xd8c0,0xd800
+	.short    0xd740,0xd680,0xd600,0xd540,0xd480,0xd3c0,0xd340,0xd280
+	.short    0xd1c0,0xd140,0xd080,0xcfc0,0xcf40,0xce80,0xcdc0,0xcd40
+	.short    0xcc80,0xcc00,0xcb40,0xcac0,0xca00,0xc980,0xc8c0,0xc840
+	.short    0xc780,0xc700,0xc640,0xc5c0,0xc540,0xc480,0xc400,0xc380
+	.short    0xc2c0,0xc240,0xc1c0,0xc100,0xc080,0xc000,0xbf80,0xbec0
+	.short    0xbe40,0xbdc0,0xbd40,0xbc80,0xbc00,0xbb80,0xbb00,0xba80
+	.short    0xba00,0xb980,0xb900,0xb840,0xb7c0,0xb740,0xb6c0,0xb640
+	.short    0xb5c0,0xb540,0xb4c0,0xb440,0xb3c0,0xb340,0xb2c0,0xb240
+	.short    0xb1c0,0xb140,0xb0c0,0xb080,0xb000,0xaf80,0xaf00,0xae80
+	.short    0xae00,0xad80,0xad40,0xacc0,0xac40,0xabc0,0xab40,0xaac0
+	.short    0xaa80,0xaa00,0xa980,0xa900,0xa8c0,0xa840,0xa7c0,0xa740
+	.short    0xa700,0xa680,0xa600,0xa5c0,0xa540,0xa4c0,0xa480,0xa400
+	.short    0xa380,0xa340,0xa2c0,0xa240,0xa200,0xa180,0xa140,0xa0c0
+	.short    0xa080,0xa000,0x9f80,0x9f40,0x9ec0,0x9e80,0x9e00,0x9dc0
+	.short    0x9d40,0x9d00,0x9c80,0x9c40,0x9bc0,0x9b80,0x9b00,0x9ac0
+	.short    0x9a40,0x9a00,0x9980,0x9940,0x98c0,0x9880,0x9840,0x97c0
+	.short    0x9780,0x9700,0x96c0,0x9680,0x9600,0x95c0,0x9580,0x9500
+	.short    0x94c0,0x9440,0x9400,0x93c0,0x9340,0x9300,0x92c0,0x9240
+	.short    0x9200,0x91c0,0x9180,0x9100,0x90c0,0x9080,0x9000,0x8fc0
+	.short    0x8f80,0x8f40,0x8ec0,0x8e80,0x8e40,0x8e00,0x8d80,0x8d40
+	.short    0x8d00,0x8cc0,0x8c80,0x8c00,0x8bc0,0x8b80,0x8b40,0x8b00
+	.short    0x8a80,0x8a40,0x8a00,0x89c0,0x8980,0x8940,0x88c0,0x8880
+	.short    0x8840,0x8800,0x87c0,0x8780,0x8740,0x8700,0x8680,0x8640
+	.short    0x8600,0x85c0,0x8580,0x8540,0x8500,0x84c0,0x8480,0x8440
+	.short    0x8400,0x8380,0x8340,0x8300,0x82c0,0x8280,0x8240,0x8200
+	.short    0x81c0,0x8180,0x8140,0x8100,0x80c0,0x8080,0x8040,0x8000
+ASM_END()
diff --git a/mpn/arm/logops_n.asm b/mpn/arm/logops_n.asm
new file mode 100644
index 0000000..c0ddaf4
--- /dev/null
+++ b/mpn/arm/logops_n.asm
@@ -0,0 +1,139 @@
+dnl  ARM mpn_and_n, mpn_andn_n. mpn_nand_n, etc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 1997, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C            cycles/limb             cycles/limb
+C          and andn ior xor         nand iorn nior xnor
+C StrongARM	 ?			 ?
+C XScale	 ?			 ?
+C Cortex-A7	 ?			 ?
+C Cortex-A8	 ?			 ?
+C Cortex-A9	2.5-2.72		2.75-3
+C Cortex-A15	2.25			2.75
+
+C TODO
+C  * It seems that 2.25 c/l and 2.75 c/l is possible for A9.
+C  * Debug popping issue, see comment below.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+define(`POSTOP')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',    `mpn_and_n')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',    `mpn_andn_n')
+  define(`LOGOP',   `bic	$1, $2, $3')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',    `mpn_nand_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',    `mpn_ior_n')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',    `mpn_iorn_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `bic	$1, $3, $2')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',    `mpn_nior_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',    `mpn_xor_n')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',    `mpn_xnor_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{ r8, r9, r10 }
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r10, [vp], #4
+	ldr	r12, [up], #4
+	LOGOP(	r12, r12, r10)
+	POSTOP(	r12)
+	str	r12, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	vp!, { r10, r12 }
+	ldmia	up!, { r8, r9 }
+	LOGOP(	r8, r8, r10)
+	LOGOP(	r9, r9, r12)
+	POSTOP(	r8)
+	POSTOP(	r9)
+	stmia	rp!, { r8, r9 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	push	{ r4, r5, r6, r7 }
+
+	ldmia	vp!, { r8, r9, r10, r12 }
+	b	L(mid)
+
+L(top):	ldmia	vp!, { r8, r9, r10, r12 }
+	POSTOP(	r4)
+	POSTOP(	r5)
+	POSTOP(	r6)
+	POSTOP(	r7)
+	stmia	rp!, { r4, r5, r6, r7 }
+L(mid):	sub	n, n, #4
+	ldmia	up!, { r4, r5, r6, r7 }
+	teq	n, #0
+	LOGOP(	r4, r4, r8)
+	LOGOP(	r5, r5, r9)
+	LOGOP(	r6, r6, r10)
+	LOGOP(	r7, r7, r12)
+	bne	L(top)
+
+	POSTOP(	r4)
+	POSTOP(	r5)
+	POSTOP(	r6)
+	POSTOP(	r7)
+	stmia	rp!, { r4, r5, r6, r7 }
+
+	pop	{ r4, r5, r6, r7 }	C popping r8-r10 here strangely fails
+
+L(rtn):	pop	{ r8, r9, r10 }
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/lshift.asm b/mpn/arm/lshift.asm
new file mode 100644
index 0000000..dd7548b
--- /dev/null
+++ b/mpn/arm/lshift.asm
@@ -0,0 +1,88 @@
+dnl  ARM mpn_lshift.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.5
+C Cortex-A15	 ?
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+define(`tnc', `r12')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	add	up, up, n, lsl #2
+	push	{r4, r6, r7, r8}
+	ldr	r4, [up, #-4]!
+	add	rp, rp, n, lsl #2
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsl cnt
+	tst	n, #1
+	beq	L(evn)			C n even
+
+L(odd):	subs	n, n, #2
+	bcc	L(1)			C n = 1
+	ldr	r8, [up, #-4]!
+	b	L(mid)
+
+L(evn):	ldr	r6, [up, #-4]!
+	subs	n, n, #2
+	beq	L(end)
+
+L(top):	ldr	r8, [up, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(mid):	ldr	r6, [up, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r8, lsl cnt
+	subs	n, n, #2
+	bgt	L(top)
+
+L(end):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(1):	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+	pop	{r4, r6, r7, r8}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/lshiftc.asm b/mpn/arm/lshiftc.asm
new file mode 100644
index 0000000..18defd8
--- /dev/null
+++ b/mpn/arm/lshiftc.asm
@@ -0,0 +1,95 @@
+dnl  ARM mpn_lshiftc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.0
+C Cortex-A15	 ?
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+define(`tnc', `r12')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	add	up, up, n, lsl #2
+	push	{r4, r6, r7, r8}
+	ldr	r4, [up, #-4]!
+	add	rp, rp, n, lsl #2
+	rsb	tnc, cnt, #32
+	mvn	r6, r4
+
+	mov	r7, r6, lsl cnt
+	tst	n, #1
+	beq	L(evn)			C n even
+
+L(odd):	subs	n, n, #2
+	bcc	L(1)			C n = 1
+	ldr	r8, [up, #-4]!
+	mvn	r8, r8
+	b	L(mid)
+
+L(evn):	ldr	r6, [up, #-4]!
+	mvn	r6, r6
+	subs	n, n, #2
+	beq	L(end)
+
+L(top):	ldr	r8, [up, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r8, r8
+	mov	r7, r6, lsl cnt
+L(mid):	ldr	r6, [up, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r6, r6
+	mov	r7, r8, lsl cnt
+	subs	n, n, #2
+	bgt	L(top)
+
+L(end):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(1):	mvn	r6, #0
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+	pop	{r4, r6, r7, r8}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/mod_34lsub1.asm b/mpn/arm/mod_34lsub1.asm
new file mode 100644
index 0000000..456dab5
--- /dev/null
+++ b/mpn/arm/mod_34lsub1.asm
@@ -0,0 +1,124 @@
+dnl  ARM mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A5	 2.67
+C Cortex-A7	 2.35
+C Cortex-A8	 2.0
+C Cortex-A9	 1.33
+C Cortex-A15	 1.33
+C Cortex-A17	 3.34
+C Cortex-A53	 2.0
+
+define(`ap',	r0)
+define(`n',	r1)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * Write cleverer summation code.
+C  * Consider loading 6 64-bit aligned registers at a time, to approach 1 c/l.
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	push	{ r4, r5, r6, r7 }
+
+	subs	n, n, #3
+	mov	r7, #0
+	blt	L(le2)			C n <= 2
+
+	ldmia	ap!, { r2, r3, r12 }
+	subs	n, n, #3
+	blt	L(sum)			C n <= 5
+	cmn	r0, #0			C clear carry
+	sub	n, n, #3
+	b	L(mid)
+
+L(top):	adcs	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, r6
+L(mid):	ldmia	ap!, { r4, r5, r6 }
+	tst	n, n
+	sub	n, n, #3
+	bpl	L(top)
+
+	add	n, n, #3
+
+	adcs	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, r6
+	movcs	r7, #1			C r7 <= 1
+
+L(sum):	cmn	n, #2
+	movlo	r4, #0
+	ldrhs	r4, [ap], #4
+	movls	r5, #0
+	ldrhi	r5, [ap], #4
+
+	adds	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, #0
+	adc	r7, r7, #0		C r7 <= 2
+
+L(sum2):
+	bic	r0, r2, #0xff000000
+	add	r0, r0, r2, lsr #24
+	add	r0, r0, r7
+
+	mov	r7, r3, lsl #8
+	bic	r1, r7, #0xff000000
+	add	r0, r0, r1
+	add	r0, r0, r3, lsr #16
+
+	mov	r7, r12, lsl #16
+	bic	r1, r7, #0xff000000
+	add	r0, r0, r1
+	add	r0, r0, r12, lsr #8
+
+	pop	{ r4, r5, r6, r7 }
+	return	lr
+
+L(le2):	cmn	n, #1
+	bne	L(1)
+	ldmia	ap!, { r2, r3 }
+	mov	r12, #0
+	b	L(sum2)
+L(1):	ldr	r2, [ap]
+	bic	r0, r2, #0xff000000
+	add	r0, r0, r2, lsr #24
+	pop	{ r4, r5, r6, r7 }
+	return	lr
+EPILOGUE()
diff --git a/mpn/arm/mode1o.asm b/mpn/arm/mode1o.asm
new file mode 100644
index 0000000..4de4cf6
--- /dev/null
+++ b/mpn/arm/mode1o.asm
@@ -0,0 +1,92 @@
+dnl  ARM mpn_modexact_1c_odd
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	10
+C Cortex-A15	 9
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	-
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`up', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cy', `r3')
+
+	.protected	binvert_limb_table
+ASM_START()
+PROLOGUE(mpn_modexact_1c_odd)
+	stmfd	sp!, {r4, r5}
+
+	LEA(	r4, binvert_limb_table)
+
+	ldr	r5, [up], #4		C up[0]
+
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	mul	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, asl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, asl #1	C r4 = inverse
+
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(end)
+
+L(top):	sbcs	cy, r5, cy
+	ldr	r5, [up], #4
+	sub	n, n, #1
+	mul	r12, r4, cy
+	tst	n, n
+	umull	r12, cy, d, r12
+	bne	L(top)
+
+L(end):	sbcs	cy, r5, cy
+	mul	r12, r4, cy
+	umull	r12, r0, d, r12
+	addcc	r0, r0, #1
+
+	ldmfd	sp!, {r4, r5}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/mul_1.asm b/mpn/arm/mul_1.asm
new file mode 100644
index 0000000..288368f
--- /dev/null
+++ b/mpn/arm/mul_1.asm
@@ -0,0 +1,94 @@
+dnl  ARM mpn_mul_1 -- Multiply a limb vector with a limb and store the result
+dnl  in a second limb vector.
+dnl  Contributed by Robert Harley.
+
+dnl  Copyright 1998, 2000, 2001, 2003, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	6-8
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.75
+C Cortex-A15	 ?
+
+C We should rewrite this along the lines of addmul_1.asm.  That should save a
+C cycle on StrongARM, and several cycles on XScale.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n',`r2')
+define(`vl',`r3')
+
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stmfd	sp!, { r8, r9, lr }
+	ands	r12, n, #1
+	beq	L(skip1)
+	ldr	lr, [up], #4
+	umull	r9, r12, lr, vl
+	str	r9, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	mov	r8, r12
+	ldmia	up!, { r12, lr }
+	mov	r9, #0
+	umlal	r8, r9, r12, vl
+	mov	r12, #0
+	umlal	r9, r12, lr, vl
+	stmia	rp!, { r8, r9 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	stmfd	sp!, { r6, r7 }
+
+L(top):	mov	r6, r12
+	ldmia	up!, { r8, r9, r12, lr }
+	ldr	r7, [rp, #12]			C cache allocate
+	mov	r7, #0
+	umlal	r6, r7, r8, vl
+	mov	r8, #0
+	umlal	r7, r8, r9, vl
+	mov	r9, #0
+	umlal	r8, r9, r12, vl
+	mov	r12, #0
+	umlal	r9, r12, lr, vl
+	subs	n, n, #4
+	stmia	rp!, { r6, r7, r8, r9 }
+	bne	L(top)
+
+	ldmfd	sp!, { r6, r7 }
+
+L(rtn):	mov	r0, r12
+	ldmfd	sp!, { r8, r9, pc }
+EPILOGUE()
diff --git a/mpn/arm/neon/hamdist.asm b/mpn/arm/neon/hamdist.asm
new file mode 100644
index 0000000..0f7acb4
--- /dev/null
+++ b/mpn/arm/neon/hamdist.asm
@@ -0,0 +1,194 @@
+dnl  ARM Neon mpn_hamdist -- mpn bit hamming distance.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.89
+C Cortex-A15	 0.95
+
+C TODO
+C  * Explore using vldr and vldm.  Does it help on A9?  (These loads do
+C    64-bits-at-a-time, which will mess up in big-endian mode.  Except not for
+C    popcount. Except perhaps also for popcount for the edge loads.)
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+C INPUT PARAMETERS
+define(`ap', r0)
+define(`bp', r1)
+define(`n',  r2)
+
+C We sum into 16 16-bit counters in q8,q9, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/32 = 0x3fff limbs.  We use a chunksize close to that, but which
+C can be represented as a 8-bit ARM constant.
+C
+define(`chunksize',0x3f80)
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+
+	cmp	n, #chunksize
+	bhi	L(gt16k)
+
+L(lt16k):
+	vmov.i64   q8, #0		C clear summation register
+	vmov.i64   q9, #0		C clear summation register
+
+	tst	   n, #1
+	beq	   L(xxx0)
+	vmov.i64   d0, #0
+	vmov.i64   d20, #0
+	sub	   n, n, #1
+	vld1.32   {d0[0]}, [ap]!	C load 1 limb
+	vld1.32   {d20[0]}, [bp]!	C load 1 limb
+	veor	   d0, d0, d20
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24		C d16/q8 = 0; could just splat
+
+L(xxx0):tst	   n, #2
+	beq	   L(xx00)
+	sub	   n, n, #2
+	vld1.32    {d0}, [ap]!		C load 2 limbs
+	vld1.32    {d20}, [bp]!		C load 2 limbs
+	veor	   d0, d0, d20
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24
+
+L(xx00):tst	   n, #4
+	beq	   L(x000)
+	sub	   n, n, #4
+	vld1.32    {q0}, [ap]!		C load 4 limbs
+	vld1.32    {q10}, [bp]!		C load 4 limbs
+	veor	   q0, q0, q10
+	vcnt.8	   q12, q0
+	vpadal.u8  q8, q12
+
+L(x000):tst	   n, #8
+	beq	   L(0000)
+
+	subs	   n, n, #8
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vld1.32    {q10,q11}, [bp]!	C load 8 limbs
+	bls	   L(sum)
+
+L(gt8):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q14,q15}, [bp]!	C load 8 limbs
+	veor	   q0, q0, q10
+	veor	   q1, q1, q11
+	sub	   n, n, #8
+	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	b	   L(mid)
+
+L(0000):subs	   n, n, #16
+	blo	   L(e0)
+
+	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vld1.32    {q14,q15}, [bp]!	C load 8 limbs
+	vld1.32    {q10,q11}, [bp]!	C load 8 limbs
+	veor	   q2, q2, q14
+	veor	   q3, q3, q15
+	vcnt.8	   q12, q2
+	vcnt.8	   q13, q3
+	subs	   n, n, #16
+	blo	   L(end)
+
+L(top):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q14,q15}, [bp]!	C load 8 limbs
+	veor	   q0, q0, q10
+	veor	   q1, q1, q11
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q0
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q1
+L(mid):	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vld1.32    {q10,q11}, [bp]!	C load 8 limbs
+	veor	   q2, q2, q14
+	veor	   q3, q3, q15
+	subs	   n, n, #16
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q2
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q3
+	bhs	   L(top)
+
+L(end):	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+L(sum):	veor	   q0, q0, q10
+	veor	   q1, q1, q11
+	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+	vadd.i16   q8, q8, q9
+					C we have 8 16-bit counts
+L(e0):	vpaddl.u16 q8, q8		C we have 4 32-bit counts
+	vpaddl.u32 q8, q8		C we have 2 64-bit counts
+	vmov.32    r0, d16[0]
+	vmov.32    r1, d17[0]
+	add	   r0, r0, r1
+	bx	lr
+
+C Code for large count.  Splits operand and calls above code.
+define(`ap2', r5)
+define(`bp2', r6)
+L(gt16k):
+	push	{r4,r5,r6,r14}
+	mov	ap2, ap
+	mov	bp2, bp
+	mov	r3, n			C full count
+	mov	r4, #0			C total sum
+
+1:	mov	n, #chunksize		C count for this invocation
+	bl	L(lt16k)		C could jump deep inside code
+	add	ap2, ap2, #chunksize*4	C point at next chunk
+	add	bp2, bp2, #chunksize*4	C point at next chunk
+	add	r4, r4, r0
+	mov	ap, ap2			C put chunk pointer in place for call
+	mov	bp, bp2			C put chunk pointer in place for call
+	sub	r3, r3, #chunksize
+	cmp	r3, #chunksize
+	bhi	1b
+
+	mov	n, r3			C count for final invocation
+	bl	L(lt16k)
+	add	r0, r4, r0
+	pop	{r4,r5,r6,pc}
+EPILOGUE()
diff --git a/mpn/arm/neon/lorrshift.asm b/mpn/arm/neon/lorrshift.asm
new file mode 100644
index 0000000..d1950da
--- /dev/null
+++ b/mpn/arm/neon/lorrshift.asm
@@ -0,0 +1,279 @@
+dnl  ARM Neon mpn_lshift and mpn_rshift.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C StrongARM	 -		 -
+C XScale	 -		 -
+C Cortex-A7	 ?		 ?
+C Cortex-A8	 ?		 ?
+C Cortex-A9	 3		 3				Y
+C Cortex-A15	 1.5		 1.5				Y
+
+
+C We read 64 bits at a time at 32-bit aligned addresses, and except for the
+C first and last store, we write using 64-bit aligned addresses.  All shifting
+C is done on 64-bit words in 'extension' registers.
+C
+C It should be possible to read also using 64-bit alignment, by manipulating
+C the shift count for unaligned operands.  Not done, since it does not seem to
+C matter for A9 or A15.
+C
+C This will not work in big-endian mode.
+
+C TODO
+C  * Try using 128-bit operations.  Note that Neon lacks pure 128-bit shifts,
+C    which might make it tricky.
+C  * Clean up and simplify.
+C  * Consider sharing most of the code for lshift and rshift, since the feed-in
+C    code, the loop, and most of the wind-down code are identical.
+C  * Replace the basecase code with code using 'extension' registers.
+C  * Optimise.  It is not clear that this loop insn permutation is optimal for
+C    either A9 or A15.
+
+C INPUT PARAMETERS
+define(`rp',  `r0')
+define(`ap',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+
+ifdef(`OPERATION_lshift',`
+	define(`IFLSH', `$1')
+	define(`IFRSH', `')
+	define(`X',`0')
+	define(`Y',`1')
+	define(`func',`mpn_lshift')
+')
+ifdef(`OPERATION_rshift',`
+	define(`IFLSH', `')
+	define(`IFRSH', `$1')
+	define(`X',`1')
+	define(`Y',`0')
+	define(`func',`mpn_rshift')
+')
+
+MULFUNC_PROLOGUE(mpn_lshift mpn_rshift)
+
+ASM_START(neon)
+	TEXT
+	ALIGN(64)
+PROLOGUE(func)
+IFLSH(`	mov	r12, n, lsl #2	')
+IFLSH(`	add	rp, rp, r12	')
+IFLSH(`	add	ap, ap, r12	')
+
+	cmp	n, #4			C SIMD code n limit
+	ble	L(base)
+
+ifdef(`OPERATION_lshift',`
+	vdup.32	d6, r3			C left shift count is positive
+	sub	r3, r3, #64		C right shift count is negative
+	vdup.32	d7, r3
+	mov	r12, #-8')		C lshift pointer update offset
+ifdef(`OPERATION_rshift',`
+	rsb	r3, r3, #0		C right shift count is negative
+	vdup.32	d6, r3
+	add	r3, r3, #64		C left shift count is positive
+	vdup.32	d7, r3
+	mov	r12, #8')		C rshift pointer update offset
+
+IFLSH(`	sub	ap, ap, #8	')
+	vld1.32	{d19}, [ap], r12	C load initial 2 limbs
+	vshl.u64 d18, d19, d7		C retval
+
+	tst	rp, #4			C is rp 64-bit aligned already?
+	beq	L(rp_aligned)		C yes, skip
+IFLSH(`	add	ap, ap, #4	')	C move back ap pointer
+IFRSH(`	sub	ap, ap, #4	')	C move back ap pointer
+	vshl.u64 d4, d19, d6
+	sub	n, n, #1		C first limb handled
+IFLSH(`	sub	 rp, rp, #4	')
+	vst1.32	 {d4[Y]}, [rp]IFRSH(!)	C store first limb, rp gets aligned
+	vld1.32	 {d19}, [ap], r12	C load ap[1] and ap[2]
+
+L(rp_aligned):
+IFLSH(`	sub	rp, rp, #8	')
+	subs	n, n, #6
+	blt	L(two_or_three_more)
+	tst	n, #2
+	beq	L(2)
+
+L(1):	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d5, d19, d6
+	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	sub	n, n, #2
+	b	 L(mid)
+
+L(2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	subs	n, n, #4
+	blt	L(end)
+
+L(top):	vld1.32	 {d16}, [ap], r12
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+L(mid):	vld1.32	 {d17}, [ap], r12
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	subs	n, n, #4
+	bge	L(top)
+
+L(end):	tst	 n, #1
+	beq	 L(evn)
+
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+	b	 L(cj1)
+
+L(evn):	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d16, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+	vorr	 d2, d5, d0
+	b	 L(cj2)
+
+C Load last 2 - 3 limbs, store last 4 - 5 limbs
+L(two_or_three_more):
+	tst	n, #1
+	beq	L(l2)
+
+L(l3):	vshl.u64 d5, d19, d6
+	vld1.32	 {d17}, [ap], r12
+L(cj1):	veor	 d16, d16, d16
+IFLSH(`	add	 ap, ap, #4	')
+	vld1.32	 {d16[Y]}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+IFLSH(`	add	 rp, rp, #4	')
+	vst1.32	 {d5[Y]}, [rp]
+	vmov.32	 r0, d18[X]
+	bx	lr
+
+L(l2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vshl.u64 d1, d16, d7
+	vshl.u64 d16, d16, d6
+	vorr	 d2, d4, d1
+L(cj2):	vst1.32	 {d2}, [rp:64], r12
+	vst1.32	 {d16}, [rp]
+	vmov.32	 r0, d18[X]
+	bx	lr
+
+
+define(`tnc', `r12')
+L(base):
+	push	{r4, r6, r7, r8}
+ifdef(`OPERATION_lshift',`
+	ldr	r4, [ap, #-4]!
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsl cnt
+	tst	n, #1
+	beq	L(ev)			C n even
+
+L(od):	subs	n, n, #2
+	bcc	L(ed1)			C n = 1
+	ldr	r8, [ap, #-4]!
+	b	L(md)			C n = 3
+
+L(ev):	ldr	r6, [ap, #-4]!
+	subs	n, n, #2
+	beq	L(ed)			C n = 3
+					C n = 4
+L(tp):	ldr	r8, [ap, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(md):	ldr	r6, [ap, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r8, lsl cnt
+
+L(ed):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(ed1):	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+')
+ifdef(`OPERATION_rshift',`
+	ldr	r4, [ap]
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsr cnt
+	tst	n, #1
+	beq	L(ev)			C n even
+
+L(od):	subs	n, n, #2
+	bcc	L(ed1)			C n = 1
+	ldr	r8, [ap, #4]!
+	b	L(md)			C n = 3
+
+L(ev):	ldr	r6, [ap, #4]!
+	subs	n, n, #2
+	beq	L(ed)			C n = 2
+					C n = 4
+
+L(tp):	ldr	r8, [ap, #4]!
+	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(md):	ldr	r6, [ap, #4]!
+	orr	r7, r7, r8, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r8, lsr cnt
+
+L(ed):	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(ed1):	str	r7, [rp], #4
+	mov	r0, r4, lsl tnc
+')
+	pop	{r4, r6, r7, r8}
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/neon/lshiftc.asm b/mpn/arm/neon/lshiftc.asm
new file mode 100644
index 0000000..9e7ca18
--- /dev/null
+++ b/mpn/arm/neon/lshiftc.asm
@@ -0,0 +1,242 @@
+dnl  ARM Neon mpn_lshiftc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C StrongARM	 -		 -
+C XScale	 -		 -
+C Cortex-A7	 ?		 ?
+C Cortex-A8	 ?		 ?
+C Cortex-A9	 3.5		 3.5				Y
+C Cortex-A15	 1.75		 1.75				Y
+
+
+C We read 64 bits at a time at 32-bit aligned addresses, and except for the
+C first and last store, we write using 64-bit aligned addresses.  All shifting
+C is done on 64-bit words in 'extension' registers.
+C
+C It should be possible to read also using 64-bit alignment, by manipulating
+C the shift count for unaligned operands.  Not done, since it does not seem to
+C matter for A9 or A15.
+C
+C This will not work in big-endian mode.
+
+C TODO
+C  * Try using 128-bit operations.  Note that Neon lacks pure 128-bit shifts,
+C    which might make it tricky.
+C  * Clean up and simplify.
+C  * Consider sharing most of the code for lshift and rshift, since the feed-in
+C    code, the loop, and most of the wind-down code are identical.
+C  * Replace the basecase code with code using 'extension' registers.
+C  * Optimise.  It is not clear that this loop insn permutation is optimal for
+C    either A9 or A15.
+
+C INPUT PARAMETERS
+define(`rp',  `r0')
+define(`ap',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+
+ASM_START(neon)
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_lshiftc)
+	mov	r12, n, lsl #2
+	add	rp, rp, r12
+	add	ap, ap, r12
+
+	cmp	n, #4			C SIMD code n limit
+	ble	L(base)
+
+	vdup.32	d6, r3			C left shift count is positive
+	sub	r3, r3, #64		C right shift count is negative
+	vdup.32	d7, r3
+	mov	r12, #-8		C lshift pointer update offset
+
+	sub	ap, ap, #8
+	vld1.32	{d19}, [ap], r12	C load initial 2 limbs
+	vshl.u64 d18, d19, d7		C retval
+
+	tst	rp, #4			C is rp 64-bit aligned already?
+	beq	L(rp_aligned)		C yes, skip
+	vmvn	 d19, d19
+	add	ap, ap, #4		C move back ap pointer
+	vshl.u64 d4, d19, d6
+	sub	n, n, #1		C first limb handled
+	sub	 rp, rp, #4
+	vst1.32	 {d4[1]}, [rp]		C store first limb, rp gets aligned
+	vld1.32	 {d19}, [ap], r12	C load ap[1] and ap[2]
+
+L(rp_aligned):
+	sub	rp, rp, #8
+	subs	n, n, #6
+	vmvn	 d19, d19
+	blt	L(two_or_three_more)
+	tst	n, #2
+	beq	L(2)
+
+L(1):	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d5, d19, d6
+	vmvn	 d17, d17
+	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	sub	n, n, #2
+	b	 L(mid)
+
+L(2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vmvn	 d16, d16
+	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	subs	n, n, #4
+	blt	L(end)
+
+L(top):	vmvn	 d17, d17
+	vld1.32	 {d16}, [ap], r12
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+L(mid):	vmvn	 d16, d16
+	vld1.32	 {d17}, [ap], r12
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	subs	n, n, #4
+	bge	L(top)
+
+L(end):	tst	 n, #1
+	beq	 L(evn)
+
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+	b	 L(cj1)
+
+L(evn):	vmvn	 d17, d17
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+	vmov.u8	 d17, #255
+	vorr	 d2, d5, d0
+	vshl.u64 d0, d17, d7
+	vorr	 d3, d4, d0
+	b	 L(cj2)
+
+C Load last 2 - 3 limbs, store last 4 - 5 limbs
+L(two_or_three_more):
+	tst	n, #1
+	beq	L(l2)
+
+L(l3):	vshl.u64 d5, d19, d6
+	vld1.32	 {d17}, [ap], r12
+L(cj1):	vmov.u8	 d16, #0
+	add	 ap, ap, #4
+	vmvn	 d17, d17
+	vld1.32	 {d16[1]}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vmvn	 d16, d16
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+	add	 rp, rp, #4
+	vst1.32	 {d5[1]}, [rp]
+	vmov.32	 r0, d18[0]
+	bx	lr
+
+L(l2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vmvn	 d16, d16
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vmov.u8	 d17, #255
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vorr	 d3, d5, d0
+L(cj2):	vst1.32	 {d2}, [rp:64], r12
+	vst1.32	 {d3}, [rp]
+	vmov.32	 r0, d18[0]
+	bx	lr
+
+
+define(`tnc', `r12')
+L(base):
+	push	{r4, r6, r7, r8}
+	ldr	r4, [ap, #-4]!
+	rsb	tnc, cnt, #32
+	mvn	r6, r4
+
+	mov	r7, r6, lsl cnt
+	tst	n, #1
+	beq	L(ev)			C n even
+
+L(od):	subs	n, n, #2
+	bcc	L(ed1)			C n = 1
+	ldr	r8, [ap, #-4]!
+	mvn	r8, r8
+	b	L(md)			C n = 3
+
+L(ev):	ldr	r6, [ap, #-4]!
+	mvn	r6, r6
+	subs	n, n, #2
+	beq	L(ed)			C n = 3
+					C n = 4
+L(tp):	ldr	r8, [ap, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r8, r8
+	mov	r7, r6, lsl cnt
+L(md):	ldr	r6, [ap, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r6, r6
+	mov	r7, r8, lsl cnt
+
+L(ed):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(ed1):	mvn	r6, #0
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+	pop	{r4, r6, r7, r8}
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/neon/popcount.asm b/mpn/arm/neon/popcount.asm
new file mode 100644
index 0000000..2cabbda
--- /dev/null
+++ b/mpn/arm/neon/popcount.asm
@@ -0,0 +1,166 @@
+dnl  ARM Neon mpn_popcount -- mpn bit population count.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.125
+C Cortex-A15	 0.56
+
+C TODO
+C  * Explore using vldr and vldm.  Does it help on A9?  (These loads do
+C    64-bits-at-a-time, which will mess up in big-endian mode.  Except not for
+C    popcount. Except perhaps also for popcount for the edge loads.)
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+C INPUT PARAMETERS
+define(`ap', r0)
+define(`n',  r1)
+
+C We sum into 16 16-bit counters in q8,q9, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/32 = 0x3fff limbs.  We use a chunksize close to that, but which
+C can be represented as a 8-bit ARM constant.
+C
+define(`chunksize',0x3f80)
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+
+	cmp	n, #chunksize
+	bhi	L(gt16k)
+
+L(lt16k):
+	vmov.i64   q8, #0		C clear summation register
+	vmov.i64   q9, #0		C clear summation register
+
+	tst	   n, #1
+	beq	   L(xxx0)
+	vmov.i64   d0, #0
+	sub	   n, n, #1
+	vld1.32   {d0[0]}, [ap]!	C load 1 limb
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24		C d16/q8 = 0; could just splat
+
+L(xxx0):tst	   n, #2
+	beq	   L(xx00)
+	sub	   n, n, #2
+	vld1.32    {d0}, [ap]!		C load 2 limbs
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24
+
+L(xx00):tst	   n, #4
+	beq	   L(x000)
+	sub	   n, n, #4
+	vld1.32    {q0}, [ap]!		C load 4 limbs
+	vcnt.8	   q12, q0
+	vpadal.u8  q8, q12
+
+L(x000):tst	   n, #8
+	beq	   L(0000)
+
+	subs	   n, n, #8
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	bls	   L(sum)
+
+L(gt8):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	sub	   n, n, #8
+	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	b	   L(mid)
+
+L(0000):subs	   n, n, #16
+	blo	   L(e0)
+
+	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vcnt.8	   q12, q2
+	vcnt.8	   q13, q3
+	subs	   n, n, #16
+	blo	   L(end)
+
+L(top):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q0
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q1
+L(mid):	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	subs	   n, n, #16
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q2
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q3
+	bhs	   L(top)
+
+L(end):	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+L(sum):	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+	vadd.i16   q8, q8, q9
+					C we have 8 16-bit counts
+L(e0):	vpaddl.u16 q8, q8		C we have 4 32-bit counts
+	vpaddl.u32 q8, q8		C we have 2 64-bit counts
+	vmov.32    r0, d16[0]
+	vmov.32    r1, d17[0]
+	add	   r0, r0, r1
+	bx	lr
+
+C Code for large count.  Splits operand and calls above code.
+define(`ap2', r2)			C caller-saves reg not used above
+L(gt16k):
+	push	{r4,r14}
+	mov	ap2, ap
+	mov	r3, n			C full count
+	mov	r4, #0			C total sum
+
+1:	mov	n, #chunksize		C count for this invocation
+	bl	L(lt16k)		C could jump deep inside code
+	add	ap2, ap2, #chunksize*4	C point at next chunk
+	add	r4, r4, r0
+	mov	ap, ap2			C put chunk pointer in place for call
+	sub	r3, r3, #chunksize
+	cmp	r3, #chunksize
+	bhi	1b
+
+	mov	n, r3			C count for final invocation
+	bl	L(lt16k)
+	add	r0, r4, r0
+	pop	{r4,pc}
+EPILOGUE()
diff --git a/mpn/arm/neon/sec_tabselect.asm b/mpn/arm/neon/sec_tabselect.asm
new file mode 100644
index 0000000..7d3fecd
--- /dev/null
+++ b/mpn/arm/neon/sec_tabselect.asm
@@ -0,0 +1,140 @@
+dnl  ARM Neon mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.15
+C Cortex-A15	 0.65
+
+define(`rp',     `r0')
+define(`tp',     `r1')
+define(`n',      `r2')
+define(`nents',  `r3')
+C define(`which',  on stack)
+
+define(`i',      `r4')
+define(`j',      `r5')
+
+define(`maskq',  `q10')
+define(`maskd',  `d20')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	push	{r4-r5}
+
+	add	  r4, sp, #8
+	vld1.32	  {d30[], d31[]}, [r4]	C 4 `which' copies
+	vmov.i32  q14, #1		C 4 copies of 1
+
+	subs	j, n, #8
+	bmi	L(outer_end)
+
+L(outer_top):
+	mov	  i, nents
+	mov	  r12, tp		C preserve tp
+	veor	  q13, q13, q13		C 4 counter copies
+	veor	  q2, q2, q2
+	veor	  q3, q3, q3
+	ALIGN(16)
+L(top):	vceq.i32  maskq, q13, q15	C compare idx copies to `which' copies
+	vld1.32	  {q0,q1}, [tp]
+	vadd.i32  q13, q13, q14
+	vbit	  q2, q0, maskq
+	vbit	  q3, q1, maskq
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(top)
+	vst1.32	  {q2,q3}, [rp]!
+	add	  tp, r12, #32		C restore tp, point to next slice
+	subs	  j, j, #8
+	bpl	  L(outer_top)
+L(outer_end):
+
+	tst	  n, #4
+	beq	  L(b0xx)
+L(b1xx):mov	  i, nents
+	mov	  r12, tp
+	veor	  q13, q13, q13
+	veor	  q2, q2, q2
+	ALIGN(16)
+L(tp4):	vceq.i32  maskq, q13, q15
+	vld1.32	  {q0}, [tp]
+	vadd.i32  q13, q13, q14
+	vbit	  q2, q0, maskq
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(tp4)
+	vst1.32	  {q2}, [rp]!
+	add	  tp, r12, #16
+
+L(b0xx):tst	  n, #2
+	beq	  L(b00x)
+L(b01x):mov	  i, nents
+	mov	  r12, tp
+	veor	  d26, d26, d26
+	veor	  d4, d4, d4
+	ALIGN(16)
+L(tp2):	vceq.i32  maskd, d26, d30
+	vld1.32	  {d0}, [tp]
+	vadd.i32  d26, d26, d28
+	vbit	  d4, d0, maskd
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(tp2)
+	vst1.32	  {d4}, [rp]!
+	add	  tp, r12, #8
+
+L(b00x):tst	  n, #1
+	beq	  L(b000)
+L(b001):mov	  i, nents
+	mov	  r12, tp
+	veor	  d26, d26, d26
+	veor	  d4, d4, d4
+	ALIGN(16)
+L(tp1):	vceq.i32  maskd, d26, d30
+	vld1.32	  {d0[0]}, [tp]
+	vadd.i32  d26, d26, d28
+	vbit	  d4, d0, maskd
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(tp1)
+	vst1.32	  {d4[0]}, [rp]
+
+L(b000):pop	{r4-r5}
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/rsh1aors_n.asm b/mpn/arm/rsh1aors_n.asm
new file mode 100644
index 0000000..c99f34c
--- /dev/null
+++ b/mpn/arm/rsh1aors_n.asm
@@ -0,0 +1,124 @@
+dnl  ARM mpn_rsh1add_n and mpn_rsh1sub_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	3.64-3.7
+C Cortex-A15	 2.5
+
+C TODO
+C  * Not optimised.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_rsh1add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`RSTCY',	`cmn	$1, $1')
+  define(`func',	mpn_rsh1add_n)
+  define(`func_nc',	mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`RSTCY',
+	`mvn	$2, #0x80000000
+	cmp	$2, $1')
+  define(`func',	mpn_rsh1sub_n)
+  define(`func_nc',	mpn_rsh1sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{r4-r11}
+	ldr	r4, [up], #4
+	ldr	r8, [vp], #4
+	ADDSUB	r4, r4, r8
+	movs	r12, r7, rrx
+	and	r11, r4, #1	C return value
+	subs	n, n, #4
+	blo	L(end)
+
+L(top):	ldmia	up!, {r5,r6,r7}
+	ldmia	vp!, {r8,r9,r10}
+	cmn	r12, r12
+	ADDSUBC	r5, r5, r8
+	ADDSUBC	r6, r6, r9
+	ADDSUBC	r7, r7, r10
+	movs	r12, r7, rrx
+	movs	r6, r6, rrx
+	movs	r5, r5, rrx
+	movs	r4, r4, rrx
+	subs	n, n, #3
+	stmia	rp!, {r4,r5,r6}
+	mov	r4, r7
+	bhs	L(top)
+
+L(end):	cmn	n, #2
+	bls	L(e2)
+	ldm	up, {r5,r6}
+	ldm	vp, {r8,r9}
+	cmn	r12, r12
+	ADDSUBC	r5, r5, r8
+	ADDSUBC	r6, r6, r9
+	movs	r12, r6, rrx
+	movs	r5, r5, rrx
+	movs	r4, r4, rrx
+	stmia	rp!, {r4,r5}
+	mov	r4, r6
+	b	L(e1)
+
+L(e2):	bne	L(e1)
+	ldr	r5, [up, #0]
+	ldr	r8, [vp, #0]
+	cmn	r12, r12
+	ADDSUBC	r5, r5, r8
+	movs	r12, r5, rrx
+	movs	r4, r4, rrx
+	str	r4, [rp], #4
+	mov	r4, r5
+
+L(e1):	RSTCY(	r12, r1)
+	mov	r4, r4, rrx
+	str	r4, [rp, #0]
+	mov	r0, r11
+	pop	{r4-r11}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/rshift.asm b/mpn/arm/rshift.asm
new file mode 100644
index 0000000..4fc7ae1
--- /dev/null
+++ b/mpn/arm/rshift.asm
@@ -0,0 +1,86 @@
+dnl  ARM mpn_rshift.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 1997, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.5
+C Cortex-A15	 ?
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+define(`tnc', `r12')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	push	{r4, r6, r7, r8}
+	ldr	r4, [up]
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsr cnt
+	tst	n, #1
+	beq	L(evn)			C n even
+
+L(odd):	subs	n, n, #2
+	bcc	L(1)			C n = 1
+	ldr	r8, [up, #4]!
+	b	L(mid)
+
+L(evn):	ldr	r6, [up, #4]!
+	subs	n, n, #2
+	beq	L(end)
+
+L(top):	ldr	r8, [up, #4]!
+	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(mid):	ldr	r6, [up, #4]!
+	orr	r7, r7, r8, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r8, lsr cnt
+	subs	n, n, #2
+	bgt	L(top)
+
+L(end):	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(1):	str	r7, [rp]
+	mov	r0, r4, lsl tnc
+	pop	{r4, r6, r7, r8}
+	return	r14
+EPILOGUE()
diff --git a/mpn/arm/sec_tabselect.asm b/mpn/arm/sec_tabselect.asm
new file mode 100644
index 0000000..348ef24
--- /dev/null
+++ b/mpn/arm/sec_tabselect.asm
@@ -0,0 +1,131 @@
+dnl  ARM mpn_sec_tabselect
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.33
+C Cortex-A15	 2.2
+
+C TODO
+C  * Consider using special code for small nents, either swapping the inner and
+C    outer loops, or providing a few completely unrolling the inner loops.
+
+define(`rp',    `r0')
+define(`tp',    `r1')
+define(`n',     `r2')
+define(`nents', `r3')
+C      which  on stack
+
+define(`i',     `r11')
+define(`j',     `r12')
+define(`c',     `r14')
+define(`mask',  `r7')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	push	{r4-r11, r14}
+
+	subs	j, n, #3
+	bmi	L(outer_end)
+L(outer_top):
+	ldr	c, [sp, #36]
+	mov	i, nents
+	push	{tp}
+
+	mov	r8, #0
+	mov	r9, #0
+	mov	r10, #0
+
+L(top):	subs	c, c, #1
+	ldm	tp, {r4,r5,r6}
+	sbc	mask, mask, mask
+	subs	i, i, #1
+	add	tp, tp, n, lsl #2
+	and	r4, r4, mask
+	and	r5, r5, mask
+	and	r6, r6, mask
+	orr	r8, r8, r4
+	orr	r9, r9, r5
+	orr	r10, r10, r6
+	bge	L(top)
+
+	stmia	rp!, {r8,r9,r10}
+	pop	{tp}
+	add	tp, tp, #12
+	subs	j, j, #3
+	bpl	L(outer_top)
+L(outer_end):
+
+	cmp	j, #-1
+	bne	L(n2)
+
+	ldr	c, [sp, #36]
+	mov	i, nents
+	mov	r8, #0
+	mov	r9, #0
+L(tp2):	subs	c, c, #1
+	sbc	mask, mask, mask
+	ldm	tp, {r4,r5}
+	subs	i, i, #1
+	add	tp, tp, n, lsl #2
+	and	r4, r4, mask
+	and	r5, r5, mask
+	orr	r8, r8, r4
+	orr	r9, r9, r5
+	bge	L(tp2)
+	stmia	rp, {r8,r9}
+	pop	{r4-r11, r14}
+	return	lr
+
+L(n2):	cmp	j, #-2
+	bne	L(n1)
+
+	ldr	c, [sp, #36]
+	mov	i, nents
+	mov	r8, #0
+L(tp1):	subs	c, c, #1
+	sbc	mask, mask, mask
+	ldr	r4, [tp]
+	subs	i, i, #1
+	add	tp, tp, n, lsl #2
+	and	r4, r4, mask
+	orr	r8, r8, r4
+	bge	L(tp1)
+	str	r8, [rp]
+L(n1):	pop	{r4-r11, r14}
+	return	lr
+EPILOGUE()
diff --git a/mpn/arm/udiv.asm b/mpn/arm/udiv.asm
new file mode 100644
index 0000000..bc24421
--- /dev/null
+++ b/mpn/arm/udiv.asm
@@ -0,0 +1,104 @@
+dnl  ARM mpn_udiv_qrnnd -- divide a two limb dividend and a one limb divisor.
+dnl  Return quotient and store remainder through a supplied pointer.
+
+dnl  Copyright 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C INPUT PARAMETERS
+define(`rem_ptr',`r0')
+define(`n1',`r1')
+define(`n0',`r2')
+define(`d',`r3')
+
+C divstep -- develop one quotient bit.  Dividend in $1$2, divisor in $3.
+C Quotient bit is shifted into $2.
+define(`divstep',
+       `adcs	$2, $2, $2
+	adc	$1, $1, $1
+	cmp	$1, $3
+	subcs	$1, $1, $3')
+
+ASM_START()
+PROLOGUE(mpn_udiv_qrnnd)
+	mov	r12, #8			C loop counter for both loops below
+	cmp	d, #0x80000000		C check divisor msb and clear carry
+	bcs	L(_large_divisor)
+
+L(oop):	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	sub	r12, r12, #1
+	teq	r12, #0
+	bne	L(oop)
+
+	str	n1, [rem_ptr]		C store remainder
+	adc	r0, n0, n0		C quotient: add last carry from divstep
+	return	lr
+
+L(_large_divisor):
+	stmfd	sp!, { r8, lr }
+
+	and	r8, n0, #1		C save lsb of dividend
+	mov	lr, n1, lsl #31
+	orrs	n0, lr, n0, lsr #1	C n0 = lo(n1n0 >> 1)
+	mov	n1, n1, lsr #1		C n1 = hi(n1n0 >> 1)
+
+	and	lr, d, #1		C save lsb of divisor
+	movs	d, d, lsr #1		C d = floor(orig_d / 2)
+	adc	d, d, #0		C d = ceil(orig_d / 2)
+
+L(oop2):
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	sub	r12, r12, #1
+	teq	r12, #0
+	bne	L(oop2)
+
+	adc	n0, n0, n0		C shift and add last carry from divstep
+	add	n1, r8, n1, lsl #1	C shift in omitted dividend lsb
+	tst	lr, lr			C test saved divisor lsb
+	beq	L(_even_divisor)
+
+	rsb	d, lr, d, lsl #1	C restore orig d value
+	adds	n1, n1, n0		C fix remainder for omitted divisor lsb
+	addcs	n0, n0, #1		C adjust quotient if rem. fix carried
+	subcs	n1, n1, d		C adjust remainder accordingly
+	cmp	n1, d			C remainder >= divisor?
+	subcs	n1, n1, d		C adjust remainder
+	addcs	n0, n0, #1		C adjust quotient
+
+L(_even_divisor):
+	str	n1, [rem_ptr]		C store remainder
+	mov	r0, n0			C quotient
+	ldmfd	sp!, { r8, pc }
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/mpn/arm/v5/gcd_11.asm b/mpn/arm/v5/gcd_11.asm
new file mode 100644
index 0000000..fa3ea44
--- /dev/null
+++ b/mpn/arm/v5/gcd_11.asm
@@ -0,0 +1,70 @@
+dnl  ARM v5 mpn_gcd_11.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for ARM by Torbjörn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/bit (approx)
+C StrongARM	 -
+C XScale	 ?
+C Cortex-A5	 6.45	obsolete
+C Cortex-A7	 6.41	obsolete
+C Cortex-A8	 5.0	obsolete
+C Cortex-A9	 5.9	obsolete
+C Cortex-A15	 4.40	obsolete
+C Cortex-A17	 5.68	obsolete
+C Cortex-A53	 4.37	obsolete
+C Numbers measured with: speed -CD -s8-32 -t24 mpn_gcd_1
+
+define(`u0',    `r0')
+define(`v0',    `r1')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	subs	r3, u0, v0	C			0
+	beq	L(end)		C
+
+	ALIGN(16)
+L(top):	sub	r2, v0, u0	C			0,5
+	and	r12, r2, r3	C			1
+	clz	r12, r12	C			2
+	rsb	r12, r12, #31	C			3
+	rsbcc	r3, r3, #0	C v = abs(u-v), even	1
+	movcs	u0, v0		C u = min(u,v)		1
+	lsr	v0, r3, r12	C			4
+	subs	r3, u0, v0	C			5
+	bne	L(top)		C
+
+L(end):	bx	lr
+EPILOGUE()
diff --git a/mpn/arm/v5/gcd_22.asm b/mpn/arm/v5/gcd_22.asm
new file mode 100644
index 0000000..6888616
--- /dev/null
+++ b/mpn/arm/v5/gcd_22.asm
@@ -0,0 +1,117 @@
+dnl  ARM v5 mpn_gcd_22.
+
+dnl  Copyright 2019, 2022 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/bit (approx)
+C StrongARM	 -
+C XScale	 -
+C ARM11		13
+C Cortex-A5	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 ?
+C Cortex-A12	 ?
+C Cortex-A15	 ?
+C Cortex-A17	 ?
+C Cortex-A53	 ?
+
+
+define(`gp',    `r0')
+
+define(`u1',    `r1')
+define(`u0',    `r2')
+define(`v1',    `r3')
+define(`v0',    `r4')
+
+define(`t0',    `r5')
+define(`t1',    `r6')
+define(`cnt',   `r7')
+
+ASM_START()
+PROLOGUE(mpn_gcd_22)
+	push	{ r4-r7 }
+
+	ldr	v0, [sp,#16]		C
+
+L(top):	subs	t0, u0, v0		C 0 7
+	beq	L(lowz)
+	sbcs	t1, u1, v1		C 1 8
+
+	sub	cnt, v0, u0
+	and	cnt, cnt, t0
+
+	negcc	t0, t0
+	mvncc	t1, t1
+L(bck):	movcc	v0, u0
+	movcc	v1, u1
+
+	clz	r12, cnt		C 2
+	rsb	cnt, r12, #31		C 3
+	add	r12, r12, #1
+
+	lsr	u0, t0, cnt		C 3
+	lsl	r12, t1, r12		C 4
+	lsr	u1, t1, cnt		C 3
+	orr	u0, u0, r12		C 5
+
+	orrs	r12, u1, v1
+	bne	L(top)
+
+
+	str	r12, [gp,#4]		C high result limb <= 0
+
+	mov	r6, gp
+	mov	r0, u0			C pass 1st argument
+	mov	r1, v0			C pass 2nd argument
+	mov	r7, r14			C preserve link register
+	bl	mpn_gcd_11
+	str	r0, [r6,#0]
+	mov	r14, r7
+	pop	{ r4-r7 }
+	bx	r14
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	subs	t0, u1, v1
+	beq	L(end)
+	mov	t1, #0
+	sub	cnt, v1, u1
+	and	cnt, cnt, t0
+	negcc	t0, t0
+	b	L(bck)
+
+L(end):	str	v0, [gp,#0]
+	str	v1, [gp,#4]
+	pop	{ r4-r7 }
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/v5/mod_1_1.asm b/mpn/arm/v5/mod_1_1.asm
new file mode 100644
index 0000000..6802346
--- /dev/null
+++ b/mpn/arm/v5/mod_1_1.asm
@@ -0,0 +1,129 @@
+dnl  ARM mpn_mod_1_1p
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 7
+C Cortex-A15	 6
+
+define(`ap', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cps',`r3')
+
+ASM_START()
+PROLOGUE(mpn_mod_1_1p)
+	push	{r4-r10}
+	add	r0, r0, r1, asl #2
+	ldr	r5, [r0, #-4]!
+	ldr	r12, [r0, #-4]!
+	subs	r1, r1, #2
+	ble	L(4)
+	ldr	r8, [r3, #12]
+	mov	r4, r12
+	mov	r10, r5
+	umull	r7, r5, r10, r8
+	sub	r1, r1, #1
+	b	L(mid)
+
+L(top):	adds	r12, r6, r7
+	adcs	r10, r4, r5
+	sub	r1, r1, #1
+	mov	r6, #0
+	movcs	r6, r8
+	umull	r7, r5, r10, r8
+	adds	r4, r12, r6
+	subcs	r4, r4, r2
+L(mid):	ldr	r6, [r0, #-4]!
+	teq	r1, #0
+	bne	L(top)
+
+	adds	r12, r6, r7
+	adcs	r5, r4, r5
+	subcs	r5, r5, r2
+L(4):	ldr	r1, [r3, #4]
+	cmp	r1, #0
+	beq	L(7)
+	ldr	r4, [r3, #8]
+	umull	r0, r6, r5, r4
+	adds	r12, r0, r12
+	addcs	r6, r6, #1
+	rsb	r0, r1, #32
+	mov	r0, r12, lsr r0
+	orr	r5, r0, r6, asl r1
+	mov	r12, r12, asl r1
+	b	L(8)
+L(7):	cmp	r5, r2
+	subcs	r5, r5, r2
+L(8):	ldr	r0, [r3, #0]
+	umull	r4, r3, r5, r0
+	add	r5, r5, #1
+	adds	r0, r4, r12
+	adc	r5, r3, r5
+	mul	r5, r2, r5
+	sub	r12, r12, r5
+	cmp	r12, r0
+	addhi	r12, r12, r2
+	cmp	r2, r12
+	subls	r12, r12, r2
+	mov	r0, r12, lsr r1
+	pop	{r4-r10}
+	bx	r14
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1_1p_cps)
+	stmfd	sp!, {r4, r5, r6, r14}
+	mov	r5, r0
+	clz	r4, r1
+	mov	r0, r1, asl r4
+	rsb	r6, r0, #0
+	bl	mpn_invert_limb
+	str	r0, [r5, #0]
+	str	r4, [r5, #4]
+	cmp	r4, #0
+	beq	L(2)
+	rsb	r1, r4, #32
+	mov	r3, #1
+	mov	r3, r3, asl r4
+	orr	r3, r3, r0, lsr r1
+	mul	r3, r6, r3
+	mov	r4, r3, lsr r4
+	str	r4, [r5, #8]
+L(2):	mul	r0, r6, r0
+	str	r0, [r5, #12]
+	ldmfd	sp!, {r4, r5, r6, pc}
+EPILOGUE()
diff --git a/mpn/arm/v5/mod_1_2.asm b/mpn/arm/v5/mod_1_2.asm
new file mode 100644
index 0000000..fb70024
--- /dev/null
+++ b/mpn/arm/v5/mod_1_2.asm
@@ -0,0 +1,156 @@
+dnl  ARM mpn_mod_1s_2p
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.25
+C Cortex-A15	 3
+
+define(`ap', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cps',`r3')
+
+ASM_START()
+PROLOGUE(mpn_mod_1s_2p)
+	push	{r4-r10}
+	tst	n, #1
+	add	r7, r3, #8
+	ldmia	r7, {r7, r8, r12}	C load B1, B2, B3
+	add	ap, ap, n, lsl #2	C put ap at operand end
+	beq	L(evn)
+
+L(odd):	subs	n, n, #1
+	beq	L(1)
+	ldmdb	ap!, {r4,r6,r9}
+	mov	r10, #0
+	umlal	r4, r10, r6, r7
+	umlal	r4, r10, r9, r8
+	b	L(com)
+
+L(evn):	ldmdb	ap!, {r4,r10}
+L(com):	subs	n, n, #2
+	ble	L(end)
+	ldmdb	ap!, {r5,r6}
+	b	L(mid)
+
+L(top):	mov	r9, #0
+	umlal	r5, r9, r6, r7		C B1
+	umlal	r5, r9, r4, r8		C B2
+	ldmdb	ap!, {r4,r6}
+	umlal	r5, r9, r10, r12	C B3
+	ble	L(xit)
+	mov	r10, #0
+	umlal	r4, r10, r6, r7		C B1
+	umlal	r4, r10, r5, r8		C B2
+	ldmdb	ap!, {r5,r6}
+	umlal	r4, r10, r9, r12	C B3
+L(mid):	subs	n, n, #4
+	bge	L(top)
+
+	mov	r9, #0
+	umlal	r5, r9, r6, r7		C B1
+	umlal	r5, r9, r4, r8		C B2
+	umlal	r5, r9, r10, r12	C B3
+	mov	r4, r5
+
+L(end):	movge	   r9, r10		C executed iff coming via xit
+	ldr	r6, [r3, #4]		C cps[1] = cnt
+	mov	r5, #0
+	umlal	r4, r5, r9, r7
+	mov	r7, r5, lsl r6
+L(x):	rsb	r1, r6, #32
+	orr	r8, r7, r4, lsr r1
+	mov	r9, r4, lsl r6
+	ldr	r5, [r3, #0]
+	add	r0, r8, #1
+	umull	r12, r1, r8, r5
+	adds	r4, r12, r9
+	adc	r1, r1, r0
+	mul	r5, r2, r1
+	sub	r9, r9, r5
+	cmp	r9, r4
+	addhi	r9, r9, r2
+	cmp	r2, r9
+	subls	r9, r9, r2
+	mov	r0, r9, lsr r6
+	pop	{r4-r10}
+	bx	r14
+
+L(xit):	mov	r10, #0
+	umlal	r4, r10, r6, r7		C B1
+	umlal	r4, r10, r5, r8		C B2
+	umlal	r4, r10, r9, r12	C B3
+	b	L(end)
+
+L(1):	ldr	r6, [r3, #4]		C cps[1] = cnt
+	ldr	r4, [ap, #-4]		C ap[0]
+	mov	r7, #0
+	b	L(x)
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1s_2p_cps)
+	push	{r4-r8, r14}
+	clz	r4, r1
+	mov	r5, r1, lsl r4		C b <<= cnt
+	mov	r6, r0			C r6 = cps
+	mov	r0, r5
+	bl	mpn_invert_limb
+	rsb	r3, r4, #32
+	mov	r3, r0, lsr r3
+	mov	r2, #1
+	orr	r3, r3, r2, lsl r4
+	rsb	r1, r5, #0
+	mul	r2, r1, r3
+	umull	r3, r12, r2, r0
+	add	r12, r2, r12
+	mvn	r12, r12
+	mul	r1, r5, r12
+	cmp	r1, r3
+	addhi	r1, r1, r5
+	umull	r12, r7, r1, r0
+	add	r7, r1, r7
+	mvn	r7, r7
+	mul	r3, r5, r7
+	cmp	r3, r12
+	addhi	r3, r3, r5
+	mov	r5, r2, lsr r4
+	mov	r7, r1, lsr r4
+	mov	r8, r3, lsr r4
+	stmia	r6, {r0,r4,r5,r7,r8}	C fill cps
+	pop	{r4-r8, pc}
+EPILOGUE()
diff --git a/mpn/arm/v6/addmul_1.asm b/mpn/arm/v6/addmul_1.asm
new file mode 100644
index 0000000..f60067e
--- /dev/null
+++ b/mpn/arm/v6/addmul_1.asm
@@ -0,0 +1,112 @@
+dnl  ARM mpn_addmul_1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 6.4
+C Cortex-A7	 5.25
+C Cortex-A8	 7
+C Cortex-A9	 3.25
+C Cortex-A15	 4
+
+C TODO
+C  * Micro-optimise feed-in code.
+C  * Optimise for n=1,2 by delaying register saving.
+C  * Try using ldm/stm.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`v0',`r3')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+	ands	r6, n, #3
+	mov	r12, #0
+	beq	L(fi0)
+	cmp	r6, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	ldr	r4, [up], #4
+	ldr	r6, [rp, #0]
+	ldr	r5, [up], #4
+	b	L(lo3)
+
+L(fi0):	ldr	r5, [up], #4
+	ldr	r7, [rp], #4
+	ldr	r4, [up], #4
+	b	L(lo0)
+
+L(fi1):	ldr	r4, [up], #4
+	ldr	r6, [rp], #8
+	subs	n, n, #1
+	beq	L(1)
+	ldr	r5, [up], #4
+	b	L(lo1)
+
+L(fi2):	ldr	r5, [up], #4
+	ldr	r7, [rp], #12
+	ldr	r4, [up], #4
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	ldr	r6, [rp, #-8]
+	ldr	r5, [up], #4
+	str	r7, [rp, #-12]
+L(lo1):	umaal	r6, r12, r4, v0
+	ldr	r7, [rp, #-4]
+	ldr	r4, [up], #4
+	str	r6, [rp, #-8]
+L(lo0):	umaal	r7, r12, r5, v0
+	ldr	r6, [rp, #0]
+	ldr	r5, [up], #4
+	str	r7, [rp, #-4]
+L(lo3):	umaal	r6, r12, r4, v0
+	ldr	r7, [rp, #4]
+	ldr	r4, [up], #4
+	str	r6, [rp], #16
+L(lo2):	umaal	r7, r12, r5, v0
+	subs	n, n, #4
+	bhi	L(top)
+
+	ldr	r6, [rp, #-8]
+	str	r7, [rp, #-12]
+L(1):	umaal	r6, r12, r4, v0
+	str	r6, [rp, #-8]
+	mov	r0, r12
+	ldmfd	sp!, { r4, r5, r6, r7 }
+	bx	lr
+EPILOGUE()
diff --git a/mpn/arm/v6/addmul_2.asm b/mpn/arm/v6/addmul_2.asm
new file mode 100644
index 0000000..5b5ffeb
--- /dev/null
+++ b/mpn/arm/v6/addmul_2.asm
@@ -0,0 +1,125 @@
+dnl  ARM mpn_addmul_2.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 4.68
+C Cortex-A5	 3.63
+C Cortex-A7	 3.65
+C Cortex-A8	 4.0
+C Cortex-A9	 2.25
+C Cortex-A15	 2.5
+C Cortex-A17	 2.13
+C Cortex-A53	 3.5
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`vp',`r3')
+
+define(`v0',`r6')
+define(`v1',`r7')
+define(`u0',`r3')
+define(`u1',`r9')
+
+define(`cya',`r8')
+define(`cyb',`r12')
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_2)
+	push	{ r4-r9 }
+
+	ldrd	v0, v1, [vp, #0]
+	mov	cya, #0
+	mov	cyb, #0
+
+	tst	n, #1
+	beq	L(evn)
+
+L(odd):	ldr	u1, [up, #0]
+	ldr	r4, [rp, #0]
+	tst	n, #2
+	beq	L(fi1)
+L(fi3):	sub	up, up, #8
+	sub	rp, rp, #8
+	b	L(lo3)
+L(fi1):	sub	n, n, #1
+	b	L(top)
+
+L(evn):	ldr	u0, [up, #0]
+	ldr	r5, [rp, #0]
+	tst	n, #2
+	bne	L(fi2)
+L(fi0):	sub	up, up, #4
+	sub	rp, rp, #4
+	b	L(lo0)
+L(fi2):	sub	up, up, #12
+	sub	rp, rp, #12
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+L(lo0):	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+L(lo3):	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+L(lo2):	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	n, n, #4
+	bhi	L(top)
+
+L(end):	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	mov	r0, cyb
+
+	pop	{ r4-r9 }
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/v6/addmul_3.asm b/mpn/arm/v6/addmul_3.asm
new file mode 100644
index 0000000..3d4ea26
--- /dev/null
+++ b/mpn/arm/v6/addmul_3.asm
@@ -0,0 +1,191 @@
+dnl  ARM mpn_addmul_3.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 4.33
+C Cortex-A5	 3.28
+C Cortex-A7	 3.25
+C Cortex-A8	 3.17
+C Cortex-A9	 2.125
+C Cortex-A15	 2
+C Cortex-A17	 2.11
+C Cortex-A53	 4.18
+
+C TODO
+C  * Use a fast path for n <= KARATSUBA_MUL_THRESHOLD using a jump table,
+C    avoiding the current multiply.
+C  * Start the first multiply or multiplies early.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`vp',`r3')
+
+define(`v0',`r4')  define(`v1',`r5')  define(`v2',`r6')
+define(`u0',`r3')  define(`u1',`r14')
+define(`w0',`r7')  define(`w1',`r8')  define(`w2',`r9')
+define(`cy0',`r10')  define(`cy1',`r11') define(`cy2',`r12')
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_3)
+	push	{ r4-r11, r14 }
+
+	ldr	w0, =0xaaaaaaab		C 3^{-1} mod 2^32
+	ldm	vp, { v0,v1,v2 }
+	mov	cy0, #0
+	mov	cy1, #0
+	mov	cy2, #0
+
+C Tricky n mod 6
+	mul	w0, w0, n		C n * 3^{-1} mod 2^32
+	and	w0, w0, #0xc0000001	C pseudo-CRT mod 3,2
+	sub	n, n, #3
+ifdef(`PIC',`
+	add	pc, pc, w0, ror $28
+	nop
+	b	L(b0)
+	b	L(b2)
+	b	L(b4)
+	.word	0xe7f000f0	C udf
+	b	L(b3)
+	b	L(b5)
+	b	L(b1)
+',`
+	ldr	pc, [pc, w0, ror $28]
+	nop
+	.word	L(b0), L(b2), L(b4), 0, L(b3), L(b5), L(b1)
+')
+
+L(b5):	add	up, up, #-8
+	ldr	w1, [rp, #0]
+	ldr	w2, [rp, #4]
+	ldr	u1, [up, #8]
+	b	L(lo5)
+
+L(b4):	add	rp, rp, #-4
+	add	up, up, #-12
+	ldr	w2, [rp, #4]
+	ldr	w0, [rp, #8]
+	ldr	u0, [up, #12]
+	b	L(lo4)
+
+L(b3):	add	rp, rp, #-8
+	add	up, up, #-16
+	ldr	w0, [rp, #8]
+	ldr	w1, [rp, #12]
+	ldr	u1, [up, #16]
+	b	L(lo3)
+
+L(b1):	add	rp, rp, #8
+	ldr	w2, [rp, #-8]
+	ldr	w0, [rp, #-4]
+	ldr	u1, [up, #0]
+	b	L(lo1)
+
+L(b0):	add	rp, rp, #4
+	add	up, up, #-4
+	ldr	w0, [rp, #-4]
+	ldr	w1, [rp, #0]
+	ldr	u0, [up, #4]
+	b	L(lo0)
+
+L(b2):	add	rp, rp, #12
+	add	up, up, #4
+	ldr	w1, [rp, #-12]
+	ldr	w2, [rp, #-8]
+	ldr	u0, [up, #-4]
+
+	ALIGN(16)
+L(top):	ldr	w0, [rp, #-4]
+	umaal	w1, cy0, u0, v0
+	ldr	u1, [up, #0]
+	umaal	w2, cy1, u0, v1
+	str	w1, [rp, #-12]
+	umaal	w0, cy2, u0, v2
+L(lo1):	ldr	w1, [rp, #0]
+	umaal	w2, cy0, u1, v0
+	ldr	u0, [up, #4]
+	umaal	w0, cy1, u1, v1
+	str	w2, [rp, #-8]
+	umaal	w1, cy2, u1, v2
+L(lo0):	ldr	w2, [rp, #4]
+	umaal	w0, cy0, u0, v0
+	ldr	u1, [up, #8]
+	umaal	w1, cy1, u0, v1
+	str	w0, [rp, #-4]
+	umaal	w2, cy2, u0, v2
+L(lo5):	ldr	w0, [rp, #8]
+	umaal	w1, cy0, u1, v0
+	ldr	u0, [up, #12]
+	umaal	w2, cy1, u1, v1
+	str	w1, [rp, #0]
+	umaal	w0, cy2, u1, v2
+L(lo4):	ldr	w1, [rp, #12]
+	umaal	w2, cy0, u0, v0
+	ldr	u1, [up, #16]
+	umaal	w0, cy1, u0, v1
+	str	w2, [rp, #4]
+	umaal	w1, cy2, u0, v2
+L(lo3):	ldr	w2, [rp, #16]
+	umaal	w0, cy0, u1, v0
+	ldr	u0, [up, #20]
+	umaal	w1, cy1, u1, v1
+	str	w0, [rp, #8]
+	umaal	w2, cy2, u1, v2
+L(lo2):	subs	n, n, #6
+	add	up, up, #24
+	add	rp, rp, #24
+	bge	L(top)
+
+L(end):	umaal	w1, cy0, u0, v0
+	ldr	u1, [up, #0]
+	umaal	w2, cy1, u0, v1
+	str	w1, [rp, #-12]
+	mov	w0, #0
+	umaal	w0, cy2, u0, v2
+	umaal	w2, cy0, u1, v0
+	umaal	w0, cy1, u1, v1
+	str	w2, [rp, #-8]
+	umaal	cy1, cy2, u1, v2
+	adds	w0, w0, cy0
+	str	w0, [rp, #-4]
+	adcs	w1, cy1, #0
+	str	w1, [rp, #0]
+	adc	r0, cy2, #0
+
+	pop	{ r4-r11, pc }
+EPILOGUE()
diff --git a/mpn/arm/v6/dive_1.asm b/mpn/arm/v6/dive_1.asm
new file mode 100644
index 0000000..974f8d4
--- /dev/null
+++ b/mpn/arm/v6/dive_1.asm
@@ -0,0 +1,149 @@
+dnl  ARM v6 mpn_divexact_1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C               cycles/limb       cycles/limb
+C               norm    unorm    modexact_1c_odd
+C StrongARM	 -	 -
+C XScale	 -	 -
+C Cortex-A7	 ?	 ?
+C Cortex-A8	 ?	 ?
+C Cortex-A9	 9	10		 9
+C Cortex-A15	 7	 7		 7
+
+C Architecture requirements:
+C v5	-
+C v5t	clz
+C v5te	-
+C v6	umaal
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`d',  `r3')
+
+define(`cy',  `r7')
+define(`cnt', `r6')
+define(`tnc', `r10')
+
+ASM_START()
+PROLOGUE(mpn_divexact_1)
+	push	{r4,r5,r6,r7,r8,r9}
+
+	tst	d, #1
+
+	rsb	r4, d, #0
+	and	r4, r4, d
+	clz	r4, r4
+	rsb	cnt, r4, #31		C count_trailing_zeros
+	mov	d, d, lsr cnt
+
+C binvert limb
+	LEA(	r4, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	mul	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, lsl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, lsl #1	C r4 = inverse
+
+	ldr	r5, [up], #4		C up[0]
+	mov	cy, #0
+	rsb	r8, r4, #0		C r8 = -inverse
+	beq	L(unnorm)
+
+L(norm):
+	subs	n, n, #1
+	mul	r5, r5, r4
+	beq	L(end)
+
+	ALIGN(16)
+L(top):	ldr	r9, [up], #4
+	mov	r12, #0
+	str	r5, [rp], #4
+	umaal	r12, cy, r5, d
+	mul	r5, r9, r4
+	mla	r5, cy, r8, r5
+	subs	n, n, #1
+	bne	L(top)
+
+L(end):	str	r5, [rp]
+	pop	{r4,r5,r6,r7,r8,r9}
+	bx	r14
+
+L(unnorm):
+	push	{r10,r11}
+	rsb	tnc, cnt, #32
+	mov	r11, r5, lsr cnt
+	subs	n, n, #1
+	beq	L(edx)
+
+	ldr	r12, [up], #4
+	orr	r9, r11, r12, lsl tnc
+	mov	r11, r12, lsr cnt
+	mul	r5, r9, r4
+	subs	n, n, #1
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r11, r12, lsl tnc
+	mov	r11, r12, lsr cnt
+	mov	r12, #0
+	str	r5, [rp], #4
+	umaal	r12, cy, r5, d
+	mul	r5, r9, r4
+	mla	r5, cy, r8, r5
+	subs	n, n, #1
+	bne	L(tpu)
+
+L(edu):	str	r5, [rp], #4
+	mov	r12, #0
+	umaal	r12, cy, r5, d
+	mul	r5, r11, r4
+	mla	r5, cy, r8, r5
+	str	r5, [rp]
+	pop	{r10,r11}
+	pop	{r4,r5,r6,r7,r8,r9}
+	bx	r14
+
+L(edx):	mul	r5, r11, r4
+	str	r5, [rp]
+	pop	{r10,r11}
+	pop	{r4,r5,r6,r7,r8,r9}
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/v6/mode1o.asm b/mpn/arm/v6/mode1o.asm
new file mode 100644
index 0000000..cd3c9bc
--- /dev/null
+++ b/mpn/arm/v6/mode1o.asm
@@ -0,0 +1,95 @@
+dnl  ARM v6 mpn_modexact_1c_odd
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 9
+C Cortex-A15	 7
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	smulbb
+C v6	umaal
+C v6t2	-
+C v7a	-
+
+define(`up', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cy', `r3')
+
+	.protected	binvert_limb_table
+ASM_START()
+PROLOGUE(mpn_modexact_1c_odd)
+	stmfd	sp!, {r4, r5, r6, r7}
+
+	LEA(	r4, binvert_limb_table)
+
+	ldr	r6, [up], #4		C up[0]
+
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	smulbb	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, asl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, asl #1	C r4 = inverse
+
+	subs	n, n, #1
+	sub	r6, r6, cy
+	mul	r6, r6, r4
+	beq	L(end)
+
+	rsb	r5, r4, #0		C r5 = -inverse
+
+L(top):	ldr	r7, [up], #4
+	mov	r12, #0
+	umaal	r12, cy, r6, d
+	mul	r6, r7, r4
+	mla	r6, cy, r5, r6
+	subs	n, n, #1
+	bne	L(top)
+
+L(end):	mov	r12, #0
+	umaal	r12, cy, r6, d
+	mov	r0, cy
+
+	ldmfd	sp!, {r4, r5, r6, r7}
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/v6/mul_1.asm b/mpn/arm/v6/mul_1.asm
new file mode 100644
index 0000000..cd1b12b
--- /dev/null
+++ b/mpn/arm/v6/mul_1.asm
@@ -0,0 +1,115 @@
+dnl  ARM mpn_mul_1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 6.4
+C Cortex-A7	 5.25
+C Cortex-A8	 7
+C Cortex-A9	 3.25
+C Cortex-A15	 4
+
+C TODO
+C  * Micro-optimise feed-in code.
+C  * Optimise for n=1,2 by delaying register saving.
+C  * Try using ldm/stm.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`v0',`r3')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+	ands	r6, n, #3
+	mov	r12, #0
+	beq	L(fi0)
+	cmp	r6, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	ldr	r4, [up], #4
+	mov	r6, #0
+	ldr	r5, [up], #4
+	b	L(lo3)
+
+L(fi0):	ldr	r5, [up], #4
+	add	rp, rp, #4
+	mov	r7, #0
+	ldr	r4, [up], #4
+	b	L(lo0)
+
+L(fi1):	ldr	r4, [up], #4
+	mov	r6, #0
+	add	rp, rp, #8
+	subs	n, n, #1
+	beq	L(1)
+	ldr	r5, [up], #4
+	b	L(lo1)
+
+L(fi2):	ldr	r5, [up], #4
+	add	rp, rp, #12
+	mov	r7, #0
+	ldr	r4, [up], #4
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	mov	r6, #0
+	ldr	r5, [up], #4
+	str	r7, [rp, #-12]
+L(lo1):	umaal	r6, r12, r4, v0
+	mov	r7, #0
+	ldr	r4, [up], #4
+	str	r6, [rp, #-8]
+L(lo0):	umaal	r7, r12, r5, v0
+	mov	r6, #0
+	ldr	r5, [up], #4
+	str	r7, [rp, #-4]
+L(lo3):	umaal	r6, r12, r4, v0
+	mov	r7, #0
+	ldr	r4, [up], #4
+	str	r6, [rp], #16
+L(lo2):	umaal	r7, r12, r5, v0
+	subs	n, n, #4
+	bhi	L(top)
+
+	mov	r6, #0
+	str	r7, [rp, #-12]
+L(1):	umaal	r6, r12, r4, v0
+	str	r6, [rp, #-8]
+	mov	r0, r12
+	ldmfd	sp!, { r4, r5, r6, r7 }
+	bx	lr
+EPILOGUE()
diff --git a/mpn/arm/v6/mul_2.asm b/mpn/arm/v6/mul_2.asm
new file mode 100644
index 0000000..72badd9
--- /dev/null
+++ b/mpn/arm/v6/mul_2.asm
@@ -0,0 +1,135 @@
+dnl  ARM mpn_mul_2.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 5.25
+C Cortex-A5	 3.63
+C Cortex-A7	 3.15
+C Cortex-A8	 5.0
+C Cortex-A9	 2.25
+C Cortex-A15	 2.5
+C Cortex-A17	 2.13
+C Cortex-A53	 3.5
+
+C TODO
+C  * This is a trivial edit of the addmul_2 code.  Check for simplifications,
+C    and possible speedups to 2.0 c/l.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`vp',`r3')
+
+define(`v0',`r6')
+define(`v1',`r7')
+define(`u0',`r3')
+define(`u1',`r9')
+
+define(`cya',`r8')
+define(`cyb',`r12')
+
+
+ASM_START()
+PROLOGUE(mpn_mul_2)
+	push	{ r4, r5, r6, r7, r8, r9 }
+
+	ldm	vp, { v0, v1 }
+	mov	cya, #0
+	mov	cyb, #0
+
+	tst	n, #1
+	beq	L(evn)
+L(odd):	mov	r5, #0
+	ldr	u0, [up, #0]
+	mov	r4, #0
+	tst	n, #2
+	beq	L(fi1)
+L(fi3):	sub	up, up, #12
+	sub	rp, rp, #16
+	b	L(lo3)
+L(fi1):	sub	n, n, #1
+	sub	up, up, #4
+	sub	rp, rp, #8
+	b	L(lo1)
+L(evn):	mov	r4, #0
+	ldr	u1, [up, #0]
+	mov	r5, #0
+	tst	n, #2
+	bne	L(fi2)
+L(fi0):	sub	up, up, #8
+	sub	rp, rp, #12
+	b	L(lo0)
+L(fi2):	subs	n, n, #2
+	sub	rp, rp, #4
+	bls	L(end)
+
+	ALIGN(16)
+L(top):	ldr	u0, [up, #4]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #4]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(lo1):	ldr	u1, [up, #8]
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #8]
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+L(lo0):	ldr	u0, [up, #12]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #12]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(lo3):	ldr	u1, [up, #16]!
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #16]!
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+	subs	n, n, #4
+	bhi	L(top)
+
+L(end):	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #4]
+	umaal	r5, cya, u0, v0
+	umaal	cya, cyb, u0, v1
+	str	r5, [rp, #8]
+	str	cya, [rp, #12]
+	mov	r0, cyb
+
+	pop	{ r4, r5, r6, r7, r8, r9 }
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/v6/popham.asm b/mpn/arm/v6/popham.asm
new file mode 100644
index 0000000..612a6ad
--- /dev/null
+++ b/mpn/arm/v6/popham.asm
@@ -0,0 +1,139 @@
+dnl  ARM mpn_popcount and mpn_hamdist.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C		     popcount	      hamdist
+C		    cycles/limb	    cycles/limb
+C StrongARM		 -
+C XScale		 -
+C Cortex-A7		 ?
+C Cortex-A8		 ?
+C Cortex-A9		 8.94		 9.47
+C Cortex-A15		 5.67		 6.44
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	usada8
+C v6t2	-
+C v7a	-
+
+ifdef(`OPERATION_popcount',`
+  define(`func',`mpn_popcount')
+  define(`ap',		`r0')
+  define(`n',		`r1')
+  define(`a0',		`r2')
+  define(`a1',		`r3')
+  define(`s',		`r5')
+  define(`b_01010101',	`r6')
+  define(`b_00110011',	`r7')
+  define(`b_00001111',	`r8')
+  define(`zero',	`r9')
+  define(`POPC',	`$1')
+  define(`HAMD',	`dnl')
+')
+ifdef(`OPERATION_hamdist',`
+  define(`func',`mpn_hamdist')
+  define(`ap',		`r0')
+  define(`bp',		`r1')
+  define(`n',		`r2')
+  define(`a0',		`r6')
+  define(`a1',		`r7')
+  define(`b0',		`r4')
+  define(`b1',		`r5')
+  define(`s',		`r11')
+  define(`b_01010101',	`r8')
+  define(`b_00110011',	`r9')
+  define(`b_00001111',	`r10')
+  define(`zero',	`r3')
+  define(`POPC',	`dnl')
+  define(`HAMD',	`$1')
+')
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+ASM_START()
+PROLOGUE(func)
+POPC(`	push	{ r4-r9 }	')
+HAMD(`	push	{ r4-r11 }	')
+
+	ldr	b_01010101, =0x55555555
+	mov	r12, #0
+	ldr	b_00110011, =0x33333333
+	mov	zero, #0
+	ldr	b_00001111, =0x0f0f0f0f
+
+	tst	n, #1
+	beq	L(evn)
+
+L(odd):	ldr	a1, [ap], #4		C 1 x 32 1-bit accumulators, 0-1
+HAMD(`	ldr	b1, [bp], #4	')	C 1 x 32 1-bit accumulators, 0-1
+HAMD(`	eor	a1, a1, b1	')
+	and	r4, b_01010101, a1, lsr #1
+	sub	a1, a1, r4
+	and	r4, a1, b_00110011
+	bic	r5, a1, b_00110011
+	add	r5, r4, r5, lsr #2	C 8 4-bit accumulators, 0-4
+	subs	n, n, #1
+	b	L(mid)
+
+L(evn):	mov	s, #0
+
+L(top):	ldrd	a0, a1, [ap], #8	C 2 x 32 1-bit accumulators, 0-1
+HAMD(`	ldrd	b0, b1, [bp], #8')
+HAMD(`	eor	a0, a0, b0	')
+HAMD(`	eor	a1, a1, b1	')
+	subs	n, n, #2
+	usada8	r12, s, zero, r12
+	and	r4, b_01010101, a0, lsr #1
+	sub	a0, a0, r4
+	and	r4, b_01010101, a1, lsr #1
+	sub	a1, a1, r4
+	and	r4, a0, b_00110011
+	bic	r5, a0, b_00110011
+	add	a0, r4, r5, lsr #2	C 8 4-bit accumulators, 0-4
+	and	r4, a1, b_00110011
+	bic	r5, a1, b_00110011
+	add	a1, r4, r5, lsr #2	C 8 4-bit accumulators, 0-4
+	add	r5, a0, a1		C 8 4-bit accumulators, 0-8
+L(mid):	and	r4, r5, b_00001111
+	bic	r5, r5, b_00001111
+	add	s, r4, r5, lsr #4	C 4 8-bit accumulators
+	bne	L(top)
+
+	usada8	r0, s, zero, r12
+POPC(`	pop	{ r4-r9 }	')
+HAMD(`	pop	{ r4-r11 }	')
+	bx	r14
+EPILOGUE()
diff --git a/mpn/arm/v6/sqr_basecase.asm b/mpn/arm/v6/sqr_basecase.asm
new file mode 100644
index 0000000..72d7078
--- /dev/null
+++ b/mpn/arm/v6/sqr_basecase.asm
@@ -0,0 +1,544 @@
+dnl  ARM v6 mpn_sqr_basecase.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C Code structure:
+C
+C
+C        m_2(0m4)        m_2(2m4)        m_2(1m4)        m_2(3m4)
+C           |               |               |               |
+C           |               |               |               |
+C           |               |               |               |
+C          \|/             \|/             \|/             \|/
+C              ____________                   ____________
+C             /            \                 /            \
+C            \|/            \               \|/            \
+C         am_2(3m4)       am_2(1m4)       am_2(0m4)       am_2(2m4)
+C            \            /|\                \            /|\
+C             \____________/                  \____________/
+C                       \                        /
+C                        \                      /
+C                         \                    /
+C                         cor3             cor2
+C                            \              /
+C                             \            /
+C                            sqr_diag_addlsh1
+
+C TODO
+C  * Align more labels.
+C  * Further tweak counter and updates in outer loops.  (This could save
+C    perhaps 5n cycles).
+C  * Avoid sub-with-lsl in outer loops.  We could keep n up-shifted, then
+C    initialise loop counter i with a right shift.
+C  * Try to use fewer register.  Perhaps coalesce r9 branch target and n_saved.
+C    (This could save 2-3 cycles for n > 4.)
+C  * Optimise sqr_diag_addlsh1 loop.  The current code uses old-style carry
+C    propagation.
+C  * Stop loops earlier suppressing writes of upper-most rp[] values.
+C  * The addmul_2 loops here runs well on all cores, but mul_2 runs poorly
+C    particularly on Cortex-A8.
+
+
+define(`rp',      r0)
+define(`up',      r1)
+define(`n',       r2)
+
+define(`v0',      r3)
+define(`v1',      r6)
+define(`i',       r8)
+define(`n_saved', r14)
+define(`cya',     r11)
+define(`cyb',     r12)
+define(`u0',      r7)
+define(`u1',      r9)
+
+ASM_START()
+PROLOGUE(mpn_sqr_basecase)
+	and	r12, n, #3
+	cmp	n, #4
+	addgt	r12, r12, #4
+	add	pc, pc, r12, lsl #2
+	nop
+	b	L(4)
+	b	L(1)
+	b	L(2)
+	b	L(3)
+	b	L(0m4)
+	b	L(1m4)
+	b	L(2m4)
+	b	L(3m4)
+
+
+L(1m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_2m4)-.-8
+	ldm	up, {v0,v1,u0}
+	sub	up, up, #4
+	mov	cyb, #0
+	mov	r5, #0
+	umull	r4, cya, v1, v0
+	str	r4, [rp], #-12
+	mov	r4, #0
+	b	L(ko0)
+
+L(3m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_0m4)-.-8
+	ldm	up, {v0,v1,u0}
+	add	up, up, #4
+	mov	cyb, #0
+	mov	r5, #0
+	umull	r4, cya, v1, v0
+	str	r4, [rp], #-4
+	mov	r4, #0
+	b	L(ko2)
+
+L(2m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_3m4)-.-8
+	ldm	up, {v0,v1,u1}
+	mov	cyb, #0
+	mov	r4, #0
+	umull	r5, cya, v1, v0
+	str	r5, [rp], #-8
+	mov	r5, #0
+	b	L(ko1)
+
+L(0m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_1m4)-.-8
+	ldm	up, {v0,v1,u1}
+	mov	cyb, #0
+	mov	r4, #0
+	add	up, up, #8
+	umull	r5, cya, v1, v0
+	str	r5, [rp, #0]
+	mov	r5, #0
+
+L(top):	ldr	u0, [up, #4]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #4]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(ko2):	ldr	u1, [up, #8]
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #8]
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+L(ko1):	ldr	u0, [up, #12]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #12]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(ko0):	ldr	u1, [up, #16]!
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #16]!
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+	subs	i, i, #4
+	bhi	L(top)
+
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #4]
+	umaal	r5, cya, u0, v0
+	umaal	cya, cyb, u0, v1
+	str	r5, [rp, #8]
+	str	cya, [rp, #12]
+	str	cyb, [rp, #16]
+
+	add	up, up, #4
+	sub	n, n, #1
+	add	rp, rp, #8
+	bx	r10
+
+L(evnloop):
+	subs	i, n, #6
+	sub	n, n, #2
+	blt	L(cor2)
+	ldm	up, {v0,v1,u1}
+	add	up, up, #8
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r4, [rp, #-4]
+	umaal	r4, cya, v1, v0
+	str	r4, [rp, #-4]
+	ldr	r4, [rp, #0]
+
+	ALIGN(16)
+L(ua2):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua2)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_0m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #8
+
+	sub	i, n, #4
+	sub	n, n, #2
+	ldm	up, {v0,v1,u1}
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r4, [rp, #4]
+	umaal	r4, cya, v1, v0
+	str	r4, [rp, #4]
+	ldr	r4, [rp, #8]
+	b	L(lo0)
+
+	ALIGN(16)
+L(ua0):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+L(lo0):	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua0)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_2m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #16
+	b	L(evnloop)
+
+
+L(oddloop):
+	sub	i, n, #5
+	sub	n, n, #2
+	ldm	up, {v0,v1,u0}
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r5, [rp, #0]
+	umaal	r5, cya, v1, v0
+	str	r5, [rp, #0]
+	ldr	r5, [rp, #4]
+	add	up, up, #4
+	b	L(lo1)
+
+	ALIGN(16)
+L(ua1):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+L(lo1):	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua1)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_3m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #4
+
+	subs	i, n, #3
+	beq	L(cor3)
+	sub	n, n, #2
+	ldm	up, {v0,v1,u0}
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r5, [rp, #8]
+	sub	up, up, #4
+	umaal	r5, cya, v1, v0
+	str	r5, [rp, #8]
+	ldr	r5, [rp, #12]
+	b	L(lo3)
+
+	ALIGN(16)
+L(ua3):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+L(lo3):	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua3)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_1m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #12
+	b	L(oddloop)
+
+
+L(cor3):ldm	up, {v0,v1,u0}
+	ldr	r5, [rp, #8]
+	mov	cya, #0
+	mov	cyb, #0
+	umaal	r5, cya, v1, v0
+	str	r5, [rp, #8]
+	ldr	r5, [rp, #12]
+	ldr	r4, [rp, #16]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #12]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #16]
+	str	cya, [rp, #20]
+	str	cyb, [rp, #24]
+	add	up, up, #16
+	mov	cya, cyb
+	adds	rp, rp, #36		C clear cy
+	mov	cyb, #0
+	umaal	cya, cyb, u1, u0
+	b	L(sqr_diag_addlsh1)
+
+L(cor2):
+	ldm	up!, {v0,v1,u0}
+	mov	r4, cya
+	mov	r5, cyb
+	mov	cya, #0
+	umaal	r4, cya, v1, v0
+	mov	cyb, #0
+	umaal	r5, cya, u0, v0
+	strd	r4, r5, [rp, #-4]
+	umaal	cya, cyb, u0, v1
+	add	rp, rp, #16
+C	b	L(sqr_diag_addlsh1)
+
+
+define(`w0',  r6)
+define(`w1',  r7)
+define(`w2',  r8)
+define(`rbx', r9)
+
+L(sqr_diag_addlsh1):
+	str	cya, [rp, #-12]
+	str	cyb, [rp, #-8]
+	sub	n, n_saved, #1
+	sub	up, up, n_saved, lsl #2
+	sub	rp, rp, n_saved, lsl #3
+	ldr	r3, [up], #4
+	umull	w1, r5, r3, r3
+	mov	w2, #0
+	mov	r10, #0
+C	cmn	r0, #0			C clear cy (already clear)
+	b	L(lm)
+
+L(tsd):	adds	w0, w0, rbx
+	adcs	w1, w1, r4
+	str	w0, [rp, #0]
+L(lm):	ldr	w0, [rp, #4]
+	str	w1, [rp, #4]
+	ldr	w1, [rp, #8]!
+	add	rbx, r5, w2
+	adcs	w0, w0, w0
+	ldr	r3, [up], #4
+	adcs	w1, w1, w1
+	adc	w2, r10, r10
+	umull	r4, r5, r3, r3
+	subs	n, n, #1
+	bne	L(tsd)
+
+	adds	w0, w0, rbx
+	adcs	w1, w1, r4
+	adc	w2, r5, w2
+	stm	rp, {w0,w1,w2}
+
+	pop	{r4-r11, pc}
+
+
+C Straight line code for n <= 4
+
+L(1):	ldr	r3, [up, #0]
+	umull	r1, r2, r3, r3
+	stm	rp, {r1,r2}
+	bx	r14
+
+L(2):	push	{r4-r5}
+	ldm	up, {r5,r12}
+	umull	r1, r2, r5, r5
+	umull	r3, r4, r12, r12
+	umull	r5, r12, r5, r12
+	adds	r5, r5, r5
+	adcs	r12, r12, r12
+	adc	r4, r4, #0
+	adds	r2, r2, r5
+	adcs	r3, r3, r12
+	adc	r4, r4, #0
+	stm	rp, {r1,r2,r3,r4}
+	pop	{r4-r5}
+	bx	r14
+
+L(3):	push	{r4-r11}
+	ldm	up, {r7,r8,r9}
+	umull	r1, r2, r7, r7
+	umull	r3, r4, r8, r8
+	umull	r5, r6, r9, r9
+	umull	r10, r11, r7, r8
+	mov	r12, #0
+	umlal	r11, r12, r7, r9
+	mov	r7, #0
+	umlal	r12, r7, r8, r9
+	adds	r10, r10, r10
+	adcs	r11, r11, r11
+	adcs	r12, r12, r12
+	adcs	r7, r7, r7
+	adc	r6, r6, #0
+	adds	r2, r2, r10
+	adcs	r3, r3, r11
+	adcs	r4, r4, r12
+	adcs	r5, r5, r7
+	adc	r6, r6, #0
+	stm	rp, {r1,r2,r3,r4,r5,r6}
+	pop	{r4-r11}
+	bx	r14
+
+L(4):	push	{r4-r11, r14}
+	ldm	up, {r9,r10,r11,r12}
+	umull	r1, r2, r9, r9
+	umull	r3, r4, r10, r10
+	umull	r5, r6, r11, r11
+	umull	r7, r8, r12, r12
+	stm	rp, {r1,r2,r3,r4,r5,r6,r7}
+	umull	r1, r2, r9, r10
+	mov	r3, #0
+	umlal	r2, r3, r9, r11
+	mov	r4, #0
+	umlal	r3, r4, r9, r12
+	mov	r5, #0
+	umlal	r3, r5, r10, r11
+	umaal	r4, r5, r10, r12
+	mov	r6, #0
+	umlal	r5, r6, r11, r12
+	adds	r1, r1, r1
+	adcs	r2, r2, r2
+	adcs	r3, r3, r3
+	adcs	r4, r4, r4
+	adcs	r5, r5, r5
+	adcs	r6, r6, r6
+	add	rp, rp, #4
+	adc	r7, r8, #0
+	ldm	rp, {r8,r9,r10,r11,r12,r14}
+	adds	r1, r1, r8
+	adcs	r2, r2, r9
+	adcs	r3, r3, r10
+	adcs	r4, r4, r11
+	adcs	r5, r5, r12
+	adcs	r6, r6, r14
+	adc	r7, r7, #0
+	stm	rp, {r1,r2,r3,r4,r5,r6,r7}
+	pop	{r4-r11, pc}
+EPILOGUE()
diff --git a/mpn/arm/v6/submul_1.asm b/mpn/arm/v6/submul_1.asm
new file mode 100644
index 0000000..59772fd
--- /dev/null
+++ b/mpn/arm/v6/submul_1.asm
@@ -0,0 +1,125 @@
+dnl  ARM mpn_submul_1.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.75
+C Cortex-A15	 4.0
+
+C This loop complements U on the fly,
+C   U' = B^n - 1 - U
+C and then uses that
+C   R - U*v = R + U'*v + v - B^n v
+
+C TODO
+C  * Micro-optimise feed-in code.
+C  * Optimise for n=1,2 by delaying register saving.
+C  * Try using ldm/stm.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`v0',`r3')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+	ands	r6, n, #3
+	mov	r12, v0
+	beq	L(fi0)
+	cmp	r6, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	ldr	r4, [up], #12
+	mvn	r4, r4
+	ldr	r6, [rp, #0]
+	ldr	r5, [up, #-8]
+	b	L(lo3)
+
+L(fi0):	ldr	r5, [up], #16
+	mvn	r5, r5
+	ldr	r7, [rp], #4
+	ldr	r4, [up, #-12]
+	b	L(lo0)
+
+L(fi1):	ldr	r4, [up], #4
+	mvn	r4, r4
+	ldr	r6, [rp], #8
+	subs	n, n, #1
+	beq	L(1)
+	ldr	r5, [up]
+	b	L(lo1)
+
+L(fi2):	ldr	r5, [up], #8
+	mvn	r5, r5
+	ldr	r7, [rp], #12
+	ldr	r4, [up, #-4]
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	ldr	r6, [rp, #-8]
+	ldr	r5, [up]
+	str	r7, [rp, #-12]
+L(lo1):	umaal	r6, r12, r4, v0
+	add	up, up, #16
+	mvn	r5, r5
+	ldr	r7, [rp, #-4]
+	ldr	r4, [up, #-12]
+	str	r6, [rp, #-8]
+L(lo0):	umaal	r7, r12, r5, v0
+	mvn	r4, r4
+	ldr	r6, [rp, #0]
+	ldr	r5, [up, #-8]
+	str	r7, [rp, #-4]
+L(lo3):	umaal	r6, r12, r4, v0
+	mvn	r5, r5
+	ldr	r7, [rp, #4]
+	ldr	r4, [up, #-4]
+	str	r6, [rp], #16
+L(lo2):	umaal	r7, r12, r5, v0
+	mvn	r4, r4
+	subs	n, n, #4
+	bhi	L(top)
+
+	ldr	r6, [rp, #-8]
+	str	r7, [rp, #-12]
+L(1):	umaal	r6, r12, r4, v0
+	str	r6, [rp, #-8]
+	sub	r0, v0, r12
+	ldmfd	sp!, { r4, r5, r6, r7 }
+	bx	lr
+EPILOGUE()
diff --git a/mpn/arm64/aors_n.asm b/mpn/arm64/aors_n.asm
new file mode 100644
index 0000000..2e870f5
--- /dev/null
+++ b/mpn/arm64/aors_n.asm
@@ -0,0 +1,125 @@
+dnl  ARM64 mpn_add_n and mpn_sub_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	2.75-3.25
+C Cortex-A57	 1.5
+C X-Gene	 2.0
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+ifdef(`OPERATION_add_n', `
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	xzr, xzr')
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`cset	x0, cs')
+  define(`func_n',	mpn_add_n)
+  define(`func_nc',	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	xzr, xzr')
+  define(`SETCY',	`cmp	xzr, $1')
+  define(`RETVAL',	`cset	x0, cc')
+  define(`func_n',	mpn_sub_n)
+  define(`func_nc',	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	SETCY(	x4)
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(func_n)
+	CLRCY
+L(ent):	lsr	x17, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x7, [up]
+	ldr	x11, [vp]
+	ADDSUBC	x13, x7, x11
+	str	x13, [rp],#8
+	tbnz	n, #1, L(b11)
+
+L(b01):	cbz	x17, L(ret)
+	ldp	x4, x5, [up,#8]
+	ldp	x8, x9, [vp,#8]
+	sub	up, up, #8
+	sub	vp, vp, #8
+	b	L(mid)
+
+L(b11):	ldp	x6, x7, [up,#8]
+	ldp	x10, x11, [vp,#8]
+	add	up, up, #8
+	add	vp, vp, #8
+	cbz	x17, L(end)
+	b	L(top)
+
+L(bx0):	tbnz	n, #1, L(b10)
+
+L(b00):	ldp	x4, x5, [up]
+	ldp	x8, x9, [vp]
+	sub	up, up, #16
+	sub	vp, vp, #16
+	b	L(mid)
+
+L(b10):	ldp	x6, x7, [up]
+	ldp	x10, x11, [vp]
+	cbz	x17, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	ldp	x8, x9, [vp,#16]
+	ADDSUBC	x12, x6, x10
+	ADDSUBC	x13, x7, x11
+	stp	x12, x13, [rp],#16
+L(mid):	ldp	x6, x7, [up,#32]!
+	ldp	x10, x11, [vp,#32]!
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	stp	x12, x13, [rp],#16
+	sub	x17, x17, #1
+	cbnz	x17, L(top)
+
+L(end):	ADDSUBC	x12, x6, x10
+	ADDSUBC	x13, x7, x11
+	stp	x12, x13, [rp]
+L(ret):	RETVAL
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/aorsmul_1.asm b/mpn/arm64/aorsmul_1.asm
new file mode 100644
index 0000000..5007a02
--- /dev/null
+++ b/mpn/arm64/aorsmul_1.asm
@@ -0,0 +1,145 @@
+dnl  ARM64 mpn_addmul_1 and mpn_submul_1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	       addmul_1        submul_1
+C	     cycles/limb     cycles/limb
+C Cortex-A53	9.3-9.8		9.3-9.8
+C Cortex-A55    9.0-9.5		9.3-9.8
+C Cortex-A57	 7		 7
+C Cortex-A72
+C Cortex-A73	 6		 6
+C X-Gene	 5		 5
+C Apple M1	 1.75		 1.75
+
+C NOTES
+C  * It is possible to keep the carry chain alive between the addition blocks
+C    and thus avoid csinc, but only for addmul_1.  Since that saves no time
+C    on the tested pipelines, we keep addmul_1 and submul_1 similar.
+C  * We could separate feed-in into 4 blocks, one for each residue (mod 4).
+C    That is likely to save a few cycles.
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+define(`v0', `x3')
+
+ifdef(`OPERATION_addmul_1', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`COND',	`cc')
+  define(`func',	mpn_addmul_1)')
+ifdef(`OPERATION_submul_1', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`COND',	`cs')
+  define(`func',	mpn_submul_1)')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+PROLOGUE(func)
+	adds	x15, xzr, xzr
+
+	tbz	n, #0, L(1)
+
+	ldr	x4, [up],#8
+	mul	x8, x4, v0
+	umulh	x12, x4, v0
+	ldr	x4, [rp]
+	ADDSUB	x8, x4, x8
+	csinc	x15, x12, x12, COND
+	str	x8, [rp],#8
+
+L(1):	tbz	n, #1, L(2)
+
+	ldp	x4, x5, [up],#16
+	mul	x8, x4, v0
+	umulh	x12, x4, v0
+	mul	x9, x5, v0
+	umulh	x13, x5, v0
+	adds	x8, x8, x15
+	adcs	x9, x9, x12
+	ldp	x4, x5, [rp]
+	adc	x15, x13, xzr
+	ADDSUB	x8, x4, x8
+	ADDSUBC	x9, x5, x9
+	csinc	x15, x15, x15, COND
+	stp	x8, x9, [rp],#16
+
+L(2):	lsr	n, n, #2
+	cbz	n, L(le3)
+	ldp	x4, x5, [up],#32
+	ldp	x6, x7, [up,#-16]
+	b	L(mid)
+L(le3):	mov	x0, x15
+	ret
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up],#32
+	ldp	x6, x7, [up,#-16]
+	ADDSUB	x8, x16, x8
+	ADDSUBC	x9, x17, x9
+	stp	x8, x9, [rp],#32
+	ADDSUBC	x10, x12, x10
+	ADDSUBC	x11, x13, x11
+	stp	x10, x11, [rp,#-16]
+	csinc	x15, x15, x15, COND
+L(mid):	sub	n, n, #1
+	mul	x8, x4, v0
+	umulh	x12, x4, v0
+	mul	x9, x5, v0
+	umulh	x13, x5, v0
+	adds	x8, x8, x15
+	mul	x10, x6, v0
+	umulh	x14, x6, v0
+	adcs	x9, x9, x12
+	mul	x11, x7, v0
+	umulh	x15, x7, v0
+	adcs	x10, x10, x13
+	ldp	x16, x17, [rp]
+	adcs	x11, x11, x14
+	ldp	x12, x13, [rp,#16]
+	adc	x15, x15, xzr
+	cbnz	n, L(top)
+
+	ADDSUB	x8, x16, x8
+	ADDSUBC	x9, x17, x9
+	ADDSUBC	x10, x12, x10
+	ADDSUBC	x11, x13, x11
+	stp	x8, x9, [rp]
+	stp	x10, x11, [rp,#16]
+	csinc	x0, x15, x15, COND
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/aorsorrlsh1_n.asm b/mpn/arm64/aorsorrlsh1_n.asm
new file mode 100644
index 0000000..c398957
--- /dev/null
+++ b/mpn/arm64/aorsorrlsh1_n.asm
@@ -0,0 +1,43 @@
+dnl  ARM64 mpn_addlsh1_n, mpn_sublsh1_n, mpn_rsblsh1_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+define(LSH,		1)
+define(RSH,		63)
+
+ifdef(`OPERATION_addlsh1_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh1_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh1_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n mpn_rsblsh1_n)
+
+include_mpn(`arm64/aorsorrlshC_n.asm')
diff --git a/mpn/arm64/aorsorrlsh2_n.asm b/mpn/arm64/aorsorrlsh2_n.asm
new file mode 100644
index 0000000..4139027
--- /dev/null
+++ b/mpn/arm64/aorsorrlsh2_n.asm
@@ -0,0 +1,43 @@
+dnl  ARM64 mpn_addlsh2_n, mpn_sublsh2_n, mpn_rsblsh2_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+define(LSH,		2)
+define(RSH,		62)
+
+ifdef(`OPERATION_addlsh2_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh2_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh2_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n mpn_rsblsh2_n)
+
+include_mpn(`arm64/aorsorrlshC_n.asm')
diff --git a/mpn/arm64/aorsorrlshC_n.asm b/mpn/arm64/aorsorrlshC_n.asm
new file mode 100644
index 0000000..61c506a
--- /dev/null
+++ b/mpn/arm64/aorsorrlshC_n.asm
@@ -0,0 +1,139 @@
+dnl  ARM64 mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	3.25-3.75
+C Cortex-A57	 2.18
+C X-Gene	 2.5
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+ifdef(`DO_add', `
+  define(`ADDSUB',	`adds	$1, $2, $3')
+  define(`ADDSUBC',	`adcs	$1, $2, $3')
+  define(`CLRRCY',	`adds	$1, xzr, xzr')
+  define(`RETVAL',	`adc	x0, $1, xzr')
+  define(`func_n',	mpn_addlsh`'LSH`'_n)')
+ifdef(`DO_sub', `
+  define(`ADDSUB',	`subs	$1, $3, $2')
+  define(`ADDSUBC',	`sbcs	$1, $3, $2')
+  define(`CLRRCY',	`subs	$1, xzr, xzr')
+  define(`RETVAL',	`cinc	x0, $1, cc')
+  define(`func_n',	mpn_sublsh`'LSH`'_n)')
+ifdef(`DO_rsb', `
+  define(`ADDSUB',	`subs	$1, $2, $3')
+  define(`ADDSUBC',	`sbcs	$1, $2, $3')
+  define(`CLRRCY',	`subs	$1, xzr, xzr')
+  define(`RETVAL',	`sbc	x0, $1, xzr')
+  define(`func_n',	mpn_rsblsh`'LSH`'_n)')
+
+ASM_START()
+PROLOGUE(func_n)
+	lsr	x6, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x5, [up]
+	tbnz	n, #1, L(b11)
+
+L(b01):	ldr	x11, [vp]
+	cbz	x6, L(1)
+	ldp	x8, x9, [vp,#8]
+	lsl	x13, x11, #LSH
+	ADDSUB(	x15, x13, x5)
+	str	x15, [rp],#8
+	sub	up, up, #24
+	sub	vp, vp, #8
+	b	L(mid)
+
+L(1):	lsl	x13, x11, #LSH
+	ADDSUB(	x15, x13, x5)
+	str	x15, [rp]
+	lsr	x0, x11, RSH
+	RETVAL(	 x0, x1)
+	ret
+
+L(b11):	ldr	x9, [vp]
+	ldp	x10, x11, [vp,#8]!
+	lsl	x13, x9, #LSH
+	ADDSUB(	x17, x13, x5)
+	str	x17, [rp],#8
+	sub	up, up, #8
+	cbz	x6, L(end)
+	b	L(top)
+
+L(bx0):	tbnz	n, #1, L(b10)
+
+L(b00):	CLRRCY(	x11)
+	ldp	x8, x9, [vp],#-16
+	sub	up, up, #32
+	b	L(mid)
+
+L(b10):	CLRRCY(	x9)
+	ldp	x10, x11, [vp]
+	sub	up, up, #16
+	cbz	x6, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	extr	x12, x10, x9, #RSH
+	ldp	x8, x9, [vp,#16]
+	extr	x13, x11, x10, #RSH
+	ADDSUBC(x14, x12, x4)
+	ADDSUBC(x15, x13, x5)
+	stp	x14, x15, [rp],#16
+L(mid):	ldp	x4, x5, [up,#32]!
+	extr	x12, x8, x11, #RSH
+	ldp	x10, x11, [vp,#32]!
+	extr	x13, x9, x8, #RSH
+	ADDSUBC(x16, x12, x4)
+	ADDSUBC(x17, x13, x5)
+	stp	x16, x17, [rp],#16
+	sub	x6, x6, #1
+	cbnz	x6, L(top)
+
+L(end):	ldp	x4, x5, [up,#16]
+	extr	x12, x10, x9, #RSH
+	extr	x13, x11, x10, #RSH
+	ADDSUBC(x14, x12, x4)
+	ADDSUBC(x15, x13, x5)
+	stp	x14, x15, [rp]
+	lsr	x0, x11, RSH
+	RETVAL(	 x0, x1)
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/arm64-defs.m4 b/mpn/arm64/arm64-defs.m4
new file mode 100644
index 0000000..46149f7
--- /dev/null
+++ b/mpn/arm64/arm64-defs.m4
@@ -0,0 +1,53 @@
+divert(-1)
+
+dnl  m4 macros for ARM64 ELF assembler.
+
+dnl  Copyright 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Standard commenting is with @, the default m4 # is for constants and we
+dnl  don't want to disable macro expansions in or after them.
+
+changecom
+
+
+dnl  LEA_HI(reg,gmp_symbol), LEA_LO(reg,gmp_symbol)
+dnl
+dnl  Load the address of gmp_symbol into a register. We split this into two
+dnl  parts to allow separation for manual insn scheduling.
+
+ifdef(`PIC',`dnl
+define(`LEA_HI', `adrp	$1, :got:$2')dnl
+define(`LEA_LO', `ldr	$1, [$1, #:got_lo12:$2]')dnl
+',`dnl
+define(`LEA_HI', `adrp	$1, $2')dnl
+define(`LEA_LO', `add	$1, $1, :lo12:$2')dnl
+')dnl
+
+divert`'dnl
diff --git a/mpn/arm64/bdiv_dbm1c.asm b/mpn/arm64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..f684d0a
--- /dev/null
+++ b/mpn/arm64/bdiv_dbm1c.asm
@@ -0,0 +1,111 @@
+dnl  ARM64 mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008, 2011, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 8
+C Cortex-A57	 7
+C X-Gene	 4.25
+
+define(`qp',	  `x0')
+define(`up',	  `x1')
+define(`n',	  `x2')
+define(`bd',	  `x3')
+define(`cy',	  `x4')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	ldr	x5, [up], #8
+	ands	x6, n, #3
+	b.eq	L(fi0)
+	cmp	x6, #2
+	b.cc	L(fi1)
+	b.eq	L(fi2)
+
+L(fi3):	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	ldr	x5, [up], #8
+	b	L(lo3)
+
+L(fi0):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	b	L(lo0)
+
+L(fi1):	subs	n, n, #1
+	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	b.ls	L(wd1)
+	ldr	x5, [up], #8
+	b	L(lo1)
+
+L(fi2):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	b	L(lo2)
+
+L(top):	ldr	x5, [up], #8
+	subs	x4, x4, x10
+	str	x4, [qp], #8
+	sbc	x4, x4, x11
+L(lo1):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	subs	x4, x4, x12
+	str	x4, [qp], #8
+	sbc	x4, x4, x13
+L(lo0):	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	ldr	x5, [up], #8
+	subs	x4, x4, x10
+	str	x4, [qp], #8
+	sbc	x4, x4, x11
+L(lo3):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	subs	x4, x4, x12
+	str	x4, [qp], #8
+	sbc	x4, x4, x13
+L(lo2):	subs	n, n, #4
+	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	b.hi	L(top)
+
+L(wd2):	subs	x4, x4, x10
+	str	x4, [qp], #8
+	sbc	x4, x4, x11
+L(wd1):	subs	x4, x4, x12
+	str	x4, [qp]
+	sbc	x0, x4, x13
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/bdiv_q_1.asm b/mpn/arm64/bdiv_q_1.asm
new file mode 100644
index 0000000..7061255
--- /dev/null
+++ b/mpn/arm64/bdiv_q_1.asm
@@ -0,0 +1,122 @@
+dnl  ARM64 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C               cycles/limb
+C               norm   unorm
+C Cortex-A53	12	15
+C Cortex-A57	12	12
+C Cortex-A72
+C Cortex-A73
+C X-Gene	11	11
+
+C TODO
+C  * Scheduling of umulh later in the unorm loop brings A53 time to 12 c/l.
+C    Unfortunately, that requires software pipelining.
+
+define(`rp',  `x0')
+define(`up',  `x1')
+define(`n',   `x2')
+define(`d',   `x3')
+define(`di',  `x4')		C	just mpn_pi1_bdiv_q_1
+define(`cnt', `x5')		C	just mpn_pi1_bdiv_q_1
+
+define(`cy',  `r7')
+define(`tnc', `x8')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_q_1)
+
+	rbit	x6, d
+	clz	cnt, x6
+	lsr	d, d, cnt
+
+	LEA_HI(	x7, binvert_limb_table)
+	ubfx	x6, d, 1, 7
+	LEA_LO(	x7, binvert_limb_table)
+	ldrb	w6, [x7, x6]
+	ubfiz	x7, x6, 1, 8
+	umull	x6, w6, w6
+	msub	x6, x6, d, x7
+	lsl	x7, x6, 1
+	mul	x6, x6, x6
+	msub	x6, x6, d, x7
+	lsl	x7, x6, 1
+	mul	x6, x6, x6
+	msub	di, x6, d, x7
+
+	b	GSYM_PREFIX`'mpn_pi1_bdiv_q_1
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	sub	n, n, #1
+	subs	x6, x6, x6		C clear r6 and C flag
+	ldr	x9, [up],#8
+	cbz	cnt, L(norm)
+
+L(unorm):
+	lsr	x12, x9, cnt
+	cbz	n, L(eu1)
+	sub	tnc, xzr, cnt
+
+L(tpu):	ldr	x9, [up],#8
+	lsl	x7, x9, tnc
+	orr	x7, x7, x12
+	sbcs	x6, x7, x6
+	mul	x7, x6, di
+	str	x7, [rp],#8
+	lsr	x12, x9, cnt
+	umulh	x6, x7, d
+	sub	n, n, #1
+	cbnz	n, L(tpu)
+
+L(eu1):	sbcs	x6, x12, x6
+	mul	x6, x6, di
+	str	x6, [rp]
+	ret
+
+L(norm):
+	mul	x5, x9, di
+	str	x5, [rp],#8
+	cbz	n, L(en1)
+
+L(tpn):	ldr	x9, [up],#8
+	umulh	x5, x5, d
+	sbcs	x5, x9, x5
+	mul	x5, x5, di
+	str	x5, [rp],#8
+	sub	n, n, #1
+	cbnz	n, L(tpn)
+
+L(en1):	ret
+EPILOGUE()
diff --git a/mpn/arm64/cnd_aors_n.asm b/mpn/arm64/cnd_aors_n.asm
new file mode 100644
index 0000000..8b39d36
--- /dev/null
+++ b/mpn/arm64/cnd_aors_n.asm
@@ -0,0 +1,129 @@
+dnl  ARM64 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	3.87-4.37
+C Cortex-A57	 1.75
+C X-Gene	 2.0
+
+changecom(blah)
+
+define(`cnd',	`x0')
+define(`rp',	`x1')
+define(`up',	`x2')
+define(`vp',	`x3')
+define(`n',	`x4')
+
+ifdef(`OPERATION_cnd_add_n', `
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	xzr, xzr')
+  define(`RETVAL',	`cset	x0, cs')
+  define(`func',	mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	xzr, xzr')
+  define(`RETVAL',	`cset	x0, cc')
+  define(`func',	mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	cmp	cnd, #1
+	sbc	cnd, cnd, cnd
+
+	CLRCY
+
+	lsr	x17, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x13, [vp]
+	ldr	x11, [up]
+	bic	x7, x13, cnd
+	ADDSUBC	x9, x11, x7
+	str	x9, [rp]
+	tbnz	n, #1, L(b11)
+
+L(b01):	cbz	x17, L(rt)
+	ldp	x12, x13, [vp,#8]
+	ldp	x10, x11, [up,#8]
+	sub	up, up, #8
+	sub	vp, vp, #8
+	sub	rp, rp, #24
+	b	L(mid)
+
+L(b11):	ldp	x12, x13, [vp,#8]!
+	ldp	x10, x11, [up,#8]!
+	sub	rp, rp, #8
+	cbz	x17, L(end)
+	b	L(top)
+
+L(bx0):	ldp	x12, x13, [vp]
+	ldp	x10, x11, [up]
+	tbnz	n, #1, L(b10)
+
+L(b00):	sub	up, up, #16
+	sub	vp, vp, #16
+	sub	rp, rp, #32
+	b	L(mid)
+
+L(b10):	sub	rp, rp, #16
+	cbz	x17, L(end)
+
+	ALIGN(16)
+L(top):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ldp	x12, x13, [vp,#16]
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	ldp	x10, x11, [up,#16]
+	stp	x8, x9, [rp,#16]
+L(mid):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ldp	x12, x13, [vp,#32]!
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	ldp	x10, x11, [up,#32]!
+	stp	x8, x9, [rp,#32]!
+	sub	x17, x17, #1
+	cbnz	x17, L(top)
+
+L(end):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	stp	x8, x9, [rp,#16]
+L(rt):	RETVAL
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/com.asm b/mpn/arm64/com.asm
new file mode 100644
index 0000000..43e052a
--- /dev/null
+++ b/mpn/arm64/com.asm
@@ -0,0 +1,92 @@
+dnl  ARM64 mpn_com.
+
+dnl  Copyright 2013, 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 
+C Cortex-A55	 
+C Cortex-A57	 
+C Cortex-A72	 
+C Cortex-A73	 
+C X-Gene	 
+C Apple M1	 
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+
+ASM_START()
+PROLOGUE(mpn_com)
+	cmp	n, #3
+	b.le	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tbz	rp, #3, L(al2)
+	ldr	x4, [up],#8
+	sub	n, n, #1
+	mvn	x4, x4
+	str	x4, [rp],#8
+
+L(al2):	ldp	x4,x5, [up],#16
+	sub	n, n, #6
+	tbnz	n, #63, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x6,x7, [up],#32
+	mvn	x4, x4
+	mvn	x5, x5
+	stp	x4,x5, [rp],#32
+	ldp	x4,x5, [up,#-16]
+	mvn	x6, x6
+	mvn	x7, x7
+	stp	x6,x7, [rp,#-16]
+	sub	n, n, #4
+	tbz	n, #63, L(top)
+
+L(end):	mvn	x4, x4
+	mvn	x5, x5
+	stp	x4,x5, [rp],#16
+
+C Copy last 0-3 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tbz	n, #1, L(tl1)
+	ldp	x4,x5, [up],#16
+	mvn	x4, x4
+	mvn	x5, x5
+	stp	x4,x5, [rp],#16
+L(tl1):	tbz	n, #0, L(tl2)
+	ldr	x4, [up]
+	mvn	x4, x4
+	str	x4, [rp]
+L(tl2):	ret
+EPILOGUE()
diff --git a/mpn/arm64/copyd.asm b/mpn/arm64/copyd.asm
new file mode 100644
index 0000000..d4705a7
--- /dev/null
+++ b/mpn/arm64/copyd.asm
@@ -0,0 +1,85 @@
+dnl  ARM64 mpn_copyd.
+
+dnl  Copyright 2013, 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 1.8
+C Cortex-A55	 1.28
+C Cortex-A57
+C Cortex-A72	 1
+C Cortex-A73	 1.1-1.35 (alignment dependent)
+C X-Gene	 1
+C Apple M1	 0.31
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	add	rp, rp, n, lsl #3
+	add	up, up, n, lsl #3
+
+	cmp	n, #3
+	b.le	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tbz	rp, #3, L(al2)
+	ldr	x4, [up,#-8]!
+	sub	n, n, #1
+	str	x4, [rp,#-8]!
+
+L(al2):	ldp	x4,x5, [up,#-16]!
+	sub	n, n, #6
+	tbnz	n, #63, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x6,x7, [up,#-16]
+	stp	x4,x5, [rp,#-16]
+	ldp	x4,x5, [up,#-32]!
+	stp	x6,x7, [rp,#-32]!
+	sub	n, n, #4
+	tbz	n, #63, L(top)
+
+L(end):	stp	x4,x5, [rp,#-16]!
+
+C Copy last 0-3 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tbz	n, #1, L(tl1)
+	ldp	x4,x5, [up,#-16]!
+	stp	x4,x5, [rp,#-16]!
+L(tl1):	tbz	n, #0, L(tl2)
+	ldr	x4, [up,#-8]
+	str	x4, [rp,#-8]
+L(tl2):	ret
+EPILOGUE()
diff --git a/mpn/arm64/copyi.asm b/mpn/arm64/copyi.asm
new file mode 100644
index 0000000..2ebda8c
--- /dev/null
+++ b/mpn/arm64/copyi.asm
@@ -0,0 +1,82 @@
+dnl  ARM64 mpn_copyi.
+
+dnl  Copyright 2013, 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 1.8
+C Cortex-A55	 1.28
+C Cortex-A57
+C Cortex-A72	 1
+C Cortex-A73	 1.1-1.35 (alignment dependent)
+C X-Gene	 1
+C Apple M1	 0.31
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	cmp	n, #3
+	b.le	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tbz	rp, #3, L(al2)
+	ldr	x4, [up],#8
+	sub	n, n, #1
+	str	x4, [rp],#8
+
+L(al2):	ldp	x4,x5, [up],#16
+	sub	n, n, #6
+	tbnz	n, #63, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x6,x7, [up],#32
+	stp	x4,x5, [rp],#32
+	ldp	x4,x5, [up,#-16]
+	stp	x6,x7, [rp,#-16]
+	sub	n, n, #4
+	tbz	n, #63, L(top)
+
+L(end):	stp	x4,x5, [rp],#16
+
+C Copy last 0-3 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tbz	n, #1, L(tl1)
+	ldp	x4,x5, [up],#16
+	stp	x4,x5, [rp],#16
+L(tl1):	tbz	n, #0, L(tl2)
+	ldr	x4, [up]
+	str	x4, [rp]
+L(tl2):	ret
+EPILOGUE()
diff --git a/mpn/arm64/darwin.m4 b/mpn/arm64/darwin.m4
new file mode 100644
index 0000000..36e72fe
--- /dev/null
+++ b/mpn/arm64/darwin.m4
@@ -0,0 +1,50 @@
+divert(-1)
+
+dnl  m4 macros for ARM64 Darwin assembler.
+
+dnl  Copyright 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Standard commenting is with @, the default m4 # is for constants and we
+dnl  don't want to disable macro expansions in or after them.
+
+changecom
+
+
+dnl  LEA_HI(reg,gmp_symbol), LEA_LO(reg,gmp_symbol)
+dnl
+dnl  Load the address of gmp_symbol into a register. We split this into two
+dnl  parts to allow separation for manual insn scheduling.  TODO: Darwin allows
+dnl  for relaxing these two insns into an adr and a nop, but that requires the
+dnl  .loh pseudo for connecting them.
+
+define(`LEA_HI',`adrp	$1, $2@GOTPAGE')dnl
+define(`LEA_LO',`ldr	$1, [$1, $2@GOTPAGEOFF]')dnl
+
+divert`'dnl
diff --git a/mpn/arm64/divrem_1.asm b/mpn/arm64/divrem_1.asm
new file mode 100644
index 0000000..32d1bbe
--- /dev/null
+++ b/mpn/arm64/divrem_1.asm
@@ -0,0 +1,231 @@
+dnl  ARM64 mpn_divrem_1 and mpn_preinv_divrem_1.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+dnl TODO
+dnl  * Handle the most significant quotient limb for the unnormalised case
+dnl    specially, just like in the C code.  (It is very often 0.)
+
+define(`qp_arg',   x0)
+define(`fn_arg',   x1)
+define(`np_arg',   x2)
+define(`n_arg',    x3)
+define(`d_arg',    x4)
+define(`dinv_arg', x5)
+define(`cnt_arg',  x6)
+
+define(`qp',   x19)
+define(`np',   x20)
+define(`n',    x21)
+define(`d',    x22)
+define(`fn',   x24)
+define(`dinv', x0)
+define(`cnt',  x23)
+define(`tnc',  x8)
+
+dnl mp_limb_t
+dnl mpn_divrem_1 (mp_ptr qp, mp_size_t fn,
+dnl               mp_srcptr np, mp_size_t n,
+dnl               mp_limb_t d_unnorm)
+
+dnl mp_limb_t
+dnl mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t fn,
+dnl                      mp_srcptr np, mp_size_t n,
+dnl                      mp_limb_t d_unnorm, mp_limb_t dinv, int cnt)
+
+ASM_START()
+
+PROLOGUE(mpn_preinv_divrem_1)
+	cbz	n_arg, L(fz)
+	stp	x29, x30, [sp, #-80]!
+	mov	x29, sp
+	stp	x19, x20, [sp, #16]
+	stp	x21, x22, [sp, #32]
+	stp	x23, x24, [sp, #48]
+
+	sub	n, n_arg, #1
+	add	x7, n, fn_arg
+	add	np, np_arg, n, lsl #3
+	add	qp, qp_arg, x7, lsl #3
+	mov	fn, fn_arg
+	mov	d, d_arg
+	mov	dinv, dinv_arg
+	tbnz	d_arg, #63, L(nentry)
+	mov	cnt, cnt_arg
+	b	L(uentry)
+EPILOGUE()
+
+PROLOGUE(mpn_divrem_1)
+	cbz	n_arg, L(fz)
+	stp	x29, x30, [sp, #-80]!
+	mov	x29, sp
+	stp	x19, x20, [sp, #16]
+	stp	x21, x22, [sp, #32]
+	stp	x23, x24, [sp, #48]
+
+	sub	n, n_arg, #1
+	add	x7, n, fn_arg
+	add	np, np_arg, n, lsl #3
+	add	qp, qp_arg, x7, lsl #3
+	mov	fn, fn_arg
+	mov	d, d_arg
+	tbnz	d_arg, #63, L(normalised)
+
+L(unnorm):
+	clz	cnt, d
+	lsl	x0, d, cnt
+	bl	GSYM_PREFIX`'MPN(invert_limb)
+L(uentry):
+	lsl	d, d, cnt
+	ldr	x7, [np], #-8
+	sub	tnc, xzr, cnt
+	lsr	x11, x7, tnc		C r
+	lsl	x1, x7, cnt
+	cbz	n, L(uend)
+
+L(utop):ldr	x7, [np], #-8
+	add	x2, x11, #1
+	mul	x10, x11, dinv
+	umulh	x17, x11, dinv
+	lsr	x9, x7, tnc
+	orr	x1, x1, x9
+	adds	x10, x1, x10
+	adc	x2, x2, x17
+	msub	x11, d, x2, x1
+	lsl	x1, x7, cnt
+	cmp	x10, x11
+	add	x14, x11, d
+	csel	x11, x14, x11, cc
+	sbc	x2, x2, xzr
+	cmp	x11, d
+	bcs	L(ufx)
+L(uok):	str	x2, [qp], #-8
+	sub	n, n, #1
+	cbnz	n, L(utop)
+
+L(uend):add	x2, x11, #1
+	mul	x10, x11, dinv
+	umulh	x17, x11, dinv
+	adds	x10, x1, x10
+	adc	x2, x2, x17
+	msub	x11, d, x2, x1
+	cmp	x10, x11
+	add	x14, x11, d
+	csel	x11, x14, x11, cc
+	sbc	x2, x2, xzr
+	subs	x14, x11, d
+	adc	x2, x2, xzr
+	csel	x11, x14, x11, cs
+	str	x2, [qp], #-8
+
+	cbnz	fn, L(ftop)
+	lsr	x0, x11, cnt
+	ldp	x19, x20, [sp, #16]
+	ldp	x21, x22, [sp, #32]
+	ldp	x23, x24, [sp, #48]
+	ldp	x29, x30, [sp], #80
+	ret
+
+L(ufx):	add	x2, x2, #1
+	sub	x11, x11, d
+	b	L(uok)
+
+
+L(normalised):
+	mov	x0, d
+	bl	GSYM_PREFIX`'MPN(invert_limb)
+L(nentry):
+	ldr	x7, [np], #-8
+	subs	x14, x7, d
+	adc	x2, xzr, xzr		C hi q limb
+	csel	x11, x14, x7, cs
+	b	L(nok)
+
+L(ntop):ldr	x1, [np], #-8
+	add	x2, x11, #1
+	mul	x10, x11, dinv
+	umulh	x17, x11, dinv
+	adds	x10, x1, x10
+	adc	x2, x2, x17
+	msub	x11, d, x2, x1
+	cmp	x10, x11
+	add	x14, x11, d
+	csel	x11, x14, x11, cc	C remainder
+	sbc	x2, x2, xzr
+	cmp	x11, d
+	bcs	L(nfx)
+L(nok):	str	x2, [qp], #-8
+	sub	n, n, #1
+	tbz	n, #63, L(ntop)
+
+L(nend):cbnz	fn, L(frac)
+	mov	x0, x11
+	ldp	x19, x20, [sp, #16]
+	ldp	x21, x22, [sp, #32]
+	ldp	x23, x24, [sp, #48]
+	ldp	x29, x30, [sp], #80
+	ret
+
+L(nfx):	add	x2, x2, #1
+	sub	x11, x11, d
+	b	L(nok)
+
+L(frac):mov	cnt, #0
+L(ftop):add	x2, x11, #1
+	mul	x10, x11, dinv
+	umulh	x17, x11, dinv
+	add	x2, x2, x17
+	msub	x11, d, x2, xzr
+	cmp	x10, x11
+	add	x14, x11, d
+	csel	x11, x14, x11, cc	C remainder
+	sbc	x2, x2, xzr
+	str	x2, [qp], #-8
+	sub	fn, fn, #1
+	cbnz	fn, L(ftop)
+
+	lsr	x0, x11, cnt
+	ldp	x19, x20, [sp, #16]
+	ldp	x21, x22, [sp, #32]
+	ldp	x23, x24, [sp, #48]
+	ldp	x29, x30, [sp], #80
+	ret
+
+C Block zero. We need this for the degenerated case of n = 0, fn != 0.
+L(fz):	cbz	fn_arg, L(zend)
+L(ztop):str	xzr, [qp_arg], #8
+	sub	fn_arg, fn_arg, #1
+	cbnz	fn_arg, L(ztop)
+L(zend):mov	x0, #0
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/gcd_11.asm b/mpn/arm64/gcd_11.asm
new file mode 100644
index 0000000..5f2dd50
--- /dev/null
+++ b/mpn/arm64/gcd_11.asm
@@ -0,0 +1,70 @@
+dnl  ARM v8a mpn_gcd_11.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for ARM by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+changecom(blah)
+
+C	     cycles/bit (approx)
+C Cortex-A35	 ?
+C Cortex-A53	 ?
+C Cortex-A55	 ?
+C Cortex-A57	 ?
+C Cortex-A72	 ?
+C Cortex-A73	 ?
+C Cortex-A75	 ?
+C Cortex-A76	 ?
+C Cortex-A77	 ?
+C Numbers measured with: speed -CD -s16-64 -t48 mpn_gcd_1
+
+define(`u0',    `x0')
+define(`v0',    `x1')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	subs	x3, u0, v0		C			0
+	b.eq	L(end)			C
+
+	ALIGN(16)
+L(top):	rbit	x12, x3			C			1,5
+	clz	x12, x12		C			2
+	csneg	x3, x3, x3, cs		C v = abs(u-v), even	1
+	csel	u0, v0, u0, cs		C u = min(u,v)		1
+	lsr	v0, x3, x12		C			3
+	subs	x3, u0, v0		C			4
+	b.ne	L(top)			C
+
+L(end):	ret
+EPILOGUE()
diff --git a/mpn/arm64/gcd_22.asm b/mpn/arm64/gcd_22.asm
new file mode 100644
index 0000000..5ea6abe
--- /dev/null
+++ b/mpn/arm64/gcd_22.asm
@@ -0,0 +1,112 @@
+dnl  ARM v8a mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+changecom(blah)
+
+C	     cycles/bit (approx)
+C Cortex-A35	 ?
+C Cortex-A53	 7.26
+C Cortex-A55	 ?
+C Cortex-A57	 ?
+C Cortex-A72	 5.72
+C Cortex-A73	 6.43
+C Cortex-A75	 ?
+C Cortex-A76	 ?
+C Cortex-A77	 ?
+
+
+define(`u1',    `x0')
+define(`u0',    `x1')
+define(`v1',    `x2')
+define(`v0',    `x3')
+
+define(`t0',    `x5')
+define(`t1',    `x6')
+define(`cnt',   `x7')
+define(`tnc',   `x8')
+
+ASM_START()
+PROLOGUE(mpn_gcd_22)
+
+	ALIGN(16)
+L(top):	subs	t0, u0, v0		C 0 6
+	cbz	t0, L(lowz)
+	sbcs	t1, u1, v1		C 1 7
+
+	rbit	cnt, t0			C 1
+
+	cneg	t0, t0, cc		C 2
+	cinv	t1, t1, cc		C 2 u = |u - v|
+L(bck):	csel	v0, v0, u0, cs		C 2
+	csel	v1, v1, u1, cs		C 2 v = min(u,v)
+
+	clz	cnt, cnt		C 2
+	sub	tnc, xzr, cnt		C 3
+
+	lsr	u0, t0, cnt		C 3
+	lsl	x14, t1, tnc		C 4
+	lsr	u1, t1, cnt		C 3
+	orr	u0, u0, x14		C 5
+
+	orr	x11, u1, v1
+	cbnz	x11, L(top)
+
+
+	subs	x4, u0, v0		C			0
+	b.eq	L(end1)			C
+
+	ALIGN(16)
+L(top1):rbit	x12, x4			C			1,5
+	clz	x12, x12		C			2
+	csneg	x4, x4, x4, cs		C v = abs(u-v), even	1
+	csel	u0, v0, u0, cs		C u = min(u,v)		1
+	lsr	v0, x4, x12		C			3
+	subs	x4, u0, v0		C			4
+	b.ne	L(top1)			C
+L(end1):mov	x0, u0
+	mov	x1, #0
+	ret
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	subs	t0, u1, v1
+	b.eq	L(end)
+	mov	t1, #0
+	rbit	cnt, t0			C 1
+	cneg	t0, t0, cc		C 2
+	b	L(bck)			C FIXME: make conditional
+
+L(end):	mov	x0, v0
+	mov	x1, v1
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/gmp-mparam.h b/mpn/arm64/gmp-mparam.h
new file mode 100644
index 0000000..7c0c193
--- /dev/null
+++ b/mpn/arm64/gmp-mparam.h
@@ -0,0 +1,192 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1536 MHz Cortex-A53 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-09-29, gcc 5.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            4
+#define MOD_1_1P_METHOD                      2  /* 2.08% faster than 1 */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        20
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     21
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 38.26% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             13
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           40
+
+#define DIV_1_VS_MUL_1_PERCENT             159
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                49
+#define MUL_TOOM44_THRESHOLD                82
+#define MUL_TOOM6H_THRESHOLD               173
+#define MUL_TOOM8H_THRESHOLD               236
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      76
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      81
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      80
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      74
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 67
+#define SQR_TOOM4_THRESHOLD                166
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                333
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD               10
+#define SQRMOD_BNM1_THRESHOLD               11
+
+#define MUL_FFT_MODF_THRESHOLD             316  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    316, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     17, 8}, \
+    {      9, 7}, {     20, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     99,10}, {     55,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255, 9}, \
+    {    131,10}, {     71, 8}, {    287,10}, {     79, 9}, \
+    {    159, 8}, {    319,10}, {     87,11}, {     47,10}, \
+    {     95, 9}, {    191, 8}, {    383,10}, {    103, 9}, \
+    {    207, 8}, {    415,10}, {    111, 9}, {    223,12}, \
+    {     31,11}, {     63, 9}, {    255, 8}, {    511,10}, \
+    {    135, 9}, {    287, 8}, {    575,11}, {     79,10}, \
+    {    159, 9}, {    319, 8}, {    639,10}, {    175, 9}, \
+    {    351, 8}, {    703,11}, {     95,10}, {    191, 9}, \
+    {    383, 8}, {    767,10}, {    207, 9}, {    415,11}, \
+    {    111,10}, {    223, 9}, {    447,12}, {     63,10}, \
+    {    255, 9}, {    511, 8}, {   1023, 9}, {    543,10}, \
+    {    287, 9}, {    575, 8}, {   1151,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351, 9}, \
+    {    703, 8}, {   1407,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 118
+#define MUL_FFT_THRESHOLD                 3200
+
+#define SQR_FFT_MODF_THRESHOLD             272  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    272, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {      8, 5}, {     17, 6}, {     17, 7}, {     17, 8}, \
+    {      9, 7}, {     19, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     15, 7}, {     31, 8}, \
+    {     19, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     47,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95, 8}, {    191,10}, {     55,11}, {     31,10}, \
+    {     63, 8}, {    255,10}, {     71, 9}, {    143, 8}, \
+    {    287,10}, {     79, 9}, {    159,11}, {     47,10}, \
+    {     95, 9}, {    191, 8}, {    383, 7}, {    767,10}, \
+    {    103, 9}, {    207,12}, {     31,11}, {     63, 9}, \
+    {    255, 8}, {    511, 7}, {   1023, 9}, {    271,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415, 8}, {    831,10}, \
+    {    223,12}, {     63,10}, {    255, 9}, {    511, 8}, \
+    {   1023,10}, {    271,11}, {    143,10}, {    287, 9}, \
+    {    575, 8}, {   1151,11}, {    159,10}, {    319, 9}, \
+    {    639,11}, {    175,10}, {    351, 9}, {    703,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,13}, {   8192,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 112
+#define SQR_FFT_THRESHOLD                 2688
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  38
+#define MULLO_MUL_N_THRESHOLD             6253
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                  67
+#define SQRLO_SQR_THRESHOLD               5240
+
+#define DC_DIV_QR_THRESHOLD                 42
+#define DC_DIVAPPR_Q_THRESHOLD             152
+#define DC_BDIV_QR_THRESHOLD                39
+#define DC_BDIV_Q_THRESHOLD                 93
+
+#define INV_MULMOD_BNM1_THRESHOLD           37
+#define INV_NEWTON_THRESHOLD               163
+#define INV_APPR_THRESHOLD                 162
+
+#define BINV_NEWTON_THRESHOLD              194
+#define REDC_1_TO_REDC_N_THRESHOLD          43
+
+#define MU_DIV_QR_THRESHOLD                998
+#define MU_DIVAPPR_Q_THRESHOLD             998
+#define MUPI_DIV_QR_THRESHOLD               98
+#define MU_BDIV_QR_THRESHOLD               807
+#define MU_BDIV_Q_THRESHOLD                924
+
+#define POWM_SEC_TABLE  6,30,194,579,1730
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        29
+#define SET_STR_DC_THRESHOLD               788
+#define SET_STR_PRECOMPUTE_THRESHOLD      1816
+
+#define FAC_DSC_THRESHOLD                  236
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         10
+#define HGCD2_DIV1_METHOD                    1  /* 7.05% faster than 3 */
+#define HGCD_THRESHOLD                     101
+#define HGCD_APPR_THRESHOLD                104
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   330
+#define GCDEXT_DC_THRESHOLD                242
+#define JACOBI_BASE_METHOD                   4  /* 20.00% faster than 1 */
diff --git a/mpn/arm64/hamdist.asm b/mpn/arm64/hamdist.asm
new file mode 100644
index 0000000..1dc6a62
--- /dev/null
+++ b/mpn/arm64/hamdist.asm
@@ -0,0 +1,181 @@
+dnl  ARM64 Neon mpn_hamdist -- mpn bit hamming distance.
+
+dnl  Copyright 2013, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 4.5
+C Cortex-A57	 1.9
+C X-Gene	 4.36
+
+C TODO
+C  * Consider greater unrolling.
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+changecom(blah)
+
+C INPUT PARAMETERS
+define(`ap', x0)
+define(`bp', x1)
+define(`n',  x2)
+
+C We sum into 16 16-bit counters in v4,v5, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/64 = 0x1fff limbs.  We use a chunksize close to that, but which
+C  allows the huge count code to jump deep into the code (at L(chu)).
+
+define(`maxsize',  0x1fff)
+define(`chunksize',0x1ff0)
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+
+	mov	x11, #maxsize
+	cmp	n, x11
+	b.hi	L(gt8k)
+
+L(lt8k):
+	movi	v4.16b, #0			C clear summation register
+	movi	v5.16b, #0			C clear summation register
+
+	tbz	n, #0, L(xx0)
+	sub	n, n, #1
+	ld1	{v0.1d}, [ap], #8		C load 1 limb
+	ld1	{v16.1d}, [bp], #8		C load 1 limb
+	eor	v0.16b, v0.16b, v16.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b			C could also splat
+
+L(xx0):	tbz	n, #1, L(x00)
+	sub	n, n, #2
+	ld1	{v0.2d}, [ap], #16		C load 2 limbs
+	ld1	{v16.2d}, [bp], #16		C load 2 limbs
+	eor	v0.16b, v0.16b, v16.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b
+
+L(x00):	tbz	n, #2, L(000)
+	subs	n, n, #4
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	ld1	{v16.2d,v17.2d}, [bp], #32	C load 4 limbs
+	b.ls	L(sum)
+
+L(gt4):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v18.2d,v19.2d}, [bp], #32	C load 4 limbs
+	eor	v0.16b, v0.16b, v16.16b
+	eor	v1.16b, v1.16b, v17.16b
+	sub	n, n, #4
+	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	b	L(mid)
+
+L(000):	subs	n, n, #8
+	b.lo	L(e0)
+
+L(chu):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	ld1	{v18.2d,v19.2d}, [bp], #32	C load 4 limbs
+	ld1	{v16.2d,v17.2d}, [bp], #32	C load 4 limbs
+	eor	v2.16b, v2.16b, v18.16b
+	eor	v3.16b, v3.16b, v19.16b
+	cnt	v6.16b, v2.16b
+	cnt	v7.16b, v3.16b
+	subs	n, n, #8
+	b.lo	L(end)
+
+L(top):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v18.2d,v19.2d}, [bp], #32	C load 4 limbs
+	eor	v0.16b, v0.16b, v16.16b
+	eor	v1.16b, v1.16b, v17.16b
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v1.16b
+L(mid):	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	ld1	{v16.2d,v17.2d}, [bp], #32	C load 4 limbs
+	eor	v2.16b, v2.16b, v18.16b
+	eor	v3.16b, v3.16b, v19.16b
+	subs	n, n, #8
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v2.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v3.16b
+	b.hs	L(top)
+
+L(end):	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+L(sum):	eor	v0.16b, v0.16b, v16.16b
+	eor	v1.16b, v1.16b, v17.16b
+	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+	add	v4.8h, v4.8h, v5.8h
+					C we have 8 16-bit counts
+L(e0):	uaddlp	v4.4s,  v4.8h		C we have 4 32-bit counts
+	uaddlp	v4.2d,  v4.4s		C we have 2 64-bit counts
+	mov	x0, v4.d[0]
+	mov	x1, v4.d[1]
+	add	x0, x0, x1
+	ret
+
+C Code for count > maxsize.  Splits operand and calls above code.
+define(`ap2', x5)			C caller-saves reg not used above
+define(`bp2', x6)			C caller-saves reg not used above
+L(gt8k):
+	mov	x8, x30
+	mov	x7, n			C full count (caller-saves reg not used above)
+	mov	x4, #0			C total sum  (caller-saves reg not used above)
+	mov	x9, #chunksize*8	C caller-saves reg not used above
+	mov	x10, #chunksize		C caller-saves reg not used above
+
+1:	add	ap2, ap, x9		C point at subsequent block
+	add	bp2, bp, x9		C point at subsequent block
+	mov	n, #chunksize-8		C count for this invocation, adjusted for entry pt
+	movi	v4.16b, #0		C clear chunk summation register
+	movi	v5.16b, #0		C clear chunk summation register
+	bl	L(chu)			C jump deep inside code
+	add	x4, x4, x0
+	mov	ap, ap2			C put chunk pointer in place for calls
+	mov	bp, bp2			C put chunk pointer in place for calls
+	sub	x7, x7, x10
+	cmp	x7, x11
+	b.hi	1b
+
+	mov	n, x7			C count for final invocation
+	bl	L(lt8k)
+	add	x0, x4, x0
+	mov	x30, x8
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/invert_limb.asm b/mpn/arm64/invert_limb.asm
new file mode 100644
index 0000000..e372dd0
--- /dev/null
+++ b/mpn/arm64/invert_limb.asm
@@ -0,0 +1,83 @@
+dnl  ARM64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C            cycles/limb
+C Cortex-A53     ?
+C Cortex-A57     ?
+
+C Compiler generated, mildly edited.  Could surely be further optimised.
+
+ASM_START()
+PROLOGUE(mpn_invert_limb)
+	lsr	x2, x0, #54
+	LEA_HI(	x1, approx_tab)
+	and	x2, x2, #0x1fe
+	LEA_LO(	x1, approx_tab)
+	ldrh	w3, [x1,x2]
+	lsr	x4, x0, #24
+	add	x4, x4, #1
+	ubfiz	x2, x3, #11, #16
+	umull	x3, w3, w3
+	mul	x3, x3, x4
+	sub	x2, x2, #1
+	sub	x2, x2, x3, lsr #40
+	lsl	x3, x2, #60
+	mul	x1, x2, x2
+	msub	x1, x1, x4, x3
+	lsl	x2, x2, #13
+	add	x1, x2, x1, lsr #47
+	and	x2, x0, #1
+	neg	x3, x2
+	and	x3, x3, x1, lsr #1
+	add	x2, x2, x0, lsr #1
+	msub	x2, x1, x2, x3
+	umulh	x2, x2, x1
+	lsl	x1, x1, #31
+	add	x1, x1, x2, lsr #1
+	mul	x3, x1, x0
+	umulh	x2, x1, x0
+	adds	x4, x3, x0
+	adc	x0, x2, x0
+	sub	x0, x1, x0
+	ret
+EPILOGUE()
+
+	RODATA
+	ALIGN(2)
+	TYPE(   approx_tab, object)
+	SIZE(   approx_tab, 512)
+approx_tab:
+forloop(i,256,512-1,dnl
+`	.hword	eval(0x7fd00/i)
+')dnl
diff --git a/mpn/arm64/logops_n.asm b/mpn/arm64/logops_n.asm
new file mode 100644
index 0000000..6520881
--- /dev/null
+++ b/mpn/arm64/logops_n.asm
@@ -0,0 +1,139 @@
+dnl  ARM64 mpn_and_n, mpn_andn_n. mpn_nand_n, etc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb     cycles/limb
+C	      nand,nior	      all other
+C Cortex-A53	3.25-3.5	2.75-3
+C Cortex-A57	 2.0		 1.5
+C X-Gene	 2.14		 2.0
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+define(`POSTOP', `dnl')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',    `mpn_and_n')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',    `mpn_andn_n')
+  define(`LOGOP',   `bic	$1, $2, $3')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',    `mpn_nand_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',    `mpn_ior_n')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',    `mpn_iorn_n')
+  define(`LOGOP',   `orn	$1, $2, $3')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',    `mpn_nior_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',    `mpn_xor_n')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',    `mpn_xnor_n')
+  define(`LOGOP',   `eon	$1, $2, $3')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	lsr	x17, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x7, [up]
+	ldr	x11, [vp]
+	LOGOP(	x15, x7, x11)
+	POSTOP(	x15)
+	str	x15, [rp],#8
+	tbnz	n, #1, L(b11)
+
+L(b01):	cbz	x17, L(ret)
+	ldp	x4, x5, [up,#8]
+	ldp	x8, x9, [vp,#8]
+	sub	up, up, #8
+	sub	vp, vp, #8
+	b	L(mid)
+
+L(b11):	ldp	x6, x7, [up,#8]
+	ldp	x10, x11, [vp,#8]
+	add	up, up, #8
+	add	vp, vp, #8
+	cbz	x17, L(end)
+	b	L(top)
+
+L(bx0):	tbnz	n, #1, L(b10)
+
+L(b00):	ldp	x4, x5, [up],#-16
+	ldp	x8, x9, [vp],#-16
+	b	L(mid)
+
+L(b10):	ldp	x6, x7, [up]
+	ldp	x10, x11, [vp]
+	cbz	x17, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	ldp	x8, x9, [vp,#16]
+	LOGOP(	x12, x6, x10)
+	LOGOP(	x13, x7, x11)
+	POSTOP(	x12)
+	POSTOP(	x13)
+	stp	x12, x13, [rp],#16
+L(mid):	ldp	x6, x7, [up,#32]!
+	ldp	x10, x11, [vp,#32]!
+	LOGOP(	x12, x4, x8)
+	LOGOP(	x13, x5, x9)
+	POSTOP(	x12)
+	POSTOP(	x13)
+	stp	x12, x13, [rp],#16
+	sub	x17, x17, #1
+	cbnz	x17, L(top)
+
+L(end):	LOGOP(	x12, x6, x10)
+	LOGOP(	x13, x7, x11)
+	POSTOP(	x12)
+	POSTOP(	x13)
+	stp	x12, x13, [rp]
+L(ret):	ret
+EPILOGUE()
diff --git a/mpn/arm64/lshift.asm b/mpn/arm64/lshift.asm
new file mode 100644
index 0000000..1c9b39a
--- /dev/null
+++ b/mpn/arm64/lshift.asm
@@ -0,0 +1,138 @@
+dnl  ARM64 mpn_lshift.
+
+dnl  Copyright 2013, 2014, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.5-4.0		 3.25
+C Cortex-A57	 2.0		 2.0
+C X-Gene	 2.67		 2.5
+
+C TODO
+C  * The feed-in code used 1 ldr for odd sized and 2 ldr for even sizes.  These
+C    numbers should be 1 and 0, respectively.  The str in wind-down should also
+C    go.
+C  * Using extr and with 63 separate loops we might reach 1.25 c/l on A57.
+C  * A53's speed depends on alignment, tune/speed -w1 gives 3.5, -w0 gives 4.0.
+
+changecom(blah)
+
+define(`rp_arg', `x0')
+define(`up',     `x1')
+define(`n',      `x2')
+define(`cnt',    `x3')
+
+define(`rp',     `x16')
+
+define(`tnc',`x8')
+
+define(`PSHIFT', lsl)
+define(`NSHIFT', lsr)
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	add	rp, rp_arg, n, lsl #3
+	add	up, up, n, lsl #3
+	sub	tnc, xzr, cnt
+	lsr	x17, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x4, [up,#-8]
+	tbnz	n, #1, L(b11)
+
+L(b01):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x17, L(gt1)
+	str	x2, [rp,#-8]
+	ret
+L(gt1):	ldp	x4, x5, [up,#-24]
+	sub	up, up, #8
+	add	rp, rp, #16
+	b	L(lo2)
+
+L(b11):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-24]!
+	b	L(lo3)
+
+L(bx0):	ldp	x4, x5, [up,#-16]
+	tbz	n, #1, L(b00)
+
+L(b10):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x17, L(gt2)
+	orr	x10, x10, x13
+	stp	x2, x10, [rp,#-16]
+	ret
+L(gt2):	ldp	x4, x5, [up,#-32]
+	orr	x10, x10, x13
+	str	x10, [rp,#-8]
+	sub	up, up, #16
+	add	rp, rp, #8
+	b	L(lo2)
+
+L(b00):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-32]!
+	orr	x10, x10, x13
+	str	x10, [rp,#-8]!
+	b	L(lo0)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#-16]
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x10, x11, [rp,#-16]
+	PSHIFT	x2, x6, cnt
+L(lo2):	NSHIFT	x10, x4, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x12, x5, tnc
+	ldp	x6, x7, [up,#-32]!
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x10, x11, [rp,#-32]!
+	PSHIFT	x2, x4, cnt
+L(lo0):	sub	x17, x17, #1
+L(lo3):	NSHIFT	x10, x6, tnc
+	PSHIFT	x13, x7, cnt
+	NSHIFT	x12, x7, tnc
+	cbnz	x17, L(top)
+
+L(end):	orr	x10, x10, x13
+	orr	x11, x12, x2
+	PSHIFT	x2, x6, cnt
+	stp	x10, x11, [rp,#-16]
+	str	x2, [rp,#-24]
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/lshiftc.asm b/mpn/arm64/lshiftc.asm
new file mode 100644
index 0000000..8b8287d
--- /dev/null
+++ b/mpn/arm64/lshiftc.asm
@@ -0,0 +1,141 @@
+dnl  ARM64 mpn_lshiftc.
+
+dnl  Copyright 2013, 2014, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.5-4.0		 3.25
+C Cortex-A57	 2.0		 2.0
+C X-Gene	 2.67		 2.5
+
+C TODO
+C  * The feed-in code used 1 ldr for odd sized and 2 ldr for even sizes.  These
+C    numbers should be 1 and 0, respectively.  The str in wind-down should also
+C    go.
+C  * Using extr and with 63 separate loops we might reach 1.5 c/l on A57.
+C  * A53's speed depends on alignment, tune/speed -w1 gives 3.5, -w0 gives 4.0.
+
+changecom(blah)
+
+define(`rp_arg', `x0')
+define(`up',     `x1')
+define(`n',      `x2')
+define(`cnt',    `x3')
+
+define(`rp',     `x16')
+
+define(`tnc',`x8')
+
+define(`PSHIFT', lsl)
+define(`NSHIFT', lsr)
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	add	rp, rp_arg, n, lsl #3
+	add	up, up, n, lsl #3
+	sub	tnc, xzr, cnt
+	lsr	x17, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x4, [up,#-8]
+	tbnz	n, #1, L(b11)
+
+L(b01):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x17, L(gt1)
+	mvn	x2, x2
+	str	x2, [rp,#-8]
+	ret
+L(gt1):	ldp	x4, x5, [up,#-24]
+	sub	up, up, #8
+	add	rp, rp, #16
+	b	L(lo2)
+
+L(b11):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-24]!
+	b	L(lo3)
+
+L(bx0):	ldp	x4, x5, [up,#-16]
+	tbz	n, #1, L(b00)
+
+L(b10):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x17, L(gt2)
+	eon	x10, x10, x13
+	mvn	x2, x2
+	stp	x2, x10, [rp,#-16]
+	ret
+L(gt2):	ldp	x4, x5, [up,#-32]
+	eon	x10, x10, x13
+	str	x10, [rp,#-8]
+	sub	up, up, #16
+	add	rp, rp, #8
+	b	L(lo2)
+
+L(b00):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-32]!
+	eon	x10, x10, x13
+	str	x10, [rp,#-8]!
+	b	L(lo0)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#-16]
+	eon	x10, x10, x13
+	eon	x11, x12, x2
+	stp	x10, x11, [rp,#-16]
+	PSHIFT	x2, x6, cnt
+L(lo2):	NSHIFT	x10, x4, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x12, x5, tnc
+	ldp	x6, x7, [up,#-32]!
+	eon	x10, x10, x13
+	eon	x11, x12, x2
+	stp	x10, x11, [rp,#-32]!
+	PSHIFT	x2, x4, cnt
+L(lo0):	sub	x17, x17, #1
+L(lo3):	NSHIFT	x10, x6, tnc
+	PSHIFT	x13, x7, cnt
+	NSHIFT	x12, x7, tnc
+	cbnz	x17, L(top)
+
+L(end):	eon	x10, x10, x13
+	eon	x11, x12, x2
+	PSHIFT	x2, x6, cnt
+	stp	x10, x11, [rp,#-16]
+	mvn	x2, x2
+	str	x2, [rp,#-24]
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/mod_34lsub1.asm b/mpn/arm64/mod_34lsub1.asm
new file mode 100644
index 0000000..5c64812
--- /dev/null
+++ b/mpn/arm64/mod_34lsub1.asm
@@ -0,0 +1,124 @@
+dnl  ARM64 mpn_mod_34lsub1 -- remainder modulo 2^48-1.
+
+dnl  Copyright 2012-2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 2
+C Cortex-A57	 1
+C X-Gene	 1.45
+
+define(`ap',	x0)
+define(`n',	x1)
+
+changecom(blah)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * An alternative inner loop which could run at 0.722 c/l on A57:
+C	adds	x8, x8, x2
+C	adcs	x9, x9, x3
+C	ldp	x2, x3, [ap, #-32]
+C	adcs	x10, x10, x4
+C	adc	x12, x12, xzr
+C	adds	x8, x8, x5
+C	ldp	x4, x5, [ap, #-16]
+C	sub	n, n, #6
+C	adcs	x9, x9, x6
+C	adcs	x10, x10, x7
+C	ldp	x6, x7, [ap], #48
+C	adc	x12, x12, xzr
+C	tbz	n, #63, L(top)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	subs	n, n, #3
+	mov	x8, #0
+	b.lt	L(le2)			C n <= 2
+
+	ldp	x2, x3, [ap, #0]
+	ldr	x4, [ap, #16]
+	add	ap, ap, #24
+	subs	n, n, #3
+	b.lt	L(sum)			C n <= 5
+	cmn	x0, #0			C clear carry
+
+L(top):	ldp	x5, x6, [ap, #0]
+	ldr	x7, [ap, #16]
+	add	ap, ap, #24
+	sub	n, n, #3
+	adcs	x2, x2, x5
+	adcs	x3, x3, x6
+	adcs	x4, x4, x7
+	tbz	n, #63, L(top)
+
+	adc	x8, xzr, xzr		C x8 <= 1
+
+L(sum):	cmn	n, #2
+	mov	x5, #0
+	b.lo	1f
+	ldr	x5, [ap], #8
+1:	mov	x6, #0
+	b.ls	1f
+	ldr	x6, [ap], #8
+1:	adds	x2, x2, x5
+	adcs	x3, x3, x6
+	adcs	x4, x4, xzr
+	adc	x8, x8, xzr		C x8 <= 2
+
+L(sum2):
+	and	x0, x2, #0xffffffffffff
+	add	x0, x0, x2, lsr #48
+	add	x0, x0, x8
+
+	lsl	x8, x3, #16
+	and	x1, x8, #0xffffffffffff
+	add	x0, x0, x1
+	add	x0, x0, x3, lsr #32
+
+	lsl	x8, x4, #32
+	and	x1, x8, #0xffffffffffff
+	add	x0, x0, x1
+	add	x0, x0, x4, lsr #16
+	ret
+
+L(le2):	cmn	n, #1
+	b.ne	L(1)
+	ldp	x2, x3, [ap]
+	mov	x4, #0
+	b	L(sum2)
+L(1):	ldr	x2, [ap]
+	and	x0, x2, #0xffffffffffff
+	add	x0, x0, x2, lsr #48
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/mul_1.asm b/mpn/arm64/mul_1.asm
new file mode 100644
index 0000000..f9bf251
--- /dev/null
+++ b/mpn/arm64/mul_1.asm
@@ -0,0 +1,128 @@
+dnl  ARM64 mpn_mul_1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	7.5-8
+C Cortex-A57	 7
+C Cortex-A72
+C X-Gene	 4
+C Apple M1	 1
+
+C TODO
+C  * Start first multiply earlier.
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+define(`v0', `x3')
+
+
+PROLOGUE(mpn_mul_1c)
+	adds	xzr, xzr, xzr		C clear cy flag
+	b	L(com)
+EPILOGUE()
+
+PROLOGUE(mpn_mul_1)
+	adds	x4, xzr, xzr		C clear register and cy flag
+L(com):	lsr	x17, n, #2
+	tbnz	n, #0, L(bx1)
+
+L(bx0):	mov	x11, x4
+	tbz	n, #1, L(b00)
+
+L(b10):	ldp	x4, x5, [up]
+	mul	x8, x4, v0
+	umulh	x10, x4, v0
+	cbz	x17, L(2)
+	ldp	x6, x7, [up,#16]!
+	mul	x9, x5, v0
+	b	L(mid)-8
+
+L(2):	mul	x9, x5, v0
+	b	L(2e)
+
+L(bx1):	ldr	x7, [up],#8
+	mul	x9, x7, v0
+	umulh	x11, x7, v0
+	adds	x9, x9, x4
+	str	x9, [rp],#8
+	tbnz	n, #1, L(b10)
+
+L(b01):	cbz	x17, L(1)
+
+L(b00):	ldp	x6, x7, [up]
+	mul	x8, x6, v0
+	umulh	x10, x6, v0
+	ldp	x4, x5, [up,#16]
+	mul	x9, x7, v0
+	adcs	x12, x8, x11
+	umulh	x11, x7, v0
+	add	rp, rp, #16
+	sub	x17, x17, #1
+	cbz	x17, L(end)
+
+	ALIGN(16)
+L(top):	mul	x8, x4, v0
+	ldp	x6, x7, [up,#32]!
+	adcs	x13, x9, x10
+	umulh	x10, x4, v0
+	mul	x9, x5, v0
+	stp	x12, x13, [rp,#-16]
+	adcs	x12, x8, x11
+	umulh	x11, x5, v0
+L(mid):	mul	x8, x6, v0
+	ldp	x4, x5, [up,#16]
+	adcs	x13, x9, x10
+	umulh	x10, x6, v0
+	mul	x9, x7, v0
+	stp	x12, x13, [rp],#32
+	adcs	x12, x8, x11
+	umulh	x11, x7, v0
+	sub	x17, x17, #1
+	cbnz	x17, L(top)
+
+L(end):	mul	x8, x4, v0
+	adcs	x13, x9, x10
+	umulh	x10, x4, v0
+	mul	x9, x5, v0
+	stp	x12, x13, [rp,#-16]
+L(2e):	adcs	x12, x8, x11
+	umulh	x11, x5, v0
+	adcs	x13, x9, x10
+	stp	x12, x13, [rp]
+L(1):	adc	x0, x11, xzr
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/popcount.asm b/mpn/arm64/popcount.asm
new file mode 100644
index 0000000..33954b9
--- /dev/null
+++ b/mpn/arm64/popcount.asm
@@ -0,0 +1,157 @@
+dnl  ARM64 Neon mpn_popcount -- mpn bit population count.
+
+dnl  Copyright 2013, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 2.5
+C Cortex-A57	 1.14
+C X-Gene	 3
+
+C TODO
+C  * Consider greater unrolling.
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+changecom(blah)
+
+C INPUT PARAMETERS
+define(`ap', x0)
+define(`n',  x1)
+
+C We sum into 16 16-bit counters in v4,v5, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/64 = 0x1fff limbs.  We use a chunksize close to that, but which
+C  allows the huge count code to jump deep into the code (at L(chu)).
+
+define(`maxsize',  0x1fff)
+define(`chunksize',0x1ff0)
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+
+	mov	x11, #maxsize
+	cmp	n, x11
+	b.hi	L(gt8k)
+
+L(lt8k):
+	movi	v4.16b, #0			C clear summation register
+	movi	v5.16b, #0			C clear summation register
+
+	tbz	n, #0, L(xx0)
+	sub	n, n, #1
+	ld1	{v0.1d}, [ap], #8		C load 1 limb
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b			C could also splat
+
+L(xx0):	tbz	n, #1, L(x00)
+	sub	n, n, #2
+	ld1	{v0.2d}, [ap], #16		C load 2 limbs
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b
+
+L(x00):	tbz	n, #2, L(000)
+	subs	n, n, #4
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	b.ls	L(sum)
+
+L(gt4):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	sub	n, n, #4
+	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	b	L(mid)
+
+L(000):	subs	n, n, #8
+	b.lo	L(e0)
+
+L(chu):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	cnt	v6.16b, v2.16b
+	cnt	v7.16b, v3.16b
+	subs	n, n, #8
+	b.lo	L(end)
+
+L(top):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v1.16b
+L(mid):	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	subs	n, n, #8
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v2.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v3.16b
+	b.hs	L(top)
+
+L(end):	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+L(sum):	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+	add	v4.8h, v4.8h, v5.8h
+					C we have 8 16-bit counts
+L(e0):	uaddlp	v4.4s,  v4.8h		C we have 4 32-bit counts
+	uaddlp	v4.2d,  v4.4s		C we have 2 64-bit counts
+	mov	x0, v4.d[0]
+	mov	x1, v4.d[1]
+	add	x0, x0, x1
+	ret
+
+C Code for count > maxsize.  Splits operand and calls above code.
+define(`ap2', x5)			C caller-saves reg not used above
+L(gt8k):
+	mov	x8, x30
+	mov	x7, n			C full count (caller-saves reg not used above)
+	mov	x4, #0			C total sum  (caller-saves reg not used above)
+	mov	x9, #chunksize*8	C caller-saves reg not used above
+	mov	x10, #chunksize		C caller-saves reg not used above
+
+1:	add	ap2, ap, x9		C point at subsequent block
+	mov	n, #chunksize-8		C count for this invocation, adjusted for entry pt
+	movi	v4.16b, #0		C clear chunk summation register
+	movi	v5.16b, #0		C clear chunk summation register
+	bl	L(chu)			C jump deep inside code
+	add	x4, x4, x0
+	mov	ap, ap2			C put chunk pointer in place for calls
+	sub	x7, x7, x10
+	cmp	x7, x11
+	b.hi	1b
+
+	mov	n, x7			C count for final invocation
+	bl	L(lt8k)
+	add	x0, x4, x0
+	mov	x30, x8
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/rsh1aors_n.asm b/mpn/arm64/rsh1aors_n.asm
new file mode 100644
index 0000000..1ce81f5
--- /dev/null
+++ b/mpn/arm64/rsh1aors_n.asm
@@ -0,0 +1,168 @@
+dnl  ARM64 mpn_rsh1add_n and mpn_rsh1sub_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.25-3.75	 3.0 steady
+C Cortex-A57	 2.15		 1.75
+C X-Gene	 2.75		 2.5
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+ifdef(`OPERATION_rsh1add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`COND',	`cs')
+  define(`func_n',	mpn_rsh1add_n)')
+ifdef(`OPERATION_rsh1sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`COND',	`cc')
+  define(`func_n',	mpn_rsh1sub_n)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func_n)
+	lsr	x6, n, #2
+
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x5, [up],#8
+	ldr	x9, [vp],#8
+	tbnz	n, #1, L(b11)
+
+L(b01):	ADDSUB	x13, x5, x9
+	and	x10, x13, #1
+	cbz	x6, L(1)
+	ldp	x4, x5, [up],#48
+	ldp	x8, x9, [vp],#48
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	ldp	x4, x5, [up,#-32]
+	ldp	x8, x9, [vp,#-32]
+	extr	x17, x14, x13, #1
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	str	x17, [rp], #24
+	sub	x6, x6, #1
+	cbz	x6, L(end)
+	b	L(top)
+
+L(1):	cset	x14, COND
+	extr	x17, x14, x13, #1
+	str	x17, [rp]
+	mov	x0, x10
+	ret
+
+L(b11):	ADDSUB	x15, x5, x9
+	and	x10, x15, #1
+
+	ldp	x4, x5, [up],#32
+	ldp	x8, x9, [vp],#32
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	cbz	x6, L(3)
+	ldp	x4, x5, [up,#-16]
+	ldp	x8, x9, [vp,#-16]
+	extr	x17, x12, x15, #1
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	str	x17, [rp], #8
+	b	L(mid)
+
+L(3):	extr	x17, x12, x15, #1
+	str	x17, [rp], #8
+	b	L(2)
+
+L(bx0):	tbz	n, #1, L(b00)
+
+L(b10):	ldp	x4, x5, [up],#32
+	ldp	x8, x9, [vp],#32
+	ADDSUB	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	and	x10, x12, #1
+	cbz	x6, L(2)
+	ldp	x4, x5, [up,#-16]
+	ldp	x8, x9, [vp,#-16]
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	b	L(mid)
+
+L(b00):	ldp	x4, x5, [up],#48
+	ldp	x8, x9, [vp],#48
+	ADDSUB	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	and	x10, x14, #1
+	ldp	x4, x5, [up,#-32]
+	ldp	x8, x9, [vp,#-32]
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	add	rp, rp, #16
+	sub	x6, x6, #1
+	cbz	x6, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#-16]
+	ldp	x8, x9, [vp,#-16]
+	extr	x16, x15, x14, #1
+	extr	x17, x12, x15, #1
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	stp	x16, x17, [rp,#-16]
+L(mid):	ldp	x4, x5, [up],#32
+	ldp	x8, x9, [vp],#32
+	extr	x16, x13, x12, #1
+	extr	x17, x14, x13, #1
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	stp	x16, x17, [rp],#32
+	sub	x6, x6, #1
+	cbnz	x6, L(top)
+
+L(end):	extr	x16, x15, x14, #1
+	extr	x17, x12, x15, #1
+	stp	x16, x17, [rp,#-16]
+L(2):	cset	x14, COND
+	extr	x16, x13, x12, #1
+	extr	x17, x14, x13, #1
+	stp	x16, x17, [rp]
+
+L(ret):	mov	x0, x10
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/rshift.asm b/mpn/arm64/rshift.asm
new file mode 100644
index 0000000..10b0a04
--- /dev/null
+++ b/mpn/arm64/rshift.asm
@@ -0,0 +1,136 @@
+dnl  ARM64 mpn_rshift.
+
+dnl  Copyright 2013, 2014, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.5-4.0		 3.25
+C Cortex-A57	 2.0		 2.0
+C X-Gene	 2.67		 2.5
+
+C TODO
+C  * The feed-in code used 1 ldr for odd sized and 2 ldr for even sizes.  These
+C    numbers should be 1 and 0, respectively.  The str in wind-down should also
+C    go.
+C  * Using extr and with 63 separate loops we might reach 1.25 c/l on A57.
+C  * A53's speed depends on alignment, but not as simply as for lshift/lshiftc.
+
+changecom(blah)
+
+define(`rp_arg', `x0')
+define(`up',     `x1')
+define(`n',      `x2')
+define(`cnt',    `x3')
+
+define(`rp',     `x16')
+
+define(`tnc',`x8')
+
+define(`PSHIFT', lsr)
+define(`NSHIFT', lsl)
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	mov	rp, rp_arg
+	sub	tnc, xzr, cnt
+	lsr	x17, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x5, [up]
+	tbnz	n, #1, L(b11)
+
+L(b01):	NSHIFT	x0, x5, tnc
+	PSHIFT	x2, x5, cnt
+	cbnz	x17, L(gt1)
+	str	x2, [rp]
+	ret
+L(gt1):	ldp	x4, x5, [up,#8]
+	sub	up, up, #8
+	sub	rp, rp, #32
+	b	L(lo2)
+
+L(b11):	NSHIFT	x0, x5, tnc
+	PSHIFT	x2, x5, cnt
+	ldp	x6, x7, [up,#8]!
+	sub	rp, rp, #16
+	b	L(lo3)
+
+L(bx0):	ldp	x4, x5, [up]
+	tbz	n, #1, L(b00)
+
+L(b10):	NSHIFT	x0, x4, tnc
+	PSHIFT	x13, x4, cnt
+	NSHIFT	x10, x5, tnc
+	PSHIFT	x2, x5, cnt
+	cbnz	x17, L(gt2)
+	orr	x10, x10, x13
+	stp	x10, x2, [rp]
+	ret
+L(gt2):	ldp	x4, x5, [up,#16]
+	orr	x10, x10, x13
+	str	x10, [rp],#-24
+	b	L(lo2)
+
+L(b00):	NSHIFT	x0, x4, tnc
+	PSHIFT	x13, x4, cnt
+	NSHIFT	x10, x5, tnc
+	PSHIFT	x2, x5, cnt
+	ldp	x6, x7, [up,#16]!
+	orr	x10, x10, x13
+	str	x10, [rp],#-8
+	b	L(lo0)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x11, x10, [rp,#16]
+	PSHIFT	x2, x7, cnt
+L(lo2):	NSHIFT	x10, x5, tnc
+	NSHIFT	x12, x4, tnc
+	PSHIFT	x13, x4, cnt
+	ldp	x6, x7, [up,#32]!
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x11, x10, [rp,#32]!
+	PSHIFT	x2, x5, cnt
+L(lo0):	sub	x17, x17, #1
+L(lo3):	NSHIFT	x10, x7, tnc
+	NSHIFT	x12, x6, tnc
+	PSHIFT	x13, x6, cnt
+	cbnz	x17, L(top)
+
+L(end):	orr	x10, x10, x13
+	orr	x11, x12, x2
+	PSHIFT	x2, x7, cnt
+	stp	x11, x10, [rp,#16]
+	str	x2, [rp,#32]
+	ret
+EPILOGUE()
diff --git a/mpn/arm64/sec_tabselect.asm b/mpn/arm64/sec_tabselect.asm
new file mode 100644
index 0000000..5cbd3b2
--- /dev/null
+++ b/mpn/arm64/sec_tabselect.asm
@@ -0,0 +1,122 @@
+dnl  ARM64 Neon mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C Cortex-A53	 2.25
+C Cortex-A57	 1.33
+C X-Gene	 2
+
+C void
+C mpn_sec_tabselect (mp_ptr rp, mp_srcptr *tab,
+C		     mp_size_t n, mp_size_t nents, mp_size_t which)
+
+changecom(blah)
+
+define(`rp',     `x0')
+define(`tp',     `x1')
+define(`n',      `x2')
+define(`nents',  `x3')
+define(`which',  `x4')
+
+define(`i',      `x5')
+define(`j',      `x6')
+
+define(`maskq',  `v4')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	dup	v7.2d, x4			C 2 `which' copies
+
+	mov	x10, #1
+	dup	v6.2d, x10			C 2 copies of 1
+
+	subs	j, n, #4
+	b.mi	L(outer_end)
+
+L(outer_top):
+	mov	i, nents
+	mov	x12, tp				C preserve tp
+	movi	v5.16b, #0			C zero 2 counter copies
+	movi	v2.16b, #0
+	movi	v3.16b, #0
+	ALIGN(16)
+L(tp4):	cmeq	maskq.2d, v5.2d, v7.2d		C compare idx copies to `which' copies
+	ld1	{v0.2d,v1.2d}, [tp]
+	add	v5.2d, v5.2d, v6.2d
+	bit	v2.16b, v0.16b, maskq.16b
+	bit	v3.16b, v1.16b, maskq.16b
+	add	tp, tp, n, lsl #3
+	sub	i, i, #1
+	cbnz	i, L(tp4)
+	st1	{v2.2d,v3.2d}, [rp], #32
+	add	tp, x12, #32			C restore tp, point to next slice
+	subs	j, j, #4
+	b.pl	L(outer_top)
+L(outer_end):
+
+	tbz	n, #1, L(b0x)
+	mov	i, nents
+	mov	x12, tp
+	movi	v5.16b, #0			C zero 2 counter copies
+	movi	v2.16b, #0
+	ALIGN(16)
+L(tp2):	cmeq	maskq.2d, v5.2d, v7.2d
+	ld1	{v0.2d}, [tp]
+	add	v5.2d, v5.2d, v6.2d
+	bit	v2.16b, v0.16b, maskq.16b
+	add	tp, tp, n, lsl #3
+	sub	i, i, #1
+	cbnz	i, L(tp2)
+	st1	{v2.2d}, [rp], #16
+	add	tp, x12, #16
+
+L(b0x):	tbz	n, #0, L(b00)
+	mov	i, nents
+	mov	x12, tp
+	movi	v5.16b, #0			C zero 2 counter copies
+	movi	v2.16b, #0
+	ALIGN(16)
+L(tp1):	cmeq	maskq.2d, v5.2d, v7.2d
+	ld1	{v0.1d}, [tp]
+	add	v5.2d, v5.2d, v6.2d		C FIXME size should be `1d'
+	bit	v2.8b, v0.8b, maskq.8b
+	add	tp, tp, n, lsl #3
+	sub	i, i, #1
+	cbnz	i, L(tp1)
+	st1	{v2.1d}, [rp], #8
+	add	tp, x12, #8
+
+L(b00):	ret
+EPILOGUE()
diff --git a/mpn/arm64/sqr_diag_addlsh1.asm b/mpn/arm64/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..b15daa9
--- /dev/null
+++ b/mpn/arm64/sqr_diag_addlsh1.asm
@@ -0,0 +1,102 @@
+dnl  ARM64 mpn_sqr_diag_addlsh1.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2016, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 5.65
+C Cortex-A57	 3.5
+C X-Gene	 3.38
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`tp', `x1')
+define(`up', `x2')
+define(`n',  `x3')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	ldr	x15, [up],#8
+	lsr	x14, n, #1
+	tbz	n, #0, L(bx0)
+
+L(bx1):	adds	x7, xzr, xzr
+	mul	x12, x15, x15
+	ldr	x16, [up],#8
+	ldp	x4, x5, [tp],#16
+	umulh	x11, x15, x15
+	b	L(mid)
+
+L(bx0):	adds	x5, xzr, xzr
+	mul	x12, x15, x15
+	ldr	x17, [up],#16
+	ldp	x6, x7, [tp],#32
+	umulh	x11, x15, x15
+	sub	x14, x14, #1
+	cbz	x14, L(end)
+
+	ALIGN(16)
+L(top):	extr	x9, x6, x5, #63
+	mul	x10, x17, x17
+	ldr	x16, [up,#-8]
+	adcs	x13, x9, x11
+	ldp	x4, x5, [tp,#-16]
+	umulh	x11, x17, x17
+	extr	x8, x7, x6, #63
+	stp	x12, x13, [rp],#16
+	adcs	x12, x8, x10
+L(mid):	extr	x9, x4, x7, #63
+	mul	x10, x16, x16
+	ldr	x17, [up],#16
+	adcs	x13, x9, x11
+	ldp	x6, x7, [tp],#32
+	umulh	x11, x16, x16
+	extr	x8, x5, x4, #63
+	stp	x12, x13, [rp],#16
+	adcs	x12, x8, x10
+	sub	x14, x14, #1
+	cbnz	x14, L(top)
+
+L(end):	extr	x9, x6, x5, #63
+	mul	x10, x17, x17
+	adcs	x13, x9, x11
+	umulh	x11, x17, x17
+	extr	x8, x7, x6, #63
+	stp	x12, x13, [rp]
+	adcs	x12, x8, x10
+	extr	x9, xzr, x7, #63
+	adcs	x13, x9, x11
+	stp	x12, x13, [rp,#16]
+
+	ret
+EPILOGUE()
diff --git a/mpn/asm-defs.m4 b/mpn/asm-defs.m4
new file mode 100644
index 0000000..1f2d9fe
--- /dev/null
+++ b/mpn/asm-defs.m4
@@ -0,0 +1,1766 @@
+divert(-1)
+dnl
+dnl  m4 macros for gmp assembly code, shared by all CPUs.
+
+dnl  Copyright 1999-2006, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  These macros are designed for use with any m4 and have been used on
+dnl  GNU, FreeBSD, NetBSD, OpenBSD and SysV.
+dnl
+dnl  GNU m4 and OpenBSD 2.7 m4 will give filenames and line numbers in error
+dnl  messages.
+dnl
+dnl
+dnl  Macros:
+dnl
+dnl  Most new m4 specific macros have an "m4_" prefix to emphasise they're
+dnl  m4 expansions.  But new defining things like deflit() and defreg() are
+dnl  named like the builtin define(), and forloop() is named following the
+dnl  GNU m4 example on which it's based.
+dnl
+dnl  GNU m4 with the -P option uses "m4_" as a prefix for builtins, but that
+dnl  option isn't going to be used, so there's no conflict or confusion.
+dnl
+dnl
+dnl  Comments in output:
+dnl
+dnl  The m4 comment delimiters are left at # and \n, the normal assembler
+dnl  commenting for most CPUs.  m4 passes comment text through without
+dnl  expanding macros in it, which is generally a good thing since it stops
+dnl  unexpected expansions and possible resultant errors.
+dnl
+dnl  But note that when a quoted string is being read, a # isn't special, so
+dnl  apostrophes in comments in quoted strings must be avoided or they'll be
+dnl  interpreted as a closing quote mark.  But when the quoted text is
+dnl  re-read # will still act like a normal comment, suppressing macro
+dnl  expansion.
+dnl
+dnl  For example,
+dnl
+dnl          # apostrophes in comments that're outside quotes are ok
+dnl          # and using macro names like PROLOGUE is ok too
+dnl          ...
+dnl          ifdef(`PIC',`
+dnl                  # but apostrophes aren't ok inside quotes
+dnl                  #                     ^--wrong
+dnl                  ...
+dnl                  # though macro names like PROLOGUE are still ok
+dnl                  ...
+dnl          ')
+dnl
+dnl  If macro expansion in a comment is wanted, use `#' in the .asm (ie. a
+dnl  quoted hash symbol), which will turn into # in the .s but get
+dnl  expansions done on that line.  This can make the .s more readable to
+dnl  humans, but it won't make a blind bit of difference to the assembler.
+dnl
+dnl  All the above applies, mutatis mutandis, when changecom() is used to
+dnl  select @ ! ; or whatever other commenting.
+dnl
+dnl
+dnl  Variations in m4 affecting gmp:
+dnl
+dnl  $# - When a macro is called as "foo" with no brackets, BSD m4 sets $#
+dnl       to 1, whereas GNU or SysV m4 set it to 0.  In all cases though
+dnl       "foo()" sets $# to 1.  This is worked around in various places.
+dnl
+dnl  len() - When "len()" is given an empty argument, BSD m4 evaluates to
+dnl       nothing, whereas GNU, SysV, and the new OpenBSD, evaluate to 0.
+dnl       See m4_length() below which works around this.
+dnl
+dnl  translit() - GNU m4 accepts character ranges like A-Z, and the new
+dnl       OpenBSD m4 does under option -g, but basic BSD and SysV don't.
+dnl
+dnl  popdef() - in BSD and SysV m4 popdef() takes multiple arguments and
+dnl       pops each, but GNU m4 only takes one argument.
+dnl
+dnl  push back - BSD m4 has some limits on the amount of text that can be
+dnl       pushed back.  The limit is reasonably big and so long as macros
+dnl       don't gratuitously duplicate big arguments it isn't a problem.
+dnl       Normally an error message is given, but sometimes it just hangs.
+dnl
+dnl  eval() &,|,^ - GNU and SysV m4 have bitwise operators &,|,^ available,
+dnl       but BSD m4 doesn't (contrary to what the man page suggests) and
+dnl       instead ^ is exponentiation.
+dnl
+dnl  eval() ?: - The C ternary operator "?:" is available in BSD m4, but not
+dnl       in SysV or GNU m4 (as of GNU m4 1.4 and betas of 1.5).
+dnl
+dnl  eval() -2^31 - BSD m4 has a bug where an eval() resulting in -2^31
+dnl       (ie. -2147483648) gives "-(".  Using -2147483648 within an
+dnl       expression is ok, it just can't be a final result.  "-(" will of
+dnl       course upset parsing, with all sorts of strange effects.
+dnl
+dnl  eval() <<,>> - SysV m4 doesn't support shift operators in eval() (on
+dnl       Solaris 7 /usr/xpg4/m4 has them but /usr/ccs/m4 doesn't).  See
+dnl       m4_lshift() and m4_rshift() below for workarounds.
+dnl
+dnl  ifdef() - OSF 4.0 m4 considers a macro defined to a zero value `0' or
+dnl       `00' etc as not defined.  See m4_ifdef below for a workaround.
+dnl
+dnl  m4wrap() sequence - in BSD m4, m4wrap() replaces any previous m4wrap()
+dnl       string, in SysV m4 it appends to it, and in GNU m4 it prepends.
+dnl       See m4wrap_prepend() below which brings uniformity to this.
+dnl
+dnl  m4wrap() 0xFF - old versions of BSD m4 store EOF in a C "char" under an
+dnl       m4wrap() and on systems where char is unsigned by default a
+dnl       spurious 0xFF is output.  This has been observed on recent Cray
+dnl       Unicos Alpha, Apple MacOS X, and HPUX 11 systems.  An autoconf
+dnl       test is used to check for this, see the m4wrap handling below.  It
+dnl       might work to end the m4wrap string with a dnl to consume the
+dnl       0xFF, but that probably induces the offending m4's to read from an
+dnl       already closed "FILE *", which could be bad on a glibc style
+dnl       stdio.
+dnl
+dnl  __file__,__line__ - GNU m4 and OpenBSD 2.7 m4 provide these, and
+dnl       they're used here to make error messages more informative.  GNU m4
+dnl       gives an unhelpful "NONE 0" in an m4wrap(), but that's worked
+dnl       around.
+dnl
+dnl  __file__ quoting - OpenBSD m4, unlike GNU m4, doesn't quote the
+dnl       filename in __file__, so care should be taken that no macro has
+dnl       the same name as a file, or an unwanted expansion will occur when
+dnl       printing an error or warning.
+dnl
+dnl  changecom() - BSD m4 changecom doesn't quite work like the man page
+dnl       suggests, in particular "changecom" or "changecom()" doesn't
+dnl       disable the comment feature, and multi-character comment sequences
+dnl       don't seem to work.  If the default `#' and newline aren't
+dnl       suitable it's necessary to change it to something else,
+dnl       eg. changecom(;).
+dnl
+dnl  OpenBSD 2.6 m4 - in this m4, eval() rejects decimal constants containing
+dnl       an 8 or 9, making it pretty much unusable.  The bug is confined to
+dnl       version 2.6 (it's not in 2.5, and was fixed in 2.7).
+dnl
+dnl  SunOS /usr/bin/m4 - this m4 lacks a number of desired features,
+dnl       including $# and $@, defn(), m4exit(), m4wrap(), pushdef(),
+dnl       popdef().  /usr/5bin/m4 is a SysV style m4 which should always be
+dnl       available, and "configure" will reject /usr/bin/m4 in favour of
+dnl       /usr/5bin/m4 (if necessary).
+dnl
+dnl       The sparc code actually has modest m4 requirements currently and
+dnl       could manage with /usr/bin/m4, but there's no reason to put our
+dnl       macros through contortions when /usr/5bin/m4 is available or GNU
+dnl       m4 can be installed.
+
+
+ifdef(`__ASM_DEFS_M4_INCLUDED__',
+`m4_error(`asm-defs.m4 already included, dont include it twice
+')m4exit(1)')
+define(`__ASM_DEFS_M4_INCLUDED__')
+
+
+dnl  Detect and give a message about the unsuitable OpenBSD 2.6 m4.
+
+ifelse(eval(89),89,,
+`errprint(
+`This m4 doesnt accept 8 and/or 9 in constants in eval(), making it unusable.
+This is probably OpenBSD 2.6 m4 (September 1999).  Upgrade to OpenBSD 2.7,
+or get a bug fix from the CVS (expr.c rev 1.9), or get GNU m4.  Dont forget
+to configure with M4=/wherever/m4 if you install one of these in a directory
+not in $PATH.
+')m4exit(1)')
+
+
+dnl  Detect and give a message about the unsuitable SunOS /usr/bin/m4.
+dnl
+dnl  Unfortunately this test doesn't work when m4 is run in the normal way
+dnl  from mpn/Makefile with "m4 -DOPERATION_foo foo.asm", since the bad m4
+dnl  takes "-" in "-D..." to mean read stdin, so it will look like it just
+dnl  hangs.  But running "m4 asm-defs.m4" to try it out will work.
+dnl
+dnl  We'd like to abort immediately on finding a problem, but unfortunately
+dnl  the bad m4 doesn't have an m4exit(), nor does an invalid eval() kill
+dnl  it.  Unexpanded $#'s in some m4_assert_numargs() later on will comment
+dnl  out some closing parentheses and kill it with "m4: arg stack overflow".
+
+define(m4_dollarhash_works_test,``$#'')
+ifelse(m4_dollarhash_works_test(x),1,,
+`errprint(
+`This m4 doesnt support $# and cant be used for GMP asm processing.
+If this is on SunOS, ./configure should choose /usr/5bin/m4 if you have that
+or can get it, otherwise install GNU m4.  Dont forget to configure with
+M4=/wherever/m4 if you install in a directory not in $PATH.
+')')
+undefine(`m4_dollarhash_works_test')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Basic error handling things.
+
+
+dnl  Usage: m4_dollarhash_1_if_noparen_p
+dnl
+dnl  Expand to 1 if a call "foo" gives $# set to 1 (as opposed to 0 like GNU
+dnl  and SysV m4 give).
+
+define(m4_dollarhash_1_if_noparen_test,`$#')
+define(m4_dollarhash_1_if_noparen_p,
+eval(m4_dollarhash_1_if_noparen_test==1))
+undefine(`m4_dollarhash_1_if_noparen_test')
+
+
+dnl  Usage: m4wrap_prepend(string)
+dnl
+dnl  Prepend the given string to what will be expanded under m4wrap at the
+dnl  end of input.
+dnl
+dnl  This macro exists to work around variations in m4wrap() behaviour in
+dnl  the various m4s (notes at the start of this file).  Don't use m4wrap()
+dnl  directly since it will interfere with this scheme.
+
+define(m4wrap_prepend,
+m4_assert_numargs(1)
+`define(`m4wrap_string',`$1'defn(`m4wrap_string'))')
+
+define(m4wrap_string,`')
+
+define(m4wrap_works_p,
+`ifelse(M4WRAP_SPURIOUS,yes,0,1)')
+
+ifelse(m4wrap_works_p,1,
+`m4wrap(`m4wrap_string')')
+
+
+dnl  Usage: m4_file_and_line
+dnl
+dnl  Expand to the current file and line number, if the GNU m4 extensions
+dnl  __file__ and __line__ are available.
+dnl
+dnl  In GNU m4 1.4 at the end of input when m4wrap text is expanded,
+dnl  __file__ is NONE and __line__ is 0, which is not a helpful thing to
+dnl  print.  If m4_file_seen() has been called to note the last file seen,
+dnl  then that file at a big line number is used, otherwise "end of input"
+dnl  is used (although "end of input" won't parse as an error message).
+
+define(m4_file_and_line,
+`ifdef(`__file__',
+`ifelse(__file__`'__line__,`NONE0',
+`ifdef(`m4_file_seen_last',`m4_file_seen_last: 999999: ',`end of input: ')',
+`__file__: __line__: ')')')
+
+
+dnl  Usage: m4_errprint_commas(arg,...)
+dnl
+dnl  The same as errprint(), but commas are printed between arguments
+dnl  instead of spaces.
+
+define(m4_errprint_commas,
+`errprint(`$1')dnl
+ifelse(eval($#>1),1,`errprint(`,')m4_errprint_commas(shift($@))')')
+
+
+dnl  Usage: m4_error(args...)
+dnl         m4_warning(args...)
+dnl
+dnl  Print an error message, using m4_errprint_commas, prefixed with the
+dnl  current filename and line number (if available).  m4_error sets up to
+dnl  give an error exit at the end of processing, m4_warning just prints.
+dnl  These macros are the recommended way to print errors.
+dnl
+dnl  The arguments here should be quoted in the usual way to prevent them
+dnl  being expanded when the macro call is read.  (m4_error takes care not
+dnl  to do any further expansion.)
+dnl
+dnl  For example,
+dnl
+dnl         m4_error(`some error message
+dnl         ')
+dnl
+dnl  which prints
+dnl
+dnl         foo.asm:123: some error message
+dnl
+dnl  or if __file__ and __line__ aren't available
+dnl
+dnl         some error message
+dnl
+dnl  The "file:line:" format is a basic style, used by gcc and GNU m4, so
+dnl  emacs and other editors will recognise it in their normal error message
+dnl  parsing.
+
+define(m4_warning,
+`m4_errprint_commas(m4_file_and_line`'$@)')
+
+define(m4_error,
+`define(`m4_error_occurred',1)m4_warning($@)dnl
+ifelse(m4wrap_works_p,0,`m4exit(1)')')
+
+define(`m4_error_occurred',0)
+
+dnl  This m4wrap_prepend() is first, so it'll be executed last.
+m4wrap_prepend(
+`ifelse(m4_error_occurred,1,
+`m4_error(`Errors occurred during m4 processing
+')m4exit(1)')')
+
+
+dnl  Usage: m4_assert_numargs(num)
+dnl
+dnl  Put this unquoted on a line on its own at the start of a macro
+dnl  definition to add some code to check that num many arguments get passed
+dnl  to the macro.  For example,
+dnl
+dnl         define(foo,
+dnl         m4_assert_numargs(2)
+dnl         `something `$1' and `$2' blah blah')
+dnl
+dnl  Then a call like foo(one,two,three) will provoke an error like
+dnl
+dnl         file:10: foo expected 2 arguments, got 3 arguments
+dnl
+dnl  Here are some calls and how many arguments they're interpreted as passing.
+dnl
+dnl         foo(abc,def)  2
+dnl         foo(xyz)      1
+dnl         foo()         0
+dnl         foo          -1
+dnl
+dnl  The -1 for no parentheses at all means a macro that's meant to be used
+dnl  that way can be checked with m4_assert_numargs(-1).  For example,
+dnl
+dnl         define(SPECIAL_SUFFIX,
+dnl         m4_assert_numargs(-1)
+dnl         `ifdef(`FOO',`_foo',`_bar')')
+dnl
+dnl  But as an alternative see also deflit() below where parenthesized
+dnl  expressions following a macro are passed through to the output.
+dnl
+dnl  Note that in BSD m4 there's no way to differentiate calls "foo" and
+dnl  "foo()", so in BSD m4 the distinction between the two isn't enforced.
+dnl  (In GNU and SysV m4 it can be checked, and is.)
+
+
+dnl  m4_assert_numargs is able to check its own arguments by calling
+dnl  assert_numargs_internal directly.
+dnl
+dnl  m4_doublequote($`'0) expands to ``$0'', whereas ``$`'0'' would expand
+dnl  to `$`'0' and do the wrong thing, and likewise for $1.  The same is
+dnl  done in other assert macros.
+dnl
+dnl  $`#' leaves $# in the new macro being defined, and stops # being
+dnl  interpreted as a comment character.
+dnl
+dnl  `dnl ' means an explicit dnl isn't necessary when m4_assert_numargs is
+dnl  used.  The space means that if there is a dnl it'll still work.
+
+dnl  Usage: m4_doublequote(x) expands to ``x''
+define(m4_doublequote,
+`m4_assert_numargs_internal(`$0',1,$#,len(`$1'))``$1''')
+
+define(m4_assert_numargs,
+`m4_assert_numargs_internal(`$0',1,$#,len(`$1'))dnl
+`m4_assert_numargs_internal'(m4_doublequote($`'0),$1,$`#',`len'(m4_doublequote($`'1)))`dnl '')
+
+dnl  Called: m4_assert_numargs_internal(`macroname',wantargs,$#,len(`$1'))
+define(m4_assert_numargs_internal,
+`m4_assert_numargs_internal_check(`$1',`$2',m4_numargs_count(`$3',`$4'))')
+
+dnl  Called: m4_assert_numargs_internal_check(`macroname',wantargs,gotargs)
+dnl
+dnl  If m4_dollarhash_1_if_noparen_p (BSD m4) then gotargs can be 0 when it
+dnl  should be -1.  If wantargs is -1 but gotargs is 0 and the two can't be
+dnl  distinguished then it's allowed to pass.
+dnl
+define(m4_assert_numargs_internal_check,
+`ifelse(eval($2 == $3
+             || ($2==-1 && $3==0 && m4_dollarhash_1_if_noparen_p)),0,
+`m4_error(`$1 expected 'm4_Narguments(`$2')`, got 'm4_Narguments(`$3')
+)')')
+
+dnl  Called: m4_numargs_count($#,len(`$1'))
+dnl  If $#==0 then -1 args, if $#==1 but len(`$1')==0 then 0 args, otherwise
+dnl  $# args.
+define(m4_numargs_count,
+`ifelse($1,0, -1,
+`ifelse(eval($1==1 && $2-0==0),1, 0, $1)')')
+
+dnl  Usage: m4_Narguments(N)
+dnl  "$1 argument" or "$1 arguments" with the plural according to $1.
+define(m4_Narguments,
+`$1 argument`'ifelse(`$1',1,,s)')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Additional error checking things.
+
+
+dnl  Usage: m4_file_seen()
+dnl
+dnl  Record __file__ for the benefit of m4_file_and_line in m4wrap text.
+dnl
+dnl  The basic __file__ macro comes out quoted in GNU m4, like `foo.asm',
+dnl  and m4_file_seen_last is defined like that too.
+dnl
+dnl  This is used by PROLOGUE, since that's normally in the main .asm file,
+dnl  and in particular it sets up m4wrap error checks for missing EPILOGUE.
+
+define(m4_file_seen,
+m4_assert_numargs(0)
+`ifelse(__file__,`NONE',,
+`define(`m4_file_seen_last',m4_doublequote(__file__))')')
+
+
+dnl  Usage: m4_assert_onearg()
+dnl
+dnl  Put this, unquoted, at the start of a macro definition to add some code
+dnl  to check that one argument is passed to the macro, but with that
+dnl  argument allowed to be empty.  For example,
+dnl
+dnl          define(foo,
+dnl          m4_assert_onearg()
+dnl          `blah blah $1 blah blah')
+dnl
+dnl  Calls "foo(xyz)" or "foo()" are accepted.  A call "foo(xyz,abc)" fails.
+dnl  A call "foo" fails too, but BSD m4 can't detect this case (GNU and SysV
+dnl  m4 can).
+
+define(m4_assert_onearg,
+m4_assert_numargs(0)
+`m4_assert_onearg_internal'(m4_doublequote($`'0),$`#')`dnl ')
+
+dnl  Called: m4_assert_onearg(`macroname',$#)
+define(m4_assert_onearg_internal,
+`ifelse($2,1,,
+`m4_error(`$1 expected 1 argument, got 'm4_Narguments(`$2')
+)')')
+
+
+dnl  Usage: m4_assert_numargs_range(low,high)
+dnl
+dnl  Put this, unquoted, at the start of a macro definition to add some code
+dnl  to check that between low and high many arguments get passed to the
+dnl  macro.  For example,
+dnl
+dnl         define(foo,
+dnl         m4_assert_numargs_range(3,5)
+dnl         `mandatory $1 $2 $3 optional $4 $5 end')
+dnl
+dnl  See m4_assert_numargs() for more info.
+
+define(m4_assert_numargs_range,
+m4_assert_numargs(2)
+``m4_assert_numargs_range_internal'(m4_doublequote($`'0),$1,$2,$`#',`len'(m4_doublequote($`'1)))`dnl '')
+
+dnl  Called: m4_assert_numargs_range_internal(`name',low,high,$#,len(`$1'))
+define(m4_assert_numargs_range_internal,
+m4_assert_numargs(5)
+`m4_assert_numargs_range_check(`$1',`$2',`$3',m4_numargs_count(`$4',`$5'))')
+
+dnl  Called: m4_assert_numargs_range_check(`name',low,high,gotargs)
+dnl
+dnl  If m4_dollarhash_1_if_noparen_p (BSD m4) then gotargs can be 0 when it
+dnl  should be -1.  To ensure a `high' of -1 works, a fudge is applied to
+dnl  gotargs if it's 0 and the 0 and -1 cases can't be distinguished.
+dnl
+define(m4_assert_numargs_range_check,
+m4_assert_numargs(4)
+`ifelse(eval($2 <= $4 &&
+             ($4 - ($4==0 && m4_dollarhash_1_if_noparen_p) <= $3)),0,
+`m4_error(`$1 expected $2 to $3 arguments, got 'm4_Narguments(`$4')
+)')')
+
+
+dnl  Usage: m4_assert_defined(symbol)
+dnl
+dnl  Put this unquoted on a line of its own at the start of a macro
+dnl  definition to add some code to check that the given symbol is defined
+dnl  when the macro is used.  For example,
+dnl
+dnl          define(foo,
+dnl          m4_assert_defined(`FOO_PREFIX')
+dnl          `FOO_PREFIX whatever')
+dnl
+dnl  This is a convenient way to check that the user or ./configure or
+dnl  whatever has defined the things needed by a macro, as opposed to
+dnl  silently generating garbage.
+
+define(m4_assert_defined,
+m4_assert_numargs(1)
+``m4_assert_defined_internal'(m4_doublequote($`'0),``$1'')`dnl '')
+
+dnl  Called: m4_assert_defined_internal(`macroname',`define_required')
+define(m4_assert_defined_internal,
+m4_assert_numargs(2)
+`m4_ifdef(`$2',,
+`m4_error(`$1 needs $2 defined
+')')')
+
+
+dnl  Usage: m4_not_for_expansion(`SYMBOL')
+dnl         define_not_for_expansion(`SYMBOL')
+dnl
+dnl  m4_not_for_expansion turns SYMBOL, if defined, into something which
+dnl  will give an error if expanded.  For example,
+dnl
+dnl         m4_not_for_expansion(`PIC')
+dnl
+dnl  define_not_for_expansion is the same, but always makes a definition.
+dnl
+dnl  These are for symbols that should be tested with ifdef(`FOO',...)
+dnl  rather than be expanded as such.  They guard against accidentally
+dnl  omitting the quotes, as in ifdef(FOO,...).  Note though that they only
+dnl  catches this when FOO is defined, so be sure to test code both with and
+dnl  without each definition.
+
+define(m4_not_for_expansion,
+m4_assert_numargs(1)
+`ifdef(`$1',`define_not_for_expansion(`$1')')')
+
+define(define_not_for_expansion,
+m4_assert_numargs(1)
+`ifelse(defn(`$1'),,,
+`m4_error(``$1' has a non-empty value, maybe it shouldnt be munged with m4_not_for_expansion()
+')')dnl
+define(`$1',`m4_not_for_expansion_internal(`$1')')')
+
+define(m4_not_for_expansion_internal,
+`m4_error(``$1' is not meant to be expanded, perhaps you mean `ifdef(`$1',...)'
+')')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Various generic m4 things.
+
+
+dnl  Usage: m4_unquote(macro)
+dnl
+dnl  Allow the argument text to be re-evaluated.  This is useful for "token
+dnl  pasting" like m4_unquote(foo`'bar).
+
+define(m4_unquote,
+m4_assert_onearg()
+`$1')
+
+
+dnl  Usage: m4_ifdef(name,yes[,no])
+dnl
+dnl  Expand to the yes argument if name is defined, or to the no argument if
+dnl  not.
+dnl
+dnl  This is the same as the builtin "ifdef", but avoids an OSF 4.0 m4 bug
+dnl  in which a macro with a zero value `0' or `00' etc is considered not
+dnl  defined.
+dnl
+dnl  There's no particular need to use this everywhere, only if there might
+dnl  be a zero value.
+
+define(m4_ifdef,
+m4_assert_numargs_range(2,3)
+`ifelse(eval(ifdef(`$1',1,0)+m4_length(defn(`$1'))),0,
+`$3',`$2')')
+
+
+dnl  Usage: m4_ifdef_anyof_p(`symbol',...)
+dnl
+dnl  Expand to 1 if any of the symbols in the argument list are defined, or
+dnl  to 0 if not.
+
+define(m4_ifdef_anyof_p,
+`ifelse(eval($#<=1 && m4_length(`$1')==0),1, 0,
+`ifdef(`$1', 1,
+`m4_ifdef_anyof_p(shift($@))')')')
+
+
+dnl  Usage: m4_length(string)
+dnl
+dnl  Determine the length of a string.  This is the same as len(), but
+dnl  always expands to a number, working around the BSD len() which
+dnl  evaluates to nothing given an empty argument.
+
+define(m4_length,
+m4_assert_onearg()
+`eval(len(`$1')-0)')
+
+
+dnl  Usage: m4_stringequal_p(x,y)
+dnl
+dnl  Expand to 1 or 0 according as strings x and y are equal or not.
+
+define(m4_stringequal_p,
+`ifelse(`$1',`$2',1,0)')
+
+
+dnl  Usage: m4_incr_or_decr(n,last)
+dnl
+dnl  Do an incr(n) or decr(n), whichever is in the direction of "last".
+dnl  Both n and last must be numbers of course.
+
+define(m4_incr_or_decr,
+m4_assert_numargs(2)
+`ifelse(eval($1<$2),1,incr($1),decr($1))')
+
+
+dnl  Usage: forloop(i, first, last, statement)
+dnl
+dnl  Based on GNU m4 examples/forloop.m4, but extended.
+dnl
+dnl  statement is expanded repeatedly, with i successively defined as
+dnl
+dnl         first, first+1, ..., last-1, last
+dnl
+dnl  Or if first > last, then it's
+dnl
+dnl         first, first-1, ..., last+1, last
+dnl
+dnl  If first == last, then one expansion is done.
+dnl
+dnl  A pushdef/popdef of i is done to preserve any previous definition (or
+dnl  lack of definition).  first and last are eval()ed and so can be
+dnl  expressions.
+dnl
+dnl  forloop_first is defined to 1 on the first iteration, 0 on the rest.
+dnl  forloop_last is defined to 1 on the last iteration, 0 on the others.
+dnl  Nested forloops are allowed, in which case forloop_first and
+dnl  forloop_last apply to the innermost loop that's open.
+dnl
+dnl  A simple example,
+dnl
+dnl         forloop(i, 1, 2*2+1, `dnl
+dnl         iteration number i ... ifelse(forloop_first,1,FIRST)
+dnl         ')
+
+
+dnl  "i" and "statement" are carefully quoted, but "first" and "last" are
+dnl  just plain numbers once eval()ed.
+
+define(`forloop',
+m4_assert_numargs(4)
+`pushdef(`$1',eval(`$2'))dnl
+pushdef(`forloop_first',1)dnl
+pushdef(`forloop_last',0)dnl
+forloop_internal(`$1',eval(`$3'),`$4')`'dnl
+popdef(`forloop_first')dnl
+popdef(`forloop_last')dnl
+popdef(`$1')')
+
+dnl  Called: forloop_internal(`var',last,statement)
+define(`forloop_internal',
+m4_assert_numargs(3)
+`ifelse($1,$2,
+`define(`forloop_last',1)$3',
+`$3`'dnl
+define(`forloop_first',0)dnl
+define(`$1',m4_incr_or_decr($1,$2))dnl
+forloop_internal(`$1',$2,`$3')')')
+
+
+dnl  Usage: foreach(var,body, item1,item2,...,itemN)
+dnl
+dnl  For each "item" argument, define "var" to that value and expand "body".
+dnl  For example,
+dnl
+dnl         foreach(i, `something i
+dnl         ', one, two)
+dnl  gives
+dnl         something one
+dnl         something two
+dnl
+dnl  Any previous definition of "var", or lack thereof, is saved and
+dnl  restored.  Empty "item"s are not allowed.
+
+define(foreach,
+m4_assert_numargs_range(2,1000)
+`ifelse(`$3',,,
+`pushdef(`$1',`$3')$2`'popdef(`$1')dnl
+foreach(`$1',`$2',shift(shift(shift($@))))')')
+
+
+dnl  Usage: m4_toupper(x)
+dnl         m4_tolower(x)
+dnl
+dnl  Convert the argument string to upper or lower case, respectively.
+dnl  Only one argument accepted.
+dnl
+dnl  BSD m4 doesn't take ranges like a-z in translit(), so the full alphabet
+dnl  is written out.
+
+define(m4_alphabet_lower, `abcdefghijklmnopqrstuvwxyz')
+define(m4_alphabet_upper, `ABCDEFGHIJKLMNOPQRSTUVWXYZ')
+
+define(m4_toupper,
+m4_assert_onearg()
+`translit(`$1', m4_alphabet_lower, m4_alphabet_upper)')
+
+define(m4_tolower,
+m4_assert_onearg()
+`translit(`$1', m4_alphabet_upper, m4_alphabet_lower)')
+
+
+dnl  Usage: m4_empty_if_zero(x)
+dnl
+dnl  Evaluate to x, or to nothing if x is 0.  x is eval()ed and so can be an
+dnl  expression.
+dnl
+dnl  This is useful for x86 addressing mode displacements since forms like
+dnl  (%ebx) are one byte shorter than 0(%ebx).  A macro `foo' for use as
+dnl  foo(%ebx) could be defined with the following so it'll be empty if the
+dnl  expression comes out zero.
+dnl
+dnl	   deflit(`foo', `m4_empty_if_zero(a+b*4-c)')
+dnl
+dnl  Naturally this shouldn't be done if, say, a computed jump depends on
+dnl  the code being a particular size.
+
+define(m4_empty_if_zero,
+m4_assert_onearg()
+`ifelse(eval($1),0,,eval($1))')
+
+
+dnl  Usage: m4_log2(x)
+dnl
+dnl  Calculate a logarithm to base 2.
+dnl  x must be an integral power of 2, between 2**0 and 2**30.
+dnl  x is eval()ed, so it can be an expression.
+dnl  An error results if x is invalid.
+dnl
+dnl  2**31 isn't supported, because an unsigned 2147483648 is out of range
+dnl  of a 32-bit signed int.  Also, the bug in BSD m4 where an eval()
+dnl  resulting in 2147483648 (or -2147483648 as the case may be) gives `-('
+dnl  means tests like eval(1<<31==(x)) would be necessary, but that then
+dnl  gives an unattractive explosion of eval() error messages if x isn't
+dnl  numeric.
+
+define(m4_log2,
+m4_assert_numargs(1)
+`m4_log2_internal(0,1,eval(`$1'))')
+
+dnl  Called: m4_log2_internal(n,2**n,target)
+define(m4_log2_internal,
+m4_assert_numargs(3)
+`ifelse($2,$3,$1,
+`ifelse($1,30,
+`m4_error(`m4_log2() argument too big or not a power of two: $3
+')',
+`m4_log2_internal(incr($1),eval(2*$2),$3)')')')
+
+
+dnl  Usage:  m4_div2_towards_zero
+dnl
+dnl  m4 division is probably whatever a C signed division is, and C doesn't
+dnl  specify what rounding gets used on negatives, so this expression forces
+dnl  a rounding towards zero.
+
+define(m4_div2_towards_zero,
+m4_assert_numargs(1)
+`eval((($1) + ((($1)<0) & ($1))) / 2)')
+
+
+dnl  Usage: m4_lshift(n,count)
+dnl         m4_rshift(n,count)
+dnl
+dnl  Calculate n shifted left or right by count many bits.  Both n and count
+dnl  are eval()ed and so can be expressions.
+dnl
+dnl  Negative counts are allowed and mean a shift in the opposite direction.
+dnl  Negative n is allowed and right shifts will be arithmetic (meaning
+dnl  divide by 2**count, rounding towards zero, also meaning the sign bit is
+dnl  duplicated).
+dnl
+dnl  Use these macros instead of << and >> in eval() since the basic ccs
+dnl  SysV m4 doesn't have those operators.
+
+define(m4_rshift,
+m4_assert_numargs(2)
+`m4_lshift(`$1',-(`$2'))')
+
+define(m4_lshift,
+m4_assert_numargs(2)
+`m4_lshift_internal(eval(`$1'),eval(`$2'))')
+
+define(m4_lshift_internal,
+m4_assert_numargs(2)
+`ifelse(eval($2-0==0),1,$1,
+`ifelse(eval($2>0),1,
+`m4_lshift_internal(eval($1*2),decr($2))',
+`m4_lshift_internal(m4_div2_towards_zero($1),incr($2))')')')
+
+
+dnl  Usage: m4_popcount(n)
+dnl
+dnl  Expand to the number 1 bits in n.
+
+define(m4_popcount,
+m4_assert_numargs(1)
+`m4_popcount_internal(0,eval(`$1'))')
+
+dnl  Called: m4_popcount_internal(count,rem)
+define(m4_popcount_internal,
+m4_assert_numargs(2)
+`ifelse($2,0,$1,
+`m4_popcount_internal(eval($1+($2%2)),eval($2/2))')')
+
+
+dnl  Usage: m4_count_trailing_zeros(N)
+dnl
+dnl  Determine the number of trailing zero bits on N.  N is eval()ed and so
+dnl  can be an expression.  If N is zero an error is generated.
+
+define(m4_count_trailing_zeros,
+m4_assert_numargs(1)
+`m4_count_trailing_zeros_internal(eval(`$1'),0)')
+
+dnl  Called: m4_count_trailing_zeros_internal(val,count)
+define(m4_count_trailing_zeros_internal,
+m4_assert_numargs(2)
+`ifelse($1,0,
+`m4_error(`m4_count_trailing_zeros() given a zero value')',
+`ifelse(eval(($1)%2),1,`$2',
+`m4_count_trailing_zeros_internal(eval($1/2),incr($2))')')')
+
+
+dnl  Usage: deflit(name,value)
+dnl
+dnl  Like define(), but "name" expands like a literal, rather than taking
+dnl  arguments.  For example "name(%eax)" expands to "value(%eax)".
+dnl
+dnl  Limitations:
+dnl
+dnl  $ characters in the value part must have quotes to stop them looking
+dnl  like macro parameters.  For example, deflit(reg,`123+$`'4+567').  See
+dnl  defreg() below for handling simple register definitions like $7 etc.
+dnl
+dnl  "name()" is turned into "name", unfortunately.  In GNU and SysV m4 an
+dnl  error is generated when this happens, but in BSD m4 it will happen
+dnl  silently.  The problem is that in BSD m4 $# is 1 in both "name" or
+dnl  "name()", so there's no way to differentiate them.  Because we want
+dnl  plain "name" to turn into plain "value", we end up with "name()"
+dnl  turning into plain "value" too.
+dnl
+dnl  "name(foo)" will lose any whitespace after commas in "foo", for example
+dnl  "disp(%eax, %ecx)" would become "128(%eax,%ecx)".
+dnl
+dnl  These parentheses oddities shouldn't matter in assembler text, but if
+dnl  they do the suggested workaround is to write "name ()" or "name (foo)"
+dnl  to stop the parentheses looking like a macro argument list.  If a space
+dnl  isn't acceptable in the output, then write "name`'()" or "name`'(foo)".
+dnl  The `' is stripped when read, but again stops the parentheses looking
+dnl  like parameters.
+
+dnl  Quoting for deflit_emptyargcheck is similar to m4_assert_numargs.  The
+dnl  stuff in the ifelse gives a $#, $1 and $@ evaluated in the new macro
+dnl  created, not in deflit.
+define(deflit,
+m4_assert_numargs(2)
+`define(`$1',
+`deflit_emptyargcheck'(``$1'',$`#',m4_doublequote($`'1))`dnl
+$2`'dnl
+ifelse(eval($'`#>1 || m4_length('m4_doublequote($`'1)`)!=0),1,($'`@))')')
+
+dnl  Called: deflit_emptyargcheck(macroname,$#,`$1')
+define(deflit_emptyargcheck,
+`ifelse(eval($2==1 && !m4_dollarhash_1_if_noparen_p && m4_length(`$3')==0),1,
+`m4_error(`dont use a deflit as $1() because it loses the brackets (see deflit in asm-defs.m4 for more information)
+')')')
+
+
+dnl  Usage: m4_assert(`expr')
+dnl
+dnl  Test a compile-time requirement with an m4 expression.  The expression
+dnl  should be quoted, and will be eval()ed and expected to be non-zero.
+dnl  For example,
+dnl
+dnl         m4_assert(`FOO*2+6 < 14')
+
+define(m4_assert,
+m4_assert_numargs(1)
+`ifelse(eval($1),1,,
+`m4_error(`assertion failed: $1
+')')')
+
+
+dnl  Usage: m4_repeat(count,text)
+dnl
+dnl  Expand to the given repetitions of the given text.  A zero count is
+dnl  allowed, and expands to nothing.
+
+define(m4_repeat,
+m4_assert_numargs(2)
+`m4_repeat_internal(eval($1),`$2')')
+
+define(m4_repeat_internal,
+m4_assert_numargs(2)
+`ifelse(`$1',0,,
+`forloop(m4_repeat_internal_counter,1,$1,``$2'')')')
+
+
+dnl  Usage: m4_hex_lowmask(bits)
+dnl
+dnl  Generate a hex constant which is a low mask of the given number of
+dnl  bits.  For example m4_hex_lowmask(10) would give 0x3ff.
+
+define(m4_hex_lowmask,
+m4_assert_numargs(1)
+`m4_cpu_hex_constant(m4_hex_lowmask_internal1(eval(`$1')))')
+
+dnl  Called: m4_hex_lowmask_internal1(bits)
+define(m4_hex_lowmask_internal1,
+m4_assert_numargs(1)
+`ifelse($1,0,`0',
+`m4_hex_lowmask_internal2(eval(($1)%4),eval(($1)/4))')')
+
+dnl  Called: m4_hex_lowmask_internal(remainder,digits)
+define(m4_hex_lowmask_internal2,
+m4_assert_numargs(2)
+`ifelse($1,1,`1',
+`ifelse($1,2,`3',
+`ifelse($1,3,`7')')')dnl
+m4_repeat($2,`f')')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  The following m4_list functions take a list as multiple arguments.
+dnl  Arguments are evaluated multiple times, there's no attempt at strict
+dnl  quoting.  Empty list elements are not allowed, since an empty final
+dnl  argument is ignored.  These restrictions don't affect the current uses,
+dnl  and make the implementation easier.
+
+
+dnl  Usage: m4_list_quote(list,...)
+dnl
+dnl  Produce a list with quoted commas, so it can be a single argument
+dnl  string.  For instance m4_list_quote(a,b,c) gives
+dnl
+dnl         a`,'b`,'c`,'
+dnl
+dnl  This can be used to put a list in a define,
+dnl
+dnl         define(foolist, m4_list_quote(a,b,c))
+dnl
+dnl  Which can then be used for instance as
+dnl
+dnl         m4_list_find(target, foolist)
+
+define(m4_list_quote,
+`ifelse(`$1',,,
+`$1`,'m4_list_quote(shift($@))')')
+
+
+dnl  Usage: m4_list_find(key,list,...)
+dnl
+dnl  Evaluate to 1 or 0 according to whether key is in the list elements.
+
+define(m4_list_find,
+m4_assert_numargs_range(1,1000)
+`ifelse(`$2',,0,
+`ifelse(`$1',`$2',1,
+`m4_list_find(`$1',shift(shift($@)))')')')
+
+
+dnl  Usage: m4_list_remove(key,list,...)
+dnl
+dnl  Evaluate to the given list with `key' removed (if present).
+
+define(m4_list_remove,
+m4_assert_numargs_range(1,1000)
+`ifelse(`$2',,,
+`ifelse(`$1',`$2',,`$2,')dnl
+m4_list_remove(`$1',shift(shift($@)))')')
+
+
+dnl  Usage: m4_list_first(list,...)
+dnl
+dnl  Evaluate to the first element of the list (if any).
+
+define(m4_list_first,`$1')
+
+
+dnl  Usage: m4_list_count(list,...)
+dnl
+dnl  Evaluate to the number of elements in the list.  This can't just use $#
+dnl  because the last element might be empty.
+
+define(m4_list_count,
+`m4_list_count_internal(0,$@)')
+
+dnl  Called: m4_list_internal(count,list,...)
+define(m4_list_count_internal,
+m4_assert_numargs_range(1,1000)
+`ifelse(`$2',,$1,
+`m4_list_count_internal(eval($1+1),shift(shift($@)))')')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Various assembler things, not specific to any particular CPU.
+dnl
+
+
+dnl  Usage: include_mpn(`filename')
+dnl
+dnl  Like include(), but adds a path to the mpn source directory.  For
+dnl  example,
+dnl
+dnl         include_mpn(`sparc64/addmul_1h.asm')
+
+define(include_mpn,
+m4_assert_numargs(1)
+m4_assert_defined(`CONFIG_TOP_SRCDIR')
+`include(CONFIG_TOP_SRCDIR`/mpn/$1')')
+
+
+dnl  Usage: C comment ...
+dnl
+dnl  This works like a FORTRAN-style comment character.  It can be used for
+dnl  comments to the right of assembly instructions, where just dnl would
+dnl  remove the newline and concatenate adjacent lines.
+dnl
+dnl  C and/or dnl are useful when an assembler doesn't support comments, or
+dnl  where different assemblers for a particular CPU need different styles.
+dnl  The intermediate ".s" files will end up with no comments, just code.
+dnl
+dnl  Using C is not intended to cause offence to anyone who doesn't like
+dnl  FORTRAN; but if that happens it's an unexpected bonus.
+dnl
+dnl  During development, if comments are wanted in the .s files to help see
+dnl  what's expanding where, C can be redefined with something like
+dnl
+dnl         define(`C',`#')
+
+define(C, `
+dnl')
+
+
+dnl  Normally PIC is defined (or not) by libtool, but it doesn't set it on
+dnl  systems which are always PIC.  PIC_ALWAYS established in config.m4
+dnl  identifies these for us.
+
+ifelse(PIC_ALWAYS,`yes',`define(`PIC')')
+
+
+dnl  Various possible defines passed from the Makefile that are to be tested
+dnl  with ifdef() rather than be expanded.
+
+m4_not_for_expansion(`PIC')
+m4_not_for_expansion(`DLL_EXPORT')
+
+dnl  aors_n
+m4_not_for_expansion(`OPERATION_add_n')
+m4_not_for_expansion(`OPERATION_sub_n')
+
+dnl  aors_err1_n
+m4_not_for_expansion(`OPERATION_add_err1_n')
+m4_not_for_expansion(`OPERATION_sub_err1_n')
+
+dnl  aors_err2_n
+m4_not_for_expansion(`OPERATION_add_err2_n')
+m4_not_for_expansion(`OPERATION_sub_err2_n')
+
+dnl  aors_err3_n
+m4_not_for_expansion(`OPERATION_add_err3_n')
+m4_not_for_expansion(`OPERATION_sub_err3_n')
+
+dnl  aorsmul_1
+m4_not_for_expansion(`OPERATION_addmul_1')
+m4_not_for_expansion(`OPERATION_submul_1')
+
+dnl  logops_n
+m4_not_for_expansion(`OPERATION_and_n')
+m4_not_for_expansion(`OPERATION_andn_n')
+m4_not_for_expansion(`OPERATION_nand_n')
+m4_not_for_expansion(`OPERATION_ior_n')
+m4_not_for_expansion(`OPERATION_iorn_n')
+m4_not_for_expansion(`OPERATION_nior_n')
+m4_not_for_expansion(`OPERATION_xor_n')
+m4_not_for_expansion(`OPERATION_xnor_n')
+
+dnl  popham
+m4_not_for_expansion(`OPERATION_popcount')
+m4_not_for_expansion(`OPERATION_hamdist')
+
+dnl  lorrshift
+m4_not_for_expansion(`OPERATION_lshift')
+m4_not_for_expansion(`OPERATION_rshift')
+
+dnl  aorslsh1_n
+m4_not_for_expansion(`OPERATION_addlsh1_n')
+m4_not_for_expansion(`OPERATION_sublsh1_n')
+m4_not_for_expansion(`OPERATION_rsblsh1_n')
+
+dnl  aorslsh2_n
+m4_not_for_expansion(`OPERATION_addlsh2_n')
+m4_not_for_expansion(`OPERATION_sublsh2_n')
+m4_not_for_expansion(`OPERATION_rsblsh2_n')
+
+dnl  rsh1aors_n
+m4_not_for_expansion(`OPERATION_rsh1add_n')
+m4_not_for_expansion(`OPERATION_rsh1sub_n')
+
+
+dnl  Usage: m4_config_gmp_mparam(`symbol')
+dnl
+dnl  Check that `symbol' is defined.  If it isn't, issue an error and
+dnl  terminate immediately.  The error message explains that the symbol
+dnl  should be in config.m4, copied from gmp-mparam.h.
+dnl
+dnl  Termination is immediate since missing say SQR_TOOM2_THRESHOLD can
+dnl  lead to infinite loops and endless error messages.
+
+define(m4_config_gmp_mparam,
+m4_assert_numargs(1)
+`ifdef(`$1',,
+`m4_error(`$1 is not defined.
+	"configure" should have extracted this from gmp-mparam.h and put it
+	in config.m4 (or in <cpu>_<file>.asm for a fat binary), but somehow
+        this has failed.
+')m4exit(1)')')
+
+
+dnl  Usage: defreg(name,reg)
+dnl
+dnl  Give a name to a $ style register.  For example,
+dnl
+dnl         defreg(foo,$12)
+dnl
+dnl  defreg() inserts an extra pair of quotes after the $ so that it's not
+dnl  interpreted as an m4 macro parameter, ie. foo is actually $`'12.  m4
+dnl  strips those quotes when foo is expanded.
+dnl
+dnl  deflit() is used to make the new definition, so it will expand
+dnl  literally even if followed by parentheses ie. foo(99) will become
+dnl  $12(99).  (But there's nowhere that would be used is there?)
+dnl
+dnl  When making further definitions from existing defreg() macros, remember
+dnl  to use defreg() again to protect the $ in the new definitions too.  For
+dnl  example,
+dnl
+dnl         defreg(a0,$4)
+dnl         defreg(a1,$5)
+dnl         ...
+dnl
+dnl         defreg(PARAM_DST,a0)
+dnl
+dnl  This is only because a0 is expanding at the time the PARAM_DST
+dnl  definition is made, leaving a literal $4 that must be re-quoted.  On
+dnl  the other hand in something like the following ra is only expanded when
+dnl  ret is used and its $`'31 protection will have its desired effect at
+dnl  that time.
+dnl
+dnl         defreg(ra,$31)
+dnl         ...
+dnl         define(ret,`j ra')
+dnl
+dnl  Note that only $n forms are meant to be used here, and something like
+dnl  128($30) doesn't get protected and will come out wrong.
+
+define(defreg,
+m4_assert_numargs(2)
+`deflit(`$1',
+substr(`$2',0,1)``''substr(`$2',1))')
+
+
+dnl  Usage: m4_instruction_wrapper()
+dnl
+dnl  Put this, unquoted, on a line on its own, at the start of a macro
+dnl  that's a wrapper around an assembler instruction.  It adds code to give
+dnl  a descriptive error message if the macro is invoked without arguments.
+dnl
+dnl  For example, suppose jmp needs to be wrapped,
+dnl
+dnl         define(jmp,
+dnl         m4_instruction_wrapper()
+dnl         m4_assert_numargs(1)
+dnl                 `.byte 0x42
+dnl                 .long  $1
+dnl                 nop')
+dnl
+dnl  The point of m4_instruction_wrapper is to get a better error message
+dnl  than m4_assert_numargs would give if jmp is accidentally used as plain
+dnl  "jmp foo" instead of the intended "jmp( foo)".  "jmp()" with no
+dnl  argument also provokes the error message.
+dnl
+dnl  m4_instruction_wrapper should only be used with wrapped instructions
+dnl  that take arguments, since obviously something meant to be used as say
+dnl  plain "ret" doesn't want to give an error when used that way.
+
+define(m4_instruction_wrapper,
+m4_assert_numargs(0)
+``m4_instruction_wrapper_internal'(m4_doublequote($`'0),dnl
+ifdef(`__file__',`m4_doublequote(__file__)',``the m4 sources''),dnl
+$`#',m4_doublequote($`'1))`dnl'')
+
+dnl  Called: m4_instruction_wrapper_internal($0,`filename',$#,$1)
+define(m4_instruction_wrapper_internal,
+`ifelse(eval($3<=1 && m4_length(`$4')==0),1,
+`m4_error(`$1 is a macro replacing that instruction and needs arguments, see $2 for details
+')')')
+
+
+dnl  Usage: m4_cpu_hex_constant(string)
+dnl
+dnl  Expand to the string prefixed by a suitable `0x' hex marker.  This
+dnl  should be redefined as necessary for CPUs with different conventions.
+
+define(m4_cpu_hex_constant,
+m4_assert_numargs(1)
+`0x`$1'')
+
+
+dnl  Usage: UNROLL_LOG2, UNROLL_MASK, UNROLL_BYTES
+dnl         CHUNK_LOG2, CHUNK_MASK, CHUNK_BYTES
+dnl
+dnl  When code supports a variable amount of loop unrolling, the convention
+dnl  is to define UNROLL_COUNT to the number of limbs processed per loop.
+dnl  When testing code this can be varied to see how much the loop overhead
+dnl  is costing.  For example,
+dnl
+dnl         deflit(UNROLL_COUNT, 32)
+dnl
+dnl  If the forloop() generating the unrolled loop has a pattern processing
+dnl  more than one limb, the convention is to express this with CHUNK_COUNT.
+dnl  For example,
+dnl
+dnl         deflit(CHUNK_COUNT, 2)
+dnl
+dnl  The LOG2, MASK and BYTES definitions below are derived from these COUNT
+dnl  definitions.  If COUNT is redefined, the LOG2, MASK and BYTES follow
+dnl  the new definition automatically.
+dnl
+dnl  LOG2 is the log base 2 of COUNT.  MASK is COUNT-1, which can be used as
+dnl  a bit mask.  BYTES is GMP_LIMB_BYTES*COUNT, the number of bytes
+dnl  processed in each unrolled loop.
+dnl
+dnl  GMP_LIMB_BYTES is defined in a CPU specific m4 include file.  It
+dnl  exists only so the BYTES definitions here can be common to all CPUs.
+dnl  In the actual code for a given CPU, an explicit 4 or 8 may as well be
+dnl  used because the code is only for a particular CPU, it doesn't need to
+dnl  be general.
+dnl
+dnl  Note that none of these macros do anything except give conventional
+dnl  names to commonly used things.  You still have to write your own
+dnl  expressions for a forloop() and the resulting address displacements.
+dnl  Something like the following would be typical for 4 bytes per limb.
+dnl
+dnl         forloop(`i',0,UNROLL_COUNT-1,`
+dnl                 deflit(`disp',eval(i*4))
+dnl                 ...
+dnl         ')
+dnl
+dnl  Or when using CHUNK_COUNT,
+dnl
+dnl         forloop(`i',0,UNROLL_COUNT/CHUNK_COUNT-1,`
+dnl                 deflit(`disp0',eval(i*CHUNK_COUNT*4))
+dnl                 deflit(`disp1',eval(disp0+4))
+dnl                 ...
+dnl         ')
+dnl
+dnl  Clearly `i' can be run starting from 1, or from high to low or whatever
+dnl  best suits.
+
+deflit(UNROLL_LOG2,
+m4_assert_defined(`UNROLL_COUNT')
+`m4_log2(UNROLL_COUNT)')
+
+deflit(UNROLL_MASK,
+m4_assert_defined(`UNROLL_COUNT')
+`eval(UNROLL_COUNT-1)')
+
+deflit(UNROLL_BYTES,
+m4_assert_defined(`UNROLL_COUNT')
+m4_assert_defined(`GMP_LIMB_BYTES')
+`eval(UNROLL_COUNT * GMP_LIMB_BYTES)')
+
+deflit(CHUNK_LOG2,
+m4_assert_defined(`CHUNK_COUNT')
+`m4_log2(CHUNK_COUNT)')
+
+deflit(CHUNK_MASK,
+m4_assert_defined(`CHUNK_COUNT')
+`eval(CHUNK_COUNT-1)')
+
+deflit(CHUNK_BYTES,
+m4_assert_defined(`CHUNK_COUNT')
+m4_assert_defined(`GMP_LIMB_BYTES')
+`eval(CHUNK_COUNT * GMP_LIMB_BYTES)')
+
+
+dnl  Usage: MPN(name)
+dnl
+dnl  Add MPN_PREFIX to a name.
+dnl  MPN_PREFIX defaults to "__gmpn_" if not defined.
+dnl
+dnl  m4_unquote is used in MPN so that when it expands to say __gmpn_foo,
+dnl  that identifier will be subject to further macro expansion.  This is
+dnl  used by some of the fat binary support for renaming symbols.
+
+ifdef(`MPN_PREFIX',,
+`define(`MPN_PREFIX',`__gmpn_')')
+
+define(MPN,
+m4_assert_numargs(1)
+`m4_unquote(MPN_PREFIX`'$1)')
+
+
+dnl  Usage: mpn_add_n, etc
+dnl
+dnl  Convenience definitions using MPN(), like the #defines in gmp.h.  Each
+dnl  function that might be implemented in assembler is here.
+
+define(define_mpn,
+m4_assert_numargs(1)
+`deflit(`mpn_$1',`MPN(`$1')')')
+
+define_mpn(add)
+define_mpn(add_1)
+define_mpn(add_err1_n)
+define_mpn(add_err2_n)
+define_mpn(add_err3_n)
+define_mpn(add_n)
+define_mpn(add_nc)
+define_mpn(addlsh1_n)
+define_mpn(addlsh1_nc)
+define_mpn(addlsh2_n)
+define_mpn(addlsh2_nc)
+define_mpn(addlsh_n)
+define_mpn(addlsh_nc)
+define_mpn(addlsh1_n_ip1)
+define_mpn(addlsh1_nc_ip1)
+define_mpn(addlsh2_n_ip1)
+define_mpn(addlsh2_nc_ip1)
+define_mpn(addlsh_n_ip1)
+define_mpn(addlsh_nc_ip1)
+define_mpn(addlsh1_n_ip2)
+define_mpn(addlsh1_nc_ip2)
+define_mpn(addlsh2_n_ip2)
+define_mpn(addlsh2_nc_ip2)
+define_mpn(addlsh_n_ip2)
+define_mpn(addlsh_nc_ip2)
+define_mpn(addmul_1)
+define_mpn(addmul_1c)
+define_mpn(addmul_2)
+define_mpn(addmul_3)
+define_mpn(addmul_4)
+define_mpn(addmul_5)
+define_mpn(addmul_6)
+define_mpn(addmul_7)
+define_mpn(addmul_8)
+define_mpn(addmul_2s)
+define_mpn(add_n_sub_n)
+define_mpn(add_n_sub_nc)
+define_mpn(addaddmul_1msb0)
+define_mpn(and_n)
+define_mpn(andn_n)
+define_mpn(bdiv_q_1)
+define_mpn(pi1_bdiv_q_1)
+define_mpn(bdiv_dbm1c)
+define_mpn(cmp)
+define_mpn(cnd_add_n)
+define_mpn(cnd_sub_n)
+define_mpn(com)
+define_mpn(copyd)
+define_mpn(copyi)
+define_mpn(count_leading_zeros)
+define_mpn(count_trailing_zeros)
+define_mpn(div_qr_1n_pi1)
+define_mpn(div_qr_2)
+define_mpn(div_qr_2n_pi1)
+define_mpn(div_qr_2u_pi1)
+define_mpn(div_qr_2n_pi2)
+define_mpn(div_qr_2u_pi2)
+define_mpn(divexact_1)
+define_mpn(divexact_by3c)
+define_mpn(divrem)
+define_mpn(divrem_1)
+define_mpn(divrem_1c)
+define_mpn(divrem_2)
+define_mpn(divrem_classic)
+define_mpn(divrem_newton)
+define_mpn(dump)
+define_mpn(gcd)
+define_mpn(gcd_1)
+define_mpn(gcd_11)
+define_mpn(gcd_22)
+define_mpn(gcdext)
+define_mpn(get_str)
+define_mpn(hamdist)
+define_mpn(invert_limb)
+define_mpn(invert_limb_table)
+define_mpn(ior_n)
+define_mpn(iorn_n)
+define_mpn(lshift)
+define_mpn(lshiftc)
+define_mpn(mod_1_1p)
+define_mpn(mod_1_1p_cps)
+define_mpn(mod_1s_2p)
+define_mpn(mod_1s_2p_cps)
+define_mpn(mod_1s_3p)
+define_mpn(mod_1s_3p_cps)
+define_mpn(mod_1s_4p)
+define_mpn(mod_1s_4p_cps)
+define_mpn(mod_1)
+define_mpn(mod_1c)
+define_mpn(mod_34lsub1)
+define_mpn(modexact_1_odd)
+define_mpn(modexact_1c_odd)
+define_mpn(mul)
+define_mpn(mul_1)
+define_mpn(mul_1c)
+define_mpn(mul_2)
+define_mpn(mul_3)
+define_mpn(mul_4)
+define_mpn(mul_5)
+define_mpn(mul_6)
+define_mpn(mul_basecase)
+define_mpn(mul_n)
+define_mpn(mullo_basecase)
+define_mpn(mulmid_basecase)
+define_mpn(perfect_square_p)
+define_mpn(popcount)
+define_mpn(preinv_divrem_1)
+define_mpn(preinv_mod_1)
+define_mpn(nand_n)
+define_mpn(neg)
+define_mpn(nior_n)
+define_mpn(powm)
+define_mpn(powlo)
+define_mpn(random)
+define_mpn(random2)
+define_mpn(redc_1)
+define_mpn(redc_2)
+define_mpn(rsblsh1_n)
+define_mpn(rsblsh1_nc)
+define_mpn(rsblsh2_n)
+define_mpn(rsblsh2_nc)
+define_mpn(rsblsh_n)
+define_mpn(rsblsh_nc)
+define_mpn(rsh1add_n)
+define_mpn(rsh1add_nc)
+define_mpn(rsh1sub_n)
+define_mpn(rsh1sub_nc)
+define_mpn(rshift)
+define_mpn(rshiftc)
+define_mpn(sbpi1_bdiv_q)
+define_mpn(sbpi1_bdiv_qr)
+define_mpn(sbpi1_bdiv_r)
+define_mpn(scan0)
+define_mpn(scan1)
+define_mpn(set_str)
+define_mpn(sqr_basecase)
+define_mpn(sqr_diagonal)
+define_mpn(sqr_diag_addlsh1)
+define_mpn(sub_n)
+define_mpn(sublsh1_n)
+define_mpn(sublsh1_nc)
+define_mpn(sublsh1_n_ip1)
+define_mpn(sublsh1_nc_ip1)
+define_mpn(sublsh2_n)
+define_mpn(sublsh2_nc)
+define_mpn(sublsh2_n_ip1)
+define_mpn(sublsh2_nc_ip1)
+define_mpn(sublsh_n)
+define_mpn(sublsh_nc)
+define_mpn(sublsh_n_ip1)
+define_mpn(sublsh_nc_ip1)
+define_mpn(sqrtrem)
+define_mpn(sub)
+define_mpn(sub_1)
+define_mpn(sub_err1_n)
+define_mpn(sub_err2_n)
+define_mpn(sub_err3_n)
+define_mpn(sub_n)
+define_mpn(sub_nc)
+define_mpn(submul_1)
+define_mpn(submul_1c)
+define_mpn(sec_tabselect)
+define_mpn(umul_ppmm)
+define_mpn(umul_ppmm_r)
+define_mpn(udiv_qrnnd)
+define_mpn(udiv_qrnnd_r)
+define_mpn(xnor_n)
+define_mpn(xor_n)
+
+
+dnl  Defines for C global arrays and variables, with names matching what's
+dnl  used in the C code.
+dnl
+dnl  Notice that GSYM_PREFIX is included, unlike with the function defines
+dnl  above.  Also, "deflit" is used so that something like __clz_tab(%ebx)
+dnl  comes out as __gmpn_clz_tab(%ebx), for the benefit of CPUs with that
+dnl  style assembler syntax.
+
+deflit(__clz_tab,
+m4_assert_defined(`GSYM_PREFIX')
+`GSYM_PREFIX`'MPN(`clz_tab')')
+
+deflit(binvert_limb_table,
+m4_assert_defined(`GSYM_PREFIX')
+`GSYM_PREFIX`'__gmp_binvert_limb_table')
+
+
+dnl  Usage: ASM_START()
+dnl
+dnl  Emit any directives needed once at the start of an assembler file, like
+dnl  ".set noreorder" or whatever.  The default for this is nothing, but
+dnl  it's redefined by CPU specific m4 files.
+
+define(ASM_START)
+
+
+dnl  Usage: ASM_END()
+dnl
+dnl  Emit any directives needed once at the end of an assembler file.  The
+dnl  default for this is nothing, but it's redefined by CPU specific m4 files.
+
+define(ASM_END)
+
+
+dnl  Usage: PROLOGUE(foo[,param])
+dnl         EPILOGUE(foo)
+dnl
+dnl  Emit directives to start or end a function.  GSYM_PREFIX is added by
+dnl  these macros if necessary, so the given "foo" is what the function will
+dnl  be called in C.
+dnl
+dnl  The second parameter to PROLOGUE is used only for some CPUs and should
+dnl  be omitted if not required.
+dnl
+dnl  Nested or overlapping PROLOGUE/EPILOGUE pairs are allowed, if that
+dnl  makes sense for the system.  The name given to EPILOGUE must be a
+dnl  currently open PROLOGUE.
+dnl
+dnl  If only one PROLOGUE is open then the name can be omitted from
+dnl  EPILOGUE.  This is encouraged, since it means the name only has to
+dnl  appear in one place, not two.
+dnl
+dnl  The given name "foo" is not fully quoted here, it will be macro
+dnl  expanded more than once.  This is the way the m4_list macros work, and
+dnl  it also helps the tune/many.pl program do a renaming like
+dnl  -D__gmpn_add_n=mpn_add_n_foo when GSYM_PREFIX is not empty.
+
+define(PROLOGUE,
+m4_assert_numargs_range(1,2)
+`m4_file_seen()dnl
+define(`PROLOGUE_list',m4_list_quote($1,PROLOGUE_list))dnl
+ifelse(`$2',,
+`PROLOGUE_cpu(GSYM_PREFIX`'$1)',
+`PROLOGUE_cpu(GSYM_PREFIX`'$1,`$2')')')
+
+define(EPILOGUE,
+m4_assert_numargs_range(0,1)
+`ifelse(`$1',,
+`ifelse(m4_list_count(PROLOGUE_list),0,
+`m4_error(`no open functions for EPILOGUE
+')',
+`ifelse(m4_list_count(PROLOGUE_list),1,
+`EPILOGUE_internal(PROLOGUE_current_function)',
+`m4_error(`more than one open function for EPILOGUE
+')')')',
+`EPILOGUE_internal(`$1')')')
+
+define(EPILOGUE_internal,
+m4_assert_numargs(1)
+m4_assert_defined(`EPILOGUE_cpu')
+`ifelse(m4_list_find($1,PROLOGUE_list),0,
+`m4_error(`EPILOGUE without PROLOGUE: $1
+')')dnl
+define(`PROLOGUE_list',m4_list_quote(m4_list_remove($1,PROLOGUE_list)))dnl
+EPILOGUE_cpu(GSYM_PREFIX`$1')')
+
+dnl  Currently open PROLOGUEs, as a comma-separated list.
+define(PROLOGUE_list)
+
+
+dnl  Called: PROLOGUE_check(list,...)
+dnl  Check there's no remaining open PROLOGUEs at the end of input.
+define(PROLOGUE_check,
+`ifelse($1,,,
+`m4_error(`no EPILOGUE for: $1
+')dnl
+PROLOGUE_check(shift($@))')')
+
+m4wrap_prepend(`PROLOGUE_check(PROLOGUE_list)')
+
+
+dnl  Usage: PROLOGUE_current_function
+dnl
+dnl  This macro expands to the current PROLOGUE/EPILOGUE function, or the
+dnl  most recent PROLOGUE if such pairs are nested or overlapped.
+
+define(PROLOGUE_current_function,
+m4_assert_numargs(-1)
+`m4_list_first(PROLOGUE_list)')
+
+
+dnl  Usage: PROLOGUE_cpu(GSYM_PREFIX`'foo[,param])
+dnl         EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  These macros hold the CPU-specific parts of PROLOGUE and EPILOGUE.
+dnl  Both are called with the function name, with GSYM_PREFIX already
+dnl  prepended.
+dnl
+dnl  The definitions here are something typical and sensible, but CPU or
+dnl  system specific m4 files should redefine them as necessary.  The
+dnl  optional extra parameter to PROLOGUE_cpu is not expected and not
+dnl  accepted here.
+
+define(PROLOGUE_cpu,
+m4_assert_numargs(1)
+`	TEXT
+	ALIGN(8)
+	GLOBL	`$1' GLOBL_ATTR
+	TYPE(`$1',`function')
+`$1'LABEL_SUFFIX')
+
+define(EPILOGUE_cpu,
+`	SIZE(`$1',.-`$1')')
+
+
+dnl  Usage: L(name)
+dnl
+dnl  Generate a local label with the given name.  This is simply a
+dnl  convenient way to add LSYM_PREFIX.
+dnl
+dnl  LSYM_PREFIX might be L$, so defn() must be used to quote it or the L
+dnl  will expand again as the L macro, making an infinite recursion.
+
+define(`L',
+m4_assert_numargs(1)
+`defn(`LSYM_PREFIX')$1')
+
+
+dnl  Usage: LDEF(name)
+dnl
+dnl  Generate a directive to define a local label.
+dnl
+dnl  On systems with a fixed syntax for defining labels there's no need to
+dnl  use this macro, it's only meant for systems where the syntax varies,
+dnl  like hppa which is "L(foo):" with gas, but just "L(foo)" in column 0
+dnl  with the system `as'.
+dnl
+dnl  The extra `' after LABEL_SUFFIX avoids any chance of a following
+dnl  "(...)"  being interpreted as an argument list.  Not that it'd be
+dnl  sensible to write anything like that after an LDEF(), but just in case.
+
+define(LDEF,
+m4_assert_numargs(1)
+m4_assert_defined(`LABEL_SUFFIX')
+`L(`$1')`'LABEL_SUFFIX`'')
+
+
+dnl  Usage: INT32(label,value)
+dnl         INT64(label,first,second)
+
+define(`INT32',
+m4_assert_defined(`W32')
+`	ALIGN(4)
+LDEF(`$1')
+	W32	$2')
+
+define(`INT64',
+m4_assert_defined(`W32')
+`	ALIGN(8)
+LDEF(`$1')
+	W32	$2
+	W32	$3')
+
+
+dnl  Usage: ALIGN(bytes)
+dnl
+dnl  Emit a ".align" directive.  The alignment is specified in bytes, and
+dnl  will normally need to be a power of 2.  The actual ".align" generated
+dnl  is either bytes or logarithmic according to what ./configure finds the
+dnl  assembler needs.
+dnl
+dnl  If ALIGN_FILL_0x90 is defined and equal to "yes", then ", 0x90" is
+dnl  appended.  This is for x86, see mpn/x86/README.
+
+define(ALIGN,
+m4_assert_numargs(1)
+m4_assert_defined(`ALIGN_LOGARITHMIC')
+`.align	ifelse(ALIGN_LOGARITHMIC,yes,`m4_log2($1)',`eval($1)')dnl
+ifelse(ALIGN_FILL_0x90,yes,`, 0x90')')
+
+
+dnl  Usage: MULFUNC_PROLOGUE(function function...)
+dnl
+dnl  A dummy macro which is grepped for by ./configure to know what
+dnl  functions a multi-function file is providing.  Use this if there aren't
+dnl  explicit PROLOGUE()s for each possible function.
+dnl
+dnl  Multiple MULFUNC_PROLOGUEs can be used, or just one with the function
+dnl  names separated by spaces.
+
+define(`MULFUNC_PROLOGUE',
+m4_assert_numargs(1)
+)
+
+
+dnl  Usage: NAILS_SUPPORT(spec spec ...)
+dnl
+dnl  A dummy macro which is grepped for by ./configure to know what nails
+dnl  are supported in an asm file.
+dnl
+dnl  Ranges can be given, or just individual values.  Multiple values or
+dnl  ranges can be given, separated by spaces.  Multiple NAILS_SUPPORT
+dnl  declarations work too.  Some examples,
+dnl
+dnl         NAILS_SUPPORT(1-20)
+dnl         NAILS_SUPPORT(1 6 9-12)
+dnl         NAILS_SUPPORT(1-10 16-20)
+
+define(NAILS_SUPPORT,
+m4_assert_numargs(1)
+)
+
+
+dnl  Usage: ABI_SUPPORT(abi)
+dnl
+dnl  A dummy macro which is grepped for by ./configure to know what ABIs
+dnl  are supported in an asm file.
+dnl
+dnl  If multiple non-standard ABIs are supported, several ABI_SUPPORT
+dnl  declarations should be used:
+dnl
+dnl         ABI_SUPPORT(FOOABI)
+dnl         ABI_SUPPORT(BARABI)
+
+define(ABI_SUPPORT,
+m4_assert_numargs(1)
+)
+
+
+dnl  Usage: GMP_NUMB_MASK
+dnl
+dnl  A bit mask for the number part of a limb.  Eg. with 6 bit nails in a
+dnl  32 bit limb, GMP_NUMB_MASK would be 0x3ffffff.
+
+define(GMP_NUMB_MASK,
+m4_assert_numargs(-1)
+m4_assert_defined(`GMP_NUMB_BITS')
+`m4_hex_lowmask(GMP_NUMB_BITS)')
+
+
+dnl  Usage: m4append(`variable',`value-to-append')
+
+define(`m4append',
+`define(`$1',  defn(`$1')`$2')
+'
+)
+
+divert`'dnl
diff --git a/mpn/generic/add.c b/mpn/generic/add.c
new file mode 100644
index 0000000..4a6e3ba
--- /dev/null
+++ b/mpn/generic/add.c
@@ -0,0 +1,33 @@
+/* mpn_add - add mpn to mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_add 1
+
+#include "gmp-impl.h"
diff --git a/mpn/generic/add_1.c b/mpn/generic/add_1.c
new file mode 100644
index 0000000..1745aed
--- /dev/null
+++ b/mpn/generic/add_1.c
@@ -0,0 +1,33 @@
+/* mpn_add_1 - add limb to mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_add_1 1
+
+#include "gmp-impl.h"
diff --git a/mpn/generic/add_err1_n.c b/mpn/generic/add_err1_n.c
new file mode 100644
index 0000000..b247f19
--- /dev/null
+++ b/mpn/generic/add_err1_n.c
@@ -0,0 +1,100 @@
+/* mpn_add_err1_n -- add_n with one error term
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} + {vp,n} (just like mpn_add_n) with incoming carry cy,
+  return value is carry out.
+
+  (2) Let c[i+1] = carry from i-th limb addition (c[0] = cy).
+  Computes c[1]*yp[n-1] + ... + c[n]*yp[0], stores two-limb result at ep.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_add_err1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		mp_ptr ep, mp_srcptr yp,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el, eh, ul, vl, yl, zl, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, rp, n));
+
+  yp += n - 1;
+  el = eh = 0;
+
+  do
+    {
+      yl = *yp--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary add_n */
+      ADDC_LIMB (cy1, sl, ul, vl);
+      ADDC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh:el) */
+      zl = (-cy) & yl;
+      el += zl;
+      eh += el < zl;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh = (eh << GMP_NAIL_BITS) + (el >> GMP_NUMB_BITS);
+  el &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el;
+  ep[1] = eh;
+
+  return cy;
+}
diff --git a/mpn/generic/add_err2_n.c b/mpn/generic/add_err2_n.c
new file mode 100644
index 0000000..d584d6d
--- /dev/null
+++ b/mpn/generic/add_err2_n.c
@@ -0,0 +1,116 @@
+/* mpn_add_err2_n -- add_n with two error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} + {vp,n} (just like mpn_add_n) with incoming carry cy,
+  return value is carry out.
+
+  (2) Let c[i+1] = carry from i-th limb addition (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+  stores two-limb results at {ep,2} and {ep+2,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_add_err2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, ul, vl, yl1, yl2, zl1, zl2, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary add_n */
+      ADDC_LIMB (cy1, sl, ul, vl);
+      ADDC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+
+  return cy;
+}
diff --git a/mpn/generic/add_err3_n.c b/mpn/generic/add_err3_n.c
new file mode 100644
index 0000000..a6ed4dc
--- /dev/null
+++ b/mpn/generic/add_err3_n.c
@@ -0,0 +1,131 @@
+/* mpn_add_err3_n -- add_n with three error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} + {vp,n} (just like mpn_add_n) with incoming carry cy,
+  return value is carry out.
+
+  (2) Let c[i+1] = carry from i-th limb addition (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+           c[1]*yp3[n-1] + ... + c[n]*yp3[0],
+  stores two-limb results at {ep,2}, {ep+2,2} and {ep+4,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_add_err3_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2, mp_srcptr yp3,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, el3, eh3, ul, vl, yl1, yl2, yl3, zl1, zl2, zl3, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  yp3 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+  el3 = eh3 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      yl3 = *yp3--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary add_n */
+      ADDC_LIMB (cy1, sl, ul, vl);
+      ADDC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+
+      /* update (eh3:el3) */
+      zl3 = (-cy) & yl3;
+      el3 += zl3;
+      eh3 += el3 < zl3;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+  eh3 = (eh3 << GMP_NAIL_BITS) + (el3 >> GMP_NUMB_BITS);
+  el3 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+  ep[4] = el3;
+  ep[5] = eh3;
+
+  return cy;
+}
diff --git a/mpn/generic/add_n.c b/mpn/generic/add_n.c
new file mode 100644
index 0000000..f62ac87
--- /dev/null
+++ b/mpn/generic/add_n.c
@@ -0,0 +1,89 @@
+/* mpn_add_n -- Add equal length limb vectors.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      sl = ul + vl;
+      cy1 = sl < ul;
+      rl = sl + cy;
+      cy2 = rl < sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 1
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, rl, cy;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      rl = ul + vl + cy;
+      cy = rl >> GMP_NUMB_BITS;
+      *rp++ = rl & GMP_NUMB_MASK;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
diff --git a/mpn/generic/add_n_sub_n.c b/mpn/generic/add_n_sub_n.c
new file mode 100644
index 0000000..1e72b5d
--- /dev/null
+++ b/mpn/generic/add_n_sub_n.c
@@ -0,0 +1,172 @@
+/* mpn_add_n_sub_n -- Add and Subtract two limb vectors of equal, non-zero length.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1999-2001, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifndef L1_CACHE_SIZE
+#define L1_CACHE_SIZE 8192	/* only 68040 has less than this */
+#endif
+
+#define PART_SIZE (L1_CACHE_SIZE / GMP_LIMB_BYTES / 6)
+
+
+/* mpn_add_n_sub_n.
+   r1[] = s1[] + s2[]
+   r2[] = s1[] - s2[]
+   All operands have n limbs.
+   In-place operations allowed.  */
+mp_limb_t
+mpn_add_n_sub_n (mp_ptr r1p, mp_ptr r2p, mp_srcptr s1p, mp_srcptr s2p, mp_size_t n)
+{
+  mp_limb_t acyn, acyo;		/* carry for add */
+  mp_limb_t scyn, scyo;		/* carry for subtract */
+  mp_size_t off;		/* offset in operands */
+  mp_size_t this_n;		/* size of current chunk */
+
+  /* We alternatingly add and subtract in chunks that fit into the (L1)
+     cache.  Since the chunks are several hundred limbs, the function call
+     overhead is insignificant, but we get much better locality.  */
+
+  /* We have three variant of the inner loop, the proper loop is chosen
+     depending on whether r1 or r2 are the same operand as s1 or s2.  */
+
+  if (r1p != s1p && r1p != s2p)
+    {
+      /* r1 is not identical to either input operand.  We can therefore write
+	 to r1 directly, without using temporary storage.  */
+      acyo = 0;
+      scyo = 0;
+      for (off = 0; off < n; off += PART_SIZE)
+	{
+	  this_n = MIN (n - off, PART_SIZE);
+#if HAVE_NATIVE_mpn_add_nc
+	  acyo = mpn_add_nc (r1p + off, s1p + off, s2p + off, this_n, acyo);
+#else
+	  acyn = mpn_add_n (r1p + off, s1p + off, s2p + off, this_n);
+	  acyo = acyn + mpn_add_1 (r1p + off, r1p + off, this_n, acyo);
+#endif
+#if HAVE_NATIVE_mpn_sub_nc
+	  scyo = mpn_sub_nc (r2p + off, s1p + off, s2p + off, this_n, scyo);
+#else
+	  scyn = mpn_sub_n (r2p + off, s1p + off, s2p + off, this_n);
+	  scyo = scyn + mpn_sub_1 (r2p + off, r2p + off, this_n, scyo);
+#endif
+	}
+    }
+  else if (r2p != s1p && r2p != s2p)
+    {
+      /* r2 is not identical to either input operand.  We can therefore write
+	 to r2 directly, without using temporary storage.  */
+      acyo = 0;
+      scyo = 0;
+      for (off = 0; off < n; off += PART_SIZE)
+	{
+	  this_n = MIN (n - off, PART_SIZE);
+#if HAVE_NATIVE_mpn_sub_nc
+	  scyo = mpn_sub_nc (r2p + off, s1p + off, s2p + off, this_n, scyo);
+#else
+	  scyn = mpn_sub_n (r2p + off, s1p + off, s2p + off, this_n);
+	  scyo = scyn + mpn_sub_1 (r2p + off, r2p + off, this_n, scyo);
+#endif
+#if HAVE_NATIVE_mpn_add_nc
+	  acyo = mpn_add_nc (r1p + off, s1p + off, s2p + off, this_n, acyo);
+#else
+	  acyn = mpn_add_n (r1p + off, s1p + off, s2p + off, this_n);
+	  acyo = acyn + mpn_add_1 (r1p + off, r1p + off, this_n, acyo);
+#endif
+	}
+    }
+  else
+    {
+      /* r1 and r2 are identical to s1 and s2 (r1==s1 and r2==s2 or vice versa)
+	 Need temporary storage.  */
+      mp_limb_t tp[PART_SIZE];
+      acyo = 0;
+      scyo = 0;
+      for (off = 0; off < n; off += PART_SIZE)
+	{
+	  this_n = MIN (n - off, PART_SIZE);
+#if HAVE_NATIVE_mpn_add_nc
+	  acyo = mpn_add_nc (tp, s1p + off, s2p + off, this_n, acyo);
+#else
+	  acyn = mpn_add_n (tp, s1p + off, s2p + off, this_n);
+	  acyo = acyn + mpn_add_1 (tp, tp, this_n, acyo);
+#endif
+#if HAVE_NATIVE_mpn_sub_nc
+	  scyo = mpn_sub_nc (r2p + off, s1p + off, s2p + off, this_n, scyo);
+#else
+	  scyn = mpn_sub_n (r2p + off, s1p + off, s2p + off, this_n);
+	  scyo = scyn + mpn_sub_1 (r2p + off, r2p + off, this_n, scyo);
+#endif
+	  MPN_COPY (r1p + off, tp, this_n);
+	}
+    }
+
+  return 2 * acyo + scyo;
+}
+
+#ifdef MAIN
+#include <stdlib.h>
+#include <stdio.h>
+#include "timing.h"
+
+long cputime ();
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr r1p, r2p, s1p, s2p;
+  double t;
+  mp_size_t n;
+
+  n = strtol (argv[1], 0, 0);
+
+  r1p = malloc (n * GMP_LIMB_BYTES);
+  r2p = malloc (n * GMP_LIMB_BYTES);
+  s1p = malloc (n * GMP_LIMB_BYTES);
+  s2p = malloc (n * GMP_LIMB_BYTES);
+  TIME (t,(mpn_add_n(r1p,s1p,s2p,n),mpn_sub_n(r1p,s1p,s2p,n)));
+  printf ("              separate add and sub: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,s1p,s2p,n));
+  printf ("combined addsub separate variables: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,r1p,s2p,n));
+  printf ("        combined addsub r1 overlap: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,r1p,s2p,n));
+  printf ("        combined addsub r2 overlap: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,r1p,r2p,n));
+  printf ("          combined addsub in-place: %.3f\n", t);
+
+  return 0;
+}
+#endif
diff --git a/mpn/generic/addmul_1.c b/mpn/generic/addmul_1.c
new file mode 100644
index 0000000..6140e8e
--- /dev/null
+++ b/mpn/generic/addmul_1.c
@@ -0,0 +1,145 @@
+/* mpn_addmul_1 -- multiply the N long limb vector pointed to by UP by VL,
+   add the N least significant limbs of the product to the limb vector
+   pointed to by RP.  Return the most significant limb of the product,
+   adjusted for carry-out from the addition.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2004, 2016 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t u0, crec, c, p1, p0, r0;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+
+  crec = 0;
+  do
+    {
+      u0 = *up++;
+      umul_ppmm (p1, p0, u0, v0);
+
+      r0 = *rp;
+
+      p0 = r0 + p0;
+      c = r0 > p0;
+
+      p1 = p1 + c;
+
+      r0 = p0 + crec;		/* cycle 0, 3, ... */
+      c = p0 > r0;		/* cycle 1, 4, ... */
+
+      crec = p1 + c;		/* cycle 2, 5, ... */
+
+      *rp++ = r0;
+    }
+  while (--n != 0);
+
+  return crec;
+}
+
+#endif
+
+#if GMP_NAIL_BITS == 1
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, crec, xl, c1, c2, c3;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  crec = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      ADDC_LIMB (c1, xl, prev_p1, p0);
+      ADDC_LIMB (c2, xl, xl, r0);
+      ADDC_LIMB (c3, xl, xl, crec);
+      crec = c1 + c2 + c3;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 + crec;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 2
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, xw, crec, xl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  crec = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      xw = prev_p1 + p0 + r0 + crec;
+      crec = xw >> GMP_NUMB_BITS;
+      xl = xw & GMP_NUMB_MASK;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 + crec;
+}
+
+#endif
diff --git a/mpn/generic/bdiv_dbm1c.c b/mpn/generic/bdiv_dbm1c.c
new file mode 100644
index 0000000..543bb6e
--- /dev/null
+++ b/mpn/generic/bdiv_dbm1c.c
@@ -0,0 +1,58 @@
+/* mpn_bdiv_dbm1c -- divide an mpn number by a divisor of B-1, where B is the
+   limb base.  The dbm1c moniker means "Divisor of B Minus 1 with Carry".
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+mp_limb_t
+mpn_bdiv_dbm1c (mp_ptr qp, mp_srcptr ap, mp_size_t n, mp_limb_t bd, mp_limb_t h)
+{
+  mp_limb_t a, p0, p1, cy;
+  mp_size_t i;
+
+  for (i = 0; i < n; i++)
+    {
+      a = ap[i];
+      umul_ppmm (p1, p0, a, bd << GMP_NAIL_BITS);
+      p0 >>= GMP_NAIL_BITS;
+      cy = h < p0;
+      h = (h - p0) & GMP_NUMB_MASK;
+      qp[i] = h;
+      h = h - p1 - cy;
+    }
+
+  return h;
+}
diff --git a/mpn/generic/bdiv_q.c b/mpn/generic/bdiv_q.c
new file mode 100644
index 0000000..52aa473
--- /dev/null
+++ b/mpn/generic/bdiv_q.c
@@ -0,0 +1,76 @@
+/* mpn_bdiv_q -- Hensel division with precomputed inverse, returning quotient.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes Q = N / D mod B^n. */
+
+void
+mpn_bdiv_q (mp_ptr qp,
+	    mp_srcptr np, mp_size_t nn,
+	    mp_srcptr dp, mp_size_t dn,
+	    mp_ptr tp)
+{
+  mp_limb_t di;
+
+  if (BELOW_THRESHOLD (dn, DC_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      mpn_sbpi1_bdiv_q (qp, tp, nn, dp, dn, di);
+    }
+  else if (BELOW_THRESHOLD (dn, MU_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      mpn_dcpi1_bdiv_q (qp, tp, nn, dp, dn, di);
+    }
+  else
+    {
+      mpn_mu_bdiv_q (qp, np, nn, dp, dn, tp);
+    }
+  return;
+}
+
+mp_size_t
+mpn_bdiv_q_itch (mp_size_t nn, mp_size_t dn)
+{
+  if (BELOW_THRESHOLD (dn, MU_BDIV_Q_THRESHOLD))
+    return nn;
+  else
+    return mpn_mu_bdiv_q_itch (nn, dn);
+}
diff --git a/mpn/generic/bdiv_q_1.c b/mpn/generic/bdiv_q_1.c
new file mode 100644
index 0000000..6beb9a0
--- /dev/null
+++ b/mpn/generic/bdiv_q_1.c
@@ -0,0 +1,121 @@
+/* mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- schoolbook Hensel division by 1-limb
+   divisor, returning quotient only.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003, 2005, 2009, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_pi1_bdiv_q_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t d,
+		  mp_limb_t di, int shift)
+{
+  mp_size_t  i;
+  mp_limb_t  c, h, l, u, u_next, dummy;
+
+  ASSERT (n >= 1);
+  ASSERT (d != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (d);
+
+  d <<= GMP_NAIL_BITS;
+
+  if (shift != 0)
+    {
+      c = 0;
+
+      u = up[0];
+      rp--;
+      for (i = 1; i < n; i++)
+	{
+	  u_next = up[i];
+	  u = ((u >> shift) | (u_next << (GMP_NUMB_BITS-shift))) & GMP_NUMB_MASK;
+
+	  SUBC_LIMB (c, l, u, c);
+
+	  l = (l * di) & GMP_NUMB_MASK;
+	  rp[i] = l;
+
+	  umul_ppmm (h, dummy, l, d);
+	  c += h;
+	  u = u_next;
+	}
+
+      u = u >> shift;
+      SUBC_LIMB (c, l, u, c);
+
+      l = (l * di) & GMP_NUMB_MASK;
+      rp[n] = l;
+    }
+  else
+    {
+      u = up[0];
+      l = (u * di) & GMP_NUMB_MASK;
+      rp[0] = l;
+      c = 0;
+
+      for (i = 1; i < n; i++)
+	{
+	  umul_ppmm (h, dummy, l, d);
+	  c += h;
+
+	  u = up[i];
+	  SUBC_LIMB (c, l, u, c);
+
+	  l = (l * di) & GMP_NUMB_MASK;
+	  rp[i] = l;
+	}
+    }
+
+  return c;
+}
+
+mp_limb_t
+mpn_bdiv_q_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t d)
+{
+  mp_limb_t di;
+  int shift;
+
+  ASSERT (n >= 1);
+  ASSERT (d != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (d);
+
+  count_trailing_zeros (shift, d);
+  d >>= shift;
+
+  binvert_limb (di, d);
+  return mpn_pi1_bdiv_q_1 (rp, up, n, d, di, shift);
+}
diff --git a/mpn/generic/bdiv_qr.c b/mpn/generic/bdiv_qr.c
new file mode 100644
index 0000000..a4f0f39
--- /dev/null
+++ b/mpn/generic/bdiv_qr.c
@@ -0,0 +1,84 @@
+/* mpn_bdiv_qr -- Hensel division with precomputed inverse, returning quotient
+   and remainder.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes Q = N / D mod B^n,
+	    R = N - QD.  */
+
+mp_limb_t
+mpn_bdiv_qr (mp_ptr qp, mp_ptr rp,
+	     mp_srcptr np, mp_size_t nn,
+	     mp_srcptr dp, mp_size_t dn,
+	     mp_ptr tp)
+{
+  mp_limb_t di;
+  mp_limb_t rh;
+
+  ASSERT (nn > dn);
+  if (BELOW_THRESHOLD (dn, DC_BDIV_QR_THRESHOLD) ||
+      BELOW_THRESHOLD (nn - dn, DC_BDIV_QR_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      rh = mpn_sbpi1_bdiv_qr (qp, tp, nn, dp, dn, di);
+      MPN_COPY (rp, tp + nn - dn, dn);
+    }
+  else if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      rh = mpn_dcpi1_bdiv_qr (qp, tp, nn, dp, dn, di);
+      MPN_COPY (rp, tp + nn - dn, dn);
+    }
+  else
+    {
+      rh = mpn_mu_bdiv_qr (qp, rp, np, nn, dp, dn, tp);
+    }
+
+  return rh;
+}
+
+mp_size_t
+mpn_bdiv_qr_itch (mp_size_t nn, mp_size_t dn)
+{
+  if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
+    return nn;
+  else
+    return  mpn_mu_bdiv_qr_itch (nn, dn);
+}
diff --git a/mpn/generic/binvert.c b/mpn/generic/binvert.c
new file mode 100644
index 0000000..a170e66
--- /dev/null
+++ b/mpn/generic/binvert.c
@@ -0,0 +1,106 @@
+/* Compute {up,n}^(-1) mod B^n.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright (C) 2004-2007, 2009, 2012, 2017, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/*
+  r[k+1] = r[k] - r[k] * (u*r[k] - 1)
+  r[k+1] = r[k] + r[k] - r[k]*(u*r[k])
+*/
+
+#if TUNE_PROGRAM_BUILD
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)))
+#else
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)) - LOG2C (BINV_NEWTON_THRESHOLD))
+#endif
+
+mp_size_t
+mpn_binvert_itch (mp_size_t n)
+{
+  mp_size_t itch_local = mpn_mulmod_bnm1_next_size (n);
+  mp_size_t itch_out = mpn_mulmod_bnm1_itch (itch_local, n, (n + 1) >> 1);
+  return itch_local + itch_out;
+}
+
+void
+mpn_binvert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch)
+{
+  mp_ptr xp;
+  mp_size_t rn, newrn;
+  mp_size_t sizes[NPOWS], *sizp;
+  mp_limb_t di;
+
+  /* Compute the computation precisions from highest to lowest, leaving the
+     base case size in 'rn'.  */
+  sizp = sizes;
+  for (rn = n; ABOVE_THRESHOLD (rn, BINV_NEWTON_THRESHOLD); rn = (rn + 1) >> 1)
+    *sizp++ = rn;
+
+  xp = scratch;
+
+  /* Compute a base value of rn limbs.  */
+  MPN_ZERO (xp, rn);
+  xp[0] = 1;
+  binvert_limb (di, up[0]);
+  if (BELOW_THRESHOLD (rn, DC_BDIV_Q_THRESHOLD))
+    mpn_sbpi1_bdiv_q (rp, xp, rn, up, rn, -di);
+  else
+    mpn_dcpi1_bdiv_q (rp, xp, rn, up, rn, -di);
+
+  mpn_neg (rp, rp, rn);
+
+  /* Use Newton iterations to get the desired precision.  */
+  for (; rn < n; rn = newrn)
+    {
+      mp_size_t m;
+      newrn = *--sizp;
+
+      /* X <- UR. */
+      m = mpn_mulmod_bnm1_next_size (newrn);
+      mpn_mulmod_bnm1 (xp, m, up, newrn, rp, rn, xp + m);
+      /* Only the values in the range xp + rn .. xp + newrn - 1 are
+	 used by the _mullo_n below.
+	 Since m >= newrn, we do not need the following. */
+      /* mpn_sub_1 (xp + m, xp, rn - (m - newrn), 1); */
+
+      /* R = R(X/B^rn) */
+      mpn_mullo_n (rp + rn, rp, xp + rn, newrn - rn);
+      mpn_neg (rp + rn, rp + rn, newrn - rn);
+    }
+}
diff --git a/mpn/generic/broot.c b/mpn/generic/broot.c
new file mode 100644
index 0000000..02fe75a
--- /dev/null
+++ b/mpn/generic/broot.c
@@ -0,0 +1,195 @@
+/* mpn_broot -- Compute hensel sqrt
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes a^e (mod B). Uses right-to-left binary algorithm, since
+   typical use will have e small. */
+static mp_limb_t
+powlimb (mp_limb_t a, mp_limb_t e)
+{
+  mp_limb_t r = 1;
+  mp_limb_t s = a;
+
+  for (r = 1, s = a; e > 0; e >>= 1, s *= s)
+    if (e & 1)
+      r *= s;
+
+  return r;
+}
+
+/* Computes a^{1/k - 1} (mod B^n). Both a and k must be odd.
+
+   Iterates
+
+     r' <-- r - r * (a^{k-1} r^k - 1) / n
+
+   If
+
+     a^{k-1} r^k = 1 (mod 2^m),
+
+   then
+
+     a^{k-1} r'^k = 1 (mod 2^{2m}),
+
+   Compute the update term as
+
+     r' = r - (a^{k-1} r^{k+1} - r) / k
+
+   where we still have cancellation of low limbs.
+
+ */
+void
+mpn_broot_invm1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t k)
+{
+  mp_size_t sizes[GMP_LIMB_BITS * 2];
+  mp_ptr akm1, tp, rnp, ep;
+  mp_limb_t a0, r0, km1, kp1h, kinv;
+  mp_size_t rn;
+  unsigned i;
+
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT (ap[0] & 1);
+  ASSERT (k & 1);
+  ASSERT (k >= 3);
+
+  TMP_MARK;
+
+  akm1 = TMP_ALLOC_LIMBS (4*n);
+  tp = akm1 + n;
+
+  km1 = k-1;
+  /* FIXME: Could arrange the iteration so we don't need to compute
+     this up front, computing a^{k-1} * r^k as (a r)^{k-1} * r. Note
+     that we can use wraparound also for a*r, since the low half is
+     unchanged from the previous iteration. Or possibly mulmid. Also,
+     a r = a^{1/k}, so we get that value too, for free? */
+  mpn_powlo (akm1, ap, &km1, 1, n, tp); /* 3 n scratch space */
+
+  a0 = ap[0];
+  binvert_limb (kinv, k);
+
+  /* 4 bits: a^{1/k - 1} (mod 16):
+
+	a % 8
+	1 3 5 7
+   k%4 +-------
+     1 |1 1 1 1
+     3 |1 9 9 1
+  */
+  r0 = 1 + (((k << 2) & ((a0 << 1) ^ (a0 << 2))) & 8);
+  r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k & 0x7f)); /* 8 bits */
+  r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k & 0x7fff)); /* 16 bits */
+  r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k)); /* 32 bits */
+#if GMP_NUMB_BITS > 32
+  {
+    unsigned prec = 32;
+    do
+      {
+	r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k));
+	prec *= 2;
+      }
+    while (prec < GMP_NUMB_BITS);
+  }
+#endif
+
+  rp[0] = r0;
+  if (n == 1)
+    {
+      TMP_FREE;
+      return;
+    }
+
+  /* For odd k, (k+1)/2 = k/2+1, and the latter avoids overflow. */
+  kp1h = k/2 + 1;
+
+  /* FIXME: Special case for two limb iteration. */
+  rnp = TMP_ALLOC_LIMBS (2*n + 1);
+  ep = rnp + n;
+
+  /* FIXME: Possible to this on the fly with some bit fiddling. */
+  for (i = 0; n > 1; n = (n + 1)/2)
+    sizes[i++] = n;
+
+  rn = 1;
+
+  while (i-- > 0)
+    {
+      /* Compute x^{k+1}. */
+      mpn_sqr (ep, rp, rn); /* For odd n, writes n+1 limbs in the
+			       final iteration. */
+      mpn_powlo (rnp, ep, &kp1h, 1, sizes[i], tp);
+
+      /* Multiply by a^{k-1}. Can use wraparound; low part equals r. */
+
+      mpn_mullo_n (ep, rnp, akm1, sizes[i]);
+      ASSERT (mpn_cmp (ep, rp, rn) == 0);
+
+      ASSERT (sizes[i] <= 2*rn);
+      mpn_pi1_bdiv_q_1 (rp + rn, ep + rn, sizes[i] - rn, k, kinv, 0);
+      mpn_neg (rp + rn, rp + rn, sizes[i] - rn);
+      rn = sizes[i];
+    }
+  TMP_FREE;
+}
+
+/* Computes a^{1/k} (mod B^n). Both a and k must be odd. */
+void
+mpn_broot (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t k)
+{
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT (ap[0] & 1);
+  ASSERT (k & 1);
+
+  if (k == 1)
+    {
+      MPN_COPY (rp, ap, n);
+      return;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (n);
+
+  mpn_broot_invm1 (tp, ap, n, k);
+  mpn_mullo_n (rp, tp, ap, n);
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/brootinv.c b/mpn/generic/brootinv.c
new file mode 100644
index 0000000..e91b597
--- /dev/null
+++ b/mpn/generic/brootinv.c
@@ -0,0 +1,159 @@
+/* mpn_brootinv, compute r such that r^k * y = 1 (mod 2^b).
+
+   Contributed to the GNU project by Martin Boij (as part of perfpow.c).
+
+Copyright 2009, 2010, 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes a^2e (mod B). Uses right-to-left binary algorithm, since
+   typical use will have e small. */
+static mp_limb_t
+powsquaredlimb (mp_limb_t a, mp_limb_t e)
+{
+  mp_limb_t r;
+
+  r = 1;
+  /* if (LIKELY (e != 0)) */
+  do {
+    a *= a;
+    if (e & 1)
+      r *= a;
+    e >>= 1;
+  } while (e != 0);
+
+  return r;
+}
+
+/* Compute r such that r^k * y = 1 (mod B^n).
+
+   Iterates
+     r' <-- k^{-1} ((k+1) r - r^{k+1} y) (mod 2^b)
+   using Hensel lifting, each time doubling the number of known bits in r.
+
+   Works just for odd k.  Else the Hensel lifting degenerates.
+
+   FIXME:
+
+     (1) Make it work for k == GMP_LIMB_MAX (k+1 below overflows).
+
+     (2) Rewrite iteration as
+	   r' <-- r - k^{-1} r (r^k y - 1)
+	 and take advantage of the zero low part of r^k y - 1.
+
+     (3) Use wrap-around trick.
+
+     (4) Use a small table to get starting value.
+
+   Scratch need: bn + (((bn + 1) >> 1) + 1) + scratch for mpn_powlo
+   Currently mpn_powlo requires 3*bn
+   so that 5*bn is surely enough, where bn = ceil (bnb / GMP_NUMB_BITS).
+*/
+
+void
+mpn_brootinv (mp_ptr rp, mp_srcptr yp, mp_size_t bn, mp_limb_t k, mp_ptr tp)
+{
+  mp_ptr tp2, tp3;
+  mp_limb_t kinv, k2, r0, y0;
+  mp_size_t order[GMP_LIMB_BITS + 1];
+  int d;
+
+  ASSERT (bn > 0);
+  ASSERT ((k & 1) != 0);
+
+  tp2 = tp + bn;
+  tp3 = tp + bn + ((bn + 3) >> 1);
+  k2 = (k >> 1) + 1; /* (k + 1) / 2 , but avoid k+1 overflow */
+
+  binvert_limb (kinv, k);
+
+  /* 4-bit initial approximation:
+
+   y%16 | 1  3  5  7  9 11 13 15,
+    k%4 +-------------------------+k2%2
+     1  | 1 11 13  7  9  3  5 15  |  1
+     3  | 1  3  5  7  9 11 13 15  |  0
+
+  */
+  y0 = yp[0];
+
+  r0 = y0 ^ (((y0 << 1) ^ (y0 << 2)) & (k2 << 3) & 8);			/* 4 bits */
+  r0 = kinv * (k2 * r0 * 2 - y0 * powsquaredlimb(r0, k2 & 0x3f));	/* 8 bits */
+  r0 = kinv * (k2 * r0 * 2 - y0 * powsquaredlimb(r0, k2 & 0x3fff));	/* 16 bits */
+#if GMP_NUMB_BITS > 16
+  {
+    unsigned prec = 16;
+    do
+      {
+	r0 = kinv * (k2 * r0 * 2 - y0 * powsquaredlimb(r0, k2));
+	prec *= 2;
+      }
+    while (prec < GMP_NUMB_BITS);
+  }
+#endif
+
+  rp[0] = r0;
+  if (bn == 1)
+    return;
+
+  d = 0;
+  for (; bn != 2; bn = (bn + 1) >> 1)
+    order[d++] = bn;
+
+  order[d] = 2;
+  bn = 1;
+
+  do
+    {
+      mpn_sqr (tp, rp, bn); /* Result may overlap tp2 */
+      tp2[bn] = mpn_mul_1 (tp2, rp, bn, k2 << 1);
+
+      bn = order[d];
+
+      mpn_powlo (rp, tp, &k2, 1, bn, tp3);
+      mpn_mullo_n (tp, yp, rp, bn);
+
+      /* mpn_sub (tp, tp2, ((bn + 1) >> 1) + 1, tp, bn); */
+      /* The function above is not handled, ((bn + 1) >> 1) + 1 <= bn*/
+      {
+	mp_size_t pbn = (bn + 3) >> 1; /* Size of tp2 */
+	int borrow;
+	borrow = mpn_sub_n (tp, tp2, tp, pbn) != 0;
+	if (bn > pbn) /* 3 < bn */
+	  {
+	    if (borrow)
+	      mpn_com (tp + pbn, tp + pbn, bn - pbn);
+	    else
+	      mpn_neg (tp + pbn, tp + pbn, bn - pbn);
+	  }
+      }
+      mpn_pi1_bdiv_q_1 (rp, tp, bn, k, kinv, 0);
+    }
+  while (--d >= 0);
+}
diff --git a/mpn/generic/bsqrt.c b/mpn/generic/bsqrt.c
new file mode 100644
index 0000000..27184f0
--- /dev/null
+++ b/mpn/generic/bsqrt.c
@@ -0,0 +1,47 @@
+/* mpn_bsqrt, a^{1/2} (mod 2^n).
+
+Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpn_bsqrt (mp_ptr rp, mp_srcptr ap, mp_bitcnt_t nb, mp_ptr tp)
+{
+  mp_ptr sp;
+  mp_size_t n;
+
+  ASSERT (nb > 0);
+
+  n = nb / GMP_NUMB_BITS;
+  sp = tp + n;
+
+  mpn_bsqrtinv (tp, ap, nb, sp);
+  mpn_mullo_n (rp, tp, ap, n);
+}
diff --git a/mpn/generic/bsqrtinv.c b/mpn/generic/bsqrtinv.c
new file mode 100644
index 0000000..c286773
--- /dev/null
+++ b/mpn/generic/bsqrtinv.c
@@ -0,0 +1,103 @@
+/* mpn_bsqrtinv, compute r such that r^2 * y = 1 (mod 2^{b+1}).
+
+   Contributed to the GNU project by Martin Boij (as part of perfpow.c).
+
+Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Compute r such that r^2 * y = 1 (mod 2^{b+1}).
+   Return non-zero if such an integer r exists.
+
+   Iterates
+     r' <-- (3r - r^3 y) / 2
+   using Hensel lifting.  Since we divide by two, the Hensel lifting is
+   somewhat degenerates.  Therefore, we lift from 2^b to 2^{b+1}-1.
+
+   FIXME:
+     (1) Simplify to do precision book-keeping in limbs rather than bits.
+
+     (2) Rewrite iteration as
+	   r' <-- r - r (r^2 y - 1) / 2
+	 and take advantage of zero low part of r^2 y - 1.
+
+     (3) Use wrap-around trick.
+
+     (4) Use a small table to get starting value.
+*/
+int
+mpn_bsqrtinv (mp_ptr rp, mp_srcptr yp, mp_bitcnt_t bnb, mp_ptr tp)
+{
+  mp_ptr tp2;
+  mp_size_t bn, order[GMP_LIMB_BITS + 1];
+  int i, d;
+
+  ASSERT (bnb > 0);
+
+  bn = 1 + bnb / GMP_LIMB_BITS;
+
+  tp2 = tp + bn;
+
+  rp[0] = 1;
+  if (bnb == 1)
+    {
+      if ((yp[0] & 3) != 1)
+	return 0;
+    }
+  else
+    {
+      if ((yp[0] & 7) != 1)
+	return 0;
+
+      d = 0;
+      for (; bnb != 2; bnb = (bnb + 2) >> 1)
+	order[d++] = bnb;
+
+      for (i = d - 1; i >= 0; i--)
+	{
+	  bnb = order[i];
+	  bn = 1 + bnb / GMP_LIMB_BITS;
+
+	  mpn_sqrlo (tp, rp, bn);
+	  mpn_mullo_n (tp2, rp, tp, bn); /* tp2 <- rp ^ 3 */
+
+	  mpn_mul_1 (tp, rp, bn, 3);
+
+	  mpn_mullo_n (rp, yp, tp2, bn);
+
+#if HAVE_NATIVE_mpn_rsh1sub_n
+	  mpn_rsh1sub_n (rp, tp, rp, bn);
+#else
+	  mpn_sub_n (tp2, tp, rp, bn);
+	  mpn_rshift (rp, tp2, bn, 1);
+#endif
+	}
+    }
+  return 1;
+}
diff --git a/mpn/generic/cmp.c b/mpn/generic/cmp.c
new file mode 100644
index 0000000..940314b
--- /dev/null
+++ b/mpn/generic/cmp.c
@@ -0,0 +1,33 @@
+/* mpn_cmp -- Compare two low-level natural-number integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_cmp 1
+
+#include "gmp-impl.h"
diff --git a/mpn/generic/cnd_add_n.c b/mpn/generic/cnd_add_n.c
new file mode 100644
index 0000000..e6b1373
--- /dev/null
+++ b/mpn/generic/cnd_add_n.c
@@ -0,0 +1,69 @@
+/* mpn_cnd_add_n -- Compute R = U + V if CND != 0 or R = U if CND == 0.
+   Both cases should take the same time and perform the exact same memory
+   accesses, since this function is intended to be used where side-channel
+   attack resilience is relevant.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2008, 2009, 2011, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_cnd_add_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2, mask;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+
+  mask = -(mp_limb_t) (cnd != 0);
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++ & mask;
+#if GMP_NAIL_BITS == 0
+      sl = ul + vl;
+      cy1 = sl < ul;
+      rl = sl + cy;
+      cy2 = rl < sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+#else
+      rl = ul + vl;
+      rl += cy;
+      cy = rl >> GMP_NUMB_BITS;
+      *rp++ = rl & GMP_NUMB_MASK;
+#endif
+    }
+  while (--n != 0);
+
+  return cy;
+}
diff --git a/mpn/generic/cnd_sub_n.c b/mpn/generic/cnd_sub_n.c
new file mode 100644
index 0000000..d04ad8a
--- /dev/null
+++ b/mpn/generic/cnd_sub_n.c
@@ -0,0 +1,69 @@
+/* mpn_cnd_sub_n -- Compute R = U - V if CND != 0 or R = U if CND == 0.
+   Both cases should take the same time and perform the exact same memory
+   accesses, since this function is intended to be used where side-channel
+   attack resilience is relevant.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2008, 2009, 2011, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_cnd_sub_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2, mask;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+
+  mask = -(mp_limb_t) (cnd != 0);
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++ & mask;
+#if GMP_NAIL_BITS == 0
+      sl = ul - vl;
+      cy1 = sl > ul;
+      rl = sl - cy;
+      cy2 = rl > sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+#else
+      rl = ul - vl;
+      rl -= cy;
+      cy = rl >> (GMP_LIMB_BITS - 1);
+      *rp++ = rl & GMP_NUMB_MASK;
+#endif
+    }
+  while (--n != 0);
+
+  return cy;
+}
diff --git a/mpn/generic/cnd_swap.c b/mpn/generic/cnd_swap.c
new file mode 100644
index 0000000..83d856d
--- /dev/null
+++ b/mpn/generic/cnd_swap.c
@@ -0,0 +1,50 @@
+/* mpn_cnd_swap
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 2013, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_cnd_swap (mp_limb_t cnd, volatile mp_limb_t *ap, volatile mp_limb_t *bp,
+	      mp_size_t n)
+{
+  volatile mp_limb_t mask = - (mp_limb_t) (cnd != 0);
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    {
+      mp_limb_t a, b, t;
+      a = ap[i];
+      b = bp[i];
+      t = (a ^ b) & mask;
+      ap[i] = a ^ t;
+      bp[i] = b ^ t;
+    }
+}
diff --git a/mpn/generic/com.c b/mpn/generic/com.c
new file mode 100644
index 0000000..4de5824
--- /dev/null
+++ b/mpn/generic/com.c
@@ -0,0 +1,44 @@
+/* mpn_com - complement an mpn.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef mpn_com
+#define mpn_com __MPN(com)
+
+void
+mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_limb_t ul;
+  do {
+      ul = *up++;
+      *rp++ = ~ul & GMP_NUMB_MASK;
+  } while (--n != 0);
+}
diff --git a/mpn/generic/comb_tables.c b/mpn/generic/comb_tables.c
new file mode 100644
index 0000000..dedb77b
--- /dev/null
+++ b/mpn/generic/comb_tables.c
@@ -0,0 +1,47 @@
+/* Const tables shared among combinatoric functions.
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Entry i contains (i!/2^t) where t is chosen such that the parenthesis
+   is an odd integer. */
+const mp_limb_t __gmp_oddfac_table[] = { ONE_LIMB_ODD_FACTORIAL_TABLE, ONE_LIMB_ODD_FACTORIAL_EXTTABLE };
+
+/* Entry i contains ((2i+1)!!/2^t) where t is chosen such that the parenthesis
+   is an odd integer. */
+const mp_limb_t __gmp_odd2fac_table[] = { ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE };
+
+/* Entry i contains 2i-popc(2i). */
+const unsigned char __gmp_fac2cnt_table[] = { TABLE_2N_MINUS_POPC_2N };
+
+const mp_limb_t __gmp_limbroots_table[] = { NTH_ROOT_NUMB_MASK_TABLE };
diff --git a/mpn/generic/compute_powtab.c b/mpn/generic/compute_powtab.c
new file mode 100644
index 0000000..f4fbc64
--- /dev/null
+++ b/mpn/generic/compute_powtab.c
@@ -0,0 +1,373 @@
+/* mpn_compute_powtab.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  CAVEATS:
+  * The exptab and powtab vectors are in opposite orders.  Probably OK.
+  * Consider getting rid of exptab, doing bit ops on the un argument instead.
+  * Consider rounding greatest power slightly upwards to save adjustments.
+  * In powtab_decide, consider computing cost from just the 2-3 largest
+    operands, since smaller operand contribute little.  This makes most sense
+    if exptab is suppressed.
+*/
+
+#include "gmp-impl.h"
+
+#ifndef DIV_1_VS_MUL_1_PERCENT
+#define DIV_1_VS_MUL_1_PERCENT 150
+#endif
+
+#define SET_powers_t(dest, ptr, size, dib, b, sh)	\
+  do {							\
+    dest.p = ptr;					\
+    dest.n = size;					\
+    dest.digits_in_base = dib;				\
+    dest.base = b;					\
+    dest.shift = sh;					\
+  } while (0)
+
+#if DIV_1_VS_MUL_1_PERCENT > 120
+#define HAVE_mpn_compute_powtab_mul 1
+static void
+mpn_compute_powtab_mul (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un,
+			int base, const size_t *exptab, size_t n_pows)
+{
+  mp_size_t n;
+  mp_ptr p, t;
+  mp_limb_t cy;
+  long start_idx;
+  int c;
+
+  mp_limb_t big_base = mp_bases[base].big_base;
+  int chars_per_limb = mp_bases[base].chars_per_limb;
+
+  mp_ptr powtab_mem_ptr = powtab_mem;
+
+  size_t digits_in_base = chars_per_limb;
+
+  powers_t *pt = powtab;
+
+  p = powtab_mem_ptr;
+  powtab_mem_ptr += 1;
+  p[0] = big_base;
+
+  SET_powers_t (pt[0], p, 1, digits_in_base, base, 0);
+  pt++;
+
+  t = powtab_mem_ptr;
+  powtab_mem_ptr += 2;
+  t[1] = mpn_mul_1 (t, p, 1, big_base);
+  n = 2;
+
+  digits_in_base *= 2;
+
+  c = t[0] == 0;
+  t += c;
+  n -= c;
+  mp_size_t shift = c;
+
+  SET_powers_t (pt[0], t, n, digits_in_base, base, shift);
+  p = t;
+  pt++;
+
+  if (exptab[0] == ((size_t) chars_per_limb << n_pows))
+    {
+      start_idx = n_pows - 2;
+    }
+  else
+    {
+      if (((digits_in_base + chars_per_limb) << (n_pows-2)) <= exptab[0])
+	{
+	  /* 3, sometimes adjusted to 4.  */
+	  t = powtab_mem_ptr;
+	  powtab_mem_ptr += 4;
+	  t[n] = cy = mpn_mul_1 (t, p, n, big_base);
+	  n += cy != 0;;
+
+	  digits_in_base += chars_per_limb;
+
+	  c  = t[0] == 0;
+	  t += c;
+	  n -= c;
+	  shift += c;
+	}
+      else
+	{
+	  /* 2 copy, will always become 3 with back-multiplication.  */
+	  t = powtab_mem_ptr;
+	  powtab_mem_ptr += 3;
+	  t[0] = p[0];
+	  t[1] = p[1];
+	}
+
+      SET_powers_t (pt[0], t, n, digits_in_base, base, shift);
+      p = t;
+      pt++;
+      start_idx = n_pows - 3;
+    }
+
+  for (long pi = start_idx; pi >= 0; pi--)
+    {
+      t = powtab_mem_ptr;
+      powtab_mem_ptr += 2 * n + 2;
+
+      ASSERT (powtab_mem_ptr < powtab_mem + mpn_str_powtab_alloc (un));
+
+      mpn_sqr (t, p, n);
+
+      digits_in_base *= 2;
+      n *= 2;
+      n -= t[n - 1] == 0;
+      shift *= 2;
+
+      c = t[0] == 0;
+      t += c;
+      n -= c;
+      shift += c;
+
+      /* Adjust new value if it is too small as input to the next squaring.  */
+      if (((digits_in_base + chars_per_limb) << pi) <= exptab[0])
+	{
+	  t[n] = cy = mpn_mul_1 (t, t, n, big_base);
+	  n += cy != 0;
+
+	  digits_in_base += chars_per_limb;
+
+	  c  = t[0] == 0;
+	  t += c;
+	  n -= c;
+	  shift += c;
+	}
+
+      SET_powers_t (pt[0], t, n, digits_in_base, base, shift);
+
+      /* Adjust previous value if it is not at its target power.  */
+      if (pt[-1].digits_in_base < exptab[pi + 1])
+	{
+	  mp_size_t n = pt[-1].n;
+	  mp_ptr p = pt[-1].p;
+	  p[n] = cy = mpn_mul_1 (p, p, n, big_base);
+	  n += cy != 0;
+
+	  ASSERT (pt[-1].digits_in_base + chars_per_limb == exptab[pi + 1]);
+	  pt[-1].digits_in_base = exptab[pi + 1];
+
+	  c = p[0] == 0;
+	  pt[-1].p = p + c;
+	  pt[-1].n = n - c;
+	  pt[-1].shift += c;
+	}
+
+      p = t;
+      pt++;
+    }
+}
+#endif
+
+#if DIV_1_VS_MUL_1_PERCENT < 275
+#define HAVE_mpn_compute_powtab_div 1
+static void
+mpn_compute_powtab_div (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un,
+			int base, const size_t *exptab, size_t n_pows)
+{
+  mp_ptr p, t;
+
+  mp_limb_t big_base = mp_bases[base].big_base;
+  int chars_per_limb = mp_bases[base].chars_per_limb;
+
+  mp_ptr powtab_mem_ptr = powtab_mem;
+
+  size_t digits_in_base = chars_per_limb;
+
+  powers_t *pt = powtab;
+
+  p = powtab_mem_ptr;
+  powtab_mem_ptr += 1;
+  p[0] = big_base;
+
+  SET_powers_t (pt[0], p, 1, digits_in_base, base, 0);
+  pt++;
+
+  mp_size_t n = 1;
+  mp_size_t shift = 0;
+  for (long pi = n_pows - 1; pi >= 0; pi--)
+    {
+      t = powtab_mem_ptr;
+      powtab_mem_ptr += 2 * n;
+
+      ASSERT (powtab_mem_ptr < powtab_mem + mpn_str_powtab_alloc (un));
+
+      mpn_sqr (t, p, n);
+      n = 2 * n - 1; n += t[n] != 0;
+      digits_in_base *= 2;
+
+      if (digits_in_base != exptab[pi])	/* if ((((un - 1) >> pi) & 2) == 0) */
+	{
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 || ! HAVE_NATIVE_mpn_divexact_1
+	  if (__GMP_LIKELY (base == 10))
+	    mpn_pi1_bdiv_q_1 (t, t, n, big_base >> MP_BASES_BIG_BASE_CTZ_10,
+			      MP_BASES_BIG_BASE_BINVERTED_10,
+			      MP_BASES_BIG_BASE_CTZ_10);
+	  else
+#endif
+	    /* FIXME: We could use _pi1 here if we add big_base_binverted and
+	       big_base_ctz fields to struct bases.  That would add about 2 KiB
+	       to mp_bases.c.
+	       FIXME: Use mpn_bdiv_q_1 here when mpn_divexact_1 is converted to
+	       mpn_bdiv_q_1 for more machines. */
+	    mpn_divexact_1 (t, t, n, big_base);
+
+	  n -= t[n - 1] == 0;
+	  digits_in_base -= chars_per_limb;
+	}
+
+      shift *= 2;
+      /* Strip low zero limbs, but be careful to keep the result divisible by
+	 big_base.  */
+      while (t[0] == 0 && (t[1] & ((big_base & -big_base) - 1)) == 0)
+	{
+	  t++;
+	  n--;
+	  shift++;
+	}
+      p = t;
+
+      SET_powers_t (pt[0], p, n, digits_in_base, base, shift);
+      pt++;
+    }
+
+  /* Strip any remaining low zero limbs.  */
+  pt -= n_pows + 1;
+  for (long pi = n_pows; pi >= 0; pi--)
+    {
+      mp_ptr t = pt[pi].p;
+      mp_size_t shift = pt[pi].shift;
+      mp_size_t n = pt[pi].n;
+      int c;
+      c = t[0] == 0;
+      t += c;
+      n -= c;
+      shift += c;
+      pt[pi].p = t;
+      pt[pi].shift = shift;
+      pt[pi].n = n;
+    }
+}
+#endif
+
+static long
+powtab_decide (size_t *exptab, size_t un, int base)
+{
+  int chars_per_limb = mp_bases[base].chars_per_limb;
+  long n_pows = 0;
+  for (size_t pn = (un + 1) >> 1; pn != 1; pn = (pn + 1) >> 1)
+    {
+      exptab[n_pows] = pn * chars_per_limb;
+      n_pows++;
+    }
+  exptab[n_pows] = chars_per_limb;
+
+#if HAVE_mpn_compute_powtab_mul && HAVE_mpn_compute_powtab_div
+  size_t pn = un - 1;
+  size_t xn = (un + 1) >> 1;
+  unsigned mcost = 1;
+  unsigned dcost = 1;
+  for (long i = n_pows - 2; i >= 0; i--)
+    {
+      size_t pow = (pn >> (i + 1)) + 1;
+
+      if (pow & 1)
+	dcost += pow;
+
+      if (xn != (pow << i))
+	{
+	  if (pow > 2 && (pow & 1) == 0)
+	    mcost += 2 * pow;
+	  else
+	    mcost += pow;
+	}
+      else
+	{
+	  if (pow & 1)
+	    mcost += pow;
+	}
+    }
+
+  dcost = dcost * DIV_1_VS_MUL_1_PERCENT / 100;
+
+  if (mcost <= dcost)
+    return n_pows;
+  else
+    return -n_pows;
+#elif HAVE_mpn_compute_powtab_mul
+  return n_pows;
+#elif HAVE_mpn_compute_powtab_div
+  return -n_pows;
+#else
+#error "no powtab function available"
+#endif
+}
+
+size_t
+mpn_compute_powtab (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un, int base)
+{
+  size_t exptab[GMP_LIMB_BITS];
+
+  long n_pows = powtab_decide (exptab, un, base);
+
+#if HAVE_mpn_compute_powtab_mul && HAVE_mpn_compute_powtab_div
+  if (n_pows >= 0)
+    {
+      mpn_compute_powtab_mul (powtab, powtab_mem, un, base, exptab, n_pows);
+      return n_pows;
+    }
+  else
+    {
+      mpn_compute_powtab_div (powtab, powtab_mem, un, base, exptab, -n_pows);
+      return -n_pows;
+    }
+#elif HAVE_mpn_compute_powtab_mul
+  ASSERT (n_pows > 0);
+  mpn_compute_powtab_mul (powtab, powtab_mem, un, base, exptab, n_pows);
+  return n_pows;
+#elif HAVE_mpn_compute_powtab_div
+  ASSERT (n_pows < 0);
+  mpn_compute_powtab_div (powtab, powtab_mem, un, base, exptab, -n_pows);
+  return -n_pows;
+#else
+#error "no powtab function available"
+#endif
+}
diff --git a/mpn/generic/copyd.c b/mpn/generic/copyd.c
new file mode 100644
index 0000000..7def007
--- /dev/null
+++ b/mpn/generic/copyd.c
@@ -0,0 +1,40 @@
+/* mpn_copyd
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_copyd (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+
+  for (i = n - 1; i >= 0; i--)
+    rp[i] = up[i];
+}
diff --git a/mpn/generic/copyi.c b/mpn/generic/copyi.c
new file mode 100644
index 0000000..736e0b5
--- /dev/null
+++ b/mpn/generic/copyi.c
@@ -0,0 +1,42 @@
+/* mpn_copyi
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_copyi (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+
+  up += n;
+  rp += n;
+  for (i = -n; i != 0; i++)
+    rp[i] = up[i];
+}
diff --git a/mpn/generic/dcpi1_bdiv_q.c b/mpn/generic/dcpi1_bdiv_q.c
new file mode 100644
index 0000000..3c21818
--- /dev/null
+++ b/mpn/generic/dcpi1_bdiv_q.c
@@ -0,0 +1,161 @@
+/* mpn_dcpi1_bdiv_q -- divide-and-conquer Hensel division with precomputed
+   inverse, returning quotient.
+
+   Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009-2011, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if 0				/* unused, so leave out for now */
+static mp_size_t
+mpn_dcpi1_bdiv_q_n_itch (mp_size_t n)
+{
+  /* NOTE: Depends on mullo_n and mpn_dcpi1_bdiv_qr_n interface */
+  return n;
+}
+#endif
+
+/* Computes Q = - N / D mod B^n, destroys N.
+
+   N = {np,n}
+   D = {dp,n}
+*/
+
+static void
+mpn_dcpi1_bdiv_q_n (mp_ptr qp,
+		    mp_ptr np, mp_srcptr dp, mp_size_t n,
+		    mp_limb_t dinv, mp_ptr tp)
+{
+  while (ABOVE_THRESHOLD (n, DC_BDIV_Q_THRESHOLD))
+    {
+      mp_size_t lo, hi;
+      mp_limb_t cy;
+
+      lo = n >> 1;			/* floor(n/2) */
+      hi = n - lo;			/* ceil(n/2) */
+
+      cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, lo, dinv, tp);
+
+      mpn_mullo_n (tp, qp, dp + hi, lo);
+      mpn_add_n (np + hi, np + hi, tp, lo);
+
+      if (lo < hi)
+	{
+	  cy += mpn_addmul_1 (np + lo, qp, lo, dp[lo]);
+	  np[n - 1] += cy;
+	}
+      qp += lo;
+      np += lo;
+      n -= lo;
+    }
+  mpn_sbpi1_bdiv_q (qp, np, n, dp, n, dinv);
+}
+
+/* Computes Q = - N / D mod B^nn, destroys N.
+
+   N = {np,nn}
+   D = {dp,dn}
+*/
+
+void
+mpn_dcpi1_bdiv_q (mp_ptr qp,
+		  mp_ptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn,
+		  mp_limb_t dinv)
+{
+  mp_size_t qn;
+  mp_limb_t cy;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 2);
+  ASSERT (nn - dn >= 0);
+  ASSERT (dp[0] & 1);
+
+  tp = TMP_SALLOC_LIMBS (dn);
+
+  qn = nn;
+
+  if (qn > dn)
+    {
+      /* Reduce qn mod dn in a super-efficient manner.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      /* Perform the typically smaller block first.  */
+      if (BELOW_THRESHOLD (qn, DC_BDIV_QR_THRESHOLD))
+	cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * qn, dp, qn, dinv);
+      else
+	cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, qn, dinv, tp);
+
+      if (qn != dn)
+	{
+	  if (qn > dn - qn)
+	    mpn_mul (tp, qp, qn, dp + qn, dn - qn);
+	  else
+	    mpn_mul (tp, dp + qn, dn - qn, qp, qn);
+	  mpn_incr_u (tp + qn, cy);
+
+	  mpn_add (np + qn, np + qn, nn - qn, tp, dn);
+	  cy = 0;
+	}
+
+      np += qn;
+      qp += qn;
+
+      qn = nn - qn;
+      while (qn > dn)
+	{
+	  mpn_add_1 (np + dn, np + dn, qn - dn, cy);
+	  cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, dn, dinv, tp);
+	  qp += dn;
+	  np += dn;
+	  qn -= dn;
+	}
+      mpn_dcpi1_bdiv_q_n (qp, np, dp, dn, dinv, tp);
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (qn, DC_BDIV_Q_THRESHOLD))
+	mpn_sbpi1_bdiv_q (qp, np, qn, dp, qn, dinv);
+      else
+	mpn_dcpi1_bdiv_q_n (qp, np, dp, qn, dinv, tp);
+    }
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/dcpi1_bdiv_qr.c b/mpn/generic/dcpi1_bdiv_qr.c
new file mode 100644
index 0000000..11da44f
--- /dev/null
+++ b/mpn/generic/dcpi1_bdiv_qr.c
@@ -0,0 +1,176 @@
+/* mpn_dcpi1_bdiv_qr -- divide-and-conquer Hensel division with precomputed
+   inverse, returning quotient and remainder.
+
+   Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2010, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes Hensel binary division of {np, 2*n} by {dp, n}.
+
+   Output:
+
+      q = -n * d^{-1} mod 2^{qn * GMP_NUMB_BITS},
+
+      r = (n + q * d) * 2^{-qn * GMP_NUMB_BITS}
+
+   Stores q at qp. Stores the n least significant limbs of r at the high half
+   of np, and returns the carry from the addition n + q*d.
+
+   d must be odd. dinv is (-d)^-1 mod 2^GMP_NUMB_BITS. */
+
+mp_size_t
+mpn_dcpi1_bdiv_qr_n_itch (mp_size_t n)
+{
+  return n;
+}
+
+mp_limb_t
+mpn_dcpi1_bdiv_qr_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
+		     mp_limb_t dinv, mp_ptr tp)
+{
+  mp_size_t lo, hi;
+  mp_limb_t cy;
+  mp_limb_t rh;
+
+  lo = n >> 1;			/* floor(n/2) */
+  hi = n - lo;			/* ceil(n/2) */
+
+  if (BELOW_THRESHOLD (lo, DC_BDIV_QR_THRESHOLD))
+    cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * lo, dp, lo, dinv);
+  else
+    cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, lo, dinv, tp);
+
+  mpn_mul (tp, dp + lo, hi, qp, lo);
+
+  mpn_incr_u (tp + lo, cy);
+  rh = mpn_add (np + lo, np + lo, n + hi, tp, n);
+
+  if (BELOW_THRESHOLD (hi, DC_BDIV_QR_THRESHOLD))
+    cy = mpn_sbpi1_bdiv_qr (qp + lo, np + lo, 2 * hi, dp, hi, dinv);
+  else
+    cy = mpn_dcpi1_bdiv_qr_n (qp + lo, np + lo, dp, hi, dinv, tp);
+
+  mpn_mul (tp, qp + lo, hi, dp + hi, lo);
+
+  mpn_incr_u (tp + hi, cy);
+  rh += mpn_add_n (np + n, np + n, tp, n);
+
+  return rh;
+}
+
+mp_limb_t
+mpn_dcpi1_bdiv_qr (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		   mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)
+{
+  mp_size_t qn;
+  mp_limb_t rr, cy;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 2);		/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (nn - dn >= 1);	/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (dp[0] & 1);
+
+  tp = TMP_SALLOC_LIMBS (dn);
+
+  qn = nn - dn;
+
+  if (qn > dn)
+    {
+      /* Reduce qn mod dn without division, optimizing small operations.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      /* Perform the typically smaller block first.  */
+      if (BELOW_THRESHOLD (qn, DC_BDIV_QR_THRESHOLD))
+	cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * qn, dp, qn, dinv);
+      else
+	cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, qn, dinv, tp);
+
+      rr = 0;
+      if (qn != dn)
+	{
+	  if (qn > dn - qn)
+	    mpn_mul (tp, qp, qn, dp + qn, dn - qn);
+	  else
+	    mpn_mul (tp, dp + qn, dn - qn, qp, qn);
+	  mpn_incr_u (tp + qn, cy);
+
+	  rr = mpn_add (np + qn, np + qn, nn - qn, tp, dn);
+	  cy = 0;
+	}
+
+      np += qn;
+      qp += qn;
+
+      qn = nn - dn - qn;
+      do
+	{
+	  rr += mpn_add_1 (np + dn, np + dn, qn, cy);
+	  cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, dn, dinv, tp);
+	  qp += dn;
+	  np += dn;
+	  qn -= dn;
+	}
+      while (qn > 0);
+      TMP_FREE;
+      return rr + cy;
+    }
+
+  if (BELOW_THRESHOLD (qn, DC_BDIV_QR_THRESHOLD))
+    cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * qn, dp, qn, dinv);
+  else
+    cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, qn, dinv, tp);
+
+  rr = 0;
+  if (qn != dn)
+    {
+      if (qn > dn - qn)
+	mpn_mul (tp, qp, qn, dp + qn, dn - qn);
+      else
+	mpn_mul (tp, dp + qn, dn - qn, qp, qn);
+      mpn_incr_u (tp + qn, cy);
+
+      rr = mpn_add (np + qn, np + qn, nn - qn, tp, dn);
+      cy = 0;
+    }
+
+  TMP_FREE;
+  return rr + cy;
+}
diff --git a/mpn/generic/dcpi1_div_q.c b/mpn/generic/dcpi1_div_q.c
new file mode 100644
index 0000000..1905c98
--- /dev/null
+++ b/mpn/generic/dcpi1_div_q.c
@@ -0,0 +1,86 @@
+/* mpn_dc_div_q -- divide-and-conquer division, returning exact quotient
+   only.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+mp_limb_t
+mpn_dcpi1_div_q (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		 mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv)
+{
+  mp_ptr tp, wp;
+  mp_limb_t qh;
+  mp_size_t qn;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 6);
+  ASSERT (nn - dn >= 3);
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+
+  tp = TMP_ALLOC_LIMBS (nn + 1);
+  MPN_COPY (tp + 1, np, nn);
+  tp[0] = 0;
+
+  qn = nn - dn;
+  wp = TMP_ALLOC_LIMBS (qn + 1);
+
+  qh = mpn_dcpi1_divappr_q (wp, tp, nn + 1, dp, dn, dinv);
+
+  if (wp[0] == 0)
+    {
+      mp_limb_t cy;
+
+      if (qn > dn)
+	mpn_mul (tp, wp + 1, qn, dp, dn);
+      else
+	mpn_mul (tp, dp, dn, wp + 1, qn);
+
+      cy = (qh != 0) ? mpn_add_n (tp + qn, tp + qn, dp, dn) : 0;
+
+      if (cy || mpn_cmp (tp, np, nn) > 0) /* At most is wrong by one, no cycle. */
+	qh -= mpn_sub_1 (qp, wp + 1, qn, 1);
+      else /* Same as below */
+	MPN_COPY (qp, wp + 1, qn);
+    }
+  else
+    MPN_COPY (qp, wp + 1, qn);
+
+  TMP_FREE;
+  return qh;
+}
diff --git a/mpn/generic/dcpi1_div_qr.c b/mpn/generic/dcpi1_div_qr.c
new file mode 100644
index 0000000..d7a65f8
--- /dev/null
+++ b/mpn/generic/dcpi1_div_qr.c
@@ -0,0 +1,248 @@
+/* mpn_dcpi1_div_qr_n -- recursive divide-and-conquer division for arbitrary
+   size operands.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+mp_limb_t
+mpn_dcpi1_div_qr_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
+		    gmp_pi1_t *dinv, mp_ptr tp)
+{
+  mp_size_t lo, hi;
+  mp_limb_t cy, qh, ql;
+
+  lo = n >> 1;			/* floor(n/2) */
+  hi = n - lo;			/* ceil(n/2) */
+
+  if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
+    qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
+  else
+    qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
+
+  mpn_mul (tp, qp + lo, hi, dp, lo);
+
+  cy = mpn_sub_n (np + lo, np + lo, tp, n);
+  if (qh != 0)
+    cy += mpn_sub_n (np + n, np + n, dp, lo);
+
+  while (cy != 0)
+    {
+      qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
+      cy -= mpn_add_n (np + lo, np + lo, dp, n);
+    }
+
+  if (BELOW_THRESHOLD (lo, DC_DIV_QR_THRESHOLD))
+    ql = mpn_sbpi1_div_qr (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
+  else
+    ql = mpn_dcpi1_div_qr_n (qp, np + hi, dp + hi, lo, dinv, tp);
+
+  mpn_mul (tp, dp, hi, qp, lo);
+
+  cy = mpn_sub_n (np, np, tp, n);
+  if (ql != 0)
+    cy += mpn_sub_n (np + lo, np + lo, dp, hi);
+
+  while (cy != 0)
+    {
+      mpn_sub_1 (qp, qp, lo, 1);
+      cy -= mpn_add_n (np, np, dp, n);
+    }
+
+  return qh;
+}
+
+mp_limb_t
+mpn_dcpi1_div_qr (mp_ptr qp,
+		  mp_ptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn,
+		  gmp_pi1_t *dinv)
+{
+  mp_size_t qn;
+  mp_limb_t qh, cy;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 6);		/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (nn - dn >= 3);	/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+
+  tp = TMP_ALLOC_LIMBS (dn);
+
+  qn = nn - dn;
+  qp += qn;
+  np += nn;
+  dp += dn;
+
+  if (qn > dn)
+    {
+      /* Reduce qn mod dn without division, optimizing small operations.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      /* Perform the typically smaller block first.  */
+      if (qn == 1)
+	{
+	  mp_limb_t q, n2, n1, n0, d1, d0;
+
+	  /* Handle qh up front, for simplicity. */
+	  qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
+	  if (qh)
+	    ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn));
+
+	  /* A single iteration of schoolbook: One 3/2 division,
+	     followed by the bignum update and adjustment. */
+	  n2 = np[0];
+	  n1 = np[-1];
+	  n0 = np[-2];
+	  d1 = dp[-1];
+	  d0 = dp[-2];
+
+	  ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
+
+	  if (UNLIKELY (n2 == d1) && n1 == d0)
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp - dn, dn, q);
+	      ASSERT (cy == n2);
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
+
+	      if (dn > 2)
+		{
+		  mp_limb_t cy, cy1;
+		  cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
+
+		  cy1 = n0 < cy;
+		  n0 = (n0 - cy) & GMP_NUMB_MASK;
+		  cy = n1 < cy1;
+		  n1 = (n1 - cy1) & GMP_NUMB_MASK;
+		  np[-2] = n0;
+
+		  if (UNLIKELY (cy != 0))
+		    {
+		      n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
+		      qh -= (q == 0);
+		      q = (q - 1) & GMP_NUMB_MASK;
+		    }
+		}
+	      else
+		np[-2] = n0;
+
+	      np[-1] = n1;
+	    }
+	  qp[0] = q;
+	}
+      else
+	{
+	  /* Do a 2qn / qn division */
+	  if (qn == 2)
+	    qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2); /* FIXME: obsolete function. Use 5/3 division? */
+	  else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+	    qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
+	  else
+	    qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
+
+	  if (qn != dn)
+	    {
+	      if (qn > dn - qn)
+		mpn_mul (tp, qp, qn, dp - dn, dn - qn);
+	      else
+		mpn_mul (tp, dp - dn, dn - qn, qp, qn);
+
+	      cy = mpn_sub_n (np - dn, np - dn, tp, dn);
+	      if (qh != 0)
+		cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
+
+	      while (cy != 0)
+		{
+		  qh -= mpn_sub_1 (qp, qp, qn, 1);
+		  cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
+		}
+	    }
+	}
+
+      qn = nn - dn - qn;
+      do
+	{
+	  qp -= dn;
+	  np -= dn;
+	  mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
+	  qn -= dn;
+	}
+      while (qn > 0);
+    }
+  else
+    {
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+	qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
+      else
+	qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
+
+      if (qn != dn)
+	{
+	  if (qn > dn - qn)
+	    mpn_mul (tp, qp, qn, dp - dn, dn - qn);
+	  else
+	    mpn_mul (tp, dp - dn, dn - qn, qp, qn);
+
+	  cy = mpn_sub_n (np - dn, np - dn, tp, dn);
+	  if (qh != 0)
+	    cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
+
+	  while (cy != 0)
+	    {
+	      qh -= mpn_sub_1 (qp, qp, qn, 1);
+	      cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
+	    }
+	}
+    }
+
+  TMP_FREE;
+  return qh;
+}
diff --git a/mpn/generic/dcpi1_divappr_q.c b/mpn/generic/dcpi1_divappr_q.c
new file mode 100644
index 0000000..0abe04e
--- /dev/null
+++ b/mpn/generic/dcpi1_divappr_q.c
@@ -0,0 +1,256 @@
+/* mpn_dcpi1_divappr_q -- divide-and-conquer division, returning approximate
+   quotient.  The quotient returned is either correct, or one too large.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+static mp_limb_t
+mpn_dcpi1_divappr_q_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
+		       gmp_pi1_t *dinv, mp_ptr tp)
+{
+  mp_size_t lo, hi;
+  mp_limb_t cy, qh, ql;
+
+  lo = n >> 1;			/* floor(n/2) */
+  hi = n - lo;			/* ceil(n/2) */
+
+  if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
+    qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
+  else
+    qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
+
+  mpn_mul (tp, qp + lo, hi, dp, lo);
+
+  cy = mpn_sub_n (np + lo, np + lo, tp, n);
+  if (qh != 0)
+    cy += mpn_sub_n (np + n, np + n, dp, lo);
+
+  while (cy != 0)
+    {
+      qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
+      cy -= mpn_add_n (np + lo, np + lo, dp, n);
+    }
+
+  if (BELOW_THRESHOLD (lo, DC_DIVAPPR_Q_THRESHOLD))
+    ql = mpn_sbpi1_divappr_q (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
+  else
+    ql = mpn_dcpi1_divappr_q_n (qp, np + hi, dp + hi, lo, dinv, tp);
+
+  if (UNLIKELY (ql != 0))
+    {
+      mp_size_t i;
+      for (i = 0; i < lo; i++)
+	qp[i] = GMP_NUMB_MASK;
+    }
+
+  return qh;
+}
+
+mp_limb_t
+mpn_dcpi1_divappr_q (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		     mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv)
+{
+  mp_size_t qn;
+  mp_limb_t qh, cy, qsave;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 6);
+  ASSERT (nn > dn);
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+
+  qn = nn - dn;
+  qp += qn;
+  np += nn;
+  dp += dn;
+
+  if (qn >= dn)
+    {
+      qn++;			/* pretend we'll need an extra limb */
+      /* Reduce qn mod dn without division, optimizing small operations.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      tp = TMP_SALLOC_LIMBS (dn);
+
+      /* Perform the typically smaller block first.  */
+      if (qn == 1)
+	{
+	  mp_limb_t q, n2, n1, n0, d1, d0;
+
+	  /* Handle qh up front, for simplicity. */
+	  qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
+	  if (qh)
+	    ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn));
+
+	  /* A single iteration of schoolbook: One 3/2 division,
+	     followed by the bignum update and adjustment. */
+	  n2 = np[0];
+	  n1 = np[-1];
+	  n0 = np[-2];
+	  d1 = dp[-1];
+	  d0 = dp[-2];
+
+	  ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
+
+	  if (UNLIKELY (n2 == d1) && n1 == d0)
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp - dn, dn, q);
+	      ASSERT (cy == n2);
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
+
+	      if (dn > 2)
+		{
+		  mp_limb_t cy, cy1;
+		  cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
+
+		  cy1 = n0 < cy;
+		  n0 = (n0 - cy) & GMP_NUMB_MASK;
+		  cy = n1 < cy1;
+		  n1 = (n1 - cy1) & GMP_NUMB_MASK;
+		  np[-2] = n0;
+
+		  if (UNLIKELY (cy != 0))
+		    {
+		      n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
+		      qh -= (q == 0);
+		      q = (q - 1) & GMP_NUMB_MASK;
+		    }
+		}
+	      else
+		np[-2] = n0;
+
+	      np[-1] = n1;
+	    }
+	  qp[0] = q;
+	}
+      else
+	{
+	  if (qn == 2)
+	    qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2);
+	  else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+	    qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
+	  else
+	    qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
+
+	  if (qn != dn)
+	    {
+	      if (qn > dn - qn)
+		mpn_mul (tp, qp, qn, dp - dn, dn - qn);
+	      else
+		mpn_mul (tp, dp - dn, dn - qn, qp, qn);
+
+	      cy = mpn_sub_n (np - dn, np - dn, tp, dn);
+	      if (qh != 0)
+		cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
+
+	      while (cy != 0)
+		{
+		  qh -= mpn_sub_1 (qp, qp, qn, 1);
+		  cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
+		}
+	    }
+	}
+      qn = nn - dn - qn + 1;
+      while (qn > dn)
+	{
+	  qp -= dn;
+	  np -= dn;
+	  mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
+	  qn -= dn;
+	}
+
+      /* Since we pretended we'd need an extra quotient limb before, we now
+	 have made sure the code above left just dn-1=qn quotient limbs to
+	 develop.  Develop that plus a guard limb. */
+      qn--;
+      qp -= qn;
+      np -= dn;
+      qsave = qp[qn];
+      mpn_dcpi1_divappr_q_n (qp, np - dn, dp - dn, dn, dinv, tp);
+      MPN_COPY_INCR (qp, qp + 1, qn);
+      qp[qn] = qsave;
+    }
+  else    /* (qn < dn) */
+    {
+      mp_ptr q2p;
+#if 0				/* not possible since we demand nn > dn */
+      if (qn == 0)
+	{
+	  qh = mpn_cmp (np - dn, dp - dn, dn) >= 0;
+	  if (qh)
+	    mpn_sub_n (np - dn, np - dn, dp - dn, dn);
+	  TMP_FREE;
+	  return qh;
+	}
+#endif
+
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      q2p = TMP_SALLOC_LIMBS (qn + 1);
+      /* Should we at all check DC_DIVAPPR_Q_THRESHOLD here, or reply on
+	 callers not to be silly?  */
+      if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD))
+	{
+	  qh = mpn_sbpi1_divappr_q (q2p, np - qn - 2, 2 * (qn + 1),
+				    dp - (qn + 1), qn + 1, dinv->inv32);
+	}
+      else
+	{
+	  /* It is tempting to use qp for recursive scratch and put quotient in
+	     tp, but the recursive scratch needs one limb too many.  */
+	  tp = TMP_SALLOC_LIMBS (qn + 1);
+	  qh = mpn_dcpi1_divappr_q_n (q2p, np - qn - 2, dp - (qn + 1), qn + 1, dinv, tp);
+	}
+      MPN_COPY (qp, q2p + 1, qn);
+    }
+
+  TMP_FREE;
+  return qh;
+}
diff --git a/mpn/generic/div_q.c b/mpn/generic/div_q.c
new file mode 100644
index 0000000..18c4ecf
--- /dev/null
+++ b/mpn/generic/div_q.c
@@ -0,0 +1,313 @@
+/* mpn_div_q -- division for arbitrary size operands.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2009, 2010, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Compute Q = N/D with truncation.
+     N = {np,nn}
+     D = {dp,dn}
+     Q = {qp,nn-dn+1}
+     T = {scratch,nn+1} is scratch space
+   N and D are both untouched by the computation.
+   N and T may overlap; pass the same space if N is irrelevant after the call,
+   but note that tp needs an extra limb.
+
+   Operand requirements:
+     N >= D > 0
+     dp[dn-1] != 0
+     No overlap between the N, D, and Q areas.
+
+   This division function does not clobber its input operands, since it is
+   intended to support average-O(qn) division, and for that to be effective, it
+   cannot put requirements on callers to copy a O(nn) operand.
+
+   If a caller does not care about the value of {np,nn+1} after calling this
+   function, it should pass np also for the scratch argument.  This function
+   will then save some time and space by avoiding allocation and copying.
+   (FIXME: Is this a good design?  We only really save any copying for
+   already-normalised divisors, which should be rare.  It also prevents us from
+   reasonably asking for all scratch space we need.)
+
+   We write nn-dn+1 limbs for the quotient, but return void.  Why not return
+   the most significant quotient limb?  Look at the 4 main code blocks below
+   (consisting of an outer if-else where each arm contains an if-else). It is
+   tricky for the first code block, since the mpn_*_div_q calls will typically
+   generate all nn-dn+1 and return 0 or 1.  I don't see how to fix that unless
+   we generate the most significant quotient limb here, before calling
+   mpn_*_div_q, or put the quotient in a temporary area.  Since this is a
+   critical division case (the SB sub-case in particular) copying is not a good
+   idea.
+
+   It might make sense to split the if-else parts of the (qn + FUDGE
+   >= dn) blocks into separate functions, since we could promise quite
+   different things to callers in these two cases.  The 'then' case
+   benefits from np=scratch, and it could perhaps even tolerate qp=np,
+   saving some headache for many callers.
+
+   FIXME: Scratch allocation leaves a lot to be desired.  E.g., for the MU size
+   operands, we do not reuse the huge scratch for adjustments.  This can be a
+   serious waste of memory for the largest operands.
+*/
+
+/* FUDGE determines when to try getting an approximate quotient from the upper
+   parts of the dividend and divisor, then adjust.  N.B. FUDGE must be >= 2
+   for the code to be correct.  */
+#define FUDGE 5			/* FIXME: tune this */
+
+#define DC_DIV_Q_THRESHOLD      DC_DIVAPPR_Q_THRESHOLD
+#define MU_DIV_Q_THRESHOLD      MU_DIVAPPR_Q_THRESHOLD
+#define MUPI_DIV_Q_THRESHOLD  MUPI_DIVAPPR_Q_THRESHOLD
+#ifndef MUPI_DIVAPPR_Q_THRESHOLD
+#define MUPI_DIVAPPR_Q_THRESHOLD  MUPI_DIV_QR_THRESHOLD
+#endif
+
+void
+mpn_div_q (mp_ptr qp,
+	   mp_srcptr np, mp_size_t nn,
+	   mp_srcptr dp, mp_size_t dn, mp_ptr scratch)
+{
+  mp_ptr new_dp, new_np, tp, rp;
+  mp_limb_t cy, dh, qh;
+  mp_size_t new_nn, qn;
+  gmp_pi1_t dinv;
+  int cnt;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (nn >= dn);
+  ASSERT (dn > 0);
+  ASSERT (dp[dn - 1] != 0);
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1, np, nn));
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1, dp, dn));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (np, scratch, nn));
+
+  ASSERT_ALWAYS (FUDGE >= 2);
+
+  dh = dp[dn - 1];
+  if (dn == 1)
+    {
+      mpn_divrem_1 (qp, 0L, np, nn, dh);
+      return;
+    }
+
+  qn = nn - dn + 1;		/* Quotient size, high limb might be zero */
+
+  if (qn + FUDGE >= dn)
+    {
+      /* |________________________|
+                          |_______|  */
+      new_np = scratch;
+
+      if (LIKELY ((dh & GMP_NUMB_HIGHBIT) == 0))
+	{
+	  count_leading_zeros (cnt, dh);
+
+	  cy = mpn_lshift (new_np, np, nn, cnt);
+	  new_np[nn] = cy;
+	  new_nn = nn + (cy != 0);
+
+	  new_dp = TMP_ALLOC_LIMBS (dn);
+	  mpn_lshift (new_dp, dp, dn, cnt);
+
+	  if (dn == 2)
+	    {
+	      qh = mpn_divrem_2 (qp, 0L, new_np, new_nn, new_dp);
+	    }
+	  else if (BELOW_THRESHOLD (dn, DC_DIV_Q_THRESHOLD) ||
+		   BELOW_THRESHOLD (new_nn - dn, DC_DIV_Q_THRESHOLD))
+	    {
+	      invert_pi1 (dinv, new_dp[dn - 1], new_dp[dn - 2]);
+	      qh = mpn_sbpi1_div_q (qp, new_np, new_nn, new_dp, dn, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (dn, MUPI_DIV_Q_THRESHOLD) ||   /* fast condition */
+		   BELOW_THRESHOLD (nn, 2 * MU_DIV_Q_THRESHOLD) || /* fast condition */
+		   (double) (2 * (MU_DIV_Q_THRESHOLD - MUPI_DIV_Q_THRESHOLD)) * dn /* slow... */
+		   + (double) MUPI_DIV_Q_THRESHOLD * nn > (double) dn * nn)   /* ...condition */
+	    {
+	      invert_pi1 (dinv, new_dp[dn - 1], new_dp[dn - 2]);
+	      qh = mpn_dcpi1_div_q (qp, new_np, new_nn, new_dp, dn, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_div_q_itch (new_nn, dn, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_div_q (qp, new_np, new_nn, new_dp, dn, scratch);
+	    }
+	  if (cy == 0)
+	    qp[qn - 1] = qh;
+	  else
+	    ASSERT (qh == 0);
+	}
+      else  /* divisor is already normalised */
+	{
+	  if (new_np != np)
+	    MPN_COPY (new_np, np, nn);
+
+	  if (dn == 2)
+	    {
+	      qh = mpn_divrem_2 (qp, 0L, new_np, nn, dp);
+	    }
+	  else if (BELOW_THRESHOLD (dn, DC_DIV_Q_THRESHOLD) ||
+		   BELOW_THRESHOLD (nn - dn, DC_DIV_Q_THRESHOLD))
+	    {
+	      invert_pi1 (dinv, dh, dp[dn - 2]);
+	      qh = mpn_sbpi1_div_q (qp, new_np, nn, dp, dn, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (dn, MUPI_DIV_Q_THRESHOLD) ||   /* fast condition */
+		   BELOW_THRESHOLD (nn, 2 * MU_DIV_Q_THRESHOLD) || /* fast condition */
+		   (double) (2 * (MU_DIV_Q_THRESHOLD - MUPI_DIV_Q_THRESHOLD)) * dn /* slow... */
+		   + (double) MUPI_DIV_Q_THRESHOLD * nn > (double) dn * nn)   /* ...condition */
+	    {
+	      invert_pi1 (dinv, dh, dp[dn - 2]);
+	      qh = mpn_dcpi1_div_q (qp, new_np, nn, dp, dn, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_div_q_itch (nn, dn, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_div_q (qp, np, nn, dp, dn, scratch);
+	    }
+	  qp[nn - dn] = qh;
+	}
+    }
+  else
+    {
+      /* |________________________|
+                |_________________|  */
+      tp = TMP_ALLOC_LIMBS (qn + 1);
+
+      new_np = scratch;
+      new_nn = 2 * qn + 1;
+      if (new_np == np)
+	/* We need {np,nn} to remain untouched until the final adjustment, so
+	   we need to allocate separate space for new_np.  */
+	new_np = TMP_ALLOC_LIMBS (new_nn + 1);
+
+
+      if (LIKELY ((dh & GMP_NUMB_HIGHBIT) == 0))
+	{
+	  count_leading_zeros (cnt, dh);
+
+	  cy = mpn_lshift (new_np, np + nn - new_nn, new_nn, cnt);
+	  new_np[new_nn] = cy;
+
+	  new_nn += (cy != 0);
+
+	  new_dp = TMP_ALLOC_LIMBS (qn + 1);
+	  mpn_lshift (new_dp, dp + dn - (qn + 1), qn + 1, cnt);
+	  new_dp[0] |= dp[dn - (qn + 1) - 1] >> (GMP_NUMB_BITS - cnt);
+
+	  if (qn + 1 == 2)
+	    {
+	      qh = mpn_divrem_2 (tp, 0L, new_np, new_nn, new_dp);
+	    }
+	  else if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, new_dp[qn], new_dp[qn - 1]);
+	      qh = mpn_sbpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (qn, MU_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, new_dp[qn], new_dp[qn - 1]);
+	      qh = mpn_dcpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_divappr_q_itch (new_nn, qn + 1, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, scratch);
+	    }
+	  if (cy == 0)
+	    tp[qn] = qh;
+	  else if (UNLIKELY (qh != 0))
+	    {
+	      /* This happens only when the quotient is close to B^n and
+		 mpn_*_divappr_q returned B^n.  */
+	      mp_size_t i, n;
+	      n = new_nn - (qn + 1);
+	      for (i = 0; i < n; i++)
+		tp[i] = GMP_NUMB_MAX;
+	      qh = 0;		/* currently ignored */
+	    }
+	}
+      else  /* divisor is already normalised */
+	{
+	  MPN_COPY (new_np, np + nn - new_nn, new_nn); /* pointless if MU will be used */
+
+	  new_dp = (mp_ptr) dp + dn - (qn + 1);
+
+	  if (qn == 2 - 1)
+	    {
+	      qh = mpn_divrem_2 (tp, 0L, new_np, new_nn, new_dp);
+	    }
+	  else if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, dh, new_dp[qn - 1]);
+	      qh = mpn_sbpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (qn, MU_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, dh, new_dp[qn - 1]);
+	      qh = mpn_dcpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_divappr_q_itch (new_nn, qn + 1, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, scratch);
+	    }
+	  tp[qn] = qh;
+	}
+
+      MPN_COPY (qp, tp + 1, qn);
+      if (tp[0] <= 4)
+        {
+	  mp_size_t rn;
+
+          rp = TMP_ALLOC_LIMBS (dn + qn);
+          mpn_mul (rp, dp, dn, tp + 1, qn);
+	  rn = dn + qn;
+	  rn -= rp[rn - 1] == 0;
+
+          if (rn > nn || mpn_cmp (np, rp, nn) < 0)
+            MPN_DECR_U (qp, qn, 1);
+        }
+    }
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/div_qr_1.c b/mpn/generic/div_qr_1.c
new file mode 100644
index 0000000..8f80d37
--- /dev/null
+++ b/mpn/generic/div_qr_1.c
@@ -0,0 +1,125 @@
+/* mpn_div_qr_1 -- mpn by limb division.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund
+
+Copyright 1991, 1993, 1994, 1996, 1998-2000, 2002, 2003, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef DIV_QR_1_NORM_THRESHOLD
+#define DIV_QR_1_NORM_THRESHOLD 3
+#endif
+#ifndef DIV_QR_1_UNNORM_THRESHOLD
+#define DIV_QR_1_UNNORM_THRESHOLD 3
+#endif
+
+#if GMP_NAIL_BITS > 0
+#error Nail bits not supported
+#endif
+
+/* Divides {up, n} by d. Writes the n-1 low quotient limbs at {qp,
+ * n-1}, and the high quotient limb at *qh. Returns remainder. */
+mp_limb_t
+mpn_div_qr_1 (mp_ptr qp, mp_limb_t *qh, mp_srcptr up, mp_size_t n,
+	      mp_limb_t d)
+{
+  unsigned cnt;
+  mp_limb_t uh;
+
+  ASSERT (n > 0);
+  ASSERT (d > 0);
+
+  if (d & GMP_NUMB_HIGHBIT)
+    {
+      /* Normalized case */
+      mp_limb_t dinv, q;
+
+      uh = up[--n];
+
+      q = (uh >= d);
+      *qh = q;
+      uh -= (-q) & d;
+
+      if (BELOW_THRESHOLD (n, DIV_QR_1_NORM_THRESHOLD))
+	{
+	  cnt = 0;
+	plain:
+	  while (n > 0)
+	    {
+	      mp_limb_t ul = up[--n];
+	      udiv_qrnnd (qp[n], uh, uh, ul, d);
+	    }
+	  return uh >> cnt;
+	}
+      invert_limb (dinv, d);
+      return mpn_div_qr_1n_pi1 (qp, up, n, uh, d, dinv);
+    }
+  else
+    {
+      /* Unnormalized case */
+      mp_limb_t dinv, ul;
+
+      if (! UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIV_QR_1_UNNORM_THRESHOLD))
+	{
+	  uh = up[--n];
+	  udiv_qrnnd (*qh, uh, CNST_LIMB(0), uh, d);
+	  cnt = 0;
+	  goto plain;
+	}
+
+      count_leading_zeros (cnt, d);
+      d <<= cnt;
+
+#if HAVE_NATIVE_mpn_div_qr_1u_pi1
+      /* FIXME: Call loop doing on-the-fly normalization */
+#endif
+
+      /* Shift up front, use qp area for shifted copy. A bit messy,
+	 since we have only n-1 limbs available, and shift the high
+	 limb manually. */
+      uh = up[--n];
+      ul = (uh << cnt) | mpn_lshift (qp, up, n, cnt);
+      uh >>= (GMP_LIMB_BITS - cnt);
+
+      if (UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIV_QR_1_UNNORM_THRESHOLD))
+	{
+	  udiv_qrnnd (*qh, uh, uh, ul, d);
+	  up = qp;
+	  goto plain;
+	}
+      invert_limb (dinv, d);
+
+      udiv_qrnnd_preinv (*qh, uh, uh, ul, d, dinv);
+      return mpn_div_qr_1n_pi1 (qp, qp, n, uh, d, dinv) >> cnt;
+    }
+}
diff --git a/mpn/generic/div_qr_1n_pi1.c b/mpn/generic/div_qr_1n_pi1.c
new file mode 100644
index 0000000..4977131
--- /dev/null
+++ b/mpn/generic/div_qr_1n_pi1.c
@@ -0,0 +1,505 @@
+/* mpn_div_qr_1n_pi1
+
+   Contributed to the GNU project by Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if GMP_NAIL_BITS > 0
+#error Nail bits not supported
+#endif
+
+#ifndef DIV_QR_1N_METHOD
+#define DIV_QR_1N_METHOD 2
+#endif
+
+/* FIXME: Duplicated in mod_1_1.c. Move to gmp-impl.h */
+
+#if defined (__GNUC__) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %k2\n\t"					\
+	     "adc	%4, %k1\n\t"					\
+	     "sbb	%k0, %k0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_x86_64 && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %q2\n\t"					\
+	     "adc	%4, %q1\n\t"					\
+	     "sbb	%q0, %q0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxcc	%r3, %4, %1\n\t"				\
+	     "subx	%%g0, %%g0, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addccc	%r7, %8, %%g0\n\t"				\
+	     "addccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl),		\
+	     "rJ" ((al) >> 32), "rI" ((bl) >> 32)			\
+	 __CLOBBER_CC)
+#if __VIS__ >= 0x300
+#undef add_mssaaaa
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add%I6c	%2, %5, %6\n\t"					\
+	     "adde	%1, %3, %4\n\t"					\
+	     "subfe	%0, %0, %0\n\t"					\
+	     "nor	%0, %0, %0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)			\
+	     __CLOBBER_CC)
+#endif
+
+#if defined (__s390x__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "algr	%2, %6\n\t"					\
+	     "alcgr	%1, %4\n\t"					\
+	     "lghi	%0, 0\n\t"					\
+	     "alcgr	%0, %0\n\t"					\
+	     "lcgr	%0, %0"						\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "r" ((UDItype)(b1)),			\
+	     "%2" ((UDItype)(a0)), "r" ((UDItype)(b0)) __CLOBBER_CC)
+#endif
+
+#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "adds	%2, %5, %6\n\t"					\
+	     "adcs	%1, %3, %4\n\t"					\
+	     "movcc	%0, #0\n\t"					\
+	     "movcs	%0, #-1"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC)
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "adds	%2, %x5, %6\n\t"				\
+	     "adcs	%1, %x3, %x4\n\t"				\
+	     "csinv	%0, xzr, xzr, cc\n\t"				\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rZ" (ah), "rZ" (bh), "%rZ" (al), "rI" (bl) __CLOBBER_CC)
+#endif
+#endif /* defined (__GNUC__) */
+
+#ifndef add_mssaaaa
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (m) = - (__c1 + (__s1 < __c0));					\
+  } while (0)
+#endif
+
+#if DIV_QR_1N_METHOD == 1
+
+/* Divides (uh B^n + {up, n}) by d, storing the quotient at {qp, n}.
+   Requires that uh < d. */
+mp_limb_t
+mpn_div_qr_1n_pi1 (mp_ptr qp, mp_srcptr up, mp_size_t n, mp_limb_t uh,
+		   mp_limb_t d, mp_limb_t dinv)
+{
+  ASSERT (n > 0);
+  ASSERT (uh < d);
+  ASSERT (d & GMP_NUMB_HIGHBIT);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp, up, n));
+
+  do
+    {
+      mp_limb_t q, ul;
+
+      ul = up[--n];
+      udiv_qrnnd_preinv (q, uh, uh, ul, d, dinv);
+      qp[n] = q;
+    }
+  while (n > 0);
+
+  return uh;
+}
+
+#elif DIV_QR_1N_METHOD == 2
+
+/* The main idea of this algorithm is to write B^2 = d (B + dinv) +
+   B2, where 1 <= B2 < d. Similarly to mpn_mod_1_1p, each iteration
+   can then replace
+
+     u1 B^2 = u1 B2 (mod d)
+
+   which gives a very short critical path for computing the remainder
+   (with some tricks to handle the carry when the next two lower limbs
+   are added in). To also get the quotient, include the corresponding
+   multiple of d in the expression,
+
+     u1 B^2 = u1 B2 + (u1 dinv + u1 B) d
+
+   We get the quotient by accumulating the (u1 dinv + u1 B) terms. The
+   two multiplies, u1 * B2 and u1 * dinv, are independent, and can be
+   executed in parallel.
+ */
+mp_limb_t
+mpn_div_qr_1n_pi1 (mp_ptr qp, mp_srcptr up, mp_size_t n, mp_limb_t u1,
+		   mp_limb_t d, mp_limb_t dinv)
+{
+  mp_limb_t B2;
+  mp_limb_t u0, u2;
+  mp_limb_t q0, q1;
+  mp_limb_t p0, p1;
+  mp_limb_t t;
+  mp_size_t j;
+
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+  ASSERT (n > 0);
+  ASSERT (u1 < d);
+
+  if (n == 1)
+    {
+      udiv_qrnnd_preinv (qp[0], u1, u1, up[0], d, dinv);
+      return u1;
+    }
+
+  /* FIXME: Could be precomputed */
+  B2 = -d*dinv;
+
+  umul_ppmm (q1, q0, dinv, u1);
+  umul_ppmm (p1, p0, B2, u1);
+  q1 += u1;
+  ASSERT (q1 >= u1);
+  u0 = up[n-1];	/* Early read, to allow qp == up. */
+  qp[n-1] = q1;
+
+  add_mssaaaa (u2, u1, u0, u0, up[n-2], p1, p0);
+
+  /* FIXME: Keep q1 in a variable between iterations, to reduce number
+     of memory accesses. */
+  for (j = n-2; j-- > 0; )
+    {
+      mp_limb_t q2, cy;
+
+      /* Additions for the q update:
+       *	+-------+
+       *        |u1 * v |
+       *        +---+---+
+       *        | u1|
+       *    +---+---+
+       *    | 1 | v |  (conditional on u2)
+       *    +---+---+
+       *        | 1 |  (conditional on u0 + u2 B2 carry)
+       *        +---+
+       * +      | q0|
+       *   -+---+---+---+
+       *    | q2| q1| q0|
+       *    +---+---+---+
+      */
+      umul_ppmm (p1, t, u1, dinv);
+      ADDC_LIMB (cy, u0, u0, u2 & B2);
+      u0 -= (-cy) & d;
+      add_ssaaaa (q2, q1, -u2, u2 & dinv, CNST_LIMB(0), u1);
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), q0);
+      q0 = t;
+
+      /* Note that p1 + cy cannot overflow */
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), p1 + cy);
+
+      umul_ppmm (p1, p0, u1, B2);
+
+      qp[j+1] = q1;
+      MPN_INCR_U (qp+j+2, n-j-2, q2);
+
+      add_mssaaaa (u2, u1, u0, u0, up[j], p1, p0);
+    }
+
+  q1 = (u2 > 0);
+  u1 -= (-q1) & d;
+
+  t = (u1 >= d);
+  q1 += t;
+  u1 -= (-t) & d;
+
+  udiv_qrnnd_preinv (t, u0, u1, u0, d, dinv);
+  add_ssaaaa (q1, q0, q1, q0, CNST_LIMB(0), t);
+
+  MPN_INCR_U (qp+1, n-1, q1);
+
+  qp[0] = q0;
+  return u0;
+}
+
+#elif DIV_QR_1N_METHOD == 3
+
+/* This variant handles carry from the u update earlier. This gives a
+   longer critical path, but reduces the work needed for the
+   quotients. */
+mp_limb_t
+mpn_div_qr_1n_pi1 (mp_ptr qp, mp_srcptr up, mp_size_t n, mp_limb_t u1,
+		   mp_limb_t d, mp_limb_t dinv)
+{
+  mp_limb_t B2;
+  mp_limb_t cy, u0;
+  mp_limb_t q0, q1;
+  mp_limb_t p0, p1;
+  mp_limb_t t;
+  mp_size_t j;
+
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+  ASSERT (n > 0);
+  ASSERT (u1 < d);
+
+  if (n == 1)
+    {
+      udiv_qrnnd_preinv (qp[0], u1, u1, up[0], d, dinv);
+      return u1;
+    }
+
+  /* FIXME: Could be precomputed */
+  B2 = -d*dinv;
+
+  umul_ppmm (q1, q0, dinv, u1);
+  umul_ppmm (p1, p0, B2, u1);
+  q1 += u1;
+  ASSERT (q1 >= u1);
+  u0 = up[n-1];	/* Early read, to allow qp == up. */
+
+  add_mssaaaa (cy, u1, u0, u0, up[n-2], p1, p0);
+  u1 -= cy & d;
+  q1 -= cy;
+  qp[n-1] = q1;
+
+  /* FIXME: Keep q1 in a variable between iterations, to reduce number
+     of memory accesses. */
+  for (j = n-2; j-- > 0; )
+    {
+      mp_limb_t q2, cy;
+      mp_limb_t t1, t0;
+
+      /* Additions for the q update:
+       *	+-------+
+       *        |u1 * v |
+       *        +---+---+
+       *        | u1|
+       *        +---+
+       *        | 1 |  (conditional on {u1, u0} carry)
+       *        +---+
+       * +      | q0|
+       *   -+---+---+---+
+       *    | q2| q1| q0|
+       *    +---+---+---+
+       *
+       * Additions for the u update:
+       *        +-------+
+       *        |u1 * B2|
+       *        +---+---+
+       *      + |u0 |u-1|
+       *        +---+---+
+       *      - | d |     (conditional on carry)
+       *     ---+---+---+
+       *        |u1 | u0|
+       *        +---+---+
+       *
+      */
+      umul_ppmm (p1, p0, u1, B2);
+      ADDC_LIMB (q2, q1, u1, q0);
+      umul_ppmm (t1, t0, u1, dinv);
+      add_mssaaaa (cy, u1, u0, u0, up[j], p1, p0);
+      u1 -= cy & d;
+
+      /* t1 <= B-2, so cy can be added in without overflow. */
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), t1 - cy);
+      q0 = t0;
+
+      /* Final q update */
+      qp[j+1] = q1;
+      MPN_INCR_U (qp+j+2, n-j-2, q2);
+    }
+
+  q1 = (u1 >= d);
+  u1 -= (-q1) & d;
+
+  udiv_qrnnd_preinv (t, u0, u1, u0, d, dinv);
+  add_ssaaaa (q1, q0, q1, q0, CNST_LIMB(0), t);
+
+  MPN_INCR_U (qp+1, n-1, q1);
+
+  qp[0] = q0;
+  return u0;
+}
+
+#elif DIV_QR_1N_METHOD == 4
+
+mp_limb_t
+mpn_div_qr_1n_pi1 (mp_ptr qp, mp_srcptr up, mp_size_t n, mp_limb_t u1,
+		   mp_limb_t d, mp_limb_t dinv)
+{
+  mp_limb_t B2;
+  mp_limb_t u2, u0;
+  mp_limb_t q0, q1;
+  mp_limb_t p0, p1;
+  mp_limb_t B2d0, B2d1;
+  mp_limb_t t;
+  mp_size_t j;
+
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+  ASSERT (n > 0);
+  ASSERT (u1 < d);
+
+  if (n == 1)
+    {
+      udiv_qrnnd_preinv (qp[0], u1, u1, up[0], d, dinv);
+      return u1;
+    }
+
+  /* FIXME: Could be precomputed */
+  B2 = -d*dinv;
+  /* B2 * (B-d) */
+  umul_ppmm (B2d1, B2d0, B2, -d);
+
+  umul_ppmm (q1, q0, dinv, u1);
+  umul_ppmm (p1, p0, B2, u1);
+  q1 += u1;
+  ASSERT (q1 >= u1);
+
+  add_mssaaaa (u2, u1, u0, up[n-1], up[n-2], p1, p0);
+
+  /* After read of up[n-1], to allow qp == up. */
+  qp[n-1] = q1 - u2;
+
+  /* FIXME: Keep q1 in a variable between iterations, to reduce number
+     of memory accesses. */
+  for (j = n-2; j-- > 0; )
+    {
+      mp_limb_t q2, cy;
+      mp_limb_t t1, t0;
+
+      /* Additions for the q update. *After* u1 -= u2 & d adjustment.
+       *	+-------+
+       *        |u1 * v |
+       *        +---+---+
+       *        | u1|
+       *        +---+
+       *        | 1 |  (conditional on {u1, u0} carry)
+       *        +---+
+       * +      | q0|
+       *   -+---+---+---+
+       *    | q2| q1| q0|
+       *    +---+---+---+
+       *
+       * Additions for the u update. *Before* u1 -= u2 & d adjstment.
+       *        +-------+
+       *        |u1 * B2|
+       *        +---+---+
+       *        |u0 |u-1|
+       *        +---+---+
+       + +      |B2(B-d)| (conditional on u2)
+       *   -+---+---+---+
+       *    |u2 |u1 | u0|
+       *    +---+---+---+
+       *
+      */
+       /* Multiply with unadjusted u1, to shorten critical path. */
+      umul_ppmm (p1, p0, u1, B2);
+      u1 -= (d & u2);
+      ADDC_LIMB (q2, q1, u1, q0);
+      umul_ppmm (t1, t0, u1, dinv);
+
+      add_mssaaaa (cy, u1, u0, u0, up[j], u2 & B2d1, u2 & B2d0);
+      add_mssaaaa (u2, u1, u0, u1, u0, p1, p0);
+      u2 += cy;
+      ASSERT(-u2 <= 1);
+
+      /* t1 <= B-2, so u2 can be added in without overflow. */
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), t1 - u2);
+      q0 = t0;
+
+      /* Final q update */
+      qp[j+1] = q1;
+      MPN_INCR_U (qp+j+2, n-j-2, q2);
+    }
+  u1 -= u2 & d;
+
+  q1 = (u1 >= d);
+  u1 -= (-q1) & d;
+
+  udiv_qrnnd_preinv (t, u0, u1, u0, d, dinv);
+  add_ssaaaa (q1, q0, q1, q0, CNST_LIMB(0), t);
+
+  MPN_INCR_U (qp+1, n-1, q1);
+
+  qp[0] = q0;
+  return u0;
+}
+#else
+#error Unknown DIV_QR_1N_METHOD
+#endif
diff --git a/mpn/generic/div_qr_1n_pi2.c b/mpn/generic/div_qr_1n_pi2.c
new file mode 100644
index 0000000..daae68f
--- /dev/null
+++ b/mpn/generic/div_qr_1n_pi2.c
@@ -0,0 +1,203 @@
+/* mpn_div_qr_1n_pi2.
+
+   THIS FILE CONTAINS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS
+   ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2013, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* ISSUES:
+
+   * Can we really use the high pi2 inverse limb for udiv_qrnnd_preinv?
+
+   * Are there any problems with generating n quotient limbs in the q area?  It
+     surely simplifies things.
+
+   * Not yet adequately tested.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Define some longlong.h-style macros, but for wider operations.
+   * add_sssaaaa is like longlong.h's add_ssaaaa but propagating carry-out into
+     an additional sum operand.
+*/
+#if defined (__GNUC__)  && ! defined (__INTEL_COMPILER) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %k2\n\tadc\t%5, %k1\n\tadc\t$0, %k0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((USItype)(s2)),					\
+	     "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %q2\n\tadc\t%5, %q1\n\tadc\t$0, %q0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((UDItype)(s2)),					\
+	     "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("adds\t%2, %x6, %7\n\tadcs\t%1, %x4, %x5\n\tadc\t%0, %x3, xzr"\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "rZ" (s2), "%rZ"  (a1), "rZ" (b1), "%rZ" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add%I7c\t%2,%6,%7\n\tadde\t%1,%4,%5\n\taddze\t%0,%3"	\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "r"  (s2), "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef add_sssaaaa
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (s2) += __c1 + (__s1 < __c0);					\
+  } while (0)
+#endif
+
+struct precomp_div_1_pi2
+{
+  mp_limb_t dip[2];
+  mp_limb_t d;
+  int norm_cnt;
+};
+
+mp_limb_t
+mpn_div_qr_1n_pi2 (mp_ptr qp,
+		   mp_srcptr up, mp_size_t un,
+		   struct precomp_div_1_pi2 *pd)
+{
+  mp_limb_t most_significant_q_limb;
+  mp_size_t i;
+  mp_limb_t r, u2, u1, u0;
+  mp_limb_t d0, di1, di0;
+  mp_limb_t q3a, q2a, q2b, q1b, q2c, q1c, q1d, q0d;
+  mp_limb_t cnd;
+
+  ASSERT (un >= 2);
+  ASSERT ((pd->d & GMP_NUMB_HIGHBIT) != 0);
+  ASSERT (! MPN_OVERLAP_P (qp, un-2, up, un) || qp+2 >= up);
+  ASSERT_MPN (up, un);
+
+#define q3 q3a
+#define q2 q2b
+#define q1 q1b
+
+  up += un - 3;
+  r = up[2];
+  d0 = pd->d;
+
+  most_significant_q_limb = (r >= d0);
+  r -= d0 & -most_significant_q_limb;
+
+  qp += un - 3;
+  qp[2] = most_significant_q_limb;
+
+  di1 = pd->dip[1];
+  di0 = pd->dip[0];
+
+  for (i = un - 3; i >= 0; i -= 2)
+    {
+      u2 = r;
+      u1 = up[1];
+      u0 = up[0];
+
+      /* Dividend in {r,u1,u0} */
+
+      umul_ppmm (q1d,q0d, u1, di0);
+      umul_ppmm (q2b,q1b, u1, di1);
+      q2b++;				/* cannot spill */
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, u1,u0);
+
+      umul_ppmm (q2c,q1c, u2,  di0);
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2c,q1c);
+      umul_ppmm (q3a,q2a, u2, di1);
+
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2a,q1d);
+
+      q3 += r;
+
+      r = u0 - q2 * d0;
+
+      cnd = (r >= q1);
+      r += d0 & -cnd;
+      sub_ddmmss (q3,q2,  q3,q2,  0,cnd);
+
+      if (UNLIKELY (r >= d0))
+	{
+	  r -= d0;
+	  add_ssaaaa (q3,q2,  q3,q2,  0,1);
+	}
+
+      qp[0] = q2;
+      qp[1] = q3;
+
+      up -= 2;
+      qp -= 2;
+    }
+
+  if ((un & 1) == 0)
+    {
+      u2 = r;
+      u1 = up[1];
+
+      udiv_qrnnd_preinv (q3, r, u2, u1, d0, di1);
+      qp[1] = q3;
+    }
+
+  return r;
+
+#undef q3
+#undef q2
+#undef q1
+}
diff --git a/mpn/generic/div_qr_1u_pi2.c b/mpn/generic/div_qr_1u_pi2.c
new file mode 100644
index 0000000..ea38e3c
--- /dev/null
+++ b/mpn/generic/div_qr_1u_pi2.c
@@ -0,0 +1,236 @@
+/* mpn_div_qr_1u_pi2.
+
+   THIS FILE CONTAINS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS
+   ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2013, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* ISSUES:
+
+   * Can we really use the high pi2 inverse limb for udiv_qrnnd_preinv?
+
+   * Are there any problems with generating n quotient limbs in the q area?  It
+     surely simplifies things.
+
+   * Not yet adequately tested.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Define some longlong.h-style macros, but for wider operations.
+   * add_sssaaaa is like longlong.h's add_ssaaaa but propagating carry-out into
+     an additional sum operand.
+*/
+#if defined (__GNUC__)  && ! defined (__INTEL_COMPILER) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %k2\n\tadc\t%5, %k1\n\tadc\t$0, %k0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((USItype)(s2)),					\
+	     "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %q2\n\tadc\t%5, %q1\n\tadc\t$0, %q0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((UDItype)(s2)),					\
+	     "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("adds\t%2, %x6, %7\n\tadcs\t%1, %x4, %x5\n\tadc\t%0, %x3, xzr"\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "rZ" (s2), "%rZ"  (a1), "rZ" (b1), "%rZ" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add%I7c\t%2,%6,%7\n\tadde\t%1,%4,%5\n\taddze\t%0,%3"	\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "r"  (s2), "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef add_sssaaaa
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (s2) += __c1 + (__s1 < __c0);					\
+  } while (0)
+#endif
+
+struct precomp_div_1_pi2
+{
+  mp_limb_t dip[2];
+  mp_limb_t d;
+  int norm_cnt;
+};
+
+mp_limb_t
+mpn_div_qr_1u_pi2 (mp_ptr qp,
+		   mp_srcptr up, mp_size_t un,
+		   struct precomp_div_1_pi2 *pd)
+{
+  mp_size_t i;
+  mp_limb_t r, u2, u1, u0;
+  mp_limb_t d0, di1, di0;
+  mp_limb_t q3a, q2a, q2b, q1b, q2c, q1c, q1d, q0d;
+  mp_limb_t cnd;
+  int cnt;
+
+  ASSERT (un >= 2);
+  ASSERT ((pd->d & GMP_NUMB_HIGHBIT) == 0);
+  ASSERT (! MPN_OVERLAP_P (qp, un-2, up, un) || qp+2 >= up);
+  ASSERT_MPN (up, un);
+
+#define q3 q3a
+#define q2 q2b
+#define q1 q1b
+
+  up += un - 3;
+  cnt = pd->norm_cnt;
+  r = up[2] >> (GMP_NUMB_BITS - cnt);
+  d0 = pd->d << cnt;
+
+  qp += un - 2;
+
+  di1 = pd->dip[1];
+  di0 = pd->dip[0];
+
+  for (i = un - 3; i >= 0; i -= 2)
+    {
+      u2 = r;
+      u1 = (up[2] << cnt) | (up[1] >> (GMP_NUMB_BITS - cnt));
+      u0 = (up[1] << cnt) | (up[0] >> (GMP_NUMB_BITS - cnt));
+
+      /* Dividend in {r,u1,u0} */
+
+      umul_ppmm (q1d,q0d, u1, di0);
+      umul_ppmm (q2b,q1b, u1, di1);
+      q2b++;				/* cannot spill */
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, u1,u0);
+
+      umul_ppmm (q2c,q1c, u2,  di0);
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2c,q1c);
+      umul_ppmm (q3a,q2a, u2, di1);
+
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2a,q1d);
+
+      q3 += r;
+
+      r = u0 - q2 * d0;
+
+      cnd = (r >= q1);
+      r += d0 & -cnd;
+      sub_ddmmss (q3,q2,  q3,q2,  0,cnd);
+
+      if (UNLIKELY (r >= d0))
+	{
+	  r -= d0;
+	  add_ssaaaa (q3,q2,  q3,q2,  0,1);
+	}
+
+      qp[0] = q2;
+      qp[1] = q3;
+
+      up -= 2;
+      qp -= 2;
+    }
+
+  if ((un & 1) != 0)
+    {
+      u2 = r;
+      u1 = (up[2] << cnt);
+
+      udiv_qrnnd_preinv (q3, r, u2, u1, d0, di1);
+      qp[1] = q3;
+    }
+  else
+    {
+      u2 = r;
+      u1 = (up[2] << cnt) | (up[1] >> (GMP_NUMB_BITS - cnt));
+      u0 = (up[1] << cnt);
+
+      /* Dividend in {r,u1,u0} */
+
+      umul_ppmm (q1d,q0d, u1, di0);
+      umul_ppmm (q2b,q1b, u1, di1);
+      q2b++;				/* cannot spill */
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, u1,u0);
+
+      umul_ppmm (q2c,q1c, u2,  di0);
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2c,q1c);
+      umul_ppmm (q3a,q2a, u2, di1);
+
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2a,q1d);
+
+      q3 += r;
+
+      r = u0 - q2 * d0;
+
+      cnd = (r >= q1);
+      r += d0 & -cnd;
+      sub_ddmmss (q3,q2,  q3,q2,  0,cnd);
+
+      if (UNLIKELY (r >= d0))
+	{
+	  r -= d0;
+	  add_ssaaaa (q3,q2,  q3,q2,  0,1);
+	}
+
+      qp[0] = q2;
+      qp[1] = q3;
+    }
+
+  return r >> cnt;
+
+#undef q3
+#undef q2
+#undef q1
+}
diff --git a/mpn/generic/div_qr_2.c b/mpn/generic/div_qr_2.c
new file mode 100644
index 0000000..c3c8f57
--- /dev/null
+++ b/mpn/generic/div_qr_2.c
@@ -0,0 +1,314 @@
+/* mpn_div_qr_2 -- Divide natural numbers, producing both remainder and
+   quotient.  The divisor is two limbs.
+
+   Contributed to the GNU project by Torbjorn Granlund and Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1996, 1999-2002, 2011, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef DIV_QR_2_PI2_THRESHOLD
+/* Disabled unless explicitly tuned. */
+#define DIV_QR_2_PI2_THRESHOLD MP_LIMB_T_MAX
+#endif
+
+#ifndef SANITY_CHECK
+#define SANITY_CHECK 0
+#endif
+
+/* Define some longlong.h-style macros, but for wider operations.
+   * add_sssaaaa is like longlong.h's add_ssaaaa but propagating carry-out into
+     an additional sum operand.
+   * add_csaac accepts two addends and a carry in, and generates a sum and a
+     carry out.  A little like a "full adder".
+*/
+#if defined (__GNUC__)  && ! defined (__INTEL_COMPILER) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %k2\n\tadc\t%5, %k1\n\tadc\t$0, %k0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((USItype)(s2)),					\
+	     "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %q2\n\tadc\t%5, %q1\n\tadc\t$0, %q0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((UDItype)(s2)),					\
+	     "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("adds\t%2, %x6, %7\n\tadcs\t%1, %x4, %x5\n\tadc\t%0, %x3, xzr"\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "rZ" (s2), "%rZ"  (a1), "rZ" (b1), "%rZ" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add%I7c\t%2,%6,%7\n\tadde\t%1,%4,%5\n\taddze\t%0,%3"	\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "r"  (s2), "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef add_sssaaaa
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (s2) += __c1 + (__s1 < __c0);					\
+  } while (0)
+#endif
+
+/* Typically used with r1, r0 same as n3, n2. Other types of overlap
+   between inputs and outputs are not supported. */
+#define udiv_qr_4by2(q1,q0, r1,r0, n3,n2,n1,n0, d1,d0, di1,di0)		\
+  do {									\
+    mp_limb_t _q3, _q2a, _q2, _q1, _q2c, _q1c, _q1d, _q0;		\
+    mp_limb_t _t1, _t0;							\
+    mp_limb_t _mask;							\
+									\
+    /* [q3,q2,q1,q0] = [n3,n2]*[di1,di0] + [n3,n2,n1,n0] + [0,1,0,0] */	\
+    umul_ppmm (_q2,_q1, n2, di1);					\
+    umul_ppmm (_q3,_q2a, n3, di1);					\
+    ++_q2;	/* _q2 cannot overflow */				\
+    add_ssaaaa (_q3,_q2, _q3,_q2, n3,_q2a);				\
+    umul_ppmm (_q2c,_q1c, n3, di0);					\
+    add_sssaaaa (_q3,_q2,_q1, _q2,_q1, n2,_q1c);			\
+    umul_ppmm (_q1d,_q0, n2, di0);					\
+    add_sssaaaa (_q2c,_q1,_q0, _q1,_q0, n1,n0); /* _q2c cannot overflow */ \
+    add_sssaaaa (_q3,_q2,_q1, _q2,_q1, _q2c,_q1d);			\
+									\
+    umul_ppmm (_t1,_t0, _q2, d0);					\
+    _t1 += _q2 * d1 + _q3 * d0;						\
+									\
+    sub_ddmmss (r1, r0, n1, n0, _t1, _t0);				\
+									\
+    _mask = -(mp_limb_t) ((r1 >= _q1) & ((r1 > _q1) | (r0 >= _q0)));  /* (r1,r0) >= (q1,q0) */  \
+    add_ssaaaa (r1, r0, r1, r0, d1 & _mask, d0 & _mask);		\
+    sub_ddmmss (_q3, _q2, _q3, _q2, CNST_LIMB(0), -_mask);		\
+									\
+    if (UNLIKELY (r1 >= d1))						\
+      {									\
+	if (r1 > d1 || r0 >= d0)					\
+	  {								\
+	    sub_ddmmss (r1, r0, r1, r0, d1, d0);			\
+	    add_ssaaaa (_q3, _q2, _q3, _q2, CNST_LIMB(0), CNST_LIMB(1));\
+	  }								\
+      }									\
+    (q1) = _q3;								\
+    (q0) = _q2;								\
+  } while (0)
+
+static void
+invert_4by2 (mp_ptr di, mp_limb_t d1, mp_limb_t d0)
+{
+  mp_limb_t v1, v0, p1, t1, t0, p0, mask;
+  invert_limb (v1, d1);
+  p1 = d1 * v1;
+  /* <1, v1> * d1 = <B-1, p1> */
+  p1 += d0;
+  if (p1 < d0)
+    {
+      v1--;
+      mask = -(mp_limb_t) (p1 >= d1);
+      p1 -= d1;
+      v1 += mask;
+      p1 -= mask & d1;
+    }
+  /* <1, v1> * d1 + d0 = <B-1, p1> */
+  umul_ppmm (t1, p0, d0, v1);
+  p1 += t1;
+  if (p1 < t1)
+    {
+      if (UNLIKELY (p1 >= d1))
+	{
+	  if (p1 > d1 || p0 >= d0)
+	    {
+	      sub_ddmmss (p1, p0, p1, p0, d1, d0);
+	      v1--;
+	    }
+	}
+      sub_ddmmss (p1, p0, p1, p0, d1, d0);
+      v1--;
+    }
+  /* Now v1 is the 3/2 inverse, <1, v1> * <d1, d0> = <B-1, p1, p0>,
+   * with <p1, p0> + <d1, d0> >= B^2.
+   *
+   * The 4/2 inverse is (B^4 - 1) / <d1, d0> = <1, v1, v0>. The
+   * partial remainder after <1, v1> is
+   *
+   * B^4 - 1 - B <1, v1> <d1, d0> = <B-1, B-1, B-1, B-1> - <B-1, p1, p0, 0>
+   *                              = <~p1, ~p0, B-1>
+   */
+  udiv_qr_3by2 (v0, t1, t0, ~p1, ~p0, MP_LIMB_T_MAX, d1, d0, v1);
+  di[0] = v0;
+  di[1] = v1;
+
+#if SANITY_CHECK
+  {
+    mp_limb_t tp[4];
+    mp_limb_t dp[2];
+    dp[0] = d0;
+    dp[1] = d1;
+    mpn_mul_n (tp, dp, di, 2);
+    ASSERT_ALWAYS (mpn_add_n (tp+2, tp+2, dp, 2) == 0);
+    ASSERT_ALWAYS (tp[2] == MP_LIMB_T_MAX);
+    ASSERT_ALWAYS (tp[3] == MP_LIMB_T_MAX);
+    ASSERT_ALWAYS (mpn_add_n (tp, tp, dp, 2) == 1);
+  }
+#endif
+}
+
+static mp_limb_t
+mpn_div_qr_2n_pi2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+		   mp_limb_t d1, mp_limb_t d0, mp_limb_t di1, mp_limb_t di0)
+{
+  mp_limb_t qh;
+  mp_size_t i;
+  mp_limb_t r1, r0;
+
+  ASSERT (nn >= 2);
+  ASSERT (d1 & GMP_NUMB_HIGHBIT);
+
+  r1 = np[nn-1];
+  r0 = np[nn-2];
+
+  qh = 0;
+  if (r1 >= d1 && (r1 > d1 || r0 >= d0))
+    {
+#if GMP_NAIL_BITS == 0
+      sub_ddmmss (r1, r0, r1, r0, d1, d0);
+#else
+      r0 = r0 - d0;
+      r1 = r1 - d1 - (r0 >> GMP_LIMB_BITS - 1);
+      r0 &= GMP_NUMB_MASK;
+#endif
+      qh = 1;
+    }
+
+  for (i = nn - 2; i >= 2; i -= 2)
+    {
+      mp_limb_t n1, n0, q1, q0;
+      n1 = np[i-1];
+      n0 = np[i-2];
+      udiv_qr_4by2 (q1, q0, r1, r0, r1, r0, n1, n0, d1, d0, di1, di0);
+      qp[i-1] = q1;
+      qp[i-2] = q0;
+    }
+
+  if (i > 0)
+    {
+      mp_limb_t q;
+      udiv_qr_3by2 (q, r1, r0, r1, r0, np[0], d1, d0, di1);
+      qp[0] = q;
+    }
+  rp[1] = r1;
+  rp[0] = r0;
+
+  return qh;
+}
+
+
+/* Divide num {np,nn} by den {dp,2} and write the nn-2 least
+   significant quotient limbs at qp and the 2 long remainder at np.
+   Return the most significant limb of the quotient.
+
+   Preconditions:
+   1. qp must either not overlap with the other operands at all, or
+      qp >= np + 2 must hold true.  (This means that it's possible to put
+      the quotient in the high part of {np,nn}, right above the remainder.)
+   2. nn >= 2.  */
+
+mp_limb_t
+mpn_div_qr_2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp)
+{
+  mp_limb_t d1;
+  mp_limb_t d0;
+  gmp_pi1_t dinv;
+
+  ASSERT (nn >= 2);
+  ASSERT (! MPN_OVERLAP_P (qp, nn-2, np, nn) || qp >= np + 2);
+  ASSERT_MPN (np, nn);
+  ASSERT_MPN (dp, 2);
+
+  d1 = dp[1]; d0 = dp[0];
+
+  ASSERT (d1 > 0);
+
+  if (UNLIKELY (d1 & GMP_NUMB_HIGHBIT))
+    {
+      if (BELOW_THRESHOLD (nn, DIV_QR_2_PI2_THRESHOLD))
+	{
+	  gmp_pi1_t dinv;
+	  invert_pi1 (dinv, d1, d0);
+	  return mpn_div_qr_2n_pi1 (qp, rp, np, nn, d1, d0, dinv.inv32);
+	}
+      else
+	{
+	  mp_limb_t di[2];
+	  invert_4by2 (di, d1, d0);
+	  return mpn_div_qr_2n_pi2 (qp, rp, np, nn, d1, d0, di[1], di[0]);
+	}
+    }
+  else
+    {
+      int shift;
+      count_leading_zeros (shift, d1);
+      d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+      d0 <<= shift;
+      invert_pi1 (dinv, d1, d0);
+      return mpn_div_qr_2u_pi1 (qp, rp, np, nn, d1, d0, shift, dinv.inv32);
+    }
+}
diff --git a/mpn/generic/div_qr_2n_pi1.c b/mpn/generic/div_qr_2n_pi1.c
new file mode 100644
index 0000000..131a811
--- /dev/null
+++ b/mpn/generic/div_qr_2n_pi1.c
@@ -0,0 +1,84 @@
+/* mpn_div_qr_2n_pi1
+
+   Contributed to the GNU project by Torbjorn Granlund and Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1996, 1999-2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* 3/2 loop, for normalized divisor */
+mp_limb_t
+mpn_div_qr_2n_pi1 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+		   mp_limb_t d1, mp_limb_t d0, mp_limb_t di)
+{
+  mp_limb_t qh;
+  mp_size_t i;
+  mp_limb_t r1, r0;
+
+  ASSERT (nn >= 2);
+  ASSERT (d1 & GMP_NUMB_HIGHBIT);
+
+  np += nn - 2;
+  r1 = np[1];
+  r0 = np[0];
+
+  qh = 0;
+  if (r1 >= d1 && (r1 > d1 || r0 >= d0))
+    {
+#if GMP_NAIL_BITS == 0
+      sub_ddmmss (r1, r0, r1, r0, d1, d0);
+#else
+      r0 = r0 - d0;
+      r1 = r1 - d1 - (r0 >> GMP_LIMB_BITS - 1);
+      r0 &= GMP_NUMB_MASK;
+#endif
+      qh = 1;
+    }
+
+  for (i = nn - 2 - 1; i >= 0; i--)
+    {
+      mp_limb_t n0, q;
+      n0 = np[-1];
+      udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
+      np--;
+      qp[i] = q;
+    }
+
+  rp[1] = r1;
+  rp[0] = r0;
+
+  return qh;
+}
diff --git a/mpn/generic/div_qr_2u_pi1.c b/mpn/generic/div_qr_2u_pi1.c
new file mode 100644
index 0000000..70e617b
--- /dev/null
+++ b/mpn/generic/div_qr_2u_pi1.c
@@ -0,0 +1,76 @@
+/* mpn_div_qr_2u_pi1
+
+   Contributed to the GNU project by Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* 3/2 loop, for unnormalized divisor. Caller must pass shifted d1 and
+   d0, while {np,nn} is shifted on the fly. */
+mp_limb_t
+mpn_div_qr_2u_pi1 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+		   mp_limb_t d1, mp_limb_t d0, int shift, mp_limb_t di)
+{
+  mp_limb_t qh;
+  mp_limb_t r2, r1, r0;
+  mp_size_t i;
+
+  ASSERT (nn >= 2);
+  ASSERT (d1 & GMP_NUMB_HIGHBIT);
+  ASSERT (shift > 0);
+
+  r2 = np[nn-1] >> (GMP_LIMB_BITS - shift);
+  r1 = (np[nn-1] << shift) | (np[nn-2] >> (GMP_LIMB_BITS - shift));
+  r0 = np[nn-2] << shift;
+
+  udiv_qr_3by2 (qh, r2, r1, r2, r1, r0, d1, d0, di);
+
+  for (i = nn - 2 - 1; i >= 0; i--)
+    {
+      mp_limb_t q;
+      r0 = np[i];
+      r1 |= r0 >> (GMP_LIMB_BITS - shift);
+      r0 <<= shift;
+      udiv_qr_3by2 (q, r2, r1, r2, r1, r0, d1, d0, di);
+      qp[i] = q;
+    }
+
+  rp[0] = (r1 >> shift) | (r2 << (GMP_LIMB_BITS - shift));
+  rp[1] = r2 >> shift;
+
+  return qh;
+}
diff --git a/mpn/generic/dive_1.c b/mpn/generic/dive_1.c
new file mode 100644
index 0000000..056f5b9
--- /dev/null
+++ b/mpn/generic/dive_1.c
@@ -0,0 +1,146 @@
+/* mpn_divexact_1 -- mpn by limb exact division.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003, 2005, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+
+/* Divide a={src,size} by d=divisor and store the quotient in q={dst,size}.
+   q will only be correct if d divides a exactly.
+
+   A separate loop is used for shift==0 because n<<GMP_LIMB_BITS doesn't
+   give zero on all CPUs (for instance it doesn't on the x86s).  This
+   separate loop might run faster too, helping odd divisors.
+
+   Possibilities:
+
+   mpn_divexact_1c could be created, accepting and returning c.  This would
+   let a long calculation be done piece by piece.  Currently there's no
+   particular need for that, and not returning c means that a final umul can
+   be skipped.
+
+   Another use for returning c would be letting the caller know whether the
+   division was in fact exact.  It would work just to return the carry bit
+   "c=(l>s)" and let the caller do a final umul if interested.
+
+   When the divisor is even, the factors of two could be handled with a
+   separate mpn_rshift, instead of shifting on the fly.  That might be
+   faster on some CPUs and would mean just the shift==0 style loop would be
+   needed.
+
+   If n<<GMP_LIMB_BITS gives zero on a particular CPU then the separate
+   shift==0 loop is unnecessary, and could be eliminated if there's no great
+   speed difference.
+
+   It's not clear whether "/" is the best way to handle size==1.  Alpha gcc
+   2.95 for instance has a poor "/" and might prefer the modular method.
+   Perhaps a tuned parameter should control this.
+
+   If src[size-1] < divisor then dst[size-1] will be zero, and one divide
+   step could be skipped.  A test at last step for s<divisor (or ls in the
+   even case) might be a good way to do that.  But if this code is often
+   used with small divisors then it might not be worth bothering  */
+
+void
+mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
+{
+  mp_size_t  i;
+  mp_limb_t  c, h, l, ls, s, s_next, inverse, dummy;
+  unsigned   shift;
+
+  ASSERT (size >= 1);
+  ASSERT (divisor != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (divisor);
+
+  if ((divisor & 1) == 0)
+    {
+      count_trailing_zeros (shift, divisor);
+      divisor >>= shift;
+    }
+  else
+    shift = 0;
+
+  binvert_limb (inverse, divisor);
+  divisor <<= GMP_NAIL_BITS;
+
+  if (shift != 0)
+    {
+      c = 0;
+
+      s = src[0];
+
+      for (i = 1; i < size; i++)
+	{
+	  s_next = src[i];
+	  ls = ((s >> shift) | (s_next << (GMP_NUMB_BITS-shift))) & GMP_NUMB_MASK;
+	  s = s_next;
+
+	  SUBC_LIMB (c, l, ls, c);
+
+	  l = (l * inverse) & GMP_NUMB_MASK;
+	  dst[i - 1] = l;
+
+	  umul_ppmm (h, dummy, l, divisor);
+	  c += h;
+	}
+
+      ls = s >> shift;
+      l = ls - c;
+      l = (l * inverse) & GMP_NUMB_MASK;
+      dst[size - 1] = l;
+    }
+  else
+    {
+      s = src[0];
+
+      l = (s * inverse) & GMP_NUMB_MASK;
+      dst[0] = l;
+      c = 0;
+
+      for (i = 1; i < size; i++)
+	{
+	  umul_ppmm (h, dummy, l, divisor);
+	  c += h;
+
+	  s = src[i];
+	  SUBC_LIMB (c, l, s, c);
+
+	  l = (l * inverse) & GMP_NUMB_MASK;
+	  dst[i] = l;
+	}
+    }
+}
diff --git a/mpn/generic/diveby3.c b/mpn/generic/diveby3.c
new file mode 100644
index 0000000..7dee0bc
--- /dev/null
+++ b/mpn/generic/diveby3.c
@@ -0,0 +1,173 @@
+/* mpn_divexact_by3c -- mpn exact division by 3.
+
+Copyright 2000-2003, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if DIVEXACT_BY3_METHOD == 0
+
+mp_limb_t
+mpn_divexact_by3c (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_limb_t c)
+{
+  mp_limb_t r;
+  r = mpn_bdiv_dbm1c (rp, up, un, GMP_NUMB_MASK / 3, GMP_NUMB_MASK / 3 * c);
+
+  /* Possible bdiv_dbm1 return values are C * (GMP_NUMB_MASK / 3), 0 <= C < 3.
+     We want to return C.  We compute the remainder mod 4 and notice that the
+     inverse of (2^(2k)-1)/3 mod 4 is 1.  */
+  return r & 3;
+}
+
+#endif
+
+#if DIVEXACT_BY3_METHOD == 1
+
+/* The algorithm here is basically the same as mpn_divexact_1, as described
+   in the manual.  Namely at each step q = (src[i]-c)*inverse, and new c =
+   borrow(src[i]-c) + high(divisor*q).  But because the divisor is just 3,
+   high(divisor*q) can be determined with two comparisons instead of a
+   multiply.
+
+   The "c += ..."s add the high limb of 3*l to c.  That high limb will be 0,
+   1 or 2.  Doing two separate "+="s seems to give better code on gcc (as of
+   2.95.2 at least).
+
+   It will be noted that the new c is formed by adding three values each 0
+   or 1.  But the total is only 0, 1 or 2.  When the subtraction src[i]-c
+   causes a borrow, that leaves a limb value of either 0xFF...FF or
+   0xFF...FE.  The multiply by MODLIMB_INVERSE_3 gives 0x55...55 or
+   0xAA...AA respectively, and in those cases high(3*q) is only 0 or 1
+   respectively, hence a total of no more than 2.
+
+   Alternatives:
+
+   This implementation has each multiply on the dependent chain, due to
+   "l=s-c".  See below for alternative code which avoids that.  */
+
+mp_limb_t
+mpn_divexact_by3c (mp_ptr restrict rp, mp_srcptr restrict up, mp_size_t un, mp_limb_t c)
+{
+  mp_limb_t  l, q, s;
+  mp_size_t  i;
+
+  ASSERT (un >= 1);
+  ASSERT (c == 0 || c == 1 || c == 2);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, un));
+
+  i = 0;
+  do
+    {
+      s = up[i];
+      SUBC_LIMB (c, l, s, c);
+
+      q = (l * MODLIMB_INVERSE_3) & GMP_NUMB_MASK;
+      rp[i] = q;
+
+      c += (q >= GMP_NUMB_CEIL_MAX_DIV3);
+      c += (q >= GMP_NUMB_CEIL_2MAX_DIV3);
+    }
+  while (++i < un);
+
+  ASSERT (c == 0 || c == 1 || c == 2);
+  return c;
+}
+
+
+#endif
+
+#if DIVEXACT_BY3_METHOD == 2
+
+/* The following alternative code re-arranges the quotient calculation from
+   (src[i]-c)*inverse to instead
+
+       q = src[i]*inverse - c*inverse
+
+   thereby allowing src[i]*inverse to be scheduled back as far as desired,
+   making full use of multiplier throughput and leaving just some carry
+   handing on the dependent chain.
+
+   The carry handling consists of determining the c for the next iteration.
+   This is the same as described above, namely look for any borrow from
+   src[i]-c, and at the high of 3*q.
+
+   high(3*q) is done with two comparisons as above (in c2 and c3).  The
+   borrow from src[i]-c is incorporated into those by noting that if there's
+   a carry then then we have src[i]-c == 0xFF..FF or 0xFF..FE, in turn
+   giving q = 0x55..55 or 0xAA..AA.  Adding 1 to either of those q values is
+   enough to make high(3*q) come out 1 bigger, as required.
+
+   l = -c*inverse is calculated at the same time as c, since for most chips
+   it can be more conveniently derived from separate c1/c2/c3 values than
+   from a combined c equal to 0, 1 or 2.
+
+   The net effect is that with good pipelining this loop should be able to
+   run at perhaps 4 cycles/limb, depending on available execute resources
+   etc.
+
+   Usage:
+
+   This code is not used by default, since we really can't rely on the
+   compiler generating a good software pipeline, nor on such an approach
+   even being worthwhile on all CPUs.
+
+   Itanium is one chip where this algorithm helps though, see
+   mpn/ia64/diveby3.asm.  */
+
+mp_limb_t
+mpn_divexact_by3c (mp_ptr restrict rp, mp_srcptr restrict up, mp_size_t un, mp_limb_t cy)
+{
+  mp_limb_t  s, sm, cl, q, qx, c2, c3;
+  mp_size_t  i;
+
+  ASSERT (un >= 1);
+  ASSERT (cy == 0 || cy == 1 || cy == 2);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, un));
+
+  cl = cy == 0 ? 0 : cy == 1 ? -MODLIMB_INVERSE_3 : -2*MODLIMB_INVERSE_3;
+
+  for (i = 0; i < un; i++)
+    {
+      s = up[i];
+      sm = (s * MODLIMB_INVERSE_3) & GMP_NUMB_MASK;
+
+      q = (cl + sm) & GMP_NUMB_MASK;
+      rp[i] = q;
+      qx = q + (s < cy);
+
+      c2 = qx >= GMP_NUMB_CEIL_MAX_DIV3;
+      c3 = qx >= GMP_NUMB_CEIL_2MAX_DIV3 ;
+
+      cy = c2 + c3;
+      cl = (-c2 & -MODLIMB_INVERSE_3) + (-c3 & -MODLIMB_INVERSE_3);
+    }
+
+  return cy;
+}
+
+#endif
diff --git a/mpn/generic/divexact.c b/mpn/generic/divexact.c
new file mode 100644
index 0000000..ec417df
--- /dev/null
+++ b/mpn/generic/divexact.c
@@ -0,0 +1,296 @@
+/* mpn_divexact(qp,np,nn,dp,dn,tp) -- Divide N = {np,nn} by D = {dp,dn} storing
+   the result in Q = {qp,nn-dn+1} expecting no remainder.  Overlap allowed
+   between Q and N; all other overlap disallowed.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if 1
+void
+mpn_divexact (mp_ptr qp,
+	      mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp, mp_size_t dn)
+{
+  unsigned shift;
+  mp_size_t qn;
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (dn > 0);
+  ASSERT (nn >= dn);
+  ASSERT (dp[dn-1] > 0);
+
+  while (dp[0] == 0)
+    {
+      ASSERT (np[0] == 0);
+      dp++;
+      np++;
+      dn--;
+      nn--;
+    }
+
+  if (dn == 1)
+    {
+      MPN_DIVREM_OR_DIVEXACT_1 (qp, np, nn, dp[0]);
+      return;
+    }
+
+  TMP_MARK;
+
+  qn = nn + 1 - dn;
+  count_trailing_zeros (shift, dp[0]);
+
+  if (shift > 0)
+    {
+      mp_ptr wp;
+      mp_size_t ss;
+      ss = (dn > qn) ? qn + 1 : dn;
+
+      tp = TMP_ALLOC_LIMBS (ss);
+      mpn_rshift (tp, dp, ss, shift);
+      dp = tp;
+
+      /* Since we have excluded dn == 1, we have nn > qn, and we need
+	 to shift one limb beyond qn. */
+      wp = TMP_ALLOC_LIMBS (qn + 1);
+      mpn_rshift (wp, np, qn + 1, shift);
+      np = wp;
+    }
+
+  if (dn > qn)
+    dn = qn;
+
+  tp = TMP_ALLOC_LIMBS (mpn_bdiv_q_itch (qn, dn));
+  mpn_bdiv_q (qp, np, qn, dp, dn, tp);
+  TMP_FREE;
+
+  /* Since bdiv_q computes -N/D (mod B^{qn}), we must negate now. */
+  mpn_neg (qp, qp, qn);
+}
+
+#else
+
+/* We use the Jebelean's bidirectional exact division algorithm.  This is
+   somewhat naively implemented, with equal quotient parts done by 2-adic
+   division and truncating division.  Since 2-adic division is faster, it
+   should be used for a larger chunk.
+
+   This code is horrendously ugly, in all sorts of ways.
+
+   * It was hacked without much care or thought, but with a testing program.
+   * It handles scratch space frivolously, and furthermore the itch function
+     is broken.
+   * Doesn't provide any measures to deal with mu_divappr_q's +3 error.  We
+     have yet to provoke an error due to this, though.
+   * Algorithm selection leaves a lot to be desired.  In particular, the choice
+     between DC and MU isn't a point, but we treat it like one.
+   * It makes the msb part 1 or 2 limbs larger than the lsb part, in spite of
+     that the latter is faster.  We should at least reverse this, but perhaps
+     we should make the lsb part considerably larger.  (How do we tune this?)
+*/
+
+mp_size_t
+mpn_divexact_itch (mp_size_t nn, mp_size_t dn)
+{
+  return nn + dn;		/* FIXME this is not right */
+}
+
+void
+mpn_divexact (mp_ptr qp,
+	      mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp, mp_size_t dn,
+	      mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_size_t nn0, qn0;
+  mp_size_t nn1, qn1;
+  mp_ptr tp;
+  mp_limb_t qml;
+  mp_limb_t qh;
+  int cnt;
+  mp_ptr xdp;
+  mp_limb_t di;
+  mp_limb_t cy;
+  gmp_pi1_t dinv;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  qn = nn - dn + 1;
+
+  /* For small divisors, and small quotients, don't use Jebelean's algorithm. */
+  if (dn < DIVEXACT_JEB_THRESHOLD || qn < DIVEXACT_JEB_THRESHOLD)
+    {
+      tp = scratch;
+      MPN_COPY (tp, np, qn);
+      binvert_limb (di, dp[0]);  di = -di;
+      dn = MIN (dn, qn);
+      mpn_sbpi1_bdiv_q (qp, tp, qn, dp, dn, di);
+      TMP_FREE;
+      return;
+    }
+
+  qn0 = ((nn - dn) >> 1) + 1;	/* low quotient size */
+
+  /* If quotient is much larger than the divisor, the bidirectional algorithm
+     does not work as currently implemented.  Fall back to plain bdiv.  */
+  if (qn0 > dn)
+    {
+      if (BELOW_THRESHOLD (dn, DC_BDIV_Q_THRESHOLD))
+	{
+	  tp = scratch;
+	  MPN_COPY (tp, np, qn);
+	  binvert_limb (di, dp[0]);  di = -di;
+	  dn = MIN (dn, qn);
+	  mpn_sbpi1_bdiv_q (qp, tp, qn, dp, dn, di);
+	}
+      else if (BELOW_THRESHOLD (dn, MU_BDIV_Q_THRESHOLD))
+	{
+	  tp = scratch;
+	  MPN_COPY (tp, np, qn);
+	  binvert_limb (di, dp[0]);  di = -di;
+	  mpn_dcpi1_bdiv_q (qp, tp, qn, dp, dn, di);
+	}
+      else
+	{
+	  mpn_mu_bdiv_q (qp, np, qn, dp, dn, scratch);
+	}
+      TMP_FREE;
+      return;
+    }
+
+  nn0 = qn0 + qn0;
+
+  nn1 = nn0 - 1 + ((nn-dn) & 1);
+  qn1 = qn0;
+  if (LIKELY (qn0 != dn))
+    {
+      nn1 = nn1 + 1;
+      qn1 = qn1 + 1;
+      if (UNLIKELY (dp[dn - 1] == 1 && qn1 != dn))
+	{
+	  /* If the leading divisor limb == 1, i.e. has just one bit, we have
+	     to include an extra limb in order to get the needed overlap.  */
+	  /* FIXME: Now with the mu_divappr_q function, we should really need
+	     more overlap. That indicates one of two things: (1) The test code
+	     is not good. (2) We actually overlap too much by default.  */
+	  nn1 = nn1 + 1;
+	  qn1 = qn1 + 1;
+	}
+    }
+
+  tp = TMP_ALLOC_LIMBS (nn1 + 1);
+
+  count_leading_zeros (cnt, dp[dn - 1]);
+
+  /* Normalize divisor, store into tmp area.  */
+  if (cnt != 0)
+    {
+      xdp = TMP_ALLOC_LIMBS (qn1);
+      mpn_lshift (xdp, dp + dn - qn1, qn1, cnt);
+    }
+  else
+    {
+      xdp = (mp_ptr) dp + dn - qn1;
+    }
+
+  /* Shift dividend according to the divisor normalization.  */
+  /* FIXME: We compute too much here for XX_divappr_q, but these functions'
+     interfaces want a pointer to the imaginative least significant limb, not
+     to the least significant *used* limb.  Of course, we could leave nn1-qn1
+     rubbish limbs in the low part, to save some time.  */
+  if (cnt != 0)
+    {
+      cy = mpn_lshift (tp, np + nn - nn1, nn1, cnt);
+      if (cy != 0)
+	{
+	  tp[nn1] = cy;
+	  nn1++;
+	}
+    }
+  else
+    {
+      /* FIXME: This copy is not needed for mpn_mu_divappr_q, except when the
+	 mpn_sub_n right before is executed.  */
+      MPN_COPY (tp, np + nn - nn1, nn1);
+    }
+
+  invert_pi1 (dinv, xdp[qn1 - 1], xdp[qn1 - 2]);
+  if (BELOW_THRESHOLD (qn1, DC_DIVAPPR_Q_THRESHOLD))
+    {
+      qp[qn0 - 1 + nn1 - qn1] = mpn_sbpi1_divappr_q (qp + qn0 - 1, tp, nn1, xdp, qn1, dinv.inv32);
+    }
+  else if (BELOW_THRESHOLD (qn1, MU_DIVAPPR_Q_THRESHOLD))
+    {
+      qp[qn0 - 1 + nn1 - qn1] = mpn_dcpi1_divappr_q (qp + qn0 - 1, tp, nn1, xdp, qn1, &dinv);
+    }
+  else
+    {
+      /* FIXME: mpn_mu_divappr_q doesn't handle qh != 0.  Work around it with a
+	 conditional subtraction here.  */
+      qh = mpn_cmp (tp + nn1 - qn1, xdp, qn1) >= 0;
+      if (qh)
+	mpn_sub_n (tp + nn1 - qn1, tp + nn1 - qn1, xdp, qn1);
+      mpn_mu_divappr_q (qp + qn0 - 1, tp, nn1, xdp, qn1, scratch);
+      qp[qn0 - 1 + nn1 - qn1] = qh;
+    }
+  qml = qp[qn0 - 1];
+
+  binvert_limb (di, dp[0]);  di = -di;
+
+  if (BELOW_THRESHOLD (qn0, DC_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, qn0);
+      mpn_sbpi1_bdiv_q (qp, tp, qn0, dp, qn0, di);
+    }
+  else if (BELOW_THRESHOLD (qn0, MU_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, qn0);
+      mpn_dcpi1_bdiv_q (qp, tp, qn0, dp, qn0, di);
+    }
+  else
+    {
+      mpn_mu_bdiv_q (qp, np, qn0, dp, qn0, scratch);
+    }
+
+  if (qml < qp[qn0 - 1])
+    mpn_decr_u (qp + qn0, 1);
+
+  TMP_FREE;
+}
+#endif
diff --git a/mpn/generic/divis.c b/mpn/generic/divis.c
new file mode 100644
index 0000000..f989ddb
--- /dev/null
+++ b/mpn/generic/divis.c
@@ -0,0 +1,194 @@
+/* mpn_divisible_p -- mpn by mpn divisibility test
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2014, 2017, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Determine whether A={ap,an} is divisible by D={dp,dn}.  Must have both
+   operands normalized, meaning high limbs non-zero, except that an==0 is
+   allowed.
+
+   There usually won't be many low zero bits on D, but the checks for this
+   are fast and might pick up a few operand combinations, in particular they
+   might reduce D to fit the single-limb mod_1/modexact_1 code.
+
+   Future:
+
+   Getting the remainder limb by limb would make an early exit possible on
+   finding a non-zero.  This would probably have to be bdivmod style so
+   there's no addback, but it would need a multi-precision inverse and so
+   might be slower than the plain method (on small sizes at least).
+
+   When D must be normalized (shifted to low bit set), it's possible to
+   suppress the bit-shifting of A down, as long as it's already been checked
+   that A has at least as many trailing zero bits as D.  */
+
+int
+mpn_divisible_p (mp_srcptr ap, mp_size_t an,
+		 mp_srcptr dp, mp_size_t dn)
+{
+  mp_limb_t  alow, dlow, dmask;
+  mp_ptr     qp, rp, tp;
+  mp_limb_t di;
+  unsigned  twos;
+  int c;
+  TMP_DECL;
+
+  ASSERT (an >= 0);
+  ASSERT (an == 0 || ap[an-1] != 0);
+  ASSERT (dn >= 1);
+  ASSERT (dp[dn-1] != 0);
+  ASSERT_MPN (ap, an);
+  ASSERT_MPN (dp, dn);
+
+  /* When a<d only a==0 is divisible.
+     Notice this test covers all cases of an==0. */
+  if (an < dn)
+    return (an == 0);
+
+  /* Strip low zero limbs from d, requiring a==0 on those. */
+  for (;;)
+    {
+      alow = *ap;
+      dlow = *dp;
+
+      if (dlow != 0)
+	break;
+
+      if (alow != 0)
+	return 0;  /* a has fewer low zero limbs than d, so not divisible */
+
+      /* a!=0 and d!=0 so won't get to n==0 */
+      an--; ASSERT (an >= 1);
+      dn--; ASSERT (dn >= 1);
+      ap++;
+      dp++;
+    }
+
+  /* a must have at least as many low zero bits as d */
+  dmask = LOW_ZEROS_MASK (dlow);
+  if ((alow & dmask) != 0)
+    return 0;
+
+  if (dn == 1)
+    {
+      if (ABOVE_THRESHOLD (an, BMOD_1_TO_MOD_1_THRESHOLD))
+	return mpn_mod_1 (ap, an, dlow) == 0;
+
+      count_trailing_zeros (twos, dlow);
+      dlow >>= twos;
+      return mpn_modexact_1_odd (ap, an, dlow) == 0;
+    }
+
+  count_trailing_zeros (twos, dlow);
+  if (dn == 2)
+    {
+      mp_limb_t  dsecond = dp[1];
+      if (dsecond <= dmask)
+	{
+	  dlow = (dlow >> twos) | (dsecond << (GMP_NUMB_BITS-twos));
+	  ASSERT_LIMB (dlow);
+	  return MPN_MOD_OR_MODEXACT_1_ODD (ap, an, dlow) == 0;
+	}
+    }
+
+  /* Should we compute Q = A * D^(-1) mod B^k,
+                       R = A - Q * D  mod B^k
+     here, for some small values of k?  Then check if R = 0 (mod B^k).  */
+
+  /* We could also compute A' = A mod T and D' = D mod P, for some
+     P = 3 * 5 * 7 * 11 ..., and then check if any prime factor from P
+     dividing D' also divides A'.  */
+
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (rp, an + 1,
+		     qp, an - dn + 1); /* FIXME: Could we avoid this? */
+
+  if (twos != 0)
+    {
+      tp = TMP_ALLOC_LIMBS (dn);
+      ASSERT_NOCARRY (mpn_rshift (tp, dp, dn, twos));
+      dp = tp;
+
+      ASSERT_NOCARRY (mpn_rshift (rp, ap, an, twos));
+    }
+  else
+    {
+      MPN_COPY (rp, ap, an);
+    }
+  if (rp[an - 1] >= dp[dn - 1])
+    {
+      rp[an] = 0;
+      an++;
+    }
+  else if (an == dn)
+    {
+      TMP_FREE;
+      return 0;
+    }
+
+  ASSERT (an > dn);		/* requirement of functions below */
+
+  if (BELOW_THRESHOLD (dn, DC_BDIV_QR_THRESHOLD) ||
+      BELOW_THRESHOLD (an - dn, DC_BDIV_QR_THRESHOLD))
+    {
+      binvert_limb (di, dp[0]);
+      mpn_sbpi1_bdiv_qr (qp, rp, an, dp, dn, -di);
+      rp += an - dn;
+    }
+  else if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
+    {
+      binvert_limb (di, dp[0]);
+      mpn_dcpi1_bdiv_qr (qp, rp, an, dp, dn, -di);
+      rp += an - dn;
+    }
+  else
+    {
+      tp = TMP_ALLOC_LIMBS (mpn_mu_bdiv_qr_itch (an, dn));
+      mpn_mu_bdiv_qr (qp, rp, rp, an, dp, dn, tp);
+    }
+
+  /* In general, bdiv may return either R = 0 or R = D when D divides
+     A. But R = 0 can happen only when A = 0, which we already have
+     excluded. Furthermore, R == D (mod B^{dn}) implies no carry, so
+     we don't need to check the carry returned from bdiv. */
+
+  MPN_CMP (c, rp, dp, dn);
+
+  TMP_FREE;
+  return c == 0;
+}
diff --git a/mpn/generic/divrem.c b/mpn/generic/divrem.c
new file mode 100644
index 0000000..1da84a8
--- /dev/null
+++ b/mpn/generic/divrem.c
@@ -0,0 +1,103 @@
+/* mpn_divrem -- Divide natural numbers, producing both remainder and
+   quotient.  This is now just a middle layer calling mpn_tdiv_qr.
+
+Copyright 1993-1997, 1999-2002, 2005, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_divrem (mp_ptr qp, mp_size_t qxn,
+	    mp_ptr np, mp_size_t nn,
+	    mp_srcptr dp, mp_size_t dn)
+{
+  ASSERT (qxn >= 0);
+  ASSERT (nn >= dn);
+  ASSERT (dn >= 1);
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (np, nn, dp, dn));
+  ASSERT (! MPN_OVERLAP_P (qp, nn-dn+qxn, np, nn) || qp==np+dn+qxn);
+  ASSERT (! MPN_OVERLAP_P (qp, nn-dn+qxn, dp, dn));
+  ASSERT_MPN (np, nn);
+  ASSERT_MPN (dp, dn);
+
+  if (dn == 1)
+    {
+      mp_limb_t ret;
+      mp_ptr q2p;
+      mp_size_t qn;
+      TMP_DECL;
+
+      TMP_MARK;
+      q2p = TMP_ALLOC_LIMBS (nn + qxn);
+
+      np[0] = mpn_divrem_1 (q2p, qxn, np, nn, dp[0]);
+      qn = nn + qxn - 1;
+      MPN_COPY (qp, q2p, qn);
+      ret = q2p[qn];
+
+      TMP_FREE;
+      return ret;
+    }
+  else if (dn == 2)
+    {
+      return mpn_divrem_2 (qp, qxn, np, nn, dp);
+    }
+  else
+    {
+      mp_ptr q2p;
+      mp_limb_t qhl;
+      mp_size_t qn;
+      TMP_DECL;
+
+      TMP_MARK;
+      if (UNLIKELY (qxn != 0))
+	{
+	  mp_ptr n2p;
+	  TMP_ALLOC_LIMBS_2 (n2p, nn + qxn,
+			     q2p, nn - dn + qxn + 1);
+	  MPN_ZERO (n2p, qxn);
+	  MPN_COPY (n2p + qxn, np, nn);
+	  mpn_tdiv_qr (q2p, np, 0L, n2p, nn + qxn, dp, dn);
+	  qn = nn - dn + qxn;
+	  MPN_COPY (qp, q2p, qn);
+	  qhl = q2p[qn];
+	}
+      else
+	{
+	  q2p = TMP_ALLOC_LIMBS (nn - dn + 1);
+	  mpn_tdiv_qr (q2p, np, 0L, np, nn, dp, dn);
+	  qn = nn - dn;
+	  MPN_COPY (qp, q2p, qn);
+	  qhl = q2p[qn];
+	}
+      TMP_FREE;
+      return qhl;
+    }
+}
diff --git a/mpn/generic/divrem_1.c b/mpn/generic/divrem_1.c
new file mode 100644
index 0000000..c13aa79
--- /dev/null
+++ b/mpn/generic/divrem_1.c
@@ -0,0 +1,254 @@
+/* mpn_divrem_1 -- mpn by limb division.
+
+Copyright 1991, 1993, 1994, 1996, 1998-2000, 2002, 2003 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The size where udiv_qrnnd_preinv should be used rather than udiv_qrnnd,
+   meaning the quotient size where that should happen, the quotient size
+   being how many udiv divisions will be done.
+
+   The default is to use preinv always, CPUs where this doesn't suit have
+   tuned thresholds.  Note in particular that preinv should certainly be
+   used if that's the only division available (USE_PREINV_ALWAYS).  */
+
+#ifndef DIVREM_1_NORM_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD  0
+#endif
+#ifndef DIVREM_1_UNNORM_THRESHOLD
+#define DIVREM_1_UNNORM_THRESHOLD  0
+#endif
+
+
+
+/* If the cpu only has multiply-by-inverse division (eg. alpha), then NORM
+   and UNNORM thresholds are 0 and only the inversion code is included.
+
+   If multiply-by-inverse is never viable, then NORM and UNNORM thresholds
+   will be MP_SIZE_T_MAX and only the plain division code is included.
+
+   Otherwise mul-by-inverse is better than plain division above some
+   threshold, and best results are obtained by having code for both present.
+
+   The main reason for separating the norm and unnorm cases is that not all
+   CPUs give zero for "n0 >> GMP_LIMB_BITS" which would arise in the unnorm
+   code used on an already normalized divisor.
+
+   If UDIV_NEEDS_NORMALIZATION is false then plain division uses the same
+   non-shifting code for both the norm and unnorm cases, though with
+   different criteria for skipping a division, and with different thresholds
+   of course.  And in fact if inversion is never viable, then that simple
+   non-shifting division would be all that's left.
+
+   The NORM and UNNORM thresholds might not differ much, but if there's
+   going to be separate code for norm and unnorm then it makes sense to have
+   separate thresholds.  One thing that's possible is that the
+   mul-by-inverse might be better only for normalized divisors, due to that
+   case not needing variable bit shifts.
+
+   Notice that the thresholds are tested after the decision to possibly skip
+   one divide step, so they're based on the actual number of divisions done.
+
+   For the unnorm case, it would be possible to call mpn_lshift to adjust
+   the dividend all in one go (into the quotient space say), rather than
+   limb-by-limb in the loop.  This might help if mpn_lshift is a lot faster
+   than what the compiler can generate for EXTRACT.  But this is left to CPU
+   specific implementations to consider, especially since EXTRACT isn't on
+   the dependent chain.  */
+
+mp_limb_t
+mpn_divrem_1 (mp_ptr qp, mp_size_t qxn,
+	      mp_srcptr up, mp_size_t un, mp_limb_t d)
+{
+  mp_size_t  n;
+  mp_size_t  i;
+  mp_limb_t  n1, n0;
+  mp_limb_t  r = 0;
+
+  ASSERT (qxn >= 0);
+  ASSERT (un >= 0);
+  ASSERT (d != 0);
+  /* FIXME: What's the correct overlap rule when qxn!=0? */
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp+qxn, up, un));
+
+  n = un + qxn;
+  if (n == 0)
+    return 0;
+
+  d <<= GMP_NAIL_BITS;
+
+  qp += (n - 1);   /* Make qp point at most significant quotient limb */
+
+  if ((d & GMP_LIMB_HIGHBIT) != 0)
+    {
+      if (un != 0)
+	{
+	  /* High quotient limb is 0 or 1, skip a divide step. */
+	  mp_limb_t q;
+	  r = up[un - 1] << GMP_NAIL_BITS;
+	  q = (r >= d);
+	  *qp-- = q;
+	  r -= (d & -q);
+	  r >>= GMP_NAIL_BITS;
+	  n--;
+	  un--;
+	}
+
+      if (BELOW_THRESHOLD (n, DIVREM_1_NORM_THRESHOLD))
+	{
+	plain:
+	  for (i = un - 1; i >= 0; i--)
+	    {
+	      n0 = up[i] << GMP_NAIL_BITS;
+	      udiv_qrnnd (*qp, r, r, n0, d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd (*qp, r, r, CNST_LIMB(0), d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r;
+	}
+      else
+	{
+	  /* Multiply-by-inverse, divisor already normalized. */
+	  mp_limb_t dinv;
+	  invert_limb (dinv, d);
+
+	  for (i = un - 1; i >= 0; i--)
+	    {
+	      n0 = up[i] << GMP_NAIL_BITS;
+	      udiv_qrnnd_preinv (*qp, r, r, n0, d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r;
+	}
+    }
+  else
+    {
+      /* Most significant bit of divisor == 0.  */
+      int cnt;
+
+      /* Skip a division if high < divisor (high quotient 0).  Testing here
+	 before normalizing will still skip as often as possible.  */
+      if (un != 0)
+	{
+	  n1 = up[un - 1] << GMP_NAIL_BITS;
+	  if (n1 < d)
+	    {
+	      r = n1 >> GMP_NAIL_BITS;
+	      *qp-- = 0;
+	      n--;
+	      if (n == 0)
+		return r;
+	      un--;
+	    }
+	}
+
+      if (! UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIVREM_1_UNNORM_THRESHOLD))
+	goto plain;
+
+      count_leading_zeros (cnt, d);
+      d <<= cnt;
+      r <<= cnt;
+
+      if (UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIVREM_1_UNNORM_THRESHOLD))
+	{
+	  mp_limb_t nshift;
+	  if (un != 0)
+	    {
+	      n1 = up[un - 1] << GMP_NAIL_BITS;
+	      r |= (n1 >> (GMP_LIMB_BITS - cnt));
+	      for (i = un - 2; i >= 0; i--)
+		{
+		  n0 = up[i] << GMP_NAIL_BITS;
+		  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+		  udiv_qrnnd (*qp, r, r, nshift, d);
+		  r >>= GMP_NAIL_BITS;
+		  qp--;
+		  n1 = n0;
+		}
+	      udiv_qrnnd (*qp, r, r, n1 << cnt, d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd (*qp, r, r, CNST_LIMB(0), d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r >> cnt;
+	}
+      else
+	{
+	  mp_limb_t  dinv, nshift;
+	  invert_limb (dinv, d);
+	  if (un != 0)
+	    {
+	      n1 = up[un - 1] << GMP_NAIL_BITS;
+	      r |= (n1 >> (GMP_LIMB_BITS - cnt));
+	      for (i = un - 2; i >= 0; i--)
+		{
+		  n0 = up[i] << GMP_NAIL_BITS;
+		  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+		  udiv_qrnnd_preinv (*qp, r, r, nshift, d, dinv);
+		  r >>= GMP_NAIL_BITS;
+		  qp--;
+		  n1 = n0;
+		}
+	      udiv_qrnnd_preinv (*qp, r, r, n1 << cnt, d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r >> cnt;
+	}
+    }
+}
diff --git a/mpn/generic/divrem_2.c b/mpn/generic/divrem_2.c
new file mode 100644
index 0000000..217f2f6
--- /dev/null
+++ b/mpn/generic/divrem_2.c
@@ -0,0 +1,118 @@
+/* mpn_divrem_2 -- Divide natural numbers, producing both remainder and
+   quotient.  The divisor is two limbs.
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1996, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Divide num {np,nn} by den {dp,2} and write the nn-2 least significant
+   quotient limbs at qp and the 2 long remainder at np.  If qxn is non-zero,
+   generate that many fraction bits and append them after the other quotient
+   limbs.  Return the most significant limb of the quotient, this is always 0
+   or 1.
+
+   Preconditions:
+   1. The most significant bit of the divisor must be set.
+   2. qp must either not overlap with the input operands at all, or
+      qp >= np + 2 must hold true.  (This means that it's possible to put
+      the quotient in the high part of {np,nn}, right above the remainder.
+   3. nn >= 2, even if qxn is non-zero.  */
+
+mp_limb_t
+mpn_divrem_2 (mp_ptr qp, mp_size_t qxn,
+	      mp_ptr np, mp_size_t nn,
+	      mp_srcptr dp)
+{
+  mp_limb_t most_significant_q_limb;
+  mp_size_t i;
+  mp_limb_t r1, r0, d1, d0;
+  gmp_pi1_t di;
+
+  ASSERT (nn >= 2);
+  ASSERT (qxn >= 0);
+  ASSERT (dp[1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (qp, nn-2+qxn, np, nn) || qp >= np+2);
+  ASSERT_MPN (np, nn);
+  ASSERT_MPN (dp, 2);
+
+  np += nn - 2;
+  d1 = dp[1];
+  d0 = dp[0];
+  r1 = np[1];
+  r0 = np[0];
+
+  most_significant_q_limb = 0;
+  if (r1 >= d1 && (r1 > d1 || r0 >= d0))
+    {
+#if GMP_NAIL_BITS == 0
+      sub_ddmmss (r1, r0, r1, r0, d1, d0);
+#else
+      r0 = r0 - d0;
+      r1 = r1 - d1 - (r0 >> GMP_LIMB_BITS - 1);
+      r0 &= GMP_NUMB_MASK;
+#endif
+      most_significant_q_limb = 1;
+    }
+
+  invert_pi1 (di, d1, d0);
+
+  qp += qxn;
+
+  for (i = nn - 2 - 1; i >= 0; i--)
+    {
+      mp_limb_t n0, q;
+      n0 = np[-1];
+      udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di.inv32);
+      np--;
+      qp[i] = q;
+    }
+
+  if (UNLIKELY (qxn != 0))
+    {
+      qp -= qxn;
+      for (i = qxn - 1; i >= 0; i--)
+	{
+	  mp_limb_t q;
+	  udiv_qr_3by2 (q, r1, r0, r1, r0, CNST_LIMB(0), d1, d0, di.inv32);
+	  qp[i] = q;
+	}
+    }
+
+  np[1] = r1;
+  np[0] = r0;
+
+  return most_significant_q_limb;
+}
diff --git a/mpn/generic/dump.c b/mpn/generic/dump.c
new file mode 100644
index 0000000..9a4ddf4
--- /dev/null
+++ b/mpn/generic/dump.c
@@ -0,0 +1,99 @@
+/* THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS NOT SAFE TO
+   CALL THIS FUNCTION DIRECTLY.  IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+   FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1996, 2000-2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+#if GMP_NUMB_BITS % 4 == 0
+void
+mpn_dump (mp_srcptr ptr, mp_size_t n)
+{
+  MPN_NORMALIZE (ptr, n);
+
+  if (n == 0)
+    printf ("0\n");
+  else
+    {
+      n--;
+#if _LONG_LONG_LIMB
+      if ((ptr[n] >> GMP_LIMB_BITS / 2) != 0)
+	{
+	  printf ("%lX", (unsigned long) (ptr[n] >> GMP_LIMB_BITS / 2));
+	  printf ("%0*lX", (GMP_LIMB_BITS / 2 / 4), (unsigned long) ptr[n]);
+	}
+      else
+#endif
+	printf ("%lX", (unsigned long) ptr[n]);
+
+      while (n)
+	{
+	  n--;
+#if _LONG_LONG_LIMB
+	  printf ("%0*lX", (GMP_NUMB_BITS - GMP_LIMB_BITS / 2) / 4,
+		  (unsigned long) (ptr[n] >> GMP_LIMB_BITS / 2));
+	  printf ("%0*lX", GMP_LIMB_BITS / 2 / 4, (unsigned long) ptr[n]);
+#else
+	  printf ("%0*lX", GMP_NUMB_BITS / 4, (unsigned long) ptr[n]);
+#endif
+	}
+      printf ("\n");
+    }
+}
+
+#else
+
+static void
+mpn_recdump (mp_ptr p, mp_size_t n)
+{
+  mp_limb_t lo;
+  if (n != 0)
+    {
+      lo = p[0] & 0xf;
+      mpn_rshift (p, p, n, 4);
+      mpn_recdump (p, n);
+      printf ("%lX", lo);
+    }
+}
+
+void
+mpn_dump (mp_srcptr p, mp_size_t n)
+{
+  mp_ptr tp;
+  TMP_DECL;
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (n);
+  MPN_COPY (tp, p, n);
+  TMP_FREE;
+}
+
+#endif
diff --git a/mpn/generic/fib2_ui.c b/mpn/generic/fib2_ui.c
new file mode 100644
index 0000000..0b81571
--- /dev/null
+++ b/mpn/generic/fib2_ui.c
@@ -0,0 +1,174 @@
+/* mpn_fib2_ui -- calculate Fibonacci numbers.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* Store F[n] at fp and F[n-1] at f1p.  fp and f1p should have room for
+   MPN_FIB2_SIZE(n) limbs.
+
+   The return value is the actual number of limbs stored, this will be at
+   least 1.  fp[size-1] will be non-zero, except when n==0, in which case
+   fp[0] is 0 and f1p[0] is 1.  f1p[size-1] can be zero, since F[n-1]<F[n]
+   (for n>0).
+
+   Notes: F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
+
+   In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
+   low limb.
+
+   In F[2k+1] with k odd, -2 is applied to F[k-1]^2 just by ORing into the
+   low limb.
+*/
+
+mp_size_t
+mpn_fib2_ui (mp_ptr fp, mp_ptr f1p, unsigned long int n)
+{
+  mp_size_t      size;
+  unsigned long  nfirst, mask;
+
+  TRACE (printf ("mpn_fib2_ui n=%lu\n", n));
+
+  ASSERT (! MPN_OVERLAP_P (fp, MPN_FIB2_SIZE(n), f1p, MPN_FIB2_SIZE(n)));
+
+  /* Take a starting pair from the table. */
+  mask = 1;
+  for (nfirst = n; nfirst > FIB_TABLE_LIMIT; nfirst /= 2)
+    mask <<= 1;
+  TRACE (printf ("nfirst=%lu mask=0x%lX\n", nfirst, mask));
+
+  f1p[0] = FIB_TABLE ((int) nfirst - 1);
+  fp[0]  = FIB_TABLE (nfirst);
+  size = 1;
+
+  /* Skip to the end if the table lookup gives the final answer. */
+  if (mask != 1)
+    {
+      mp_size_t  alloc;
+      mp_ptr        xp;
+      TMP_DECL;
+
+      TMP_MARK;
+      alloc = MPN_FIB2_SIZE (n);
+      xp = TMP_ALLOC_LIMBS (alloc);
+
+      do
+	{
+	  /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
+	     n&mask upwards.
+
+	     The next bit of n is n&(mask>>1) and we'll double to the pair
+	     fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
+	     that bit is 0 or 1 respectively.  */
+
+	  TRACE (printf ("k=%lu mask=0x%lX size=%ld alloc=%ld\n",
+			 n >> refmpn_count_trailing_zeros(mask),
+			 mask, size, alloc);
+		 mpn_trace ("fp ", fp, size);
+		 mpn_trace ("f1p", f1p, size));
+
+	  /* fp normalized, f1p at most one high zero */
+	  ASSERT (fp[size-1] != 0);
+	  ASSERT (f1p[size-1] != 0 || f1p[size-2] != 0);
+
+	  /* f1p[size-1] might be zero, but this occurs rarely, so it's not
+	     worth bothering checking for it */
+	  ASSERT (alloc >= 2*size);
+	  mpn_sqr (xp, fp,  size);
+	  mpn_sqr (fp, f1p, size);
+	  size *= 2;
+
+	  /* Shrink if possible.  Since fp was normalized there'll be at
+	     most one high zero on xp (and if there is then there's one on
+	     yp too).  */
+	  ASSERT (xp[size-1] != 0 || fp[size-1] == 0);
+	  size -= (xp[size-1] == 0);
+	  ASSERT (xp[size-1] != 0);  /* only one xp high zero */
+
+	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */
+	  f1p[size] = mpn_add_n (f1p, xp, fp, size);
+
+	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
+	     n&mask is the low bit of our implied k.  */
+
+	  ASSERT ((fp[0] & 2) == 0);
+	  /* fp is F[k-1]^2 == 0 or 1 mod 4, like all squares. */
+	  fp[0] |= (n & mask ? 2 : 0);			/* possible -2 */
+#if HAVE_NATIVE_mpn_rsblsh2_n
+	  fp[size] = mpn_rsblsh2_n (fp, fp, xp, size);
+	  MPN_INCR_U(fp, size + 1, (n & mask ? 0 : 2));	/* possible +2 */
+#else
+	  {
+	    mp_limb_t  c;
+
+	    c = mpn_lshift (xp, xp, size, 2);
+	    xp[0] |= (n & mask ? 0 : 2);	/* possible +2 */
+	    c -= mpn_sub_n (fp, xp, fp, size);
+	    fp[size] = c;
+	  }
+#endif
+	  ASSERT (alloc >= size+1);
+	  size += (fp[size] != 0);
+
+	  /* now n&mask is the new bit of n being considered */
+	  mask >>= 1;
+
+	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
+	     F[2k+1] and F[2k-1].  */
+	  if (n & mask)
+	    ASSERT_NOCARRY (mpn_sub_n (f1p, fp, f1p, size));
+	  else {
+	    ASSERT_NOCARRY (mpn_sub_n ( fp, fp, f1p, size));
+
+	    /* Can have a high zero after replacing F[2k+1] with F[2k].
+	       f1p will have a high zero if fp does. */
+	    ASSERT (fp[size-1] != 0 || f1p[size-1] == 0);
+	    size -= (fp[size-1] == 0);
+	  }
+	}
+      while (mask != 1);
+
+      TMP_FREE;
+    }
+
+  TRACE (printf ("done size=%ld\n", size);
+	 mpn_trace ("fp ", fp, size);
+	 mpn_trace ("f1p", f1p, size));
+
+  return size;
+}
diff --git a/mpn/generic/fib2m.c b/mpn/generic/fib2m.c
new file mode 100644
index 0000000..89d2b86
--- /dev/null
+++ b/mpn/generic/fib2m.c
@@ -0,0 +1,252 @@
+/* mpn_fib2m -- calculate Fibonacci numbers, modulo m.
+
+Contributed to the GNU project by Marco Bodrato, based on the previous
+fib2_ui.c file.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Stores |{ap,n}-{bp,n}| in {rp,n},
+   returns the sign of {ap,n}-{bp,n}. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_limb_t  x, y;
+  while (--n >= 0)
+    {
+      x = ap[n];
+      y = bp[n];
+      if (x != y)
+        {
+          ++n;
+          if (x > y)
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, ap, bp, n));
+              return 1;
+            }
+          else
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, bp, ap, n));
+              return -1;
+            }
+        }
+      rp[n] = 0;
+    }
+  return 0;
+}
+
+/* Store F[n] at fp and F[n-1] at f1p.  Both are computed modulo m.
+   fp and f1p should have room for mn*2+1 limbs.
+
+   The sign of one or both the values may be flipped (n-F, instead of F),
+   the return value is 0 (zero) if the signs are coherent (both positive
+   or both negative) and 1 (one) otherwise.
+
+   Notes:
+
+   In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
+   low limb.
+
+   In F[2k+1] with k odd, -2 is applied to F[k-1]^2 just by ORing into the
+   low limb.
+
+   TODO: Should {tp, 2 * mn} be passed as a scratch pointer?
+   Should the call to mpn_fib2_ui() obtain (up to) 2*mn limbs?
+*/
+
+int
+mpn_fib2m (mp_ptr fp, mp_ptr f1p, mp_srcptr np, mp_size_t nn, mp_srcptr mp, mp_size_t mn)
+{
+  unsigned long	nfirst;
+  mp_limb_t	nh;
+  mp_bitcnt_t	nbi;
+  mp_size_t	sn, fn;
+  int		fcnt, ncnt;
+
+  ASSERT (! MPN_OVERLAP_P (fp, MAX(2*mn+1,5), f1p, MAX(2*mn+1,5)));
+  ASSERT (nn > 0 && np[nn - 1] != 0);
+
+  /* Estimate the maximal n such that fibonacci(n) fits in mn limbs. */
+#if GMP_NUMB_BITS % 16 == 0
+  if (UNLIKELY (ULONG_MAX / (23 * (GMP_NUMB_BITS / 16)) <= mn))
+    nfirst = ULONG_MAX;
+  else
+    nfirst = mn * (23 * (GMP_NUMB_BITS / 16));
+#else
+  {
+    mp_bitcnt_t	mbi;
+    mbi = (mp_bitcnt_t) mn * GMP_NUMB_BITS;
+
+    if (UNLIKELY (ULONG_MAX / 23 < mbi))
+      {
+	if (UNLIKELY (ULONG_MAX / 23 * 16 <= mbi))
+	  nfirst = ULONG_MAX;
+	else
+	  nfirst = mbi / 16 * 23;
+      }
+    else
+      nfirst = mbi * 23 / 16;
+  }
+#endif
+
+  sn = nn - 1;
+  nh = np[sn];
+  count_leading_zeros (ncnt, nh);
+  count_leading_zeros (fcnt, nfirst);
+
+  if (fcnt >= ncnt)
+    {
+      ncnt = fcnt - ncnt;
+      nh >>= ncnt;
+    }
+  else if (sn > 0)
+    {
+      ncnt -= fcnt;
+      nh <<= ncnt;
+      ncnt = GMP_NUMB_BITS - ncnt;
+      --sn;
+      nh |= np[sn] >> ncnt;
+    }
+  else
+    ncnt = 0;
+
+  nbi = sn * GMP_NUMB_BITS + ncnt;
+  if (nh > nfirst)
+    {
+      nh >>= 1;
+      ++nbi;
+    }
+
+  ASSERT (nh <= nfirst);
+  /* Take a starting pair from mpn_fib2_ui. */
+  fn = mpn_fib2_ui (fp, f1p, nh);
+  MPN_ZERO (fp + fn, mn - fn);
+  MPN_ZERO (f1p + fn, mn - fn);
+
+  if (nbi == 0)
+    {
+      if (fn == mn)
+	{
+	  mp_limb_t qp[2];
+	  mpn_tdiv_qr (qp, fp, 0, fp, fn, mp, mn);
+	  mpn_tdiv_qr (qp, f1p, 0, f1p, fn, mp, mn);
+	}
+
+      return 0;
+    }
+  else
+    {
+      mp_ptr	tp;
+      unsigned	pb = nh & 1;
+      int	neg;
+      TMP_DECL;
+
+      TMP_MARK;
+
+      tp = TMP_ALLOC_LIMBS (2 * mn + (mn < 2));
+
+      do
+	{
+	  mp_ptr	rp;
+	  /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
+	     nbi upwards.
+
+	     Based on the next bit of n, we'll double to the pair
+	     fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
+	     that bit is 0 or 1 respectively.  */
+
+	  mpn_sqr (tp, fp,  mn);
+	  mpn_sqr (fp, f1p, mn);
+
+	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */
+	  f1p[2 * mn] = mpn_add_n (f1p, tp, fp, 2 * mn);
+
+	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
+	     pb is the low bit of our implied k.  */
+
+	  /* fp is F[k-1]^2 == 0 or 1 mod 4, like all squares. */
+	  ASSERT ((fp[0] & 2) == 0);
+	  ASSERT (pb == (pb & 1));
+	  ASSERT ((fp[0] + (pb ? 2 : 0)) == (fp[0] | (pb << 1)));
+	  fp[0] |= pb << 1;		/* possible -2 */
+#if HAVE_NATIVE_mpn_rsblsh2_n
+	  fp[2 * mn] = 1 + mpn_rsblsh2_n (fp, fp, tp, 2 * mn);
+	  MPN_INCR_U(fp, 2 * mn + 1, (1 ^ pb) << 1);	/* possible +2 */
+	  fp[2 * mn] = (fp[2 * mn] - 1) & GMP_NUMB_MAX;
+#else
+	  {
+	    mp_limb_t  c;
+
+	    c = mpn_lshift (tp, tp, 2 * mn, 2);
+	    tp[0] |= (1 ^ pb) << 1;	/* possible +2 */
+	    c -= mpn_sub_n (fp, tp, fp, 2 * mn);
+	    fp[2 * mn] = c & GMP_NUMB_MAX;
+	  }
+#endif
+	  neg = fp[2 * mn] == GMP_NUMB_MAX;
+
+	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2 */
+	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k */
+
+	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
+	     F[2k+1] and F[2k-1].  */
+	  --nbi;
+	  pb = (np [nbi / GMP_NUMB_BITS] >> (nbi % GMP_NUMB_BITS)) & 1;
+	  rp = pb ? f1p : fp;
+	  if (neg)
+	    {
+	      /* Calculate -(F[2k+1] - F[2k-1]) */
+	      rp[2 * mn] = f1p[2 * mn] + 1 - mpn_sub_n (rp, f1p, fp, 2 * mn);
+	      neg = ! pb;
+	      if (pb) /* fp not overwritten, negate it. */
+		fp [2 * mn] = 1 ^ mpn_neg (fp, fp, 2 * mn);
+	    }
+	  else
+	    {
+	      neg = abs_sub_n (rp, fp, f1p, 2 * mn + 1) < 0;
+	    }
+
+	  mpn_tdiv_qr (tp, fp, 0, fp, 2 * mn + 1, mp, mn);
+	  mpn_tdiv_qr (tp, f1p, 0, f1p, 2 * mn + 1, mp, mn);
+	}
+      while (nbi != 0);
+
+      TMP_FREE;
+
+      return neg;
+    }
+}
diff --git a/mpn/generic/gcd.c b/mpn/generic/gcd.c
new file mode 100644
index 0000000..3f92cbf
--- /dev/null
+++ b/mpn/generic/gcd.c
@@ -0,0 +1,266 @@
+/* mpn/gcd.c: mpn_gcd for gcd of two odd integers.
+
+Copyright 1991, 1993-1998, 2000-2005, 2008, 2010, 2012, 2019 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Uses the HGCD operation described in
+
+     N. Möller, On Schönhage's algorithm and subquadratic integer gcd
+     computation, Math. Comp. 77 (2008), 589-607.
+
+  to reduce inputs until they are of size below GCD_DC_THRESHOLD, and
+  then uses Lehmer's algorithm.
+*/
+
+/* Some reasonable choices are n / 2 (same as in hgcd), and p = (n +
+ * 2)/3, which gives a balanced multiplication in
+ * mpn_hgcd_matrix_adjust. However, p = 2 n/3 gives slightly better
+ * performance. The matrix-vector multiplication is then
+ * 4:1-unbalanced, with matrix elements of size n/6, and vector
+ * elements of size p = 2n/3. */
+
+/* From analysis of the theoretical running time, it appears that when
+ * multiplication takes time O(n^alpha), p should be chosen so that
+ * the ratio of the time for the mpn_hgcd call, and the time for the
+ * multiplication in mpn_hgcd_matrix_adjust, is roughly 1/(alpha -
+ * 1). */
+#ifdef TUNE_GCD_P
+#define P_TABLE_SIZE 10000
+mp_size_t p_table[P_TABLE_SIZE];
+#define CHOOSE_P(n) ( (n) < P_TABLE_SIZE ? p_table[n] : 2*(n)/3)
+#else
+#define CHOOSE_P(n) (2*(n) / 3)
+#endif
+
+struct gcd_ctx
+{
+  mp_ptr gp;
+  mp_size_t gn;
+};
+
+static void
+gcd_hook (void *p, mp_srcptr gp, mp_size_t gn,
+	  mp_srcptr qp, mp_size_t qn, int d)
+{
+  struct gcd_ctx *ctx = (struct gcd_ctx *) p;
+  MPN_COPY (ctx->gp, gp, gn);
+  ctx->gn = gn;
+}
+
+mp_size_t
+mpn_gcd (mp_ptr gp, mp_ptr up, mp_size_t usize, mp_ptr vp, mp_size_t n)
+{
+  mp_size_t talloc;
+  mp_size_t scratch;
+  mp_size_t matrix_scratch;
+
+  struct gcd_ctx ctx;
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (usize >= n);
+  ASSERT (n > 0);
+  ASSERT (vp[n-1] > 0);
+
+  /* FIXME: Check for small sizes first, before setting up temporary
+     storage etc. */
+  talloc = MPN_GCD_SUBDIV_STEP_ITCH(n);
+
+  /* For initial division */
+  scratch = usize - n + 1;
+  if (scratch > talloc)
+    talloc = scratch;
+
+#if TUNE_GCD_P
+  if (CHOOSE_P (n) > 0)
+#else
+  if (ABOVE_THRESHOLD (n, GCD_DC_THRESHOLD))
+#endif
+    {
+      mp_size_t hgcd_scratch;
+      mp_size_t update_scratch;
+      mp_size_t p = CHOOSE_P (n);
+      mp_size_t scratch;
+#if TUNE_GCD_P
+      /* Worst case, since we don't guarantee that n - CHOOSE_P(n)
+	 is increasing */
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n);
+      hgcd_scratch = mpn_hgcd_itch (n);
+      update_scratch = 2*(n - 1);
+#else
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      hgcd_scratch = mpn_hgcd_itch (n - p);
+      update_scratch = p + n - 1;
+#endif
+      scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch);
+      if (scratch > talloc)
+	talloc = scratch;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS(talloc);
+
+  if (usize > n)
+    {
+      mpn_tdiv_qr (tp, up, 0, up, usize, vp, n);
+
+      if (mpn_zero_p (up, n))
+	{
+	  MPN_COPY (gp, vp, n);
+	  ctx.gn = n;
+	  goto done;
+	}
+    }
+
+  ctx.gp = gp;
+
+#if TUNE_GCD_P
+  while (CHOOSE_P (n) > 0)
+#else
+  while (ABOVE_THRESHOLD (n, GCD_DC_THRESHOLD))
+#endif
+    {
+      struct hgcd_matrix M;
+      mp_size_t p = CHOOSE_P (n);
+      mp_size_t matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      mp_size_t nn;
+      mpn_hgcd_matrix_init (&M, n - p, tp);
+      nn = mpn_hgcd (up + p, vp + p, n - p, &M, tp + matrix_scratch);
+      if (nn > 0)
+	{
+	  ASSERT (M.n <= (n - p - 1)/2);
+	  ASSERT (M.n + p <= (p + n - 1) / 2);
+	  /* Temporary storage 2 (p + M->n) <= p + n - 1. */
+	  n = mpn_hgcd_matrix_adjust (&M, p + nn, up, vp, p, tp + matrix_scratch);
+	}
+      else
+	{
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (up, vp, n, 0, gcd_hook, &ctx, tp);
+	  if (n == 0)
+	    goto done;
+	}
+    }
+
+  while (n > 2)
+    {
+      struct hgcd_matrix1 M;
+      mp_limb_t uh, ul, vh, vl;
+      mp_limb_t mask;
+
+      mask = up[n-1] | vp[n-1];
+      ASSERT (mask > 0);
+
+      if (mask & GMP_NUMB_HIGHBIT)
+	{
+	  uh = up[n-1]; ul = up[n-2];
+	  vh = vp[n-1]; vl = vp[n-2];
+	}
+      else
+	{
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  uh = MPN_EXTRACT_NUMB (shift, up[n-1], up[n-2]);
+	  ul = MPN_EXTRACT_NUMB (shift, up[n-2], up[n-3]);
+	  vh = MPN_EXTRACT_NUMB (shift, vp[n-1], vp[n-2]);
+	  vl = MPN_EXTRACT_NUMB (shift, vp[n-2], vp[n-3]);
+	}
+
+      /* Try an mpn_hgcd2 step */
+      if (mpn_hgcd2 (uh, ul, vh, vl, &M))
+	{
+	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, up, vp, n);
+	  MP_PTR_SWAP (up, tp);
+	}
+      else
+	{
+	  /* mpn_hgcd2 has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (up, vp, n, 0, &gcd_hook, &ctx, tp);
+	  if (n == 0)
+	    goto done;
+	}
+    }
+
+  ASSERT(up[n-1] | vp[n-1]);
+
+  /* Due to the calling convention for mpn_gcd, at most one can be even. */
+  if ((up[0] & 1) == 0)
+    MP_PTR_SWAP (up, vp);
+  ASSERT ((up[0] & 1) != 0);
+
+  {
+    mp_limb_t u0, u1, v0, v1;
+    mp_double_limb_t g;
+
+    u0 = up[0];
+    v0 = vp[0];
+
+    if (n == 1)
+      {
+	int cnt;
+	count_trailing_zeros (cnt, v0);
+	*gp = mpn_gcd_11 (u0, v0 >> cnt);
+	ctx.gn = 1;
+	goto done;
+      }
+
+    v1 = vp[1];
+    if (UNLIKELY (v0 == 0))
+      {
+	v0 = v1;
+	v1 = 0;
+	/* FIXME: We could invoke a mpn_gcd_21 here, just like mpn_gcd_22 could
+	   when this situation occurs internally.  */
+      }
+    if ((v0 & 1) == 0)
+      {
+	int cnt;
+	count_trailing_zeros (cnt, v0);
+	v0 = ((v1 << (GMP_NUMB_BITS - cnt)) & GMP_NUMB_MASK) | (v0 >> cnt);
+	v1 >>= cnt;
+      }
+
+    u1 = up[1];
+    g = mpn_gcd_22 (u1, u0, v1, v0);
+    gp[0] = g.d0;
+    gp[1] = g.d1;
+    ctx.gn = 1 + (g.d1 > 0);
+  }
+done:
+  TMP_FREE;
+  return ctx.gn;
+}
diff --git a/mpn/generic/gcd_1.c b/mpn/generic/gcd_1.c
new file mode 100644
index 0000000..22b1422
--- /dev/null
+++ b/mpn/generic/gcd_1.c
@@ -0,0 +1,103 @@
+/* mpn_gcd_1 -- mpn and limb greatest common divisor.
+
+Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Does not work for U == 0 or V == 0.  It would be tough to make it work for
+   V == 0 since gcd(x,0) = x, and U does not generally fit in an mp_limb_t.
+
+   The threshold for doing u%v when size==1 will vary by CPU according to
+   the speed of a division and the code generated for the main loop.  Any
+   tuning for this is left to a CPU specific implementation.  */
+
+mp_limb_t
+mpn_gcd_1 (mp_srcptr up, mp_size_t size, mp_limb_t vlimb)
+{
+  mp_limb_t      ulimb;
+  unsigned long  zero_bits, u_low_zero_bits;
+  int c;
+
+  ASSERT (size >= 1);
+  ASSERT (vlimb != 0);
+  ASSERT_MPN_NONZERO_P (up, size);
+
+  ulimb = up[0];
+
+  /* Need vlimb odd for modexact, want it odd to get common zeros. */
+  count_trailing_zeros (zero_bits, vlimb);
+  vlimb >>= zero_bits;
+
+  if (size > 1)
+    {
+      /* Must get common zeros before the mod reduction.  If ulimb==0 then
+	 vlimb already gives the common zeros.  */
+      if (ulimb != 0)
+	{
+	  count_trailing_zeros (u_low_zero_bits, ulimb);
+	  zero_bits = MIN (zero_bits, u_low_zero_bits);
+	}
+
+      ulimb = MPN_MOD_OR_MODEXACT_1_ODD (up, size, vlimb);
+      if (ulimb == 0)
+	goto done;
+
+      count_trailing_zeros (c, ulimb);
+      ulimb >>= c;
+    }
+  else
+    {
+      /* size==1, so up[0]!=0 */
+      count_trailing_zeros (u_low_zero_bits, ulimb);
+      ulimb >>= u_low_zero_bits;
+      zero_bits = MIN (zero_bits, u_low_zero_bits);
+
+      /* make u bigger */
+      if (vlimb > ulimb)
+	MP_LIMB_T_SWAP (ulimb, vlimb);
+
+      /* if u is much bigger than v, reduce using a division rather than
+	 chipping away at it bit-by-bit */
+      if ((ulimb >> 16) > vlimb)
+	{
+	  ulimb %= vlimb;
+	  if (ulimb == 0)
+	    goto done;
+
+	  count_trailing_zeros (c, ulimb);
+	  ulimb >>= c;
+	}
+    }
+
+  vlimb = mpn_gcd_11 (ulimb, vlimb);
+
+ done:
+  return vlimb << zero_bits;
+}
diff --git a/mpn/generic/gcd_11.c b/mpn/generic/gcd_11.c
new file mode 100644
index 0000000..214e45c
--- /dev/null
+++ b/mpn/generic/gcd_11.c
@@ -0,0 +1,74 @@
+/* mpn_gcd_11 -- limb greatest common divisor.
+
+Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
+{
+  ASSERT (u & v & 1);
+
+  /* In this loop, we represent the odd numbers ulimb and vlimb
+     without the redundant least significant one bit. This reduction
+     in size by one bit ensures that the high bit of t, below, is set
+     if and only if vlimb > ulimb. */
+
+  u >>= 1;
+  v >>= 1;
+
+  while (u != v)
+    {
+      mp_limb_t t;
+      mp_limb_t vgtu;
+      int c;
+
+      t = u - v;
+      vgtu = LIMB_HIGHBIT_TO_MASK (t);
+
+      /* v <-- min (u, v) */
+      v += (vgtu & t);
+
+      /* u <-- |u - v| */
+      u = (t ^ vgtu) - vgtu;
+
+      count_trailing_zeros (c, t);
+      /* We have c <= GMP_LIMB_BITS - 2 here, so that
+
+	   ulimb >>= (c + 1);
+
+	 would be safe. But unlike the addition c + 1, a separate
+	 shift by 1 is independent of c, and can be executed in
+	 parallel with count_trailing_zeros. */
+      u = (u >> 1) >> c;
+    }
+  return (u << 1) + 1;
+}
diff --git a/mpn/generic/gcd_22.c b/mpn/generic/gcd_22.c
new file mode 100644
index 0000000..d97f096
--- /dev/null
+++ b/mpn/generic/gcd_22.c
@@ -0,0 +1,131 @@
+/* mpn_gcd_22 -- double limb greatest common divisor.
+
+Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if GMP_NAIL_BITS > 0
+#error Nails not supported.
+#endif
+
+mp_double_limb_t
+mpn_gcd_22 (mp_limb_t u1, mp_limb_t u0, mp_limb_t v1, mp_limb_t v0)
+{
+  mp_double_limb_t g;
+  ASSERT (u0 & v0 & 1);
+
+  /* Implicit least significant bit */
+  u0 = (u0 >> 1) | (u1 << (GMP_LIMB_BITS - 1));
+  u1 >>= 1;
+
+  v0 = (v0 >> 1) | (v1 << (GMP_LIMB_BITS - 1));
+  v1 >>= 1;
+
+  while (u1 || v1) /* u1 == 0 can happen at most twice per call */
+    {
+      mp_limb_t vgtu, t1, t0;
+      sub_ddmmss (t1, t0, u1, u0, v1, v0);
+      vgtu = LIMB_HIGHBIT_TO_MASK(t1);
+
+      if (UNLIKELY (t0 == 0))
+	{
+	  if (t1 == 0)
+	    {
+	      g.d1 = (u1 << 1) | (u0 >> (GMP_LIMB_BITS - 1));
+	      g.d0 = (u0 << 1) | 1;
+	      return g;
+	    }
+	  int c;
+	  count_trailing_zeros (c, t1);
+
+	  /* v1 = min (u1, v1) */
+	  v1 += (vgtu & t1);
+	  /* u0 = |u1 - v1| */
+	  u0 = (t1 ^ vgtu) - vgtu;
+	  ASSERT (c < GMP_LIMB_BITS - 1);
+	  u0 >>= c + 1;
+	  u1 = 0;
+	}
+      else
+	{
+	  int c;
+	  count_trailing_zeros (c, t0);
+	  c++;
+	  /* V <-- min (U, V).
+
+	     Assembly version should use cmov. Another alternative,
+	     avoiding carry propagation, would be
+
+	     v0 += vgtu & t0; v1 += vtgu & (u1 - v1);
+	  */
+	  add_ssaaaa (v1, v0, v1, v0, vgtu & t1, vgtu & t0);
+	  /* U  <--  |U - V|
+	     No carry handling needed in this conditional negation,
+	     since t0 != 0. */
+	  u0 = (t0 ^ vgtu) - vgtu;
+	  u1 = t1 ^ vgtu;
+	  if (UNLIKELY (c == GMP_LIMB_BITS))
+	    {
+	      u0 = u1;
+	      u1 = 0;
+	    }
+	  else
+	    {
+	      u0 = (u0 >> c) | (u1 << (GMP_LIMB_BITS - c));
+	      u1 >>= c;
+	    }
+	}
+    }
+  while ((v0 | u0) & GMP_LIMB_HIGHBIT)
+    { /* At most two iterations */
+      mp_limb_t vgtu, t0;
+      int c;
+      sub_ddmmss (vgtu, t0, 0, u0, 0, v0);
+      if (UNLIKELY (t0 == 0))
+	{
+	  g.d1 = u0 >> (GMP_LIMB_BITS - 1);
+	  g.d0 = (u0 << 1) | 1;
+	  return g;
+	}
+
+      /* v <-- min (u, v) */
+      v0 += (vgtu & t0);
+
+      /* u <-- |u - v| */
+      u0 = (t0 ^ vgtu) - vgtu;
+
+      count_trailing_zeros (c, t0);
+      u0 = (u0 >> 1) >> c;
+    }
+
+  g.d0 = mpn_gcd_11 ((u0 << 1) + 1, (v0 << 1) + 1);
+  g.d1 = 0;
+  return g;
+}
diff --git a/mpn/generic/gcd_subdiv_step.c b/mpn/generic/gcd_subdiv_step.c
new file mode 100644
index 0000000..9c3b88d
--- /dev/null
+++ b/mpn/generic/gcd_subdiv_step.c
@@ -0,0 +1,204 @@
+/* gcd_subdiv_step.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2010, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>		/* for NULL */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Used when mpn_hgcd or mpn_hgcd2 has failed. Then either one of a or
+   b is small, or the difference is small. Perform one subtraction
+   followed by one division. The normal case is to compute the reduced
+   a and b, and return the new size.
+
+   If s == 0 (used for gcd and gcdext), returns zero if the gcd is
+   found.
+
+   If s > 0, don't reduce to size <= s, and return zero if no
+   reduction is possible (if either a, b or |a-b| is of size <= s). */
+
+/* The hook function is called as
+
+     hook(ctx, gp, gn, qp, qn, d)
+
+   in the following cases:
+
+   + If A = B at the start, G is the gcd, Q is NULL, d = -1.
+
+   + If one input is zero at the start, G is the gcd, Q is NULL,
+     d = 0 if A = G and d = 1 if B = G.
+
+   Otherwise, if d = 0 we have just subtracted a multiple of A from B,
+   and if d = 1 we have subtracted a multiple of B from A.
+
+   + If A = B after subtraction, G is the gcd, Q is NULL.
+
+   + If we get a zero remainder after division, G is the gcd, Q is the
+     quotient.
+
+   + Otherwise, G is NULL, Q is the quotient (often 1).
+
+ */
+
+mp_size_t
+mpn_gcd_subdiv_step (mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t s,
+		     gcd_subdiv_step_hook *hook, void *ctx,
+		     mp_ptr tp)
+{
+  static const mp_limb_t one = CNST_LIMB(1);
+  mp_size_t an, bn, qn;
+
+  int swapped;
+
+  ASSERT (n > 0);
+  ASSERT (ap[n-1] > 0 || bp[n-1] > 0);
+
+  an = bn = n;
+  MPN_NORMALIZE (ap, an);
+  MPN_NORMALIZE (bp, bn);
+
+  swapped = 0;
+
+  /* Arrange so that a < b, subtract b -= a, and maintain
+     normalization. */
+  if (an == bn)
+    {
+      int c;
+      MPN_CMP (c, ap, bp, an);
+      if (UNLIKELY (c == 0))
+	{
+	  /* For gcdext, return the smallest of the two cofactors, so
+	     pass d = -1. */
+	  if (s == 0)
+	    hook (ctx, ap, an, NULL, 0, -1);
+	  return 0;
+	}
+      else if (c > 0)
+	{
+	  MP_PTR_SWAP (ap, bp);
+	  swapped ^= 1;
+	}
+    }
+  else
+    {
+      if (an > bn)
+	{
+	  MPN_PTR_SWAP (ap, an, bp, bn);
+	  swapped ^= 1;
+	}
+    }
+  if (an <= s)
+    {
+      if (s == 0)
+	hook (ctx, bp, bn, NULL, 0, swapped ^ 1);
+      return 0;
+    }
+
+  ASSERT_NOCARRY (mpn_sub (bp, bp, bn, ap, an));
+  MPN_NORMALIZE (bp, bn);
+  ASSERT (bn > 0);
+
+  if (bn <= s)
+    {
+      /* Undo subtraction. */
+      mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
+      if (cy > 0)
+	bp[an] = cy;
+      return 0;
+    }
+
+  /* Arrange so that a < b */
+  if (an == bn)
+    {
+      int c;
+      MPN_CMP (c, ap, bp, an);
+      if (UNLIKELY (c == 0))
+	{
+	  if (s > 0)
+	    /* Just record subtraction and return */
+	    hook (ctx, NULL, 0, &one, 1, swapped);
+	  else
+	    /* Found gcd. */
+	    hook (ctx, bp, bn, NULL, 0, swapped);
+	  return 0;
+	}
+
+      hook (ctx, NULL, 0, &one, 1, swapped);
+
+      if (c > 0)
+	{
+	  MP_PTR_SWAP (ap, bp);
+	  swapped ^= 1;
+	}
+    }
+  else
+    {
+      hook (ctx, NULL, 0, &one, 1, swapped);
+
+      if (an > bn)
+	{
+	  MPN_PTR_SWAP (ap, an, bp, bn);
+	  swapped ^= 1;
+	}
+    }
+
+  mpn_tdiv_qr (tp, bp, 0, bp, bn, ap, an);
+  qn = bn - an + 1;
+  bn = an;
+  MPN_NORMALIZE (bp, bn);
+
+  if (UNLIKELY (bn <= s))
+    {
+      if (s == 0)
+	{
+	  hook (ctx, ap, an, tp, qn, swapped);
+	  return 0;
+	}
+
+      /* Quotient is one too large, so decrement it and add back A. */
+      if (bn > 0)
+	{
+	  mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
+	  if (cy)
+	    bp[an++] = cy;
+	}
+      else
+	MPN_COPY (bp, ap, an);
+
+      MPN_DECR_U (tp, qn, 1);
+    }
+
+  hook (ctx, NULL, 0, tp, qn, swapped);
+  return an;
+}
diff --git a/mpn/generic/gcdext.c b/mpn/generic/gcdext.c
new file mode 100644
index 0000000..5501480
--- /dev/null
+++ b/mpn/generic/gcdext.c
@@ -0,0 +1,557 @@
+/* mpn_gcdext -- Extended Greatest Common Divisor.
+
+Copyright 1996, 1998, 2000-2005, 2008, 2009, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Computes (r;b) = (a; b) M. Result is of size n + M->n +/- 1, and
+   the size is returned (if inputs are non-normalized, result may be
+   non-normalized too). Temporary space needed is M->n + n.
+ */
+static size_t
+hgcd_mul_matrix_vector (struct hgcd_matrix *M,
+			mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ah, bh;
+
+  /* Compute (r,b) <-- (u00 a + u10 b, u01 a + u11 b) as
+
+     t  = u00 * a
+     r  = u10 * b
+     r += t;
+
+     t  = u11 * b
+     b  = u01 * a
+     b += t;
+  */
+
+  if (M->n >= n)
+    {
+      mpn_mul (tp, M->p[0][0], M->n, ap, n);
+      mpn_mul (rp, M->p[1][0], M->n, bp, n);
+    }
+  else
+    {
+      mpn_mul (tp, ap, n, M->p[0][0], M->n);
+      mpn_mul (rp, bp, n, M->p[1][0], M->n);
+    }
+
+  ah = mpn_add_n (rp, rp, tp, n + M->n);
+
+  if (M->n >= n)
+    {
+      mpn_mul (tp, M->p[1][1], M->n, bp, n);
+      mpn_mul (bp, M->p[0][1], M->n, ap, n);
+    }
+  else
+    {
+      mpn_mul (tp, bp, n, M->p[1][1], M->n);
+      mpn_mul (bp, ap, n, M->p[0][1], M->n);
+    }
+  bh = mpn_add_n (bp, bp, tp, n + M->n);
+
+  n += M->n;
+  if ( (ah | bh) > 0)
+    {
+      rp[n] = ah;
+      bp[n] = bh;
+      n++;
+    }
+  else
+    {
+      /* Normalize */
+      while ( (rp[n-1] | bp[n-1]) == 0)
+	n--;
+    }
+
+  return n;
+}
+
+#define COMPUTE_V_ITCH(n) (2*(n))
+
+/* Computes |v| = |(g - u a)| / b, where u may be positive or
+   negative, and v is of the opposite sign. max(a, b) is of size n, u and
+   v at most size n, and v must have space for n+1 limbs. */
+static mp_size_t
+compute_v (mp_ptr vp,
+	   mp_srcptr ap, mp_srcptr bp, mp_size_t n,
+	   mp_srcptr gp, mp_size_t gn,
+	   mp_srcptr up, mp_size_t usize,
+	   mp_ptr tp)
+{
+  mp_size_t size;
+  mp_size_t an;
+  mp_size_t bn;
+  mp_size_t vn;
+
+  ASSERT (n > 0);
+  ASSERT (gn > 0);
+  ASSERT (usize != 0);
+
+  size = ABS (usize);
+  ASSERT (size <= n);
+  ASSERT (up[size-1] > 0);
+
+  an = n;
+  MPN_NORMALIZE (ap, an);
+  ASSERT (gn <= an);
+
+  if (an >= size)
+    mpn_mul (tp, ap, an, up, size);
+  else
+    mpn_mul (tp, up, size, ap, an);
+
+  size += an;
+
+  if (usize > 0)
+    {
+      /* |v| = -v = (u a - g) / b */
+
+      ASSERT_NOCARRY (mpn_sub (tp, tp, size, gp, gn));
+      MPN_NORMALIZE (tp, size);
+      if (size == 0)
+	return 0;
+    }
+  else
+    { /* |v| = v = (g - u a) / b = (g + |u| a) / b. Since g <= a,
+	 (g + |u| a) always fits in (|usize| + an) limbs. */
+
+      ASSERT_NOCARRY (mpn_add (tp, tp, size, gp, gn));
+      size -= (tp[size - 1] == 0);
+    }
+
+  /* Now divide t / b. There must be no remainder */
+  bn = n;
+  MPN_NORMALIZE (bp, bn);
+  ASSERT (size >= bn);
+
+  vn = size + 1 - bn;
+  ASSERT (vn <= n + 1);
+
+  mpn_divexact (vp, tp, size, bp, bn);
+  vn -= (vp[vn-1] == 0);
+
+  return vn;
+}
+
+/* Temporary storage:
+
+   Initial division: Quotient of at most an - n + 1 <= an limbs.
+
+   Storage for u0 and u1: 2(n+1).
+
+   Storage for hgcd matrix M, with input ceil(n/2): 5 * ceil(n/4)
+
+   Storage for hgcd, input (n + 1)/2: 9 n/4 plus some.
+
+   When hgcd succeeds: 1 + floor(3n/2) for adjusting a and b, and 2(n+1) for the cofactors.
+
+   When hgcd fails: 2n + 1 for mpn_gcdext_subdiv_step, which is less.
+
+   For the lehmer call after the loop, Let T denote
+   GCDEXT_DC_THRESHOLD. For the gcdext_lehmer call, we need T each for
+   u, a and b, and 4T+3 scratch space. Next, for compute_v, we need T
+   for u, T+1 for v and 2T scratch space. In all, 7T + 3 is
+   sufficient for both operations.
+
+*/
+
+/* Optimal choice of p seems difficult. In each iteration the division
+ * of work between hgcd and the updates of u0 and u1 depends on the
+ * current size of the u. It may be desirable to use a different
+ * choice of p in each iteration. Also the input size seems to matter;
+ * choosing p = n / 3 in the first iteration seems to improve
+ * performance slightly for input size just above the threshold, but
+ * degrade performance for larger inputs. */
+#define CHOOSE_P_1(n) ((n) / 2)
+#define CHOOSE_P_2(n) ((n) / 3)
+
+mp_size_t
+mpn_gcdext (mp_ptr gp, mp_ptr up, mp_size_t *usizep,
+	    mp_ptr ap, mp_size_t an, mp_ptr bp, mp_size_t n)
+{
+  mp_size_t talloc;
+  mp_size_t scratch;
+  mp_size_t matrix_scratch;
+  mp_size_t ualloc = n + 1;
+
+  struct gcdext_ctx ctx;
+  mp_size_t un;
+  mp_ptr u0;
+  mp_ptr u1;
+
+  mp_ptr tp;
+
+  TMP_DECL;
+
+  ASSERT (an >= n);
+  ASSERT (n > 0);
+  ASSERT (bp[n-1] > 0);
+
+  TMP_MARK;
+
+  /* FIXME: Check for small sizes first, before setting up temporary
+     storage etc. */
+  talloc = MPN_GCDEXT_LEHMER_N_ITCH(n);
+
+  /* For initial division */
+  scratch = an - n + 1;
+  if (scratch > talloc)
+    talloc = scratch;
+
+  if (ABOVE_THRESHOLD (n, GCDEXT_DC_THRESHOLD))
+    {
+      /* For hgcd loop. */
+      mp_size_t hgcd_scratch;
+      mp_size_t update_scratch;
+      mp_size_t p1 = CHOOSE_P_1 (n);
+      mp_size_t p2 = CHOOSE_P_2 (n);
+      mp_size_t min_p = MIN(p1, p2);
+      mp_size_t max_p = MAX(p1, p2);
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - min_p);
+      hgcd_scratch = mpn_hgcd_itch (n - min_p);
+      update_scratch = max_p + n - 1;
+
+      scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch);
+      if (scratch > talloc)
+	talloc = scratch;
+
+      /* Final mpn_gcdext_lehmer_n call. Need space for u and for
+	 copies of a and b. */
+      scratch = MPN_GCDEXT_LEHMER_N_ITCH (GCDEXT_DC_THRESHOLD)
+	+ 3*GCDEXT_DC_THRESHOLD;
+
+      if (scratch > talloc)
+	talloc = scratch;
+
+      /* Cofactors u0 and u1 */
+      talloc += 2*(n+1);
+    }
+
+  tp = TMP_ALLOC_LIMBS(talloc);
+
+  if (an > n)
+    {
+      mpn_tdiv_qr (tp, ap, 0, ap, an, bp, n);
+
+      if (mpn_zero_p (ap, n))
+	{
+	  MPN_COPY (gp, bp, n);
+	  *usizep = 0;
+	  TMP_FREE;
+	  return n;
+	}
+    }
+
+  if (BELOW_THRESHOLD (n, GCDEXT_DC_THRESHOLD))
+    {
+      mp_size_t gn = mpn_gcdext_lehmer_n(gp, up, usizep, ap, bp, n, tp);
+
+      TMP_FREE;
+      return gn;
+    }
+
+  MPN_ZERO (tp, 2*ualloc);
+  u0 = tp; tp += ualloc;
+  u1 = tp; tp += ualloc;
+
+  ctx.gp = gp;
+  ctx.up = up;
+  ctx.usize = usizep;
+
+  {
+    /* For the first hgcd call, there are no u updates, and it makes
+       some sense to use a different choice for p. */
+
+    /* FIXME: We could trim use of temporary storage, since u0 and u1
+       are not used yet. For the hgcd call, we could swap in the u0
+       and u1 pointers for the relevant matrix elements. */
+
+    struct hgcd_matrix M;
+    mp_size_t p = CHOOSE_P_1 (n);
+    mp_size_t nn;
+
+    mpn_hgcd_matrix_init (&M, n - p, tp);
+    nn = mpn_hgcd (ap + p, bp + p, n - p, &M, tp + matrix_scratch);
+    if (nn > 0)
+      {
+	ASSERT (M.n <= (n - p - 1)/2);
+	ASSERT (M.n + p <= (p + n - 1) / 2);
+
+	/* Temporary storage 2 (p + M->n) <= p + n - 1 */
+	n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, tp + matrix_scratch);
+
+	MPN_COPY (u0, M.p[1][0], M.n);
+	MPN_COPY (u1, M.p[1][1], M.n);
+	un = M.n;
+	while ( (u0[un-1] | u1[un-1] ) == 0)
+	  un--;
+      }
+    else
+      {
+	/* mpn_hgcd has failed. Then either one of a or b is very
+	   small, or the difference is very small. Perform one
+	   subtraction followed by one division. */
+	u1[0] = 1;
+
+	ctx.u0 = u0;
+	ctx.u1 = u1;
+	ctx.tp = tp + n; /* ualloc */
+	ctx.un = 1;
+
+	/* Temporary storage n */
+	n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
+	if (n == 0)
+	  {
+	    TMP_FREE;
+	    return ctx.gn;
+	  }
+
+	un = ctx.un;
+	ASSERT (un < ualloc);
+      }
+  }
+
+  while (ABOVE_THRESHOLD (n, GCDEXT_DC_THRESHOLD))
+    {
+      struct hgcd_matrix M;
+      mp_size_t p = CHOOSE_P_2 (n);
+      mp_size_t nn;
+
+      mpn_hgcd_matrix_init (&M, n - p, tp);
+      nn = mpn_hgcd (ap + p, bp + p, n - p, &M, tp + matrix_scratch);
+      if (nn > 0)
+	{
+	  mp_ptr t0;
+
+	  t0 = tp + matrix_scratch;
+	  ASSERT (M.n <= (n - p - 1)/2);
+	  ASSERT (M.n + p <= (p + n - 1) / 2);
+
+	  /* Temporary storage 2 (p + M->n) <= p + n - 1 */
+	  n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, t0);
+
+	  /* By the same analysis as for mpn_hgcd_matrix_mul */
+	  ASSERT (M.n + un <= ualloc);
+
+	  /* FIXME: This copying could be avoided by some swapping of
+	   * pointers. May need more temporary storage, though. */
+	  MPN_COPY (t0, u0, un);
+
+	  /* Temporary storage ualloc */
+	  un = hgcd_mul_matrix_vector (&M, u0, t0, u1, un, t0 + un);
+
+	  ASSERT (un < ualloc);
+	  ASSERT ( (u0[un-1] | u1[un-1]) > 0);
+	}
+      else
+	{
+	  /* mpn_hgcd has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+	  ctx.u0 = u0;
+	  ctx.u1 = u1;
+	  ctx.tp = tp + n; /* ualloc */
+	  ctx.un = un;
+
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
+	  if (n == 0)
+	    {
+	      TMP_FREE;
+	      return ctx.gn;
+	    }
+
+	  un = ctx.un;
+	  ASSERT (un < ualloc);
+	}
+    }
+  /* We have A = ... a + ... b
+	     B =  u0 a +  u1 b
+
+	     a = u1  A + ... B
+	     b = -u0 A + ... B
+
+     with bounds
+
+       |u0|, |u1| <= B / min(a, b)
+
+     We always have u1 > 0, and u0 == 0 is possible only if u1 == 1,
+     in which case the only reduction done so far is a = A - k B for
+     some k.
+
+     Compute g = u a + v b = (u u1 - v u0) A + (...) B
+     Here, u, v are bounded by
+
+       |u| <= b,
+       |v| <= a
+  */
+
+  ASSERT ( (ap[n-1] | bp[n-1]) > 0);
+
+  if (UNLIKELY (mpn_cmp (ap, bp, n) == 0))
+    {
+      /* Must return the smallest cofactor, +u1 or -u0 */
+      int c;
+
+      MPN_COPY (gp, ap, n);
+
+      MPN_CMP (c, u0, u1, un);
+      /* c == 0 can happen only when A = (2k+1) G, B = 2 G. And in
+	 this case we choose the cofactor + 1, corresponding to G = A
+	 - k B, rather than -1, corresponding to G = - A + (k+1) B. */
+      ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
+      if (c < 0)
+	{
+	  MPN_NORMALIZE (u0, un);
+	  MPN_COPY (up, u0, un);
+	  *usizep = -un;
+	}
+      else
+	{
+	  MPN_NORMALIZE_NOT_ZERO (u1, un);
+	  MPN_COPY (up, u1, un);
+	  *usizep = un;
+	}
+
+      TMP_FREE;
+      return n;
+    }
+  else if (UNLIKELY (u0[0] == 0) && un == 1)
+    {
+      mp_size_t gn;
+      ASSERT (u1[0] == 1);
+
+      /* g = u a + v b = (u u1 - v u0) A + (...) B = u A + (...) B */
+      gn = mpn_gcdext_lehmer_n (gp, up, usizep, ap, bp, n, tp);
+
+      TMP_FREE;
+      return gn;
+    }
+  else
+    {
+      mp_size_t u0n;
+      mp_size_t u1n;
+      mp_size_t lehmer_un;
+      mp_size_t lehmer_vn;
+      mp_size_t gn;
+
+      mp_ptr lehmer_up;
+      mp_ptr lehmer_vp;
+      int negate;
+
+      lehmer_up = tp; tp += n;
+
+      /* Call mpn_gcdext_lehmer_n with copies of a and b. */
+      MPN_COPY (tp, ap, n);
+      MPN_COPY (tp + n, bp, n);
+      gn = mpn_gcdext_lehmer_n (gp, lehmer_up, &lehmer_un, tp, tp + n, n, tp + 2*n);
+
+      u0n = un;
+      MPN_NORMALIZE (u0, u0n);
+      ASSERT (u0n > 0);
+
+      if (lehmer_un == 0)
+	{
+	  /* u == 0  ==>  v = g / b == 1  ==> g = - u0 A + (...) B */
+	  MPN_COPY (up, u0, u0n);
+	  *usizep = -u0n;
+
+	  TMP_FREE;
+	  return gn;
+	}
+
+      lehmer_vp = tp;
+      /* Compute v = (g - u a) / b */
+      lehmer_vn = compute_v (lehmer_vp,
+			     ap, bp, n, gp, gn, lehmer_up, lehmer_un, tp + n + 1);
+
+      if (lehmer_un > 0)
+	negate = 0;
+      else
+	{
+	  lehmer_un = -lehmer_un;
+	  negate = 1;
+	}
+
+      u1n = un;
+      MPN_NORMALIZE (u1, u1n);
+      ASSERT (u1n > 0);
+
+      ASSERT (lehmer_un + u1n <= ualloc);
+      ASSERT (lehmer_vn + u0n <= ualloc);
+
+      /* We may still have v == 0 */
+
+      /* Compute u u0 */
+      if (lehmer_un <= u1n)
+	/* Should be the common case */
+	mpn_mul (up, u1, u1n, lehmer_up, lehmer_un);
+      else
+	mpn_mul (up, lehmer_up, lehmer_un, u1, u1n);
+
+      un = u1n + lehmer_un;
+      un -= (up[un - 1] == 0);
+
+      if (lehmer_vn > 0)
+	{
+	  mp_limb_t cy;
+
+	  /* Overwrites old u1 value */
+	  if (lehmer_vn <= u0n)
+	    /* Should be the common case */
+	    mpn_mul (u1, u0, u0n, lehmer_vp, lehmer_vn);
+	  else
+	    mpn_mul (u1, lehmer_vp, lehmer_vn, u0, u0n);
+
+	  u1n = u0n + lehmer_vn;
+	  u1n -= (u1[u1n - 1] == 0);
+
+	  if (u1n <= un)
+	    {
+	      cy = mpn_add (up, up, un, u1, u1n);
+	    }
+	  else
+	    {
+	      cy = mpn_add (up, u1, u1n, up, un);
+	      un = u1n;
+	    }
+	  up[un] = cy;
+	  un += (cy != 0);
+
+	  ASSERT (un < ualloc);
+	}
+      *usizep = negate ? -un : un;
+
+      TMP_FREE;
+      return gn;
+    }
+}
diff --git a/mpn/generic/gcdext_1.c b/mpn/generic/gcdext_1.c
new file mode 100644
index 0000000..b221a92
--- /dev/null
+++ b/mpn/generic/gcdext_1.c
@@ -0,0 +1,275 @@
+/* mpn_gcdext -- Extended Greatest Common Divisor.
+
+Copyright 1996, 1998, 2000-2005, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef GCDEXT_1_USE_BINARY
+#define GCDEXT_1_USE_BINARY 0
+#endif
+
+#ifndef GCDEXT_1_BINARY_METHOD
+#define GCDEXT_1_BINARY_METHOD 2
+#endif
+
+#if GCDEXT_1_USE_BINARY
+
+mp_limb_t
+mpn_gcdext_1 (mp_limb_signed_t *sp, mp_limb_signed_t *tp,
+	      mp_limb_t u, mp_limb_t v)
+{
+  /* Maintain
+
+     U = t1 u + t0 v
+     V = s1 u + s0 v
+
+     where U, V are the inputs (without any shared power of two),
+     and the matrix has determinant ± 2^{shift}.
+  */
+  mp_limb_t s0 = 1;
+  mp_limb_t t0 = 0;
+  mp_limb_t s1 = 0;
+  mp_limb_t t1 = 1;
+  mp_limb_t ug;
+  mp_limb_t vg;
+  mp_limb_t ugh;
+  mp_limb_t vgh;
+  unsigned zero_bits;
+  unsigned shift;
+  unsigned i;
+#if GCDEXT_1_BINARY_METHOD == 2
+  mp_limb_t det_sign;
+#endif
+
+  ASSERT (u > 0);
+  ASSERT (v > 0);
+
+  count_trailing_zeros (zero_bits, u | v);
+  u >>= zero_bits;
+  v >>= zero_bits;
+
+  if ((u & 1) == 0)
+    {
+      count_trailing_zeros (shift, u);
+      u >>= shift;
+      t1 <<= shift;
+    }
+  else if ((v & 1) == 0)
+    {
+      count_trailing_zeros (shift, v);
+      v >>= shift;
+      s0 <<= shift;
+    }
+  else
+    shift = 0;
+
+#if GCDEXT_1_BINARY_METHOD == 1
+  while (u != v)
+    {
+      unsigned count;
+      if (u > v)
+	{
+	  u -= v;
+
+	  count_trailing_zeros (count, u);
+	  u >>= count;
+
+	  t0 += t1; t1 <<= count;
+	  s0 += s1; s1 <<= count;
+	}
+      else
+	{
+	  v -= u;
+
+	  count_trailing_zeros (count, v);
+	  v >>= count;
+
+	  t1 += t0; t0 <<= count;
+	  s1 += s0; s0 <<= count;
+	}
+      shift += count;
+    }
+#else
+# if GCDEXT_1_BINARY_METHOD == 2
+  u >>= 1;
+  v >>= 1;
+
+  det_sign = 0;
+
+  while (u != v)
+    {
+      unsigned count;
+      mp_limb_t d =  u - v;
+      mp_limb_t vgtu = LIMB_HIGHBIT_TO_MASK (d);
+      mp_limb_t sx;
+      mp_limb_t tx;
+
+      /* When v <= u (vgtu == 0), the updates are:
+
+	   (u; v)   <-- ( (u - v) >> count; v)    (det = +(1<<count) for corr. M factor)
+	   (t1, t0) <-- (t1 << count, t0 + t1)
+
+	 and when v > 0, the updates are
+
+	   (u; v)   <-- ( (v - u) >> count; u)    (det = -(1<<count))
+	   (t1, t0) <-- (t0 << count, t0 + t1)
+
+	 and similarly for s1, s0
+      */
+
+      /* v <-- min (u, v) */
+      v += (vgtu & d);
+
+      /* u <-- |u - v| */
+      u = (d ^ vgtu) - vgtu;
+
+      /* Number of trailing zeros is the same no matter if we look at
+       * d or u, but using d gives more parallelism. */
+      count_trailing_zeros (count, d);
+
+      det_sign ^= vgtu;
+
+      tx = vgtu & (t0 - t1);
+      sx = vgtu & (s0 - s1);
+      t0 += t1;
+      s0 += s1;
+      t1 += tx;
+      s1 += sx;
+
+      count++;
+      u >>= count;
+      t1 <<= count;
+      s1 <<= count;
+      shift += count;
+    }
+  u = (u << 1) + 1;
+# else /* GCDEXT_1_BINARY_METHOD == 2 */
+#  error Unknown GCDEXT_1_BINARY_METHOD
+# endif
+#endif
+
+  /* Now u = v = g = gcd (u,v). Compute U/g and V/g */
+  ug = t0 + t1;
+  vg = s0 + s1;
+
+  ugh = ug/2 + (ug & 1);
+  vgh = vg/2 + (vg & 1);
+
+  /* Now 2^{shift} g = s0 U - t0 V. Get rid of the power of two, using
+     s0 U - t0 V = (s0 + V/g) U - (t0 + U/g) V. */
+  for (i = 0; i < shift; i++)
+    {
+      mp_limb_t mask = - ( (s0 | t0) & 1);
+
+      s0 /= 2;
+      t0 /= 2;
+      s0 += mask & vgh;
+      t0 += mask & ugh;
+    }
+
+  ASSERT_ALWAYS (s0 <= vg);
+  ASSERT_ALWAYS (t0 <= ug);
+
+  if (s0 > vg - s0)
+    {
+      s0 -= vg;
+      t0 -= ug;
+    }
+#if GCDEXT_1_BINARY_METHOD == 2
+  /* Conditional negation. */
+  s0 = (s0 ^ det_sign) - det_sign;
+  t0 = (t0 ^ det_sign) - det_sign;
+#endif
+  *sp = s0;
+  *tp = -t0;
+
+  return u << zero_bits;
+}
+
+#else /* !GCDEXT_1_USE_BINARY */
+
+
+/* FIXME: Takes two single-word limbs. It could be extended to a
+ * function that accepts a bignum for the first input, and only
+ * returns the first co-factor. */
+
+mp_limb_t
+mpn_gcdext_1 (mp_limb_signed_t *up, mp_limb_signed_t *vp,
+	      mp_limb_t a, mp_limb_t b)
+{
+  /* Maintain
+
+     a =  u0 A + v0 B
+     b =  u1 A + v1 B
+
+     where A, B are the original inputs.
+  */
+  mp_limb_signed_t u0 = 1;
+  mp_limb_signed_t v0 = 0;
+  mp_limb_signed_t u1 = 0;
+  mp_limb_signed_t v1 = 1;
+
+  ASSERT (a > 0);
+  ASSERT (b > 0);
+
+  if (a < b)
+    goto divide_by_b;
+
+  for (;;)
+    {
+      mp_limb_t q;
+
+      q = a / b;
+      a -= q * b;
+
+      if (a == 0)
+	{
+	  *up = u1;
+	  *vp = v1;
+	  return b;
+	}
+      u0 -= q * u1;
+      v0 -= q * v1;
+
+    divide_by_b:
+      q = b / a;
+      b -= q * a;
+
+      if (b == 0)
+	{
+	  *up = u0;
+	  *vp = v0;
+	  return a;
+	}
+      u1 -= q * u0;
+      v1 -= q * v0;
+    }
+}
+#endif /* !GCDEXT_1_USE_BINARY */
diff --git a/mpn/generic/gcdext_lehmer.c b/mpn/generic/gcdext_lehmer.c
new file mode 100644
index 0000000..ea4e86d
--- /dev/null
+++ b/mpn/generic/gcdext_lehmer.c
@@ -0,0 +1,336 @@
+/* mpn_gcdext -- Extended Greatest Common Divisor.
+
+Copyright 1996, 1998, 2000-2005, 2008, 2009, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Here, d is the index of the cofactor to update. FIXME: Could use qn
+   = 0 for the common case q = 1. */
+void
+mpn_gcdext_hook (void *p, mp_srcptr gp, mp_size_t gn,
+		 mp_srcptr qp, mp_size_t qn, int d)
+{
+  struct gcdext_ctx *ctx = (struct gcdext_ctx *) p;
+  mp_size_t un = ctx->un;
+
+  if (gp)
+    {
+      mp_srcptr up;
+
+      ASSERT (gn > 0);
+      ASSERT (gp[gn-1] > 0);
+
+      MPN_COPY (ctx->gp, gp, gn);
+      ctx->gn = gn;
+
+      if (d < 0)
+	{
+	  int c;
+
+	  /* Must return the smallest cofactor, +u1 or -u0 */
+	  MPN_CMP (c, ctx->u0, ctx->u1, un);
+	  ASSERT (c != 0 || (un == 1 && ctx->u0[0] == 1 && ctx->u1[0] == 1));
+
+	  d = c < 0;
+	}
+
+      up = d ? ctx->u0 : ctx->u1;
+
+      MPN_NORMALIZE (up, un);
+      MPN_COPY (ctx->up, up, un);
+
+      *ctx->usize = d ? -un : un;
+    }
+  else
+    {
+      mp_limb_t cy;
+      mp_ptr u0 = ctx->u0;
+      mp_ptr u1 = ctx->u1;
+
+      ASSERT (d >= 0);
+
+      if (d)
+	MP_PTR_SWAP (u0, u1);
+
+      qn -= (qp[qn-1] == 0);
+
+      /* Update u0 += q  * u1 */
+      if (qn == 1)
+	{
+	  mp_limb_t q = qp[0];
+
+	  if (q == 1)
+	    /* A common case. */
+	    cy = mpn_add_n (u0, u0, u1, un);
+	  else
+	    cy = mpn_addmul_1 (u0, u1, un, q);
+	}
+      else
+	{
+	  mp_size_t u1n;
+	  mp_ptr tp;
+
+	  u1n = un;
+	  MPN_NORMALIZE (u1, u1n);
+
+	  if (u1n == 0)
+	    return;
+
+	  /* Should always have u1n == un here, and u1 >= u0. The
+	     reason is that we alternate adding u0 to u1 and u1 to u0
+	     (corresponding to subtractions a - b and b - a), and we
+	     can get a large quotient only just after a switch, which
+	     means that we'll add (a multiple of) the larger u to the
+	     smaller. */
+
+	  tp = ctx->tp;
+
+	  if (qn > u1n)
+	    mpn_mul (tp, qp, qn, u1, u1n);
+	  else
+	    mpn_mul (tp, u1, u1n, qp, qn);
+
+	  u1n += qn;
+	  u1n -= tp[u1n-1] == 0;
+
+	  if (u1n >= un)
+	    {
+	      cy = mpn_add (u0, tp, u1n, u0, un);
+	      un = u1n;
+	    }
+	  else
+	    /* Note: Unlikely case, maybe never happens? */
+	    cy = mpn_add (u0, u0, un, tp, u1n);
+
+	}
+      u0[un] = cy;
+      ctx->un = un + (cy > 0);
+    }
+}
+
+/* Temporary storage: 3*(n+1) for u. If hgcd2 succeeds, we need n for
+   the matrix-vector multiplication adjusting a, b. If hgcd fails, we
+   need at most n for the quotient and n+1 for the u update (reusing
+   the extra u). In all, 4n + 3. */
+
+mp_size_t
+mpn_gcdext_lehmer_n (mp_ptr gp, mp_ptr up, mp_size_t *usize,
+		     mp_ptr ap, mp_ptr bp, mp_size_t n,
+		     mp_ptr tp)
+{
+  mp_size_t ualloc = n + 1;
+
+  /* Keeps track of the second row of the reduction matrix
+   *
+   *   M = (v0, v1 ; u0, u1)
+   *
+   * which correspond to the first column of the inverse
+   *
+   *   M^{-1} = (u1, -v1; -u0, v0)
+   *
+   * This implies that
+   *
+   *   a =  u1 A (mod B)
+   *   b = -u0 A (mod B)
+   *
+   * where A, B denotes the input values.
+   */
+
+  struct gcdext_ctx ctx;
+  mp_size_t un;
+  mp_ptr u0;
+  mp_ptr u1;
+  mp_ptr u2;
+
+  MPN_ZERO (tp, 3*ualloc);
+  u0 = tp; tp += ualloc;
+  u1 = tp; tp += ualloc;
+  u2 = tp; tp += ualloc;
+
+  u1[0] = 1; un = 1;
+
+  ctx.gp = gp;
+  ctx.up = up;
+  ctx.usize = usize;
+
+  /* FIXME: Handle n == 2 differently, after the loop? */
+  while (n >= 2)
+    {
+      struct hgcd_matrix1 M;
+      mp_limb_t ah, al, bh, bl;
+      mp_limb_t mask;
+
+      mask = ap[n-1] | bp[n-1];
+      ASSERT (mask > 0);
+
+      if (mask & GMP_NUMB_HIGHBIT)
+	{
+	  ah = ap[n-1]; al = ap[n-2];
+	  bh = bp[n-1]; bl = bp[n-2];
+	}
+      else if (n == 2)
+	{
+	  /* We use the full inputs without truncation, so we can
+	     safely shift left. */
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  ah = MPN_EXTRACT_NUMB (shift, ap[1], ap[0]);
+	  al = ap[0] << shift;
+	  bh = MPN_EXTRACT_NUMB (shift, bp[1], bp[0]);
+	  bl = bp[0] << shift;
+	}
+      else
+	{
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+	  al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+	  bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+	  bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+	}
+
+      /* Try an mpn_nhgcd2 step */
+      if (mpn_hgcd2 (ah, al, bh, bl, &M))
+	{
+	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
+	  MP_PTR_SWAP (ap, tp);
+	  un = mpn_hgcd_mul_matrix1_vector(&M, u2, u0, u1, un);
+	  MP_PTR_SWAP (u0, u2);
+	}
+      else
+	{
+	  /* mpn_hgcd2 has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+	  ctx.u0 = u0;
+	  ctx.u1 = u1;
+	  ctx.tp = u2;
+	  ctx.un = un;
+
+	  /* Temporary storage n for the quotient and ualloc for the
+	     new cofactor. */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
+	  if (n == 0)
+	    return ctx.gn;
+
+	  un = ctx.un;
+	}
+    }
+  ASSERT_ALWAYS (ap[0] > 0);
+  ASSERT_ALWAYS (bp[0] > 0);
+
+  if (ap[0] == bp[0])
+    {
+      int c;
+
+      /* Which cofactor to return now? Candidates are +u1 and -u0,
+	 depending on which of a and b was most recently reduced,
+	 which we don't keep track of. So compare and get the smallest
+	 one. */
+
+      gp[0] = ap[0];
+
+      MPN_CMP (c, u0, u1, un);
+      ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
+      if (c < 0)
+	{
+	  MPN_NORMALIZE (u0, un);
+	  MPN_COPY (up, u0, un);
+	  *usize = -un;
+	}
+      else
+	{
+	  MPN_NORMALIZE_NOT_ZERO (u1, un);
+	  MPN_COPY (up, u1, un);
+	  *usize = un;
+	}
+      return 1;
+    }
+  else
+    {
+      mp_limb_t uh, vh;
+      mp_limb_signed_t u;
+      mp_limb_signed_t v;
+      int negate;
+
+      gp[0] = mpn_gcdext_1 (&u, &v, ap[0], bp[0]);
+
+      /* Set up = u u1 - v u0. Keep track of size, un grows by one or
+	 two limbs. */
+
+      if (u == 0)
+	{
+	  ASSERT (v == 1);
+	  MPN_NORMALIZE (u0, un);
+	  MPN_COPY (up, u0, un);
+	  *usize = -un;
+	  return 1;
+	}
+      else if (v == 0)
+	{
+	  ASSERT (u == 1);
+	  MPN_NORMALIZE (u1, un);
+	  MPN_COPY (up, u1, un);
+	  *usize = un;
+	  return 1;
+	}
+      else if (u > 0)
+	{
+	  negate = 0;
+	  ASSERT (v < 0);
+	  v = -v;
+	}
+      else
+	{
+	  negate = 1;
+	  ASSERT (v > 0);
+	  u = -u;
+	}
+
+      uh = mpn_mul_1 (up, u1, un, u);
+      vh = mpn_addmul_1 (up, u0, un, v);
+
+      if ( (uh | vh) > 0)
+	{
+	  uh += vh;
+	  up[un++] = uh;
+	  if (uh < vh)
+	    up[un++] = 1;
+	}
+
+      MPN_NORMALIZE_NOT_ZERO (up, un);
+
+      *usize = negate ? -un : un;
+      return 1;
+    }
+}
diff --git a/mpn/generic/get_d.c b/mpn/generic/get_d.c
new file mode 100644
index 0000000..4c1f3b6
--- /dev/null
+++ b/mpn/generic/get_d.c
@@ -0,0 +1,438 @@
+/* mpn_get_d -- limbs to double conversion.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2003, 2004, 2007, 2009, 2010, 2012, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MANT_DIG and FLT_RADIX */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef _GMP_IEEE_FLOATS
+#define _GMP_IEEE_FLOATS 0
+#endif
+
+/* To force use of the generic C code for testing, put
+   "#define _GMP_IEEE_FLOATS 0" at this point.  */
+
+
+/* In alpha gcc prior to 3.4, signed DI comparisons involving constants are
+   rearranged from "x < n" to "x+(-n) < 0", which is of course hopelessly
+   wrong if that addition overflows.
+
+   The workaround here avoids this bug by ensuring n is not a literal constant.
+   Note that this is alpha specific.  The offending transformation is/was in
+   alpha.c alpha_emit_conditional_branch() under "We want to use cmpcc/bcc".
+
+   Bizarrely, this happens also with Cray cc on alphaev5-cray-unicosmk2.0.6.X,
+   and has the same solution.  Don't know why or how.  */
+
+#if HAVE_HOST_CPU_FAMILY_alpha				\
+  && ((defined (__GNUC__) && ! __GMP_GNUC_PREREQ(3,4))	\
+      || defined (_CRAY))
+static volatile const long CONST_1024 = 1024;
+static volatile const long CONST_NEG_1023 = -1023;
+static volatile const long CONST_NEG_1022_SUB_53 = -1022 - 53;
+#else
+#define CONST_1024	      (1024)
+#define CONST_NEG_1023	      (-1023)
+#define CONST_NEG_1022_SUB_53 (-1022 - 53)
+#endif
+
+
+/* Return the value {ptr,size}*2^exp, and negative if sign<0.  Must have
+   size>=1, and a non-zero high limb ptr[size-1].
+
+   When we know the fp format, the result is truncated towards zero.  This is
+   consistent with other gmp conversions, like mpz_set_f or mpz_set_q, and is
+   easy to implement and test.
+
+   When we do not know the format, such truncation seems much harder.  One
+   would need to defeat any rounding mode, including round-up.
+
+   It's felt that GMP is not primarily concerned with hardware floats, and
+   really isn't enhanced by getting involved with hardware rounding modes
+   (which could even be some weird unknown style), so something unambiguous and
+   straightforward is best.
+
+
+   The IEEE code below is the usual case, it knows either a 32-bit or 64-bit
+   limb and is done with shifts and masks.  The 64-bit case in particular
+   should come out nice and compact.
+
+   The generic code used to work one bit at a time, which was not only slow,
+   but implicitly relied upon denorms for intermediates, since the lowest bits'
+   weight of a perfectly valid fp number underflows in non-denorm.  Therefore,
+   the generic code now works limb-per-limb, initially creating a number x such
+   that 1 <= x <= BASE.  (BASE is reached only as result of rounding.)  Then
+   x's exponent is scaled with explicit code (not ldexp to avoid libm
+   dependency).  It is a tap-dance to avoid underflow or overflow, beware!
+
+
+   Traps:
+
+   Hardware traps for overflow to infinity, underflow to zero, or unsupported
+   denorms may or may not be taken.  The IEEE code works bitwise and so
+   probably won't trigger them, the generic code works by float operations and
+   so probably will.  This difference might be thought less than ideal, but
+   again its felt straightforward code is better than trying to get intimate
+   with hardware exceptions (of perhaps unknown nature).
+
+
+   Not done:
+
+   mpz_get_d in the past handled size==1 with a cast limb->double.  This might
+   still be worthwhile there (for up to the mantissa many bits), but for
+   mpn_get_d here, the cost of applying "exp" to the resulting exponent would
+   probably use up any benefit a cast may have over bit twiddling.  Also, if
+   the exponent is pushed into denorm range then bit twiddling is the only
+   option, to ensure the desired truncation is obtained.
+
+
+   Other:
+
+   For reference, note that HPPA 8000, 8200, 8500 and 8600 trap FCNV,UDW,DBL
+   to the kernel for values >= 2^63.  This makes it slow, and worse the kernel
+   Linux (what versions?) apparently uses untested code in its trap handling
+   routines, and gets the sign wrong.  We don't use such a limb-to-double
+   cast, neither in the IEEE or generic code.  */
+
+
+
+#undef FORMAT_RECOGNIZED
+
+double
+mpn_get_d (mp_srcptr up, mp_size_t size, mp_size_t sign, long exp)
+{
+  int lshift, nbits;
+  mp_limb_t x, mhi, mlo;
+
+  ASSERT (size >= 0);
+  ASSERT_MPN (up, size);
+  ASSERT (size == 0 || up[size-1] != 0);
+
+  if (size == 0)
+    return 0.0;
+
+  /* Adjust exp to a radix point just above {up,size}, guarding against
+     overflow.  After this exp can of course be reduced to anywhere within
+     the {up,size} region without underflow.  */
+  if (UNLIKELY ((unsigned long) (GMP_NUMB_BITS) * (unsigned long) (size)
+		> (LONG_MAX - (unsigned long) exp)))
+    {
+#if _GMP_IEEE_FLOATS
+      goto ieee_infinity;
+#endif
+
+      /* generic */
+      exp = LONG_MAX;
+    }
+  else
+    {
+      exp += GMP_NUMB_BITS * size;
+    }
+
+#if _GMP_IEEE_FLOATS
+    {
+      union ieee_double_extract u;
+
+      up += size;
+
+#if GMP_LIMB_BITS == 64
+      mlo = up[-1];
+      count_leading_zeros (lshift, mlo);
+
+      exp -= (lshift - GMP_NAIL_BITS) + 1;
+      mlo <<= lshift;
+
+      nbits = GMP_LIMB_BITS - lshift;
+
+      if (nbits < 53 && size > 1)
+	{
+	  x = up[-2];
+	  x <<= GMP_NAIL_BITS;
+	  x >>= nbits;
+	  mlo |= x;
+	  nbits += GMP_NUMB_BITS;
+
+	  if (LIMBS_PER_DOUBLE >= 3 && nbits < 53 && size > 2)
+	    {
+	      x = up[-3];
+	      x <<= GMP_NAIL_BITS;
+	      x >>= nbits;
+	      mlo |= x;
+	      nbits += GMP_NUMB_BITS;
+	    }
+	}
+      mhi = mlo >> (32 + 11);
+      mlo = mlo >> 11;		/* later implicitly truncated to 32 bits */
+#endif
+#if GMP_LIMB_BITS == 32
+      x = *--up;
+      count_leading_zeros (lshift, x);
+
+      exp -= (lshift - GMP_NAIL_BITS) + 1;
+      x <<= lshift;
+      mhi = x >> 11;
+
+      if (lshift < 11)		/* FIXME: never true if NUMB < 20 bits */
+	{
+	  /* All 20 bits in mhi */
+	  mlo = x << 21;
+	  /* >= 1 bit in mlo */
+	  nbits = GMP_LIMB_BITS - lshift - 21;
+	}
+      else
+	{
+	  if (size > 1)
+	    {
+	      nbits = GMP_LIMB_BITS - lshift;
+
+	      x = *--up, size--;
+	      x <<= GMP_NAIL_BITS;
+	      mhi |= x >> nbits >> 11;
+
+	      mlo = x << (GMP_LIMB_BITS - nbits - 11);
+	      nbits = nbits + 11 - GMP_NAIL_BITS;
+	    }
+	  else
+	    {
+	      mlo = 0;
+	      goto done;
+	    }
+	}
+
+      /* Now all needed bits in mhi have been accumulated.  Add bits to mlo.  */
+
+      if (LIMBS_PER_DOUBLE >= 2 && nbits < 32 && size > 1)
+	{
+	  x = up[-1];
+	  x <<= GMP_NAIL_BITS;
+	  x >>= nbits;
+	  mlo |= x;
+	  nbits += GMP_NUMB_BITS;
+
+	  if (LIMBS_PER_DOUBLE >= 3 && nbits < 32 && size > 2)
+	    {
+	      x = up[-2];
+	      x <<= GMP_NAIL_BITS;
+	      x >>= nbits;
+	      mlo |= x;
+	      nbits += GMP_NUMB_BITS;
+
+	      if (LIMBS_PER_DOUBLE >= 4 && nbits < 32 && size > 3)
+		{
+		  x = up[-3];
+		  x <<= GMP_NAIL_BITS;
+		  x >>= nbits;
+		  mlo |= x;
+		  nbits += GMP_NUMB_BITS;
+		}
+	    }
+	}
+
+    done:;
+
+#endif
+      if (UNLIKELY (exp >= CONST_1024))
+	{
+	  /* overflow, return infinity */
+	ieee_infinity:
+	  mhi = 0;
+	  mlo = 0;
+	  exp = 1024;
+	}
+      else if (UNLIKELY (exp <= CONST_NEG_1023))
+	{
+	  int rshift;
+
+	  if (LIKELY (exp <= CONST_NEG_1022_SUB_53))
+	    return 0.0;	 /* denorm underflows to zero */
+
+	  rshift = -1022 - exp;
+	  ASSERT (rshift > 0 && rshift < 53);
+#if GMP_LIMB_BITS > 53
+	  mlo >>= rshift;
+	  mhi = mlo >> 32;
+#else
+	  if (rshift >= 32)
+	    {
+	      mlo = mhi;
+	      mhi = 0;
+	      rshift -= 32;
+	    }
+	  lshift = GMP_LIMB_BITS - rshift;
+	  mlo = (mlo >> rshift) | (rshift == 0 ? 0 : mhi << lshift);
+	  mhi >>= rshift;
+#endif
+	  exp = -1023;
+	}
+      u.s.manh = mhi;
+      u.s.manl = mlo;
+      u.s.exp = exp + 1023;
+      u.s.sig = (sign < 0);
+      return u.d;
+    }
+#define FORMAT_RECOGNIZED 1
+#endif
+
+#if HAVE_DOUBLE_VAX_D
+    {
+      union double_extract u;
+
+      up += size;
+
+      mhi = up[-1];
+
+      count_leading_zeros (lshift, mhi);
+      exp -= lshift;
+      mhi <<= lshift;
+
+      mlo = 0;
+      if (size > 1)
+	{
+	  mlo = up[-2];
+	  if (lshift != 0)
+	    mhi += mlo >> (GMP_LIMB_BITS - lshift);
+	  mlo <<= lshift;
+
+	  if (size > 2 && lshift > 8)
+	    {
+	      x = up[-3];
+	      mlo += x >> (GMP_LIMB_BITS - lshift);
+	    }
+	}
+
+      if (UNLIKELY (exp >= 128))
+	{
+	  /* overflow, return maximum number */
+	  mhi = 0xffffffff;
+	  mlo = 0xffffffff;
+	  exp = 127;
+	}
+      else if (UNLIKELY (exp < -128))
+	{
+	  return 0.0;	 /* underflows to zero */
+	}
+
+      u.s.man3 = mhi >> 24;	/* drop msb, since implicit */
+      u.s.man2 = mhi >> 8;
+      u.s.man1 = (mhi << 8) + (mlo >> 24);
+      u.s.man0 = mlo >> 8;
+      u.s.exp = exp + 128;
+      u.s.sig = sign < 0;
+      return u.d;
+    }
+#define FORMAT_RECOGNIZED 1
+#endif
+
+#if ! FORMAT_RECOGNIZED
+
+#if !defined(GMP_DBL_MANT_BITS)
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+#define GMP_DBL_MANT_BITS DBL_MANT_DIG
+#else
+/* FIXME: Chose a smarter default value. */
+#define GMP_DBL_MANT_BITS (16 * sizeof (double))
+#endif
+#endif
+
+    { /* Non-IEEE or strange limb size, generically convert
+	 GMP_DBL_MANT_BITS bits. */
+      mp_limb_t l;
+      int m;
+      mp_size_t i;
+      double d, weight;
+      unsigned long uexp;
+
+      /* First generate an fp number disregarding exp, instead keeping things
+	 within the numb base factor from 1, which should prevent overflow and
+	 underflow even for the most exponent limited fp formats.  */
+      i = size - 1;
+      l = up[i];
+      count_leading_zeros (m, l);
+      m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
+      if (m < 0)
+	l &= GMP_NUMB_MAX << -m;
+      d = l;
+      for (weight = 1/MP_BASE_AS_DOUBLE; m > 0 && --i >= 0;)
+	{
+	  l = up[i];
+	  m -= GMP_NUMB_BITS;
+	  if (m < 0)
+	    l &= GMP_NUMB_MAX << -m;
+	  d += l * weight;
+	  weight /= MP_BASE_AS_DOUBLE;
+	  if (weight == 0)
+	    break;
+	}
+
+      /* Now apply exp.  */
+      exp -= GMP_NUMB_BITS;
+      if (exp > 0)
+	{
+	  weight = 2.0;
+	  uexp = exp;
+	}
+      else
+	{
+	  weight = 0.5;
+	  uexp = NEG_CAST (unsigned long, exp);
+	}
+#if 1
+      /* Square-and-multiply exponentiation.  */
+      if (uexp & 1)
+	d *= weight;
+      while (uexp >>= 1)
+	{
+	  weight *= weight;
+	  if (uexp & 1)
+	    d *= weight;
+	}
+#else
+      /* Plain exponentiation.  */
+      while (uexp > 0)
+	{
+	  d *= weight;
+	  uexp--;
+	}
+#endif
+
+      return sign >= 0 ? d : -d;
+    }
+#endif
+}
diff --git a/mpn/generic/get_str.c b/mpn/generic/get_str.c
new file mode 100644
index 0000000..19cc581
--- /dev/null
+++ b/mpn/generic/get_str.c
@@ -0,0 +1,451 @@
+/* mpn_get_str -- Convert {UP,USIZE} to a base BASE string in STR.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE, EXCEPT mpn_get_str, ARE INTERNAL WITH MUTABLE
+   INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
+   IN FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A
+   FUTURE GNU MP RELEASE.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Conversion of U {up,un} to a string in base b.  Internally, we convert to
+   base B = b^m, the largest power of b that fits a limb.  Basic algorithms:
+
+  A) Divide U repeatedly by B, generating a quotient and remainder, until the
+     quotient becomes zero.  The remainders hold the converted digits.  Digits
+     come out from right to left.  (Used in mpn_bc_get_str.)
+
+  B) Divide U by b^g, for g such that 1/b <= U/b^g < 1, generating a fraction.
+     Then develop digits by multiplying the fraction repeatedly by b.  Digits
+     come out from left to right.  (Currently not used herein, except for in
+     code for converting single limbs to individual digits.)
+
+  C) Compute B^1, B^2, B^4, ..., B^s, for s such that B^s is just above
+     sqrt(U).  Then divide U by B^s, generating quotient and remainder.
+     Recursively convert the quotient, then the remainder, using the
+     precomputed powers.  Digits come out from left to right.  (Used in
+     mpn_dc_get_str.)
+
+  When using algorithm C, algorithm B might be suitable for basecase code,
+  since the required b^g power will be readily accessible.
+
+  Optimization ideas:
+  1. The recursive function of (C) could use less temporary memory.  The powtab
+     allocation could be trimmed with some computation, and the tmp area could
+     be reduced, or perhaps eliminated if up is reused for both quotient and
+     remainder (it is currently used just for remainder).
+  2. Store the powers of (C) in normalized form, with the normalization count.
+     Quotients will usually need to be left-shifted before each divide, and
+     remainders will either need to be left-shifted of right-shifted.
+  3. In the code for developing digits from a single limb, we could avoid using
+     a full umul_ppmm except for the first (or first few) digits, provided base
+     is even.  Subsequent digits can be developed using plain multiplication.
+     (This saves on register-starved machines (read x86) and on all machines
+     that generate the upper product half using a separate instruction (alpha,
+     powerpc, IA-64) or lacks such support altogether (sparc64, hppa64).
+  4. Separate mpn_dc_get_str basecase code from code for small conversions. The
+     former code will have the exact right power readily available in the
+     powtab parameter for dividing the current number into a fraction.  Convert
+     that using algorithm B.
+  5. Completely avoid division.  Compute the inverses of the powers now in
+     powtab instead of the actual powers.
+  6. Decrease powtab allocation for even bases.  E.g. for base 10 we could save
+     about 30% (1-log(5)/log(10)).
+
+  Basic structure of (C):
+    mpn_get_str:
+      if POW2_P (n)
+	...
+      else
+	if (un < GET_STR_PRECOMPUTE_THRESHOLD)
+	  mpn_bx_get_str (str, base, up, un);
+	else
+	  precompute_power_tables
+	  mpn_dc_get_str
+
+    mpn_dc_get_str:
+	mpn_tdiv_qr
+	if (qn < GET_STR_DC_THRESHOLD)
+	  mpn_bc_get_str
+	else
+	  mpn_dc_get_str
+	if (rn < GET_STR_DC_THRESHOLD)
+	  mpn_bc_get_str
+	else
+	  mpn_dc_get_str
+
+
+  The reason for the two threshold values is the cost of
+  precompute_power_tables.  GET_STR_PRECOMPUTE_THRESHOLD will be
+  considerably larger than GET_STR_DC_THRESHOLD.  */
+
+
+/* The x86s and m68020 have a quotient and remainder "div" instruction and
+   gcc recognises an adjacent "/" and "%" can be combined using that.
+   Elsewhere "/" and "%" are either separate instructions, or separate
+   libgcc calls (which unfortunately gcc as of version 3.0 doesn't combine).
+   A multiply and subtract should be faster than a "%" in those cases.  */
+#if HAVE_HOST_CPU_FAMILY_x86            \
+  || HAVE_HOST_CPU_m68020               \
+  || HAVE_HOST_CPU_m68030               \
+  || HAVE_HOST_CPU_m68040               \
+  || HAVE_HOST_CPU_m68060               \
+  || HAVE_HOST_CPU_m68360 /* CPU32 */
+#define udiv_qrnd_unnorm(q,r,n,d)       \
+  do {                                  \
+    mp_limb_t  __q = (n) / (d);         \
+    mp_limb_t  __r = (n) % (d);         \
+    (q) = __q;                          \
+    (r) = __r;                          \
+  } while (0)
+#else
+#define udiv_qrnd_unnorm(q,r,n,d)       \
+  do {                                  \
+    mp_limb_t  __q = (n) / (d);         \
+    mp_limb_t  __r = (n) - __q*(d);     \
+    (q) = __q;                          \
+    (r) = __r;                          \
+  } while (0)
+#endif
+
+
+/* Convert {up,un} to a string in base base, and put the result in str.
+   Generate len characters, possibly padding with zeros to the left.  If len is
+   zero, generate as many characters as required.  Return a pointer immediately
+   after the last digit of the result string.  Complexity is O(un^2); intended
+   for small conversions.  */
+static unsigned char *
+mpn_bc_get_str (unsigned char *str, size_t len,
+		mp_ptr up, mp_size_t un, int base)
+{
+  mp_limb_t rl, ul;
+  unsigned char *s;
+  size_t l;
+  /* Allocate memory for largest possible string, given that we only get here
+     for operands with un < GET_STR_PRECOMPUTE_THRESHOLD and that the smallest
+     base is 3.  7/11 is an approximation to 1/log2(3).  */
+#if TUNE_PROGRAM_BUILD
+#define BUF_ALLOC (GET_STR_THRESHOLD_LIMIT * GMP_LIMB_BITS * 7 / 11)
+#else
+#define BUF_ALLOC (GET_STR_PRECOMPUTE_THRESHOLD * GMP_LIMB_BITS * 7 / 11)
+#endif
+  unsigned char buf[BUF_ALLOC];
+#if TUNE_PROGRAM_BUILD
+  mp_limb_t rp[GET_STR_THRESHOLD_LIMIT];
+#else
+  mp_limb_t rp[GET_STR_PRECOMPUTE_THRESHOLD];
+#endif
+
+  if (base == 10)
+    {
+      /* Special case code for base==10 so that the compiler has a chance to
+	 optimize things.  */
+
+      MPN_COPY (rp + 1, up, un);
+
+      s = buf + BUF_ALLOC;
+      while (un > 1)
+	{
+	  int i;
+	  mp_limb_t frac, digit;
+	  MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
+					 MP_BASES_BIG_BASE_10,
+					 MP_BASES_BIG_BASE_INVERTED_10,
+					 MP_BASES_NORMALIZATION_STEPS_10);
+	  un -= rp[un] == 0;
+	  frac = (rp[0] + 1) << GMP_NAIL_BITS;
+	  s -= MP_BASES_CHARS_PER_LIMB_10;
+#if HAVE_HOST_CPU_FAMILY_x86
+	  /* The code below turns out to be a bit slower for x86 using gcc.
+	     Use plain code.  */
+	  i = MP_BASES_CHARS_PER_LIMB_10;
+	  do
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  while (--i);
+#else
+	  /* Use the fact that 10 in binary is 1010, with the lowest bit 0.
+	     After a few umul_ppmm, we will have accumulated enough low zeros
+	     to use a plain multiply.  */
+	  if (MP_BASES_NORMALIZATION_STEPS_10 == 0)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 1)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 2)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 3)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  i = (MP_BASES_CHARS_PER_LIMB_10 - ((MP_BASES_NORMALIZATION_STEPS_10 < 4)
+					     ? (4-MP_BASES_NORMALIZATION_STEPS_10)
+					     : 0));
+	  frac = (frac + 0xf) >> 4;
+	  do
+	    {
+	      frac *= 10;
+	      digit = frac >> (GMP_LIMB_BITS - 4);
+	      *s++ = digit;
+	      frac &= (~(mp_limb_t) 0) >> 4;
+	    }
+	  while (--i);
+#endif
+	  s -= MP_BASES_CHARS_PER_LIMB_10;
+	}
+
+      ul = rp[1];
+      while (ul != 0)
+	{
+	  udiv_qrnd_unnorm (ul, rl, ul, 10);
+	  *--s = rl;
+	}
+    }
+  else /* not base 10 */
+    {
+      unsigned chars_per_limb;
+      mp_limb_t big_base, big_base_inverted;
+      unsigned normalization_steps;
+
+      chars_per_limb = mp_bases[base].chars_per_limb;
+      big_base = mp_bases[base].big_base;
+      big_base_inverted = mp_bases[base].big_base_inverted;
+      count_leading_zeros (normalization_steps, big_base);
+
+      MPN_COPY (rp + 1, up, un);
+
+      s = buf + BUF_ALLOC;
+      while (un > 1)
+	{
+	  int i;
+	  mp_limb_t frac;
+	  MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
+					 big_base, big_base_inverted,
+					 normalization_steps);
+	  un -= rp[un] == 0;
+	  frac = (rp[0] + 1) << GMP_NAIL_BITS;
+	  s -= chars_per_limb;
+	  i = chars_per_limb;
+	  do
+	    {
+	      mp_limb_t digit;
+	      umul_ppmm (digit, frac, frac, base);
+	      *s++ = digit;
+	    }
+	  while (--i);
+	  s -= chars_per_limb;
+	}
+
+      ul = rp[1];
+      while (ul != 0)
+	{
+	  udiv_qrnd_unnorm (ul, rl, ul, base);
+	  *--s = rl;
+	}
+    }
+
+  l = buf + BUF_ALLOC - s;
+  while (l < len)
+    {
+      *str++ = 0;
+      len--;
+    }
+  while (l != 0)
+    {
+      *str++ = *s++;
+      l--;
+    }
+  return str;
+}
+
+
+/* Convert {UP,UN} to a string with a base as represented in POWTAB, and put
+   the string in STR.  Generate LEN characters, possibly padding with zeros to
+   the left.  If LEN is zero, generate as many characters as required.
+   Return a pointer immediately after the last digit of the result string.
+   This uses divide-and-conquer and is intended for large conversions.  */
+static unsigned char *
+mpn_dc_get_str (unsigned char *str, size_t len,
+		mp_ptr up, mp_size_t un,
+		const powers_t *powtab, mp_ptr tmp)
+{
+  if (BELOW_THRESHOLD (un, GET_STR_DC_THRESHOLD))
+    {
+      if (un != 0)
+	str = mpn_bc_get_str (str, len, up, un, powtab->base);
+      else
+	{
+	  while (len != 0)
+	    {
+	      *str++ = 0;
+	      len--;
+	    }
+	}
+    }
+  else
+    {
+      mp_ptr pwp, qp, rp;
+      mp_size_t pwn, qn;
+      mp_size_t sn;
+
+      pwp = powtab->p;
+      pwn = powtab->n;
+      sn = powtab->shift;
+
+      if (un < pwn + sn || (un == pwn + sn && mpn_cmp (up + sn, pwp, un - sn) < 0))
+	{
+	  str = mpn_dc_get_str (str, len, up, un, powtab - 1, tmp);
+	}
+      else
+	{
+	  qp = tmp;		/* (un - pwn + 1) limbs for qp */
+	  rp = up;		/* pwn limbs for rp; overwrite up area */
+
+	  mpn_tdiv_qr (qp, rp + sn, 0L, up + sn, un - sn, pwp, pwn);
+	  qn = un - sn - pwn; qn += qp[qn] != 0;		/* quotient size */
+
+	  ASSERT (qn < pwn + sn || (qn == pwn + sn && mpn_cmp (qp + sn, pwp, pwn) < 0));
+
+	  if (len != 0)
+	    len = len - powtab->digits_in_base;
+
+	  str = mpn_dc_get_str (str, len, qp, qn, powtab - 1, tmp + qn);
+	  str = mpn_dc_get_str (str, powtab->digits_in_base, rp, pwn + sn, powtab - 1, tmp);
+	}
+    }
+  return str;
+}
+
+/* There are no leading zeros on the digits generated at str, but that's not
+   currently a documented feature.  The current mpz_out_str and mpz_get_str
+   rely on it.  */
+
+size_t
+mpn_get_str (unsigned char *str, int base, mp_ptr up, mp_size_t un)
+{
+  mp_ptr powtab_mem;
+  powers_t powtab[GMP_LIMB_BITS];
+  int pi;
+  size_t out_len;
+  mp_ptr tmp;
+  TMP_DECL;
+
+  /* Special case zero, as the code below doesn't handle it.  */
+  if (un == 0)
+    {
+      str[0] = 0;
+      return 1;
+    }
+
+  if (POW2_P (base))
+    {
+      /* The base is a power of 2.  Convert from most significant end.  */
+      mp_limb_t n1, n0;
+      int bits_per_digit = mp_bases[base].big_base;
+      int cnt;
+      int bit_pos;
+      mp_size_t i;
+      unsigned char *s = str;
+      mp_bitcnt_t bits;
+
+      n1 = up[un - 1];
+      count_leading_zeros (cnt, n1);
+
+      /* BIT_POS should be R when input ends in least significant nibble,
+	 R + bits_per_digit * n when input ends in nth least significant
+	 nibble. */
+
+      bits = (mp_bitcnt_t) GMP_NUMB_BITS * un - cnt + GMP_NAIL_BITS;
+      cnt = bits % bits_per_digit;
+      if (cnt != 0)
+	bits += bits_per_digit - cnt;
+      bit_pos = bits - (mp_bitcnt_t) (un - 1) * GMP_NUMB_BITS;
+
+      /* Fast loop for bit output.  */
+      i = un - 1;
+      for (;;)
+	{
+	  bit_pos -= bits_per_digit;
+	  while (bit_pos >= 0)
+	    {
+	      *s++ = (n1 >> bit_pos) & ((1 << bits_per_digit) - 1);
+	      bit_pos -= bits_per_digit;
+	    }
+	  i--;
+	  if (i < 0)
+	    break;
+	  n0 = (n1 << -bit_pos) & ((1 << bits_per_digit) - 1);
+	  n1 = up[i];
+	  bit_pos += GMP_NUMB_BITS;
+	  *s++ = n0 | (n1 >> bit_pos);
+	}
+
+      return s - str;
+    }
+
+  /* General case.  The base is not a power of 2.  */
+
+  if (BELOW_THRESHOLD (un, GET_STR_PRECOMPUTE_THRESHOLD))
+    return mpn_bc_get_str (str, (size_t) 0, up, un, base) - str;
+
+  TMP_MARK;
+
+  /* Allocate one large block for the powers of big_base.  */
+  powtab_mem = TMP_BALLOC_LIMBS (mpn_str_powtab_alloc (un));
+
+  /* Compute a table of powers, were the largest power is >= sqrt(U).  */
+  size_t ndig;
+  mp_size_t xn;
+  DIGITS_IN_BASE_PER_LIMB (ndig, un, base);
+  xn = 1 + ndig / mp_bases[base].chars_per_limb; /* FIXME: scalar integer division */
+
+  pi = 1 + mpn_compute_powtab (powtab, powtab_mem, xn, base);
+
+  /* Using our precomputed powers, now in powtab[], convert our number.  */
+  tmp = TMP_BALLOC_LIMBS (mpn_dc_get_str_itch (un));
+  out_len = mpn_dc_get_str (str, 0, up, un, powtab + (pi - 1), tmp) - str;
+  TMP_FREE;
+
+  return out_len;
+}
diff --git a/mpn/generic/gmp-mparam.h b/mpn/generic/gmp-mparam.h
new file mode 100644
index 0000000..7dc057a
--- /dev/null
+++ b/mpn/generic/gmp-mparam.h
@@ -0,0 +1,33 @@
+/* Generic C gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Values for GMP_LIMB_BITS etc will be determined by ./configure and put
+   in config.h. */
diff --git a/mpn/generic/hgcd.c b/mpn/generic/hgcd.c
new file mode 100644
index 0000000..e3e9c66
--- /dev/null
+++ b/mpn/generic/hgcd.c
@@ -0,0 +1,182 @@
+/* hgcd.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Size analysis for hgcd:
+
+   For the recursive calls, we have n1 <= ceil(n / 2). Then the
+   storage need is determined by the storage for the recursive call
+   computing M1, and hgcd_matrix_adjust and hgcd_matrix_mul calls that use M1
+   (after this, the storage needed for M1 can be recycled).
+
+   Let S(r) denote the required storage. For M1 we need 4 * (ceil(n1/2) + 1)
+   = 4 * (ceil(n/4) + 1), for the hgcd_matrix_adjust call, we need n + 2,
+   and for the hgcd_matrix_mul, we may need 3 ceil(n/2) + 8. In total,
+   4 * ceil(n/4) + 3 ceil(n/2) + 12 <= 10 ceil(n/4) + 12.
+
+   For the recursive call, we need S(n1) = S(ceil(n/2)).
+
+   S(n) <= 10*ceil(n/4) + 12 + S(ceil(n/2))
+	<= 10*(ceil(n/4) + ... + ceil(n/2^(1+k))) + 12k + S(ceil(n/2^k))
+	<= 10*(2 ceil(n/4) + k) + 12k + S(ceil(n/2^k))
+	<= 20 ceil(n/4) + 22k + S(ceil(n/2^k))
+*/
+
+mp_size_t
+mpn_hgcd_itch (mp_size_t n)
+{
+  unsigned k;
+  int count;
+  mp_size_t nscaled;
+
+  if (BELOW_THRESHOLD (n, HGCD_THRESHOLD))
+    return n;
+
+  /* Get the recursion depth. */
+  nscaled = (n - 1) / (HGCD_THRESHOLD - 1);
+  count_leading_zeros (count, nscaled);
+  k = GMP_LIMB_BITS - count;
+
+  return 20 * ((n+3) / 4) + 22 * k + HGCD_THRESHOLD;
+}
+
+/* Reduces a,b until |a-b| fits in n/2 + 1 limbs. Constructs matrix M
+   with elements of size at most (n+1)/2 - 1. Returns new size of a,
+   b, or zero if no reduction is possible. */
+
+mp_size_t
+mpn_hgcd (mp_ptr ap, mp_ptr bp, mp_size_t n,
+	  struct hgcd_matrix *M, mp_ptr tp)
+{
+  mp_size_t s = n/2 + 1;
+
+  mp_size_t nn;
+  int success = 0;
+
+  if (n <= s)
+    /* Happens when n <= 2, a fairly uninteresting case but exercised
+       by the random inputs of the testsuite. */
+    return 0;
+
+  ASSERT ((ap[n-1] | bp[n-1]) > 0);
+
+  ASSERT ((n+1)/2 - 1 < M->alloc);
+
+  if (ABOVE_THRESHOLD (n, HGCD_THRESHOLD))
+    {
+      mp_size_t n2 = (3*n)/4 + 1;
+      mp_size_t p = n/2;
+
+      nn = mpn_hgcd_reduce (M, ap, bp, n, p, tp);
+      if (nn)
+	{
+	  n = nn;
+	  success = 1;
+	}
+
+      /* NOTE: It appears this loop never runs more than once (at
+	 least when not recursing to hgcd_appr). */
+      while (n > n2)
+	{
+	  /* Needs n + 1 storage */
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+	  if (!nn)
+	    return success ? n : 0;
+
+	  n = nn;
+	  success = 1;
+	}
+
+      if (n > s + 2)
+	{
+	  struct hgcd_matrix M1;
+	  mp_size_t scratch;
+
+	  p = 2*s - n + 1;
+	  scratch = MPN_HGCD_MATRIX_INIT_ITCH (n-p);
+
+	  mpn_hgcd_matrix_init(&M1, n - p, tp);
+
+	  /* FIXME: Should use hgcd_reduce, but that may require more
+	     scratch space, which requires review. */
+
+	  nn = mpn_hgcd (ap + p, bp + p, n - p, &M1, tp + scratch);
+	  if (nn > 0)
+	    {
+	      /* We always have max(M) > 2^{-(GMP_NUMB_BITS + 1)} max(M1) */
+	      ASSERT (M->n + 2 >= M1.n);
+
+	      /* Furthermore, assume M ends with a quotient (1, q; 0, 1),
+		 then either q or q + 1 is a correct quotient, and M1 will
+		 start with either (1, 0; 1, 1) or (2, 1; 1, 1). This
+		 rules out the case that the size of M * M1 is much
+		 smaller than the expected M->n + M1->n. */
+
+	      ASSERT (M->n + M1.n < M->alloc);
+
+	      /* Needs 2 (p + M->n) <= 2 (2*s - n2 + 1 + n2 - s - 1)
+		 = 2*s <= 2*(floor(n/2) + 1) <= n + 2. */
+	      n = mpn_hgcd_matrix_adjust (&M1, p + nn, ap, bp, p, tp + scratch);
+
+	      /* We need a bound for of M->n + M1.n. Let n be the original
+		 input size. Then
+
+		 ceil(n/2) - 1 >= size of product >= M.n + M1.n - 2
+
+		 and it follows that
+
+		 M.n + M1.n <= ceil(n/2) + 1
+
+		 Then 3*(M.n + M1.n) + 5 <= 3 * ceil(n/2) + 8 is the
+		 amount of needed scratch space. */
+	      mpn_hgcd_matrix_mul (M, &M1, tp + scratch);
+	      success = 1;
+	    }
+	}
+    }
+
+  for (;;)
+    {
+      /* Needs s+3 < n */
+      nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+      if (!nn)
+	return success ? n : 0;
+
+      n = nn;
+      success = 1;
+    }
+}
diff --git a/mpn/generic/hgcd2-div.h b/mpn/generic/hgcd2-div.h
new file mode 100644
index 0000000..45ba453
--- /dev/null
+++ b/mpn/generic/hgcd2-div.h
@@ -0,0 +1,504 @@
+/* hgcd2-div.h
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2012, 2019, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 3
+#endif
+
+#ifndef HGCD2_DIV2_METHOD
+#define HGCD2_DIV2_METHOD 2
+#endif
+
+#if HAVE_NATIVE_mpn_div_11
+
+#define div1 mpn_div_11
+/* Single-limb division optimized for small quotients.
+   Returned value holds d0 = r, d1 = q. */
+mp_double_limb_t div1 (mp_limb_t, mp_limb_t);
+
+#elif HGCD2_DIV1_METHOD == 1
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  mp_double_limb_t res;
+  res.d1 = n0 / d0;
+  res.d0 = n0 - res.d1 * d0;
+
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 2
+
+static mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  mp_double_limb_t res;
+  int ncnt, dcnt, cnt;
+  mp_limb_t q;
+  mp_limb_t mask;
+
+  ASSERT (n0 >= d0);
+
+  count_leading_zeros (ncnt, n0);
+  count_leading_zeros (dcnt, d0);
+  cnt = dcnt - ncnt;
+
+  d0 <<= cnt;
+
+  q = -(mp_limb_t) (n0 >= d0);
+  n0 -= d0 & q;
+  d0 >>= 1;
+  q = -q;
+
+  while (--cnt >= 0)
+    {
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      d0 >>= 1;
+      q = (q << 1) - mask;
+    }
+
+  res.d0 = n0;
+  res.d1 = q;
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 3
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  mp_double_limb_t res;
+  if (UNLIKELY ((d0 >> (GMP_LIMB_BITS - 3)) != 0)
+      || UNLIKELY (n0 >= (d0 << 3)))
+    {
+      res.d1 = n0 / d0;
+      res.d0 = n0 - res.d1 * d0;
+    }
+  else
+    {
+      mp_limb_t q, mask;
+
+      d0 <<= 2;
+
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      q = 4 & mask;
+
+      d0 >>= 1;
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      q += 2 & mask;
+
+      d0 >>= 1;
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      q -= mask;
+
+      res.d0 = n0;
+      res.d1 = q;
+    }
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 4
+
+/* Table quotients.  We extract the NBITS most significant bits of the
+   numerator limb, and the corresponding bits from the divisor limb, and use
+   these to form an index into the table.  This method is probably only useful
+   for short pipelines with slow multiplication.
+
+   Possible improvements:
+
+   * Perhaps extract the highest NBITS of the divisor instead of the same bits
+     as from the numerator.  That would require another count_leading_zeros,
+     and a post-multiply shift of the quotient.
+
+   * Compress tables?  Their values are tiny, and there are lots of zero
+     entries (which are never used).
+
+   * Round the table entries more cleverly?
+*/
+
+#ifndef NBITS
+#define NBITS 5
+#endif
+
+#if NBITS == 5
+/* This needs full division about 13.2% of the time. */
+static const unsigned char tab[512] = {
+17, 9, 5,4,3,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+18, 9, 6,4,3,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+19,10, 6,4,3,3,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+20,10, 6,5,3,3,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
+21,11, 7,5,4,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
+22,11, 7,5,4,3,3,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
+23,12, 7,5,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+24,12, 8,6,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+25,13, 8,6,5,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+26,13, 8,6,5,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+27,14, 9,6,5,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+28,14, 9,7,5,4,3,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+29,15,10,7,5,4,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+30,15,10,7,6,5,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+31,16,10,7,6,5,4,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+32,16,11,8,6,5,4,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+#elif NBITS == 6
+/* This needs full division about 9.8% of the time. */
+static const unsigned char tab[2048] = {
+33,17,11, 8, 6, 5,4,4,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+34,17,11, 8, 6, 5,4,4,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+35,18,12, 9, 7, 5,5,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+36,18,12, 9, 7, 6,5,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+37,19,13, 9, 7, 6,5,4,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+38,19,13, 9, 7, 6,5,4,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+39,20,13,10, 7, 6,5,4,4,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+40,20,14,10, 8, 6,5,5,4,3,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+41,21,14,10, 8, 6,5,5,4,4,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+42,21,14,10, 8, 7,6,5,4,4,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+43,22,15,11, 8, 7,6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+44,22,15,11, 9, 7,6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+45,23,15,11, 9, 7,6,5,5,4,4,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+46,23,16,11, 9, 7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+47,24,16,12, 9, 7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+48,24,16,12, 9, 8,6,6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+49,25,17,12,10, 8,7,6,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+50,25,17,13,10, 8,7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+51,26,18,13,10, 8,7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+52,26,18,13,10, 8,7,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
+53,27,18,13,10, 9,7,6,5,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
+54,27,19,14,11, 9,7,6,6,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
+55,28,19,14,11, 9,7,6,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+56,28,19,14,11, 9,8,7,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+57,29,20,14,11, 9,8,7,6,5,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+58,29,20,15,11, 9,8,7,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+59,30,20,15,12,10,8,7,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+60,30,21,15,12,10,8,7,6,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+61,31,21,15,12,10,8,7,6,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+62,31,22,16,12,10,9,7,6,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+63,32,22,16,13,10,9,7,7,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+64,32,22,16,13,10,9,8,7,6,5,5,4,4,4,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,
+ 1, 1, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+#else
+#error No table for provided NBITS
+#endif
+
+/* Doing tabp with a #define makes compiler warnings about pointing outside an
+   object go away.  We used to define this as a variable.  It is not clear if
+   e.g.  (vector[100] - 10) + 10 is well- defined as per the C standard;
+   (vector[100] + 10) - 10 surely is and there is no sequence point so the
+   expressions should be equivalent.  To make this safe, we might want to
+   define tabp as a macro with the index as an argument.  Depending on the
+   platform, relocs might allow for assembly-time or linker-time resolution to
+   take place. */
+#define tabp (tab - (1 << (NBITS - 1) << NBITS))
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  int ncnt;
+  size_t nbi, dbi;
+  mp_limb_t q0;
+  mp_limb_t r0;
+  mp_limb_t mask;
+  mp_double_limb_t res;
+
+  ASSERT (n0 >= d0);		/* Actually only msb position is critical. */
+
+  count_leading_zeros (ncnt, n0);
+  nbi = n0 << ncnt >> (GMP_LIMB_BITS - NBITS);
+  dbi = d0 << ncnt >> (GMP_LIMB_BITS - NBITS);
+
+  q0 = tabp[(nbi << NBITS) + dbi];
+  r0 = n0 - q0 * d0;
+  mask = -(mp_limb_t) (r0 >= d0);
+  q0 -= mask;
+  r0 -= d0 & mask;
+
+  if (UNLIKELY (r0 >= d0))
+    {
+      q0 = n0 / d0;
+      r0 = n0 - q0 * d0;
+    }
+
+  res.d1 = q0;
+  res.d0 = r0;
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 5
+
+/* Table inverses of divisors.  We don't bother with suppressing the msb from
+   the tables.  We index with the NBITS most significant divisor bits,
+   including the always-set highest bit, but use addressing trickery via tabp
+   to suppress it.
+
+   Possible improvements:
+
+   * Do first multiply using 32-bit operations on 64-bit computers.  At least
+     on most Arm64 cores, that uses 3 times less resources.  It also saves on
+     many x86-64 processors.
+*/
+
+#ifndef NBITS
+#define NBITS 7
+#endif
+
+#if NBITS == 5
+/* This needs full division about 1.63% of the time. */
+static const unsigned char tab[16] = {
+ 63, 59, 55, 52, 50, 47, 45, 43, 41, 39, 38, 36, 35, 34, 33, 32
+};
+#elif NBITS == 6
+/* This needs full division about 0.93% of the time. */
+static const unsigned char tab[32] = {
+127,123,119,116,112,109,106,104,101, 98, 96, 94, 92, 90, 88, 86,
+ 84, 82, 80, 79, 77, 76, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64
+};
+#elif NBITS == 7
+/* This needs full division about 0.49% of the time. */
+static const unsigned char tab[64] = {
+255,251,247,243,239,236,233,229,226,223,220,217,214,211,209,206,
+203,201,198,196,194,191,189,187,185,183,181,179,177,175,173,171,
+169,167,166,164,162,161,159,158,156,155,153,152,150,149,147,146,
+145,143,142,141,140,139,137,136,135,134,133,132,131,130,129,128
+};
+#elif NBITS == 8
+/* This needs full division about 0.26% of the time. */
+static const unsigned short tab[128] = {
+511,507,503,499,495,491,488,484,480,477,473,470,467,463,460,457,
+454,450,447,444,441,438,435,433,430,427,424,421,419,416,413,411,
+408,406,403,401,398,396,393,391,389,386,384,382,380,377,375,373,
+371,369,367,365,363,361,359,357,355,353,351,349,347,345,343,342,
+340,338,336,335,333,331,329,328,326,325,323,321,320,318,317,315,
+314,312,311,309,308,306,305,303,302,301,299,298,296,295,294,292,
+291,290,288,287,286,285,283,282,281,280,279,277,276,275,274,273,
+272,270,269,268,267,266,265,264,263,262,261,260,259,258,257,256
+};
+#else
+#error No table for provided NBITS
+#endif
+
+/* Doing tabp with a #define makes compiler warnings about pointing outside an
+   object go away.  We used to define this as a variable.  It is not clear if
+   e.g.  (vector[100] - 10) + 10 is well- defined as per the C standard;
+   (vector[100] + 10) - 10 surely is and there is no sequence point so the
+   expressions should be equivalent.  To make this safe, we might want to
+   define tabp as a macro with the index as an argument.  Depending on the
+   platform, relocs might allow for assembly-time or linker-time resolution to
+   take place. */
+#define tabp (tab - (1 << (NBITS - 1)))
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  int ncnt, dcnt;
+  size_t dbi;
+  mp_limb_t inv;
+  mp_limb_t q0;
+  mp_limb_t r0;
+  mp_limb_t mask;
+  mp_double_limb_t res;
+
+  count_leading_zeros (ncnt, n0);
+  count_leading_zeros (dcnt, d0);
+
+  dbi = d0 << dcnt >> (GMP_LIMB_BITS - NBITS);
+  inv = tabp[dbi];
+  q0 = ((n0 << ncnt) >> (NBITS + 1)) * inv >> (GMP_LIMB_BITS - 1 + ncnt - dcnt);
+  r0 = n0 - q0 * d0;
+  mask = -(mp_limb_t) (r0 >= d0);
+  q0 -= mask;
+  r0 -= d0 & mask;
+
+  if (UNLIKELY (r0 >= d0))
+    {
+      q0 = n0 / d0;
+      r0 = n0 - q0 * d0;
+    }
+
+  res.d1 = q0;
+  res.d0 = r0;
+  return res;
+}
+
+#else
+#error Unknown HGCD2_DIV1_METHOD
+#endif
+
+#if HAVE_NATIVE_mpn_div_22
+
+#define div2 mpn_div_22
+/* Two-limb division optimized for small quotients.  */
+mp_limb_t div2 (mp_ptr, mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#elif HGCD2_DIV2_METHOD == 1
+
+static mp_limb_t
+div2 (mp_ptr rp,
+      mp_limb_t n1, mp_limb_t n0,
+      mp_limb_t d1, mp_limb_t d0)
+{
+  mp_double_limb_t rq = div1 (n1, d1);
+  if (UNLIKELY (rq.d1 > d1))
+    {
+      mp_limb_t n2, q, t1, t0;
+      int c;
+
+      /* Normalize */
+      count_leading_zeros (c, d1);
+      ASSERT (c > 0);
+
+      n2 = n1 >> (GMP_LIMB_BITS - c);
+      n1 = (n1 << c) | (n0 >> (GMP_LIMB_BITS - c));
+      n0 <<= c;
+      d1 = (d1 << c) | (d0 >> (GMP_LIMB_BITS - c));
+      d0 <<= c;
+
+      udiv_qrnnd (q, n1, n2, n1, d1);
+      umul_ppmm (t1, t0, q, d0);
+      if (t1 > n1 || (t1 == n1 && t0 > n0))
+	{
+	  ASSERT (q > 0);
+	  q--;
+	  sub_ddmmss (t1, t0, t1, t0, d1, d0);
+	}
+      sub_ddmmss (n1, n0, n1, n0, t1, t0);
+
+      /* Undo normalization */
+      rp[0] = (n0 >> c) | (n1 << (GMP_LIMB_BITS - c));
+      rp[1] = n1 >> c;
+
+      return q;
+    }
+  else
+    {
+      mp_limb_t q, t1, t0;
+      n1 = rq.d0;
+      q = rq.d1;
+      umul_ppmm (t1, t0, q, d0);
+      if (UNLIKELY (t1 >= n1) && (t1 > n1 || t0 > n0))
+	{
+	  ASSERT (q > 0);
+	  q--;
+	  sub_ddmmss (t1, t0, t1, t0, d1, d0);
+	}
+      sub_ddmmss (rp[1], rp[0], n1, n0, t1, t0);
+      return q;
+    }
+}
+
+#elif HGCD2_DIV2_METHOD == 2
+
+/* Bit-wise div2. Relies on fast count_leading_zeros. */
+static mp_limb_t
+div2 (mp_ptr rp,
+      mp_limb_t n1, mp_limb_t n0,
+      mp_limb_t d1, mp_limb_t d0)
+{
+  mp_limb_t q = 0;
+  int ncnt;
+  int dcnt;
+
+  count_leading_zeros (ncnt, n1);
+  count_leading_zeros (dcnt, d1);
+  dcnt -= ncnt;
+
+  d1 = (d1 << dcnt) + (d0 >> 1 >> (GMP_LIMB_BITS - 1 - dcnt));
+  d0 <<= dcnt;
+
+  do
+    {
+      mp_limb_t mask;
+      q <<= 1;
+      if (UNLIKELY (n1 == d1))
+	mask = -(n0 >= d0);
+      else
+	mask = -(n1 > d1);
+
+      q -= mask;
+
+      sub_ddmmss (n1, n0, n1, n0, mask & d1, mask & d0);
+
+      d0 = (d1 << (GMP_LIMB_BITS - 1)) | (d0 >> 1);
+      d1 = d1 >> 1;
+    }
+  while (dcnt--);
+
+  rp[0] = n0;
+  rp[1] = n1;
+
+  return q;
+}
+#else
+#error Unknown HGCD2_DIV2_METHOD
+#endif
diff --git a/mpn/generic/hgcd2.c b/mpn/generic/hgcd2.c
new file mode 100644
index 0000000..43d4d48
--- /dev/null
+++ b/mpn/generic/hgcd2.c
@@ -0,0 +1,283 @@
+/* hgcd2.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2012, 2019 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/generic/hgcd2-div.h"
+
+#if GMP_NAIL_BITS != 0
+#error Nails not implemented
+#endif
+
+/* Reduces a,b until |a-b| (almost) fits in one limb + 1 bit. Constructs
+   matrix M. Returns 1 if we make progress, i.e. can perform at least
+   one subtraction. Otherwise returns zero. */
+
+/* FIXME: Possible optimizations:
+
+   The div2 function starts with checking the most significant bit of
+   the numerator. We can maintained normalized operands here, call
+   hgcd with normalized operands only, which should make the code
+   simpler and possibly faster.
+
+   Experiment with table lookups on the most significant bits.
+
+   This function is also a candidate for assembler implementation.
+*/
+int
+mpn_hgcd2 (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
+	   struct hgcd_matrix1 *M)
+{
+  mp_limb_t u00, u01, u10, u11;
+
+  if (ah < 2 || bh < 2)
+    return 0;
+
+  if (ah > bh || (ah == bh && al > bl))
+    {
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+      if (ah < 2)
+	return 0;
+
+      u00 = u01 = u11 = 1;
+      u10 = 0;
+    }
+  else
+    {
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+      if (bh < 2)
+	return 0;
+
+      u00 = u10 = u11 = 1;
+      u01 = 0;
+    }
+
+  if (ah < bh)
+    goto subtract_a;
+
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+      if (ah == bh)
+	goto done;
+
+      if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  break;
+	}
+
+      /* Subtract a -= q b, and multiply M from the right by (1 q ; 0
+	 1), affecting the second column of M. */
+      ASSERT (ah > bh);
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+
+      if (ah < 2)
+	goto done;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, ah, al, bh, bl);
+	  al = r[0]; ah = r[1];
+	  if (ah < 2)
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      goto done;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	}
+    subtract_a:
+      ASSERT (bh >= ah);
+      if (ah == bh)
+	goto done;
+
+      if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  goto subtract_a1;
+	}
+
+      /* Subtract b -= q a, and multiply M from the right by (1 0 ; q
+	 1), affecting the first column of M. */
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+
+      if (bh < 2)
+	goto done;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, bh, bl, ah, al);
+	  bl = r[0]; bh = r[1];
+	  if (bh < 2)
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      goto done;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	}
+    }
+
+  /* NOTE: Since we discard the least significant half limb, we don't get a
+     truly maximal M (corresponding to |a - b| < 2^{GMP_LIMB_BITS +1}). */
+  /* Single precision loop */
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+
+      ah -= bh;
+      if (ah < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	}
+      else
+	{
+	  mp_double_limb_t rq = div1 (ah, bh);
+	  mp_limb_t q = rq.d1;
+	  ah = rq.d0;
+
+	  if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      break;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	}
+    subtract_a1:
+      ASSERT (bh >= ah);
+
+      bh -= ah;
+      if (bh < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	}
+      else
+	{
+	  mp_double_limb_t rq = div1 (bh, ah);
+	  mp_limb_t q = rq.d1;
+	  bh = rq.d0;
+
+	  if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      break;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	}
+    }
+
+ done:
+  M->u[0][0] = u00; M->u[0][1] = u01;
+  M->u[1][0] = u10; M->u[1][1] = u11;
+
+  return 1;
+}
+
+/* Sets (r;b) = (a;b) M, with M = (u00, u01; u10, u11). Vector must
+ * have space for n + 1 limbs. Uses three buffers to avoid a copy*/
+mp_size_t
+mpn_hgcd_mul_matrix1_vector (const struct hgcd_matrix1 *M,
+			     mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
+{
+  mp_limb_t ah, bh;
+
+  /* Compute (r,b) <-- (u00 a + u10 b, u01 a + u11 b) as
+
+     r  = u00 * a
+     r += u10 * b
+     b *= u11
+     b += u01 * a
+  */
+
+#if HAVE_NATIVE_mpn_addaddmul_1msb0
+  ah = mpn_addaddmul_1msb0 (rp, ap, bp, n, M->u[0][0], M->u[1][0]);
+  bh = mpn_addaddmul_1msb0 (bp, bp, ap, n, M->u[1][1], M->u[0][1]);
+#else
+  ah =     mpn_mul_1 (rp, ap, n, M->u[0][0]);
+  ah += mpn_addmul_1 (rp, bp, n, M->u[1][0]);
+
+  bh =     mpn_mul_1 (bp, bp, n, M->u[1][1]);
+  bh += mpn_addmul_1 (bp, ap, n, M->u[0][1]);
+#endif
+  rp[n] = ah;
+  bp[n] = bh;
+
+  n += (ah | bh) > 0;
+  return n;
+}
diff --git a/mpn/generic/hgcd2_jacobi.c b/mpn/generic/hgcd2_jacobi.c
new file mode 100644
index 0000000..95d4af1
--- /dev/null
+++ b/mpn/generic/hgcd2_jacobi.c
@@ -0,0 +1,251 @@
+/* hgcd2_jacobi.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2011, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/generic/hgcd2-div.h"
+
+#if GMP_NAIL_BITS != 0
+#error Nails not implemented
+#endif
+
+int
+mpn_hgcd2_jacobi (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
+		  struct hgcd_matrix1 *M, unsigned *bitsp)
+{
+  mp_limb_t u00, u01, u10, u11;
+  unsigned bits = *bitsp;
+
+  if (ah < 2 || bh < 2)
+    return 0;
+
+  if (ah > bh || (ah == bh && al > bl))
+    {
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+      if (ah < 2)
+	return 0;
+
+      u00 = u01 = u11 = 1;
+      u10 = 0;
+      bits = mpn_jacobi_update (bits, 1, 1);
+    }
+  else
+    {
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+      if (bh < 2)
+	return 0;
+
+      u00 = u10 = u11 = 1;
+      u01 = 0;
+      bits = mpn_jacobi_update (bits, 0, 1);
+    }
+
+  if (ah < bh)
+    goto subtract_a;
+
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+      if (ah == bh)
+	goto done;
+
+      if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  break;
+	}
+
+      /* Subtract a -= q b, and multiply M from the right by (1 q ; 0
+	 1), affecting the second column of M. */
+      ASSERT (ah > bh);
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+
+      if (ah < 2)
+	goto done;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	  bits = mpn_jacobi_update (bits, 1, 1);
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, ah, al, bh, bl);
+	  al = r[0]; ah = r[1];
+	  if (ah < 2)
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      bits = mpn_jacobi_update (bits, 1, q & 3);
+	      goto done;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	  bits = mpn_jacobi_update (bits, 1, q & 3);
+	}
+    subtract_a:
+      ASSERT (bh >= ah);
+      if (ah == bh)
+	goto done;
+
+      if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  goto subtract_a1;
+	}
+
+      /* Subtract b -= q a, and multiply M from the right by (1 0 ; q
+	 1), affecting the first column of M. */
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+
+      if (bh < 2)
+	goto done;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	  bits = mpn_jacobi_update (bits, 0, 1);
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, bh, bl, ah, al);
+	  bl = r[0]; bh = r[1];
+	  if (bh < 2)
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      bits = mpn_jacobi_update (bits, 0, q & 3);
+	      goto done;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	  bits = mpn_jacobi_update (bits, 0, q & 3);
+	}
+    }
+
+  /* NOTE: Since we discard the least significant half limb, we don't get a
+     truly maximal M (corresponding to |a - b| < 2^{GMP_LIMB_BITS +1}). */
+  /* Single precision loop */
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+
+      ah -= bh;
+      if (ah < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	  bits = mpn_jacobi_update (bits, 1, 1);
+	}
+      else
+	{
+	  mp_double_limb_t rq = div1 (ah, bh);
+	  mp_limb_t q = rq.d1;
+	  ah = rq.d0;
+
+	  if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      bits = mpn_jacobi_update (bits, 1, q & 3);
+	      break;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	  bits = mpn_jacobi_update (bits, 1, q & 3);
+	}
+    subtract_a1:
+      ASSERT (bh >= ah);
+
+      bh -= ah;
+      if (bh < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	  bits = mpn_jacobi_update (bits, 0, 1);
+	}
+      else
+	{
+	  mp_double_limb_t rq = div1 (bh, ah);
+	  mp_limb_t q = rq.d1;
+	  bh = rq.d0;
+
+	  if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      bits = mpn_jacobi_update (bits, 0, q & 3);
+	      break;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	  bits = mpn_jacobi_update (bits, 0, q & 3);
+	}
+    }
+
+ done:
+  M->u[0][0] = u00; M->u[0][1] = u01;
+  M->u[1][0] = u10; M->u[1][1] = u11;
+  *bitsp = bits;
+
+  return 1;
+}
diff --git a/mpn/generic/hgcd_appr.c b/mpn/generic/hgcd_appr.c
new file mode 100644
index 0000000..bb01738
--- /dev/null
+++ b/mpn/generic/hgcd_appr.c
@@ -0,0 +1,267 @@
+/* hgcd_appr.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Identical to mpn_hgcd_itch. FIXME: Do we really need to add
+   HGCD_THRESHOLD at the end? */
+mp_size_t
+mpn_hgcd_appr_itch (mp_size_t n)
+{
+  if (BELOW_THRESHOLD (n, HGCD_APPR_THRESHOLD))
+    return n;
+  else
+    {
+      unsigned k;
+      int count;
+      mp_size_t nscaled;
+
+      /* Get the recursion depth. */
+      nscaled = (n - 1) / (HGCD_APPR_THRESHOLD - 1);
+      count_leading_zeros (count, nscaled);
+      k = GMP_LIMB_BITS - count;
+
+      return 20 * ((n+3) / 4) + 22 * k + HGCD_THRESHOLD;
+    }
+}
+
+/* Destroys inputs. */
+int
+mpn_hgcd_appr (mp_ptr ap, mp_ptr bp, mp_size_t n,
+	       struct hgcd_matrix *M, mp_ptr tp)
+{
+  mp_size_t s;
+  int success = 0;
+
+  ASSERT (n > 0);
+
+  ASSERT ((ap[n-1] | bp[n-1]) != 0);
+
+  if (n <= 2)
+    /* Implies s = n. A fairly uninteresting case but exercised by the
+       random inputs of the testsuite. */
+    return 0;
+
+  ASSERT ((n+1)/2 - 1 < M->alloc);
+
+  /* We aim for reduction of to GMP_NUMB_BITS * s bits. But each time
+     we discard some of the least significant limbs, we must keep one
+     additional bit to account for the truncation error. We maintain
+     the GMP_NUMB_BITS * s - extra_bits as the current target size. */
+
+  s = n/2 + 1;
+  if (BELOW_THRESHOLD (n, HGCD_APPR_THRESHOLD))
+    {
+      unsigned extra_bits = 0;
+
+      while (n > 2)
+	{
+	  mp_size_t nn;
+
+	  ASSERT (n > s);
+	  ASSERT (n <= 2*s);
+
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+	  if (!nn)
+	    break;
+
+	  n = nn;
+	  success = 1;
+
+	  /* We can truncate and discard the lower p bits whenever nbits <=
+	     2*sbits - p. To account for the truncation error, we must
+	     adjust
+
+	     sbits <-- sbits + 1 - p,
+
+	     rather than just sbits <-- sbits - p. This adjustment makes
+	     the produced matrix slightly smaller than it could be. */
+
+	  if (GMP_NUMB_BITS * (n + 1) + 2 * extra_bits <= 2*GMP_NUMB_BITS * s)
+	    {
+	      mp_size_t p = (GMP_NUMB_BITS * (2*s - n) - 2*extra_bits) / GMP_NUMB_BITS;
+
+	      if (extra_bits == 0)
+		{
+		  /* We cross a limb boundary and bump s. We can't do that
+		     if the result is that it makes makes min(U, V)
+		     smaller than 2^{GMP_NUMB_BITS} s. */
+		  if (s + 1 == n
+		      || mpn_zero_p (ap + s + 1, n - s - 1)
+		      || mpn_zero_p (bp + s + 1, n - s - 1))
+		    continue;
+
+		  extra_bits = GMP_NUMB_BITS - 1;
+		  s++;
+		}
+	      else
+		{
+		  extra_bits--;
+		}
+
+	      /* Drop the p least significant limbs */
+	      ap += p; bp += p; n -= p; s -= p;
+	    }
+	}
+
+      ASSERT (s > 0);
+
+      if (extra_bits > 0)
+	{
+	  /* We can get here only of we have dropped at least one of the least
+	     significant bits, so we can decrement ap and bp. We can then shift
+	     left extra bits using mpn_rshift. */
+	  /* NOTE: In the unlikely case that n is large, it would be preferable
+	     to do an initial subdiv step to reduce the size before shifting,
+	     but that would mean duplicating mpn_gcd_subdiv_step with a bit
+	     count rather than a limb count. */
+	  ap--; bp--;
+	  ap[0] = mpn_rshift (ap+1, ap+1, n, GMP_NUMB_BITS - extra_bits);
+	  bp[0] = mpn_rshift (bp+1, bp+1, n, GMP_NUMB_BITS - extra_bits);
+	  n += (ap[n] | bp[n]) > 0;
+
+	  ASSERT (success);
+
+	  while (n > 2)
+	    {
+	      mp_size_t nn;
+
+	      ASSERT (n > s);
+	      ASSERT (n <= 2*s);
+
+	      nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+
+	      if (!nn)
+		return 1;
+
+	      n = nn;
+	    }
+	}
+
+      if (n == 2)
+	{
+	  struct hgcd_matrix1 M1;
+	  ASSERT (s == 1);
+
+	  if (mpn_hgcd2 (ap[1], ap[0], bp[1], bp[0], &M1))
+	    {
+	      /* Multiply M <- M * M1 */
+	      mpn_hgcd_matrix_mul_1 (M, &M1, tp);
+	      success = 1;
+	    }
+	}
+      return success;
+    }
+  else
+    {
+      mp_size_t n2 = (3*n)/4 + 1;
+      mp_size_t p = n/2;
+      mp_size_t nn;
+
+      nn = mpn_hgcd_reduce (M, ap, bp, n, p, tp);
+      if (nn)
+	{
+	  n = nn;
+	  /* FIXME: Discard some of the low limbs immediately? */
+	  success = 1;
+	}
+
+      while (n > n2)
+	{
+	  mp_size_t nn;
+
+	  /* Needs n + 1 storage */
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+	  if (!nn)
+	    return success;
+
+	  n = nn;
+	  success = 1;
+	}
+      if (n > s + 2)
+	{
+	  struct hgcd_matrix M1;
+	  mp_size_t scratch;
+
+	  p = 2*s - n + 1;
+	  scratch = MPN_HGCD_MATRIX_INIT_ITCH (n-p);
+
+	  mpn_hgcd_matrix_init(&M1, n - p, tp);
+	  if (mpn_hgcd_appr (ap + p, bp + p, n - p, &M1, tp + scratch))
+	    {
+	      /* We always have max(M) > 2^{-(GMP_NUMB_BITS + 1)} max(M1) */
+	      ASSERT (M->n + 2 >= M1.n);
+
+	      /* Furthermore, assume M ends with a quotient (1, q; 0, 1),
+		 then either q or q + 1 is a correct quotient, and M1 will
+		 start with either (1, 0; 1, 1) or (2, 1; 1, 1). This
+		 rules out the case that the size of M * M1 is much
+		 smaller than the expected M->n + M1->n. */
+
+	      ASSERT (M->n + M1.n < M->alloc);
+
+	      /* We need a bound for of M->n + M1.n. Let n be the original
+		 input size. Then
+
+		 ceil(n/2) - 1 >= size of product >= M.n + M1.n - 2
+
+		 and it follows that
+
+		 M.n + M1.n <= ceil(n/2) + 1
+
+		 Then 3*(M.n + M1.n) + 5 <= 3 * ceil(n/2) + 8 is the
+		 amount of needed scratch space. */
+	      mpn_hgcd_matrix_mul (M, &M1, tp + scratch);
+	      return 1;
+	    }
+	}
+
+      for(;;)
+	{
+	  mp_size_t nn;
+
+	  ASSERT (n > s);
+	  ASSERT (n <= 2*s);
+
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+
+	  if (!nn)
+	    return success;
+
+	  n = nn;
+	  success = 1;
+	}
+    }
+}
diff --git a/mpn/generic/hgcd_jacobi.c b/mpn/generic/hgcd_jacobi.c
new file mode 100644
index 0000000..24014ce
--- /dev/null
+++ b/mpn/generic/hgcd_jacobi.c
@@ -0,0 +1,243 @@
+/* hgcd_jacobi.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* This file is almost a copy of hgcd.c, with some added calls to
+   mpn_jacobi_update */
+
+struct hgcd_jacobi_ctx
+{
+  struct hgcd_matrix *M;
+  unsigned *bitsp;
+};
+
+static void
+hgcd_jacobi_hook (void *p, mp_srcptr gp, mp_size_t gn,
+		  mp_srcptr qp, mp_size_t qn, int d)
+{
+  ASSERT (!gp);
+  ASSERT (d >= 0);
+
+  MPN_NORMALIZE (qp, qn);
+  if (qn > 0)
+    {
+      struct hgcd_jacobi_ctx *ctx = (struct hgcd_jacobi_ctx *) p;
+      /* NOTES: This is a bit ugly. A tp area is passed to
+	 gcd_subdiv_step, which stores q at the start of that area. We
+	 now use the rest. */
+      mp_ptr tp = (mp_ptr) qp + qn;
+
+      mpn_hgcd_matrix_update_q (ctx->M, qp, qn, d, tp);
+      *ctx->bitsp = mpn_jacobi_update (*ctx->bitsp, d, qp[0] & 3);
+    }
+}
+
+/* Perform a few steps, using some of mpn_hgcd2, subtraction and
+   division. Reduces the size by almost one limb or more, but never
+   below the given size s. Return new size for a and b, or 0 if no
+   more steps are possible.
+
+   If hgcd2 succeeds, needs temporary space for hgcd_matrix_mul_1, M->n
+   limbs, and hgcd_mul_matrix1_inverse_vector, n limbs. If hgcd2
+   fails, needs space for the quotient, qn <= n - s + 1 limbs, for and
+   hgcd_matrix_update_q, qn + (size of the appropriate column of M) <=
+   resulting size of M.
+
+   If N is the input size to the calling hgcd, then s = floor(N/2) +
+   1, M->n < N, qn + matrix size <= n - s + 1 + n - s = 2 (n - s) + 1
+   < N, so N is sufficient.
+*/
+
+static mp_size_t
+hgcd_jacobi_step (mp_size_t n, mp_ptr ap, mp_ptr bp, mp_size_t s,
+		  struct hgcd_matrix *M, unsigned *bitsp, mp_ptr tp)
+{
+  struct hgcd_matrix1 M1;
+  mp_limb_t mask;
+  mp_limb_t ah, al, bh, bl;
+
+  ASSERT (n > s);
+
+  mask = ap[n-1] | bp[n-1];
+  ASSERT (mask > 0);
+
+  if (n == s + 1)
+    {
+      if (mask < 4)
+	goto subtract;
+
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else if (mask & GMP_NUMB_HIGHBIT)
+    {
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else
+    {
+      int shift;
+
+      count_leading_zeros (shift, mask);
+      ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+      al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+      bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+      bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+    }
+
+  /* Try an mpn_hgcd2 step */
+  if (mpn_hgcd2_jacobi (ah, al, bh, bl, &M1, bitsp))
+    {
+      /* Multiply M <- M * M1 */
+      mpn_hgcd_matrix_mul_1 (M, &M1, tp);
+
+      /* Can't swap inputs, so we need to copy. */
+      MPN_COPY (tp, ap, n);
+      /* Multiply M1^{-1} (a;b) */
+      return mpn_matrix22_mul1_inverse_vector (&M1, ap, tp, bp, n);
+    }
+
+ subtract:
+  {
+    struct hgcd_jacobi_ctx ctx;
+    ctx.M = M;
+    ctx.bitsp = bitsp;
+
+    return mpn_gcd_subdiv_step (ap, bp, n, s, hgcd_jacobi_hook, &ctx, tp);
+  }
+}
+
+/* Reduces a,b until |a-b| fits in n/2 + 1 limbs. Constructs matrix M
+   with elements of size at most (n+1)/2 - 1. Returns new size of a,
+   b, or zero if no reduction is possible. */
+
+/* Same scratch requirements as for mpn_hgcd. */
+mp_size_t
+mpn_hgcd_jacobi (mp_ptr ap, mp_ptr bp, mp_size_t n,
+		 struct hgcd_matrix *M, unsigned *bitsp, mp_ptr tp)
+{
+  mp_size_t s = n/2 + 1;
+
+  mp_size_t nn;
+  int success = 0;
+
+  if (n <= s)
+    /* Happens when n <= 2, a fairly uninteresting case but exercised
+       by the random inputs of the testsuite. */
+    return 0;
+
+  ASSERT ((ap[n-1] | bp[n-1]) > 0);
+
+  ASSERT ((n+1)/2 - 1 < M->alloc);
+
+  if (ABOVE_THRESHOLD (n, HGCD_THRESHOLD))
+    {
+      mp_size_t n2 = (3*n)/4 + 1;
+      mp_size_t p = n/2;
+
+      nn = mpn_hgcd_jacobi (ap + p, bp + p, n - p, M, bitsp, tp);
+      if (nn > 0)
+	{
+	  /* Needs 2*(p + M->n) <= 2*(floor(n/2) + ceil(n/2) - 1)
+	     = 2 (n - 1) */
+	  n = mpn_hgcd_matrix_adjust (M, p + nn, ap, bp, p, tp);
+	  success = 1;
+	}
+      while (n > n2)
+	{
+	  /* Needs n + 1 storage */
+	  nn = hgcd_jacobi_step (n, ap, bp, s, M, bitsp, tp);
+	  if (!nn)
+	    return success ? n : 0;
+	  n = nn;
+	  success = 1;
+	}
+
+      if (n > s + 2)
+	{
+	  struct hgcd_matrix M1;
+	  mp_size_t scratch;
+
+	  p = 2*s - n + 1;
+	  scratch = MPN_HGCD_MATRIX_INIT_ITCH (n-p);
+
+	  mpn_hgcd_matrix_init(&M1, n - p, tp);
+	  nn = mpn_hgcd_jacobi (ap + p, bp + p, n - p, &M1, bitsp, tp + scratch);
+	  if (nn > 0)
+	    {
+	      /* We always have max(M) > 2^{-(GMP_NUMB_BITS + 1)} max(M1) */
+	      ASSERT (M->n + 2 >= M1.n);
+
+	      /* Furthermore, assume M ends with a quotient (1, q; 0, 1),
+		 then either q or q + 1 is a correct quotient, and M1 will
+		 start with either (1, 0; 1, 1) or (2, 1; 1, 1). This
+		 rules out the case that the size of M * M1 is much
+		 smaller than the expected M->n + M1->n. */
+
+	      ASSERT (M->n + M1.n < M->alloc);
+
+	      /* Needs 2 (p + M->n) <= 2 (2*s - n2 + 1 + n2 - s - 1)
+		 = 2*s <= 2*(floor(n/2) + 1) <= n + 2. */
+	      n = mpn_hgcd_matrix_adjust (&M1, p + nn, ap, bp, p, tp + scratch);
+
+	      /* We need a bound for of M->n + M1.n. Let n be the original
+		 input size. Then
+
+		 ceil(n/2) - 1 >= size of product >= M.n + M1.n - 2
+
+		 and it follows that
+
+		 M.n + M1.n <= ceil(n/2) + 1
+
+		 Then 3*(M.n + M1.n) + 5 <= 3 * ceil(n/2) + 8 is the
+		 amount of needed scratch space. */
+	      mpn_hgcd_matrix_mul (M, &M1, tp + scratch);
+	      success = 1;
+	    }
+	}
+    }
+
+  for (;;)
+    {
+      /* Needs s+3 < n */
+      nn = hgcd_jacobi_step (n, ap, bp, s, M, bitsp, tp);
+      if (!nn)
+	return success ? n : 0;
+
+      n = nn;
+      success = 1;
+    }
+}
diff --git a/mpn/generic/hgcd_matrix.c b/mpn/generic/hgcd_matrix.c
new file mode 100644
index 0000000..54c795d
--- /dev/null
+++ b/mpn/generic/hgcd_matrix.c
@@ -0,0 +1,265 @@
+/* hgcd_matrix.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* For input of size n, matrix elements are of size at most ceil(n/2)
+   - 1, but we need two limbs extra. */
+void
+mpn_hgcd_matrix_init (struct hgcd_matrix *M, mp_size_t n, mp_ptr p)
+{
+  mp_size_t s = (n+1)/2 + 1;
+  M->alloc = s;
+  M->n = 1;
+  MPN_ZERO (p, 4 * s);
+  M->p[0][0] = p;
+  M->p[0][1] = p + s;
+  M->p[1][0] = p + 2 * s;
+  M->p[1][1] = p + 3 * s;
+
+  M->p[0][0][0] = M->p[1][1][0] = 1;
+}
+
+/* Update column COL, adding in Q * column (1-COL). Temporary storage:
+ * qn + n <= M->alloc, where n is the size of the largest element in
+ * column 1 - COL. */
+void
+mpn_hgcd_matrix_update_q (struct hgcd_matrix *M, mp_srcptr qp, mp_size_t qn,
+			  unsigned col, mp_ptr tp)
+{
+  ASSERT (col < 2);
+
+  if (qn == 1)
+    {
+      mp_limb_t q = qp[0];
+      mp_limb_t c0, c1;
+
+      c0 = mpn_addmul_1 (M->p[0][col], M->p[0][1-col], M->n, q);
+      c1 = mpn_addmul_1 (M->p[1][col], M->p[1][1-col], M->n, q);
+
+      M->p[0][col][M->n] = c0;
+      M->p[1][col][M->n] = c1;
+
+      M->n += (c0 | c1) != 0;
+    }
+  else
+    {
+      unsigned row;
+
+      /* Carries for the unlikely case that we get both high words
+	 from the multiplication and carries from the addition. */
+      mp_limb_t c[2];
+      mp_size_t n;
+
+      /* The matrix will not necessarily grow in size by qn, so we
+	 need normalization in order not to overflow M. */
+
+      for (n = M->n; n + qn > M->n; n--)
+	{
+	  ASSERT (n > 0);
+	  if (M->p[0][1-col][n-1] > 0 || M->p[1][1-col][n-1] > 0)
+	    break;
+	}
+
+      ASSERT (qn + n <= M->alloc);
+
+      for (row = 0; row < 2; row++)
+	{
+	  if (qn <= n)
+	    mpn_mul (tp, M->p[row][1-col], n, qp, qn);
+	  else
+	    mpn_mul (tp, qp, qn, M->p[row][1-col], n);
+
+	  ASSERT (n + qn >= M->n);
+	  c[row] = mpn_add (M->p[row][col], tp, n + qn, M->p[row][col], M->n);
+	}
+
+      n += qn;
+
+      if (c[0] | c[1])
+	{
+	  M->p[0][col][n] = c[0];
+	  M->p[1][col][n] = c[1];
+	  n++;
+	}
+      else
+	{
+	  n -= (M->p[0][col][n-1] | M->p[1][col][n-1]) == 0;
+	  ASSERT (n >= M->n);
+	}
+      M->n = n;
+    }
+
+  ASSERT (M->n < M->alloc);
+}
+
+/* Multiply M by M1 from the right. Since the M1 elements fit in
+   GMP_NUMB_BITS - 1 bits, M grows by at most one limb. Needs
+   temporary space M->n */
+void
+mpn_hgcd_matrix_mul_1 (struct hgcd_matrix *M, const struct hgcd_matrix1 *M1,
+		       mp_ptr tp)
+{
+  mp_size_t n0, n1;
+
+  /* Could avoid copy by some swapping of pointers. */
+  MPN_COPY (tp, M->p[0][0], M->n);
+  n0 = mpn_hgcd_mul_matrix1_vector (M1, M->p[0][0], tp, M->p[0][1], M->n);
+  MPN_COPY (tp, M->p[1][0], M->n);
+  n1 = mpn_hgcd_mul_matrix1_vector (M1, M->p[1][0], tp, M->p[1][1], M->n);
+
+  /* Depends on zero initialization */
+  M->n = MAX(n0, n1);
+  ASSERT (M->n < M->alloc);
+}
+
+/* Multiply M by M1 from the right. Needs 3*(M->n + M1->n) + 5 limbs
+   of temporary storage (see mpn_matrix22_mul_itch). */
+void
+mpn_hgcd_matrix_mul (struct hgcd_matrix *M, const struct hgcd_matrix *M1,
+		     mp_ptr tp)
+{
+  mp_size_t n;
+
+  /* About the new size of M:s elements. Since M1's diagonal elements
+     are > 0, no element can decrease. The new elements are of size
+     M->n + M1->n, one limb more or less. The computation of the
+     matrix product produces elements of size M->n + M1->n + 1. But
+     the true size, after normalization, may be three limbs smaller.
+
+     The reason that the product has normalized size >= M->n + M1->n -
+     2 is subtle. It depends on the fact that M and M1 can be factored
+     as products of (1,1; 0,1) and (1,0; 1,1), and that we can't have
+     M ending with a large power and M1 starting with a large power of
+     the same matrix. */
+
+  /* FIXME: Strassen multiplication gives only a small speedup. In FFT
+     multiplication range, this function could be sped up quite a lot
+     using invariance. */
+  ASSERT (M->n + M1->n < M->alloc);
+
+  ASSERT ((M->p[0][0][M->n-1] | M->p[0][1][M->n-1]
+	   | M->p[1][0][M->n-1] | M->p[1][1][M->n-1]) > 0);
+
+  ASSERT ((M1->p[0][0][M1->n-1] | M1->p[0][1][M1->n-1]
+	   | M1->p[1][0][M1->n-1] | M1->p[1][1][M1->n-1]) > 0);
+
+  mpn_matrix22_mul (M->p[0][0], M->p[0][1],
+		    M->p[1][0], M->p[1][1], M->n,
+		    M1->p[0][0], M1->p[0][1],
+		    M1->p[1][0], M1->p[1][1], M1->n, tp);
+
+  /* Index of last potentially non-zero limb, size is one greater. */
+  n = M->n + M1->n;
+
+  n -= ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) == 0);
+  n -= ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) == 0);
+  n -= ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) == 0);
+
+  ASSERT ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) > 0);
+
+  M->n = n + 1;
+}
+
+/* Multiplies the least significant p limbs of (a;b) by M^-1.
+   Temporary space needed: 2 * (p + M->n)*/
+mp_size_t
+mpn_hgcd_matrix_adjust (const struct hgcd_matrix *M,
+			mp_size_t n, mp_ptr ap, mp_ptr bp,
+			mp_size_t p, mp_ptr tp)
+{
+  /* M^-1 (a;b) = (r11, -r01; -r10, r00) (a ; b)
+     = (r11 a - r01 b; - r10 a + r00 b */
+
+  mp_ptr t0 = tp;
+  mp_ptr t1 = tp + p + M->n;
+  mp_limb_t ah, bh;
+  mp_limb_t cy;
+
+  ASSERT (p + M->n  < n);
+
+  /* First compute the two values depending on a, before overwriting a */
+
+  if (M->n >= p)
+    {
+      mpn_mul (t0, M->p[1][1], M->n, ap, p);
+      mpn_mul (t1, M->p[1][0], M->n, ap, p);
+    }
+  else
+    {
+      mpn_mul (t0, ap, p, M->p[1][1], M->n);
+      mpn_mul (t1, ap, p, M->p[1][0], M->n);
+    }
+
+  /* Update a */
+  MPN_COPY (ap, t0, p);
+  ah = mpn_add (ap + p, ap + p, n - p, t0 + p, M->n);
+
+  if (M->n >= p)
+    mpn_mul (t0, M->p[0][1], M->n, bp, p);
+  else
+    mpn_mul (t0, bp, p, M->p[0][1], M->n);
+
+  cy = mpn_sub (ap, ap, n, t0, p + M->n);
+  ASSERT (cy <= ah);
+  ah -= cy;
+
+  /* Update b */
+  if (M->n >= p)
+    mpn_mul (t0, M->p[0][0], M->n, bp, p);
+  else
+    mpn_mul (t0, bp, p, M->p[0][0], M->n);
+
+  MPN_COPY (bp, t0, p);
+  bh = mpn_add (bp + p, bp + p, n - p, t0 + p, M->n);
+  cy = mpn_sub (bp, bp, n, t1, p + M->n);
+  ASSERT (cy <= bh);
+  bh -= cy;
+
+  if (ah > 0 || bh > 0)
+    {
+      ap[n] = ah;
+      bp[n] = bh;
+      n++;
+    }
+  else
+    {
+      /* The subtraction can reduce the size by at most one limb. */
+      if (ap[n-1] == 0 && bp[n-1] == 0)
+	n--;
+    }
+  ASSERT (ap[n-1] > 0 || bp[n-1] > 0);
+  return n;
+}
diff --git a/mpn/generic/hgcd_reduce.c b/mpn/generic/hgcd_reduce.c
new file mode 100644
index 0000000..3aee77d
--- /dev/null
+++ b/mpn/generic/hgcd_reduce.c
@@ -0,0 +1,242 @@
+/* hgcd_reduce.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Computes R -= A * B. Result must be non-negative. Normalized down
+   to size an, and resulting size is returned. */
+static mp_size_t
+submul (mp_ptr rp, mp_size_t rn,
+	mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (bn > 0);
+  ASSERT (an >= bn);
+  ASSERT (rn >= an);
+  ASSERT (an + bn <= rn + 1);
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (an + bn);
+
+  mpn_mul (tp, ap, an, bp, bn);
+  ASSERT ((an + bn <= rn) || (tp[rn] == 0));
+  ASSERT_NOCARRY (mpn_sub (rp, rp, rn, tp, an + bn - (an + bn > rn)));
+  TMP_FREE;
+
+  while (rn > an && (rp[rn-1] == 0))
+    rn--;
+
+  return rn;
+}
+
+/* Computes (a, b)  <--  M^{-1} (a; b) */
+/* FIXME:
+    x Take scratch parameter, and figure out scratch need.
+
+    x Use some fallback for small M->n?
+*/
+static mp_size_t
+hgcd_matrix_apply (const struct hgcd_matrix *M,
+		   mp_ptr ap, mp_ptr bp,
+		   mp_size_t n)
+{
+  mp_size_t an, bn, un, vn, nn;
+  mp_size_t mn[2][2];
+  mp_size_t modn;
+  mp_ptr tp, sp, scratch;
+  mp_limb_t cy;
+  unsigned i, j;
+
+  TMP_DECL;
+
+  ASSERT ( (ap[n-1] | bp[n-1]) > 0);
+
+  an = n;
+  MPN_NORMALIZE (ap, an);
+  bn = n;
+  MPN_NORMALIZE (bp, bn);
+
+  for (i = 0; i < 2; i++)
+    for (j = 0; j < 2; j++)
+      {
+	mp_size_t k;
+	k = M->n;
+	MPN_NORMALIZE (M->p[i][j], k);
+	mn[i][j] = k;
+      }
+
+  ASSERT (mn[0][0] > 0);
+  ASSERT (mn[1][1] > 0);
+  ASSERT ( (mn[0][1] | mn[1][0]) > 0);
+
+  TMP_MARK;
+
+  if (mn[0][1] == 0)
+    {
+      /* A unchanged, M = (1, 0; q, 1) */
+      ASSERT (mn[0][0] == 1);
+      ASSERT (M->p[0][0][0] == 1);
+      ASSERT (mn[1][1] == 1);
+      ASSERT (M->p[1][1][0] == 1);
+
+      /* Put B <-- B - q A */
+      nn = submul (bp, bn, ap, an, M->p[1][0], mn[1][0]);
+    }
+  else if (mn[1][0] == 0)
+    {
+      /* B unchanged, M = (1, q; 0, 1) */
+      ASSERT (mn[0][0] == 1);
+      ASSERT (M->p[0][0][0] == 1);
+      ASSERT (mn[1][1] == 1);
+      ASSERT (M->p[1][1][0] == 1);
+
+      /* Put A  <-- A - q * B */
+      nn = submul (ap, an, bp, bn, M->p[0][1], mn[0][1]);
+    }
+  else
+    {
+      /* A = m00 a + m01 b  ==> a <= A / m00, b <= A / m01.
+	 B = m10 a + m11 b  ==> a <= B / m10, b <= B / m11. */
+      un = MIN (an - mn[0][0], bn - mn[1][0]) + 1;
+      vn = MIN (an - mn[0][1], bn - mn[1][1]) + 1;
+
+      nn = MAX (un, vn);
+      /* In the range of interest, mulmod_bnm1 should always beat mullo. */
+      modn = mpn_mulmod_bnm1_next_size (nn + 1);
+
+      TMP_ALLOC_LIMBS_3 (tp, modn,
+			 sp, modn,
+			 scratch, mpn_mulmod_bnm1_itch (modn, modn, M->n));
+
+      ASSERT (n <= 2*modn);
+
+      if (n > modn)
+	{
+	  cy = mpn_add (ap, ap, modn, ap + modn, n - modn);
+	  MPN_INCR_U (ap, modn, cy);
+
+	  cy = mpn_add (bp, bp, modn, bp + modn, n - modn);
+	  MPN_INCR_U (bp, modn, cy);
+
+	  n = modn;
+	}
+
+      mpn_mulmod_bnm1 (tp, modn, ap, n, M->p[1][1], mn[1][1], scratch);
+      mpn_mulmod_bnm1 (sp, modn, bp, n, M->p[0][1], mn[0][1], scratch);
+
+      /* FIXME: Handle the small n case in some better way. */
+      if (n + mn[1][1] < modn)
+	MPN_ZERO (tp + n + mn[1][1], modn - n - mn[1][1]);
+      if (n + mn[0][1] < modn)
+	MPN_ZERO (sp + n + mn[0][1], modn - n - mn[0][1]);
+
+      cy = mpn_sub_n (tp, tp, sp, modn);
+      MPN_DECR_U (tp, modn, cy);
+
+      ASSERT (mpn_zero_p (tp + nn, modn - nn));
+
+      mpn_mulmod_bnm1 (sp, modn, ap, n, M->p[1][0], mn[1][0], scratch);
+      MPN_COPY (ap, tp, nn);
+      mpn_mulmod_bnm1 (tp, modn, bp, n, M->p[0][0], mn[0][0], scratch);
+
+      if (n + mn[1][0] < modn)
+	MPN_ZERO (sp + n + mn[1][0], modn - n - mn[1][0]);
+      if (n + mn[0][0] < modn)
+	MPN_ZERO (tp + n + mn[0][0], modn - n - mn[0][0]);
+
+      cy = mpn_sub_n (tp, tp, sp, modn);
+      MPN_DECR_U (tp, modn, cy);
+
+      ASSERT (mpn_zero_p (tp + nn, modn - nn));
+      MPN_COPY (bp, tp, nn);
+
+      while ( (ap[nn-1] | bp[nn-1]) == 0)
+	{
+	  nn--;
+	  ASSERT (nn > 0);
+	}
+    }
+  TMP_FREE;
+
+  return nn;
+}
+
+mp_size_t
+mpn_hgcd_reduce_itch (mp_size_t n, mp_size_t p)
+{
+  mp_size_t itch;
+  if (BELOW_THRESHOLD (n, HGCD_REDUCE_THRESHOLD))
+    {
+      itch = mpn_hgcd_itch (n-p);
+
+      /* For arbitrary p, the storage for _adjust is 2*(p + M->n) = 2 *
+	 (p + ceil((n-p)/2) - 1 <= n + p - 1 */
+      if (itch < n + p - 1)
+	itch = n + p - 1;
+    }
+  else
+    {
+      itch = 2*(n-p) + mpn_hgcd_itch (n-p);
+      /* Currently, hgcd_matrix_apply allocates its own storage. */
+    }
+  return itch;
+}
+
+/* FIXME: Document storage need. */
+mp_size_t
+mpn_hgcd_reduce (struct hgcd_matrix *M,
+		 mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t p,
+		 mp_ptr tp)
+{
+  mp_size_t nn;
+  if (BELOW_THRESHOLD (n, HGCD_REDUCE_THRESHOLD))
+    {
+      nn = mpn_hgcd (ap + p, bp + p, n - p, M, tp);
+      if (nn > 0)
+	/* Needs 2*(p + M->n) <= 2*(floor(n/2) + ceil(n/2) - 1)
+	   = 2 (n - 1) */
+	return mpn_hgcd_matrix_adjust (M, p + nn, ap, bp, p, tp);
+    }
+  else
+    {
+      MPN_COPY (tp, ap + p, n - p);
+      MPN_COPY (tp + n - p, bp + p, n - p);
+      if (mpn_hgcd_appr (tp, tp + n - p, n - p, M, tp + 2*(n-p)))
+	return hgcd_matrix_apply (M, ap, bp, n);
+    }
+  return 0;
+}
diff --git a/mpn/generic/hgcd_step.c b/mpn/generic/hgcd_step.c
new file mode 100644
index 0000000..a978a88
--- /dev/null
+++ b/mpn/generic/hgcd_step.c
@@ -0,0 +1,127 @@
+/* hgcd_step.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+static void
+hgcd_hook (void *p, mp_srcptr gp, mp_size_t gn,
+	   mp_srcptr qp, mp_size_t qn, int d)
+{
+  ASSERT (!gp);
+  ASSERT (d >= 0);
+  ASSERT (d <= 1);
+
+  MPN_NORMALIZE (qp, qn);
+  if (qn > 0)
+    {
+      struct hgcd_matrix *M = (struct hgcd_matrix *) p;
+      /* NOTES: This is a bit ugly. A tp area is passed to
+	 gcd_subdiv_step, which stores q at the start of that area. We
+	 now use the rest. */
+      mp_ptr tp = (mp_ptr) qp + qn;
+      mpn_hgcd_matrix_update_q (M, qp, qn, d, tp);
+    }
+}
+
+/* Perform a few steps, using some of mpn_hgcd2, subtraction and
+   division. Reduces the size by almost one limb or more, but never
+   below the given size s. Return new size for a and b, or 0 if no
+   more steps are possible.
+
+   If hgcd2 succeeds, needs temporary space for hgcd_matrix_mul_1, M->n
+   limbs, and hgcd_mul_matrix1_inverse_vector, n limbs. If hgcd2
+   fails, needs space for the quotient, qn <= n - s limbs, for and
+   hgcd_matrix_update_q, qn + (size of the appropriate column of M) <=
+   (resulting size of M) + 1.
+
+   If N is the input size to the calling hgcd, then s = floor(N/2) +
+   1, M->n < N, qn + product size <= n - s + n - s + 1 = 2 (n - s) + 1
+   <= N.
+*/
+
+mp_size_t
+mpn_hgcd_step (mp_size_t n, mp_ptr ap, mp_ptr bp, mp_size_t s,
+	       struct hgcd_matrix *M, mp_ptr tp)
+{
+  struct hgcd_matrix1 M1;
+  mp_limb_t mask;
+  mp_limb_t ah, al, bh, bl;
+
+  ASSERT (n > s);
+
+  mask = ap[n-1] | bp[n-1];
+  ASSERT (mask > 0);
+
+  if (n == s + 1)
+    {
+      if (mask < 4)
+	goto subtract;
+
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else if (mask & GMP_NUMB_HIGHBIT)
+    {
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else
+    {
+      int shift;
+
+      count_leading_zeros (shift, mask);
+      ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+      al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+      bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+      bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+    }
+
+  /* Try an mpn_hgcd2 step */
+  if (mpn_hgcd2 (ah, al, bh, bl, &M1))
+    {
+      /* Multiply M <- M * M1 */
+      mpn_hgcd_matrix_mul_1 (M, &M1, tp);
+
+      /* Can't swap inputs, so we need to copy. */
+      MPN_COPY (tp, ap, n);
+      /* Multiply M1^{-1} (a;b) */
+      return mpn_matrix22_mul1_inverse_vector (&M1, ap, tp, bp, n);
+    }
+
+ subtract:
+
+  return mpn_gcd_subdiv_step (ap, bp, n, s, hgcd_hook, M, tp);
+}
diff --git a/mpn/generic/invert.c b/mpn/generic/invert.c
new file mode 100644
index 0000000..157ff2b
--- /dev/null
+++ b/mpn/generic/invert.c
@@ -0,0 +1,86 @@
+/* invert.c -- Compute floor((B^{2n}-1)/U) - B^n.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright (C) 2007, 2009, 2010, 2012, 2014-2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_invert (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch)
+{
+  ASSERT (n > 0);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, scratch, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, scratch, mpn_invertappr_itch(n)));
+
+  if (n == 1)
+    invert_limb (*ip, *dp);
+  else if (BELOW_THRESHOLD (n, INV_APPR_THRESHOLD))
+    {
+	/* Maximum scratch needed by this branch: 2*n */
+	mp_ptr xp;
+
+	xp = scratch;				/* 2 * n limbs */
+	/* n > 1 here */
+	MPN_FILL (xp, n, GMP_NUMB_MAX);
+	mpn_com (xp + n, dp, n);
+	if (n == 2) {
+	  mpn_divrem_2 (ip, 0, xp, 4, dp);
+	} else {
+	  gmp_pi1_t inv;
+	  invert_pi1 (inv, dp[n-1], dp[n-2]);
+	  /* FIXME: should we use dcpi1_div_q, for big sizes? */
+	  mpn_sbpi1_div_q (ip, xp, 2 * n, dp, n, inv.inv32);
+	}
+    }
+  else { /* Use approximated inverse; correct the result if needed. */
+      mp_limb_t e; /* The possible error in the approximate inverse */
+
+      ASSERT ( mpn_invert_itch (n) >= mpn_invertappr_itch (n) );
+      e = mpn_ni_invertappr (ip, dp, n, scratch);
+
+      if (UNLIKELY (e)) { /* Assume the error can only be "0" (no error) or "1". */
+	/* Code to detect and correct the "off by one" approximation. */
+	mpn_mul_n (scratch, ip, dp, n);
+	e = mpn_add_n (scratch, scratch, dp, n); /* FIXME: we only need e.*/
+	if (LIKELY(e)) /* The high part can not give a carry by itself. */
+	  e = mpn_add_nc (scratch + n, scratch + n, dp, n, e); /* FIXME:e */
+	/* If the value was wrong (no carry), correct it (increment). */
+	e ^= CNST_LIMB (1);
+	MPN_INCR_U (ip, n, e);
+      }
+  }
+}
diff --git a/mpn/generic/invertappr.c b/mpn/generic/invertappr.c
new file mode 100644
index 0000000..3be5596
--- /dev/null
+++ b/mpn/generic/invertappr.c
@@ -0,0 +1,300 @@
+/* mpn_invertappr and helper functions.  Compute I such that
+   floor((B^{2n}-1)/U - 1 <= I + B^n <= floor((B^{2n}-1)/U.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   The algorithm used here was inspired by ApproximateReciprocal from "Modern
+   Computer Arithmetic", by Richard P. Brent and Paul Zimmermann.  Special
+   thanks to Paul Zimmermann for his very valuable suggestions on all the
+   theoretical aspects during the work on this code.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright (C) 2007, 2009, 2010, 2012, 2015, 2016 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* FIXME: The iterative version splits the operand in two slightly unbalanced
+   parts, the use of log_2 (or counting the bits) underestimate the maximum
+   number of iterations.  */
+
+#if TUNE_PROGRAM_BUILD
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)))
+#define MAYBE_dcpi1_divappr   1
+#else
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)) - LOG2C (INV_NEWTON_THRESHOLD))
+#define MAYBE_dcpi1_divappr \
+  (INV_NEWTON_THRESHOLD < DC_DIVAPPR_Q_THRESHOLD)
+#if (INV_NEWTON_THRESHOLD > INV_MULMOD_BNM1_THRESHOLD) && \
+    (INV_APPR_THRESHOLD > INV_MULMOD_BNM1_THRESHOLD)
+#undef  INV_MULMOD_BNM1_THRESHOLD
+#define INV_MULMOD_BNM1_THRESHOLD 0 /* always when Newton */
+#endif
+#endif
+
+/* All the three functions mpn{,_bc,_ni}_invertappr (ip, dp, n, scratch), take
+   the strictly normalised value {dp,n} (i.e., most significant bit must be set)
+   as an input, and compute {ip,n}: the approximate reciprocal of {dp,n}.
+
+   Let e = mpn*_invertappr (ip, dp, n, scratch) be the returned value; the
+   following conditions are satisfied by the output:
+     0 <= e <= 1;
+     {dp,n}*(B^n+{ip,n}) < B^{2n} <= {dp,n}*(B^n+{ip,n}+1+e) .
+   I.e. e=0 means that the result {ip,n} equals the one given by mpn_invert.
+	e=1 means that the result _may_ be one less than expected.
+
+   The _bc version returns e=1 most of the time.
+   The _ni version should return e=0 most of the time; only about 1% of
+   possible random input should give e=1.
+
+   When the strict result is needed, i.e., e=0 in the relation above:
+     {dp,n}*(B^n+{ip,n}) < B^{2n} <= {dp,n}*(B^n+{ip,n}+1) ;
+   the function mpn_invert (ip, dp, n, scratch) should be used instead.  */
+
+/* Maximum scratch needed by this branch (at xp): 2*n */
+static mp_limb_t
+mpn_bc_invertappr (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr xp)
+{
+  ASSERT (n > 0);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, xp, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, xp, mpn_invertappr_itch(n)));
+
+  /* Compute a base value of r limbs. */
+  if (n == 1)
+    invert_limb (*ip, *dp);
+  else {
+    /* n > 1 here */
+    MPN_FILL (xp, n, GMP_NUMB_MAX);
+    mpn_com (xp + n, dp, n);
+
+    /* Now xp contains B^2n - {dp,n}*B^n - 1 */
+
+    /* FIXME: if mpn_*pi1_divappr_q handles n==2, use it! */
+    if (n == 2) {
+      mpn_divrem_2 (ip, 0, xp, 4, dp);
+    } else {
+      gmp_pi1_t inv;
+      invert_pi1 (inv, dp[n-1], dp[n-2]);
+      if (! MAYBE_dcpi1_divappr
+	  || BELOW_THRESHOLD (n, DC_DIVAPPR_Q_THRESHOLD))
+	mpn_sbpi1_divappr_q (ip, xp, 2 * n, dp, n, inv.inv32);
+      else
+	mpn_dcpi1_divappr_q (ip, xp, 2 * n, dp, n, &inv);
+      MPN_DECR_U(ip, n, CNST_LIMB (1));
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* mpn_ni_invertappr: computes the approximate reciprocal using Newton's
+   iterations (at least one).
+
+   Inspired by Algorithm "ApproximateReciprocal", published in "Modern Computer
+   Arithmetic" by Richard P. Brent and Paul Zimmermann, algorithm 3.5, page 121
+   in version 0.4 of the book.
+
+   Some adaptations were introduced, to allow product mod B^m-1 and return the
+   value e.
+
+   We introduced a correction in such a way that "the value of
+   B^{n+h}-T computed at step 8 cannot exceed B^n-1" (the book reads
+   "2B^n-1").
+
+   Maximum scratch needed by this branch <= 2*n, but have to fit 3*rn
+   in the scratch, i.e. 3*rn <= 2*n: we require n>4.
+
+   We use a wrapped product modulo B^m-1.  NOTE: is there any normalisation
+   problem for the [0] class?  It shouldn't: we compute 2*|A*X_h - B^{n+h}| <
+   B^m-1.  We may get [0] if and only if we get AX_h = B^{n+h}.  This can
+   happen only if A=B^{n}/2, but this implies X_h = B^{h}*2-1 i.e., AX_h =
+   B^{n+h} - A, then we get into the "negative" branch, where X_h is not
+   incremented (because A < B^n).
+
+   FIXME: the scratch for mulmod_bnm1 does not currently fit in the scratch, it
+   is allocated apart.
+ */
+
+mp_limb_t
+mpn_ni_invertappr (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch)
+{
+  mp_limb_t cy;
+  mp_size_t rn, mn;
+  mp_size_t sizes[NPOWS], *sizp;
+  mp_ptr tp;
+  TMP_DECL;
+#define xp scratch
+
+  ASSERT (n > 4);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, scratch, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, scratch, mpn_invertappr_itch(n)));
+
+  /* Compute the computation precisions from highest to lowest, leaving the
+     base case size in 'rn'.  */
+  sizp = sizes;
+  rn = n;
+  do {
+    *sizp = rn;
+    rn = (rn >> 1) + 1;
+    ++sizp;
+  } while (ABOVE_THRESHOLD (rn, INV_NEWTON_THRESHOLD));
+
+  /* We search the inverse of 0.{dp,n}, we compute it as 1.{ip,n} */
+  dp += n;
+  ip += n;
+
+  /* Compute a base value of rn limbs. */
+  mpn_bc_invertappr (ip - rn, dp - rn, rn, scratch);
+
+  TMP_MARK;
+
+  if (ABOVE_THRESHOLD (n, INV_MULMOD_BNM1_THRESHOLD))
+    {
+      mn = mpn_mulmod_bnm1_next_size (n + 1);
+      tp = TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (mn, n, (n >> 1) + 1));
+    }
+  /* Use Newton's iterations to get the desired precision.*/
+
+  while (1) {
+    n = *--sizp;
+    /*
+      v    n  v
+      +----+--+
+      ^ rn ^
+    */
+
+    /* Compute i_jd . */
+    if (BELOW_THRESHOLD (n, INV_MULMOD_BNM1_THRESHOLD)
+	|| ((mn = mpn_mulmod_bnm1_next_size (n + 1)) > (n + rn))) {
+      /* FIXME: We do only need {xp,n+1}*/
+      mpn_mul (xp, dp - n, n, ip - rn, rn);
+      mpn_add_n (xp + rn, xp + rn, dp - n, n - rn + 1);
+      cy = CNST_LIMB(1); /* Remember we truncated, Mod B^(n+1) */
+      /* We computed (truncated) {xp,n+1} <- 1.{ip,rn} * 0.{dp,n} */
+    } else { /* Use B^mn-1 wraparound */
+      mpn_mulmod_bnm1 (xp, mn, dp - n, n, ip - rn, rn, tp);
+      /* We computed {xp,mn} <- {ip,rn} * {dp,n} mod (B^mn-1) */
+      /* We know that 2*|ip*dp + dp*B^rn - B^{rn+n}| < B^mn-1 */
+      /* Add dp*B^rn mod (B^mn-1) */
+      ASSERT (n >= mn - rn);
+      cy = mpn_add_n (xp + rn, xp + rn, dp - n, mn - rn);
+      cy = mpn_add_nc (xp, xp, dp - (n - (mn - rn)), n - (mn - rn), cy);
+      /* Subtract B^{rn+n}, maybe only compensate the carry*/
+      xp[mn] = CNST_LIMB (1); /* set a limit for DECR_U */
+      MPN_DECR_U (xp + rn + n - mn, 2 * mn + 1 - rn - n, CNST_LIMB (1) - cy);
+      MPN_DECR_U (xp, mn, CNST_LIMB (1) - xp[mn]); /* if DECR_U eroded xp[mn] */
+      cy = CNST_LIMB(0); /* Remember we are working Mod B^mn-1 */
+    }
+
+    if (xp[n] < CNST_LIMB (2)) { /* "positive" residue class */
+      cy = xp[n]; /* 0 <= cy <= 1 here. */
+#if HAVE_NATIVE_mpn_sublsh1_n
+      if (cy++) {
+	if (mpn_cmp (xp, dp - n, n) > 0) {
+	  mp_limb_t chk;
+	  chk = mpn_sublsh1_n (xp, xp, dp - n, n);
+	  ASSERT (chk == xp[n]);
+	  ++ cy;
+	} else
+	  ASSERT_CARRY (mpn_sub_n (xp, xp, dp - n, n));
+      }
+#else /* no mpn_sublsh1_n*/
+      if (cy++ && !mpn_sub_n (xp, xp, dp - n, n)) {
+	ASSERT_CARRY (mpn_sub_n (xp, xp, dp - n, n));
+	++cy;
+      }
+#endif
+      /* 1 <= cy <= 3 here. */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+      if (mpn_cmp (xp, dp - n, n) > 0) {
+	ASSERT_NOCARRY (mpn_rsblsh1_n (xp + n, xp, dp - n, n));
+	++cy;
+      } else
+	ASSERT_NOCARRY (mpn_sub_nc (xp + 2 * n - rn, dp - rn, xp + n - rn, rn, mpn_cmp (xp, dp - n, n - rn) > 0));
+#else /* no mpn_rsblsh1_n*/
+      if (mpn_cmp (xp, dp - n, n) > 0) {
+	ASSERT_NOCARRY (mpn_sub_n (xp, xp, dp - n, n));
+	++cy;
+      }
+      ASSERT_NOCARRY (mpn_sub_nc (xp + 2 * n - rn, dp - rn, xp + n - rn, rn, mpn_cmp (xp, dp - n, n - rn) > 0));
+#endif
+      MPN_DECR_U(ip - rn, rn, cy); /* 1 <= cy <= 4 here. */
+    } else { /* "negative" residue class */
+      ASSERT (xp[n] >= GMP_NUMB_MAX - CNST_LIMB(1));
+      MPN_DECR_U(xp, n + 1, cy);
+      if (xp[n] != GMP_NUMB_MAX) {
+	MPN_INCR_U(ip - rn, rn, CNST_LIMB (1));
+	ASSERT_CARRY (mpn_add_n (xp, xp, dp - n, n));
+      }
+      mpn_com (xp + 2 * n - rn, xp + n - rn, rn);
+    }
+
+    /* Compute x_ju_j. FIXME:We need {xp+rn,rn}, mulhi? */
+    mpn_mul_n (xp, xp + 2 * n - rn, ip - rn, rn);
+    cy = mpn_add_n (xp + rn, xp + rn, xp + 2 * n - rn, 2 * rn - n);
+    cy = mpn_add_nc (ip - n, xp + 3 * rn - n, xp + n + rn, n - rn, cy);
+    MPN_INCR_U (ip - rn, rn, cy);
+    if (sizp == sizes) { /* Get out of the cycle */
+      /* Check for possible carry propagation from below. */
+      cy = xp[3 * rn - n - 1] > GMP_NUMB_MAX - CNST_LIMB (7); /* Be conservative. */
+      /*    cy = mpn_add_1 (xp + rn, xp + rn, 2*rn - n, 4); */
+      break;
+    }
+    rn = n;
+  }
+  TMP_FREE;
+
+  return cy;
+#undef xp
+}
+
+mp_limb_t
+mpn_invertappr (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch)
+{
+  ASSERT (n > 0);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, scratch, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, scratch, mpn_invertappr_itch(n)));
+
+  if (BELOW_THRESHOLD (n, INV_NEWTON_THRESHOLD))
+    return mpn_bc_invertappr (ip, dp, n, scratch);
+  else
+    return mpn_ni_invertappr (ip, dp, n, scratch);
+}
diff --git a/mpn/generic/jacbase.c b/mpn/generic/jacbase.c
new file mode 100644
index 0000000..391ceac
--- /dev/null
+++ b/mpn/generic/jacbase.c
@@ -0,0 +1,242 @@
+/* mpn_jacobi_base -- limb/limb Jacobi symbol with restricted arguments.
+
+   THIS INTERFACE IS PRELIMINARY AND MIGHT DISAPPEAR OR BE SUBJECT TO
+   INCOMPATIBLE CHANGES IN A FUTURE RELEASE OF GMP.
+
+Copyright 1999-2002, 2010, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Use the simple loop by default.  The generic count_trailing_zeros is not
+   very fast, and the extra trickery of method 3 has proven to be less use
+   than might have been though.  */
+#ifndef JACOBI_BASE_METHOD
+#define JACOBI_BASE_METHOD  2
+#endif
+
+
+/* Use count_trailing_zeros.  */
+#if JACOBI_BASE_METHOD == 1
+#define PROCESS_TWOS_ANY                                \
+  {                                                     \
+    mp_limb_t  twos;                                    \
+    count_trailing_zeros (twos, a);                     \
+    result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b);        \
+    a >>= twos;                                         \
+  }
+#define PROCESS_TWOS_EVEN  PROCESS_TWOS_ANY
+#endif
+
+/* Use a simple loop.  A disadvantage of this is that there's a branch on a
+   50/50 chance of a 0 or 1 low bit.  */
+#if JACOBI_BASE_METHOD == 2
+#define PROCESS_TWOS_EVEN               \
+  {                                     \
+    int  two;                           \
+    two = JACOBI_TWO_U_BIT1 (b);        \
+    do                                  \
+      {                                 \
+	a >>= 1;                        \
+	result_bit1 ^= two;             \
+	ASSERT (a != 0);                \
+      }                                 \
+    while ((a & 1) == 0);               \
+  }
+#define PROCESS_TWOS_ANY        \
+  if ((a & 1) == 0)             \
+    PROCESS_TWOS_EVEN;
+#endif
+
+/* Process one bit arithmetically, then a simple loop.  This cuts the loop
+   condition down to a 25/75 chance, which should branch predict better.
+   The CPU will need a reasonable variable left shift.  */
+#if JACOBI_BASE_METHOD == 3
+#define PROCESS_TWOS_EVEN               \
+  {                                     \
+    int  two, mask, shift;              \
+					\
+    two = JACOBI_TWO_U_BIT1 (b);        \
+    mask = (~a & 2);                    \
+    a >>= 1;                            \
+					\
+    shift = (~a & 1);                   \
+    a >>= shift;                        \
+    result_bit1 ^= two ^ (two & mask);  \
+					\
+    while ((a & 1) == 0)                \
+      {                                 \
+	a >>= 1;                        \
+	result_bit1 ^= two;             \
+	ASSERT (a != 0);                \
+      }                                 \
+  }
+#define PROCESS_TWOS_ANY                \
+  {                                     \
+    int  two, mask, shift;              \
+					\
+    two = JACOBI_TWO_U_BIT1 (b);        \
+    shift = (~a & 1);                   \
+    a >>= shift;                        \
+					\
+    mask = shift << 1;                  \
+    result_bit1 ^= (two & mask);        \
+					\
+    while ((a & 1) == 0)                \
+      {                                 \
+	a >>= 1;                        \
+	result_bit1 ^= two;             \
+	ASSERT (a != 0);                \
+      }                                 \
+  }
+#endif
+
+#if JACOBI_BASE_METHOD < 4
+/* Calculate the value of the Jacobi symbol (a/b) of two mp_limb_t's, but
+   with a restricted range of inputs accepted, namely b>1, b odd.
+
+   The initial result_bit1 is taken as a parameter for the convenience of
+   mpz_kronecker_ui() et al.  The sign changes both here and in those
+   routines accumulate nicely in bit 1, see the JACOBI macros.
+
+   The return value here is the normal +1, 0, or -1.  Note that +1 and -1
+   have bit 1 in the "BIT1" sense, which could be useful if the caller is
+   accumulating it into some extended calculation.
+
+   Duplicating the loop body to avoid the MP_LIMB_T_SWAP(a,b) would be
+   possible, but a couple of tests suggest it's not a significant speedup,
+   and may even be a slowdown, so what's here is good enough for now. */
+
+int
+mpn_jacobi_base (mp_limb_t a, mp_limb_t b, int result_bit1)
+{
+  ASSERT (b & 1);  /* b odd */
+  ASSERT (b != 1);
+
+  if (a == 0)
+    return 0;
+
+  PROCESS_TWOS_ANY;
+  if (a == 1)
+    goto done;
+
+  if (a >= b)
+    goto a_gt_b;
+
+  for (;;)
+    {
+      result_bit1 ^= JACOBI_RECIP_UU_BIT1 (a, b);
+      MP_LIMB_T_SWAP (a, b);
+
+    a_gt_b:
+      do
+	{
+	  /* working on (a/b), a,b odd, a>=b */
+	  ASSERT (a & 1);
+	  ASSERT (b & 1);
+	  ASSERT (a >= b);
+
+	  if ((a -= b) == 0)
+	    return 0;
+
+	  PROCESS_TWOS_EVEN;
+	  if (a == 1)
+	    goto done;
+	}
+      while (a >= b);
+    }
+
+ done:
+  return JACOBI_BIT1_TO_PN (result_bit1);
+}
+#endif
+
+#if JACOBI_BASE_METHOD == 4
+/* Computes (a/b) for odd b > 1 and any a. The initial bit is taken as a
+ * parameter. We have no need for the convention that the sign is in
+ * bit 1, internally we use bit 0. */
+
+/* FIXME: Could try table-based count_trailing_zeros. */
+int
+mpn_jacobi_base (mp_limb_t a, mp_limb_t b, int bit)
+{
+  int c;
+
+  ASSERT (b & 1);
+  ASSERT (b > 1);
+
+  if (a == 0)
+    /* This is the only line which depends on b > 1 */
+    return 0;
+
+  bit >>= 1;
+
+  /* Below, we represent a and b shifted right so that the least
+     significant one bit is implicit. */
+
+  b >>= 1;
+
+  count_trailing_zeros (c, a);
+  bit ^= c & (b ^ (b >> 1));
+
+  /* We may have c==GMP_LIMB_BITS-1, so we can't use a>>c+1. */
+  a >>= c;
+  a >>= 1;
+
+  do
+    {
+      mp_limb_t t = a - b;
+      mp_limb_t bgta = LIMB_HIGHBIT_TO_MASK (t);
+
+      if (t == 0)
+	return 0;
+
+      /* If b > a, invoke reciprocity */
+      bit ^= (bgta & a & b);
+
+      /* b <-- min (a, b) */
+      b += (bgta & t);
+
+      /* a <-- |a - b| */
+      a = (t ^ bgta) - bgta;
+
+      /* Number of trailing zeros is the same no matter if we look at
+       * t or a, but using t gives more parallelism. */
+      count_trailing_zeros (c, t);
+      c ++;
+      /* (2/b) = -1 if b = 3 or 5 mod 8 */
+      bit ^= c & (b ^ (b >> 1));
+      a >>= c;
+    }
+  while (a > 0);
+
+  return 1-2*(bit & 1);
+}
+#endif /* JACOBI_BASE_METHOD == 4 */
diff --git a/mpn/generic/jacobi.c b/mpn/generic/jacobi.c
new file mode 100644
index 0000000..d98b126
--- /dev/null
+++ b/mpn/generic/jacobi.c
@@ -0,0 +1,294 @@
+/* jacobi.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2010, 2011 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef JACOBI_DC_THRESHOLD
+#define JACOBI_DC_THRESHOLD GCD_DC_THRESHOLD
+#endif
+
+/* Schönhage's rules:
+ *
+ * Assume r0 = r1 q1 + r2, with r0 odd, and r1 = q2 r2 + r3
+ *
+ * If r1 is odd, then
+ *
+ *   (r1 | r0) = s(r1, r0) (r0 | r1) = s(r1, r0) (r2, r1)
+ *
+ * where s(x,y) = (-1)^{(x-1)(y-1)/4} = (-1)^[x = y = 3 (mod 4)].
+ *
+ * If r1 is even, r2 must be odd. We have
+ *
+ *   (r1 | r0) = (r1 - r0 | r0) = (-1)^(r0-1)/2 (r0 - r1 | r0)
+ *             = (-1)^(r0-1)/2 s(r0, r0 - r1) (r0 | r0 - r1)
+ *             = (-1)^(r0-1)/2 s(r0, r0 - r1) (r1 | r0 - r1)
+ *
+ * Now, if r1 = 0 (mod 4), then the sign factor is +1, and repeating
+ * q1 times gives
+ *
+ *   (r1 | r0) = (r1 | r2) = (r3 | r2)
+ *
+ * On the other hand, if r1 = 2 (mod 4), the sign factor is
+ * (-1)^{(r0-1)/2}, and repeating q1 times gives the exponent
+ *
+ *   (r0-1)/2 + (r0-r1-1)/2 + ... + (r0 - (q1-1) r1)/2
+ *   = q1 (r0-1)/2 + q1 (q1-1)/2
+ *
+ * and we can summarize the even case as
+ *
+ *   (r1 | r0) = t(r1, r0, q1) (r3 | r2)
+ *
+ * where t(x,y,q) = (-1)^{[x = 2 (mod 4)] (q(y-1)/2 + y(q-1)/2)}
+ *
+ * What about termination? The remainder sequence ends with (0|1) = 1
+ * (or (0 | r) = 0 if r != 1). What are the possible cases? If r1 is
+ * odd, r2 may be zero. If r1 is even, then r2 = r0 - q1 r1 is odd and
+ * hence non-zero. We may have r3 = r1 - q2 r2 = 0.
+ *
+ * Examples: (11|15) = - (15|11) = - (4|11)
+ *            (4|11) =    (4| 3) =   (1| 3)
+ *            (1| 3) = (3|1) = (0|1) = 1
+ *
+ *             (2|7) = (2|1) = (0|1) = 1
+ *
+ * Detail:     (2|7) = (2-7|7) = (-1|7)(5|7) = -(7|5) = -(2|5)
+ *             (2|5) = (2-5|5) = (-1|5)(3|5) =  (5|3) =  (2|3)
+ *             (2|3) = (2-3|3) = (-1|3)(1|3) = -(3|1) = -(2|1)
+ *
+ */
+
+/* In principle, the state consists of four variables: e (one bit), a,
+   b (two bits each), d (one bit). Collected factors are (-1)^e. a and
+   b are the least significant bits of the current remainders. d
+   (denominator) is 0 if we're currently subtracting multiplies of a
+   from b, and 1 if we're subtracting b from a.
+
+   e is stored in the least significant bit, while a, b and d are
+   coded as only 13 distinct values in bits 1-4, according to the
+   following table. For rows not mentioning d, the value is either
+   implied, or it doesn't matter. */
+
+#if WANT_ASSERT
+static const struct
+{
+  unsigned char a;
+  unsigned char b;
+} decode_table[13] = {
+  /*  0 */ { 0, 1 },
+  /*  1 */ { 0, 3 },
+  /*  2 */ { 1, 1 },
+  /*  3 */ { 1, 3 },
+  /*  4 */ { 2, 1 },
+  /*  5 */ { 2, 3 },
+  /*  6 */ { 3, 1 },
+  /*  7 */ { 3, 3 }, /* d = 1 */
+  /*  8 */ { 1, 0 },
+  /*  9 */ { 1, 2 },
+  /* 10 */ { 3, 0 },
+  /* 11 */ { 3, 2 },
+  /* 12 */ { 3, 3 }, /* d = 0 */
+};
+#define JACOBI_A(bits) (decode_table[(bits)>>1].a)
+#define JACOBI_B(bits) (decode_table[(bits)>>1].b)
+#endif /* WANT_ASSERT */
+
+const unsigned char jacobi_table[208] = {
+#include "jacobitab.h"
+};
+
+#define BITS_FAIL 31
+
+static void
+jacobi_hook (void *p, mp_srcptr gp, mp_size_t gn,
+	     mp_srcptr qp, mp_size_t qn, int d)
+{
+  unsigned *bitsp = (unsigned *) p;
+
+  if (gp)
+    {
+      ASSERT (gn > 0);
+      if (gn != 1 || gp[0] != 1)
+	{
+	  *bitsp = BITS_FAIL;
+	  return;
+	}
+    }
+
+  if (qp)
+    {
+      ASSERT (qn > 0);
+      ASSERT (d >= 0);
+      *bitsp = mpn_jacobi_update (*bitsp, d, qp[0] & 3);
+    }
+}
+
+#define CHOOSE_P(n) (2*(n) / 3)
+
+int
+mpn_jacobi_n (mp_ptr ap, mp_ptr bp, mp_size_t n, unsigned bits)
+{
+  mp_size_t scratch;
+  mp_size_t matrix_scratch;
+  mp_ptr tp;
+
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT ( (ap[n-1] | bp[n-1]) > 0);
+  ASSERT ( (bp[0] | ap[0]) & 1);
+
+  /* FIXME: Check for small sizes first, before setting up temporary
+     storage etc. */
+  scratch = MPN_GCD_SUBDIV_STEP_ITCH(n);
+
+  if (ABOVE_THRESHOLD (n, JACOBI_DC_THRESHOLD))
+    {
+      mp_size_t hgcd_scratch;
+      mp_size_t update_scratch;
+      mp_size_t p = CHOOSE_P (n);
+      mp_size_t dc_scratch;
+
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      hgcd_scratch = mpn_hgcd_itch (n - p);
+      update_scratch = p + n - 1;
+
+      dc_scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch);
+      if (dc_scratch > scratch)
+	scratch = dc_scratch;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS(scratch);
+
+  while (ABOVE_THRESHOLD (n, JACOBI_DC_THRESHOLD))
+    {
+      struct hgcd_matrix M;
+      mp_size_t p = 2*n/3;
+      mp_size_t matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      mp_size_t nn;
+      mpn_hgcd_matrix_init (&M, n - p, tp);
+
+      nn = mpn_hgcd_jacobi (ap + p, bp + p, n - p, &M, &bits,
+			    tp + matrix_scratch);
+      if (nn > 0)
+	{
+	  ASSERT (M.n <= (n - p - 1)/2);
+	  ASSERT (M.n + p <= (p + n - 1) / 2);
+	  /* Temporary storage 2 (p + M->n) <= p + n - 1. */
+	  n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, tp + matrix_scratch);
+	}
+      else
+	{
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, jacobi_hook, &bits, tp);
+	  if (!n)
+	    {
+	      TMP_FREE;
+	      return bits == BITS_FAIL ? 0 : mpn_jacobi_finish (bits);
+	    }
+	}
+    }
+
+  while (n > 2)
+    {
+      struct hgcd_matrix1 M;
+      mp_limb_t ah, al, bh, bl;
+      mp_limb_t mask;
+
+      mask = ap[n-1] | bp[n-1];
+      ASSERT (mask > 0);
+
+      if (mask & GMP_NUMB_HIGHBIT)
+	{
+	  ah = ap[n-1]; al = ap[n-2];
+	  bh = bp[n-1]; bl = bp[n-2];
+	}
+      else
+	{
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+	  al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+	  bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+	  bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+	}
+
+      /* Try an mpn_nhgcd2 step */
+      if (mpn_hgcd2_jacobi (ah, al, bh, bl, &M, &bits))
+	{
+	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
+	  MP_PTR_SWAP (ap, tp);
+	}
+      else
+	{
+	  /* mpn_hgcd2 has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, &jacobi_hook, &bits, tp);
+	  if (!n)
+	    {
+	      TMP_FREE;
+	      return bits == BITS_FAIL ? 0 : mpn_jacobi_finish (bits);
+	    }
+	}
+    }
+
+  if (bits >= 16)
+    MP_PTR_SWAP (ap, bp);
+
+  ASSERT (bp[0] & 1);
+
+  if (n == 1)
+    {
+      mp_limb_t al, bl;
+      al = ap[0];
+      bl = bp[0];
+
+      TMP_FREE;
+      if (bl == 1)
+	return 1 - 2*(bits & 1);
+      else
+	return mpn_jacobi_base (al, bl, bits << 1);
+    }
+
+  else
+    {
+      int res = mpn_jacobi_2 (ap, bp, bits & 1);
+      TMP_FREE;
+      return res;
+    }
+}
diff --git a/mpn/generic/jacobi_2.c b/mpn/generic/jacobi_2.c
new file mode 100644
index 0000000..028b8a4
--- /dev/null
+++ b/mpn/generic/jacobi_2.c
@@ -0,0 +1,351 @@
+/* jacobi_2.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef JACOBI_2_METHOD
+#define JACOBI_2_METHOD 2
+#endif
+
+/* Computes (a / b) where b is odd, and a and b are otherwise arbitrary
+   two-limb numbers. */
+#if JACOBI_2_METHOD == 1
+int
+mpn_jacobi_2 (mp_srcptr ap, mp_srcptr bp, unsigned bit)
+{
+  mp_limb_t ah, al, bh, bl;
+  int c;
+
+  al = ap[0];
+  ah = ap[1];
+  bl = bp[0];
+  bh = bp[1];
+
+  ASSERT (bl & 1);
+
+  bl = ((bh << (GMP_NUMB_BITS - 1)) & GMP_NUMB_MASK) | (bl >> 1);
+  bh >>= 1;
+
+  if ( (bh | bl) == 0)
+    return 1 - 2*(bit & 1);
+
+  if ( (ah | al) == 0)
+    return 0;
+
+  if (al == 0)
+    {
+      al = ah;
+      ah = 0;
+      bit ^= GMP_NUMB_BITS & (bl ^ (bl >> 1));
+    }
+  count_trailing_zeros (c, al);
+  bit ^= c & (bl ^ (bl >> 1));
+
+  c++;
+  if (UNLIKELY (c == GMP_NUMB_BITS))
+    {
+      al = ah;
+      ah = 0;
+    }
+  else
+    {
+      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+      ah >>= c;
+    }
+  while ( (ah | bh) > 0)
+    {
+      mp_limb_t th, tl;
+      mp_limb_t bgta;
+
+      sub_ddmmss (th, tl, ah, al, bh, bl);
+      if ( (tl | th) == 0)
+	return 0;
+
+      bgta = LIMB_HIGHBIT_TO_MASK (th);
+
+      /* If b > a, invoke reciprocity */
+      bit ^= (bgta & al & bl);
+
+      /* b <-- min (a, b) */
+      add_ssaaaa (bh, bl, bh, bl, th & bgta, tl & bgta);
+
+      if ( (bh | bl) == 0)
+	return 1 - 2*(bit & 1);
+
+      /* a <-- |a - b| */
+      al = (bgta ^ tl) - bgta;
+      ah = (bgta ^ th);
+
+      if (UNLIKELY (al == 0))
+	{
+	  /* If b > a, al == 0 implies that we have a carry to
+	     propagate. */
+	  al = ah - bgta;
+	  ah = 0;
+	  bit ^= GMP_NUMB_BITS & (bl ^ (bl >> 1));
+	}
+      count_trailing_zeros (c, al);
+      c++;
+      bit ^= c & (bl ^ (bl >> 1));
+
+      if (UNLIKELY (c == GMP_NUMB_BITS))
+	{
+	  al = ah;
+	  ah = 0;
+	}
+      else
+	{
+	  al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+	  ah >>= c;
+	}
+    }
+
+  ASSERT (bl > 0);
+
+  while ( (al | bl) & GMP_LIMB_HIGHBIT)
+    {
+      /* Need an extra comparison to get the mask. */
+      mp_limb_t t = al - bl;
+      mp_limb_t bgta = - (bl > al);
+
+      if (t == 0)
+	return 0;
+
+      /* If b > a, invoke reciprocity */
+      bit ^= (bgta & al & bl);
+
+      /* b <-- min (a, b) */
+      bl += (bgta & t);
+
+      /* a <-- |a - b| */
+      al = (t ^ bgta) - bgta;
+
+      /* Number of trailing zeros is the same no matter if we look at
+       * t or a, but using t gives more parallelism. */
+      count_trailing_zeros (c, t);
+      c ++;
+      /* (2/b) = -1 if b = 3 or 5 mod 8 */
+      bit ^= c & (bl ^ (bl >> 1));
+
+      if (UNLIKELY (c == GMP_NUMB_BITS))
+	return 1 - 2*(bit & 1);
+
+      al >>= c;
+    }
+
+  /* Here we have a little impedance mismatch. Better to inline it? */
+  return mpn_jacobi_base (2*al+1, 2*bl+1, bit << 1);
+}
+#elif JACOBI_2_METHOD == 2
+int
+mpn_jacobi_2 (mp_srcptr ap, mp_srcptr bp, unsigned bit)
+{
+  mp_limb_t ah, al, bh, bl;
+  int c;
+
+  al = ap[0];
+  ah = ap[1];
+  bl = bp[0];
+  bh = bp[1];
+
+  ASSERT (bl & 1);
+
+  /* Use bit 1. */
+  bit <<= 1;
+
+  if (bh == 0 && bl == 1)
+    /* (a|1) = 1 */
+    return 1 - (bit & 2);
+
+  if (al == 0)
+    {
+      if (ah == 0)
+	/* (0|b) = 0, b > 1 */
+	return 0;
+
+      count_trailing_zeros (c, ah);
+      bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
+
+      al = bl;
+      bl = ah >> c;
+
+      if (bl == 1)
+	/* (1|b) = 1 */
+	return 1 - (bit & 2);
+
+      ah = bh;
+
+      bit ^= al & bl;
+
+      goto b_reduced;
+    }
+  if ( (al & 1) == 0)
+    {
+      count_trailing_zeros (c, al);
+
+      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+      ah >>= c;
+      bit ^= (c << 1) & (bl ^ (bl >> 1));
+    }
+  if (ah == 0)
+    {
+      if (bh > 0)
+	{
+	  bit ^= al & bl;
+	  MP_LIMB_T_SWAP (al, bl);
+	  ah = bh;
+	  goto b_reduced;
+	}
+      goto ab_reduced;
+    }
+
+  while (bh > 0)
+    {
+      /* Compute (a|b) */
+      while (ah > bh)
+	{
+	  sub_ddmmss (ah, al, ah, al, bh, bl);
+	  if (al == 0)
+	    {
+	      count_trailing_zeros (c, ah);
+	      bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
+
+	      al = bl;
+	      bl = ah >> c;
+	      ah = bh;
+
+	      bit ^= al & bl;
+	      goto b_reduced;
+	    }
+	  count_trailing_zeros (c, al);
+	  bit ^= (c << 1) & (bl ^ (bl >> 1));
+	  al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+	  ah >>= c;
+	}
+      if (ah == bh)
+	goto cancel_hi;
+
+      if (ah == 0)
+	{
+	  bit ^= al & bl;
+	  MP_LIMB_T_SWAP (al, bl);
+	  ah = bh;
+	  break;
+	}
+
+      bit ^= al & bl;
+
+      /* Compute (b|a) */
+      while (bh > ah)
+	{
+	  sub_ddmmss (bh, bl, bh, bl, ah, al);
+	  if (bl == 0)
+	    {
+	      count_trailing_zeros (c, bh);
+	      bit ^= ((GMP_NUMB_BITS + c) << 1) & (al ^ (al >> 1));
+
+	      bl = bh >> c;
+	      bit ^= al & bl;
+	      goto b_reduced;
+	    }
+	  count_trailing_zeros (c, bl);
+	  bit ^= (c << 1) & (al ^ (al >> 1));
+	  bl = ((bh << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (bl >> c);
+	  bh >>= c;
+	}
+      bit ^= al & bl;
+
+      /* Compute (a|b) */
+      if (ah == bh)
+	{
+	cancel_hi:
+	  if (al < bl)
+	    {
+	      MP_LIMB_T_SWAP (al, bl);
+	      bit ^= al & bl;
+	    }
+	  al -= bl;
+	  if (al == 0)
+	    return 0;
+
+	  count_trailing_zeros (c, al);
+	  bit ^= (c << 1) & (bl ^ (bl >> 1));
+	  al >>= c;
+
+	  if (al == 1)
+	    return 1 - (bit & 2);
+
+	  MP_LIMB_T_SWAP (al, bl);
+	  bit ^= al & bl;
+	  break;
+	}
+    }
+
+ b_reduced:
+  /* Compute (a|b), with b a single limb. */
+  ASSERT (bl & 1);
+
+  if (bl == 1)
+    /* (a|1) = 1 */
+    return 1 - (bit & 2);
+
+  while (ah > 0)
+    {
+      ah -= (al < bl);
+      al -= bl;
+      if (al == 0)
+	{
+	  if (ah == 0)
+	    return 0;
+	  count_trailing_zeros (c, ah);
+	  bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
+	  al = ah >> c;
+	  goto ab_reduced;
+	}
+      count_trailing_zeros (c, al);
+
+      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+      ah >>= c;
+      bit ^= (c << 1) & (bl ^ (bl >> 1));
+    }
+ ab_reduced:
+  ASSERT (bl & 1);
+  ASSERT (bl > 1);
+
+  return mpn_jacobi_base (al, bl, bit);
+}
+#else
+#error Unsupported value for JACOBI_2_METHOD
+#endif
diff --git a/mpn/generic/logops_n.c b/mpn/generic/logops_n.c
new file mode 100644
index 0000000..3adba2c
--- /dev/null
+++ b/mpn/generic/logops_n.c
@@ -0,0 +1,77 @@
+/* mpn_and_n, mpn_ior_n, etc -- mpn logical operations.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifdef OPERATION_and_n
+#define func __MPN(and_n)
+#define call mpn_and_n
+#endif
+
+#ifdef OPERATION_andn_n
+#define func __MPN(andn_n)
+#define call mpn_andn_n
+#endif
+
+#ifdef OPERATION_nand_n
+#define func __MPN(nand_n)
+#define call mpn_nand_n
+#endif
+
+#ifdef OPERATION_ior_n
+#define func __MPN(ior_n)
+#define call mpn_ior_n
+#endif
+
+#ifdef OPERATION_iorn_n
+#define func __MPN(iorn_n)
+#define call mpn_iorn_n
+#endif
+
+#ifdef OPERATION_nior_n
+#define func __MPN(nior_n)
+#define call mpn_nior_n
+#endif
+
+#ifdef OPERATION_xor_n
+#define func __MPN(xor_n)
+#define call mpn_xor_n
+#endif
+
+#ifdef OPERATION_xnor_n
+#define func __MPN(xnor_n)
+#define call mpn_xnor_n
+#endif
+
+void
+func (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  call (rp, up, vp, n);
+}
diff --git a/mpn/generic/lshift.c b/mpn/generic/lshift.c
new file mode 100644
index 0000000..7e1fdef
--- /dev/null
+++ b/mpn/generic/lshift.c
@@ -0,0 +1,72 @@
+/* mpn_lshift -- Shift left low level.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Shift U (pointed to by up and n limbs long) cnt bits to the left
+   and store the n least significant limbs of the result at rp.
+   Return the bits shifted out from the most significant limb.
+
+   Argument constraints:
+   1. 0 < cnt < GMP_NUMB_BITS.
+   2. If the result is to be written over the input, rp must be >= up.
+*/
+
+mp_limb_t
+mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  ASSERT (n >= 1);
+  ASSERT (cnt >= 1);
+  ASSERT (cnt < GMP_NUMB_BITS);
+  ASSERT (MPN_SAME_OR_DECR_P (rp, up, n));
+
+  up += n;
+  rp += n;
+
+  tnc = GMP_NUMB_BITS - cnt;
+  low_limb = *--up;
+  retval = low_limb >> tnc;
+  high_limb = (low_limb << cnt) & GMP_NUMB_MASK;
+
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = high_limb | (low_limb >> tnc);
+      high_limb = (low_limb << cnt) & GMP_NUMB_MASK;
+    }
+  *--rp = high_limb;
+
+  return retval;
+}
diff --git a/mpn/generic/lshiftc.c b/mpn/generic/lshiftc.c
new file mode 100644
index 0000000..a583602
--- /dev/null
+++ b/mpn/generic/lshiftc.c
@@ -0,0 +1,73 @@
+/* mpn_lshiftc -- Shift left low level with complement.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2009 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Shift U (pointed to by up and n limbs long) cnt bits to the left
+   and store the n least significant limbs of the result at rp.
+   Return the bits shifted out from the most significant limb.
+
+   Argument constraints:
+   1. 0 < cnt < GMP_NUMB_BITS.
+   2. If the result is to be written over the input, rp must be >= up.
+*/
+
+mp_limb_t
+mpn_lshiftc (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  ASSERT (n >= 1);
+  ASSERT (cnt >= 1);
+  ASSERT (cnt < GMP_NUMB_BITS);
+  ASSERT (MPN_SAME_OR_DECR_P (rp, up, n));
+
+  up += n;
+  rp += n;
+
+  tnc = GMP_NUMB_BITS - cnt;
+  low_limb = *--up;
+  retval = low_limb >> tnc;
+  high_limb = (low_limb << cnt);
+
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = (~(high_limb | (low_limb >> tnc))) & GMP_NUMB_MASK;
+      high_limb = low_limb << cnt;
+    }
+  *--rp = (~high_limb) & GMP_NUMB_MASK;
+
+  return retval;
+}
diff --git a/mpn/generic/matrix22_mul.c b/mpn/generic/matrix22_mul.c
new file mode 100644
index 0000000..6a1299a
--- /dev/null
+++ b/mpn/generic/matrix22_mul.c
@@ -0,0 +1,321 @@
+/* matrix22_mul.c.
+
+   Contributed by Niels Möller and Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define MUL(rp, ap, an, bp, bn) do {		\
+  if (an >= bn)					\
+    mpn_mul (rp, ap, an, bp, bn);		\
+  else						\
+    mpn_mul (rp, bp, bn, ap, an);		\
+} while (0)
+
+/* Inputs are unsigned. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  int c;
+  MPN_CMP (c, ap, bp, n);
+  if (c >= 0)
+    {
+      mpn_sub_n (rp, ap, bp, n);
+      return 0;
+    }
+  else
+    {
+      mpn_sub_n (rp, bp, ap, n);
+      return 1;
+    }
+}
+
+static int
+add_signed_n (mp_ptr rp,
+	      mp_srcptr ap, int as, mp_srcptr bp, int bs, mp_size_t n)
+{
+  if (as != bs)
+    return as ^ abs_sub_n (rp, ap, bp, n);
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n (rp, ap, bp, n));
+      return as;
+    }
+}
+
+mp_size_t
+mpn_matrix22_mul_itch (mp_size_t rn, mp_size_t mn)
+{
+  if (BELOW_THRESHOLD (rn, MATRIX22_STRASSEN_THRESHOLD)
+      || BELOW_THRESHOLD (mn, MATRIX22_STRASSEN_THRESHOLD))
+    return 3*rn + 2*mn;
+  else
+    return 3*(rn + mn) + 5;
+}
+
+/* Algorithm:
+
+    / s0 \   /  1  0  0  0 \ / r0 \
+    | s1 |   |  0  1  0  1 | | r1 |
+    | s2 |   |  0  0 -1  1 | | r2 |
+    | s3 | = |  0  1 -1  1 | \ r3 /
+    | s4 |   | -1  1 -1  1 |
+    | s5 |   |  0  1  0  0 |
+    \ s6 /   \  0  0  1  0 /
+
+    / t0 \   /  1  0  0  0 \ / m0 \
+    | t1 |   |  0  1  0  1 | | m1 |
+    | t2 |   |  0  0 -1  1 | | m2 |
+    | t3 | = |  0  1 -1  1 | \ m3 /
+    | t4 |   | -1  1 -1  1 |
+    | t5 |   |  0  1  0  0 |
+    \ t6 /   \  0  0  1  0 /
+
+  Note: the two matrices above are the same, but s_i and t_i are used
+  in the same product, only for i<4, see "A Strassen-like Matrix
+  Multiplication suited for squaring and higher power computation" by
+  M. Bodrato, in Proceedings of ISSAC 2010.
+
+    / r0 \   / 1 0  0  0  0  1  0 \ / s0*t0 \
+    | r1 | = | 0 0 -1  1 -1  1  0 | | s1*t1 |
+    | r2 |   | 0 1  0 -1  0 -1 -1 | | s2*t2 |
+    \ r3 /   \ 0 1  1 -1  0 -1  0 / | s3*t3 |
+				    | s4*t5 |
+				    | s5*t6 |
+				    \ s6*t4 /
+
+  The scheduling uses two temporaries U0 and U1 to store products, and
+  two, S0 and T0, to store combinations of entries of the two
+  operands.
+*/
+
+/* Computes R = R * M. Elements are numbers R = (r0, r1; r2, r3).
+ *
+ * Resulting elements are of size up to rn + mn + 1.
+ *
+ * Temporary storage: 3 rn + 3 mn + 5. */
+static void
+mpn_matrix22_mul_strassen (mp_ptr r0, mp_ptr r1, mp_ptr r2, mp_ptr r3, mp_size_t rn,
+			   mp_srcptr m0, mp_srcptr m1, mp_srcptr m2, mp_srcptr m3, mp_size_t mn,
+			   mp_ptr tp)
+{
+  mp_ptr s0, t0, u0, u1;
+  int r1s, r3s, s0s, t0s, u1s;
+  s0 = tp; tp += rn + 1;
+  t0 = tp; tp += mn + 1;
+  u0 = tp; tp += rn + mn + 1;
+  u1 = tp; /* rn + mn + 2 */
+
+  MUL (u0, r1, rn, m2, mn);		/* u5 = s5 * t6 */
+  r3s = abs_sub_n (r3, r3, r2, rn);	/* r3 - r2 */
+  if (r3s)
+    {
+      r1s = abs_sub_n (r1, r1, r3, rn);
+      r1[rn] = 0;
+    }
+  else
+    {
+      r1[rn] = mpn_add_n (r1, r1, r3, rn);
+      r1s = 0;				/* r1 - r2 + r3  */
+    }
+  if (r1s)
+    {
+      s0[rn] = mpn_add_n (s0, r1, r0, rn);
+      s0s = 0;
+    }
+  else if (r1[rn] != 0)
+    {
+      s0[rn] = r1[rn] - mpn_sub_n (s0, r1, r0, rn);
+      s0s = 1;				/* s4 = -r0 + r1 - r2 + r3 */
+					/* Reverse sign! */
+    }
+  else
+    {
+      s0s = abs_sub_n (s0, r0, r1, rn);
+      s0[rn] = 0;
+    }
+  MUL (u1, r0, rn, m0, mn);		/* u0 = s0 * t0 */
+  r0[rn+mn] = mpn_add_n (r0, u0, u1, rn + mn);
+  ASSERT (r0[rn+mn] < 2);		/* u0 + u5 */
+
+  t0s = abs_sub_n (t0, m3, m2, mn);
+  u1s = r3s^t0s^1;			/* Reverse sign! */
+  MUL (u1, r3, rn, t0, mn);		/* u2 = s2 * t2 */
+  u1[rn+mn] = 0;
+  if (t0s)
+    {
+      t0s = abs_sub_n (t0, m1, t0, mn);
+      t0[mn] = 0;
+    }
+  else
+    {
+      t0[mn] = mpn_add_n (t0, t0, m1, mn);
+    }
+
+  /* FIXME: Could be simplified if we had space for rn + mn + 2 limbs
+     at r3. I'd expect that for matrices of random size, the high
+     words t0[mn] and r1[rn] are non-zero with a pretty small
+     probability. If that can be confirmed this should be done as an
+     unconditional rn x (mn+1) followed by an if (UNLIKELY (r1[rn]))
+     add_n. */
+  if (t0[mn] != 0)
+    {
+      MUL (r3, r1, rn, t0, mn + 1);	/* u3 = s3 * t3 */
+      ASSERT (r1[rn] < 2);
+      if (r1[rn] != 0)
+	mpn_add_n (r3 + rn, r3 + rn, t0, mn + 1);
+    }
+  else
+    {
+      MUL (r3, r1, rn + 1, t0, mn);
+    }
+
+  ASSERT (r3[rn+mn] < 4);
+
+  u0[rn+mn] = 0;
+  if (r1s^t0s)
+    {
+      r3s = abs_sub_n (r3, u0, r3, rn + mn + 1);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n (r3, r3, u0, rn + mn + 1));
+      r3s = 0;				/* u3 + u5 */
+    }
+
+  if (t0s)
+    {
+      t0[mn] = mpn_add_n (t0, t0, m0, mn);
+    }
+  else if (t0[mn] != 0)
+    {
+      t0[mn] -= mpn_sub_n (t0, t0, m0, mn);
+    }
+  else
+    {
+      t0s = abs_sub_n (t0, t0, m0, mn);
+    }
+  MUL (u0, r2, rn, t0, mn + 1);		/* u6 = s6 * t4 */
+  ASSERT (u0[rn+mn] < 2);
+  if (r1s)
+    {
+      ASSERT_NOCARRY (mpn_sub_n (r1, r2, r1, rn));
+    }
+  else
+    {
+      r1[rn] += mpn_add_n (r1, r1, r2, rn);
+    }
+  rn++;
+  t0s = add_signed_n (r2, r3, r3s, u0, t0s, rn + mn);
+					/* u3 + u5 + u6 */
+  ASSERT (r2[rn+mn-1] < 4);
+  r3s = add_signed_n (r3, r3, r3s, u1, u1s, rn + mn);
+					/* -u2 + u3 + u5  */
+  ASSERT (r3[rn+mn-1] < 3);
+  MUL (u0, s0, rn, m1, mn);		/* u4 = s4 * t5 */
+  ASSERT (u0[rn+mn-1] < 2);
+  t0[mn] = mpn_add_n (t0, m3, m1, mn);
+  MUL (u1, r1, rn, t0, mn + 1);		/* u1 = s1 * t1 */
+  mn += rn;
+  ASSERT (u1[mn-1] < 4);
+  ASSERT (u1[mn] == 0);
+  ASSERT_NOCARRY (add_signed_n (r1, r3, r3s, u0, s0s, mn));
+					/* -u2 + u3 - u4 + u5  */
+  ASSERT (r1[mn-1] < 2);
+  if (r3s)
+    {
+      ASSERT_NOCARRY (mpn_add_n (r3, u1, r3, mn));
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_n (r3, u1, r3, mn));
+					/* u1 + u2 - u3 - u5  */
+    }
+  ASSERT (r3[mn-1] < 2);
+  if (t0s)
+    {
+      ASSERT_NOCARRY (mpn_add_n (r2, u1, r2, mn));
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_n (r2, u1, r2, mn));
+					/* u1 - u3 - u5 - u6  */
+    }
+  ASSERT (r2[mn-1] < 2);
+}
+
+void
+mpn_matrix22_mul (mp_ptr r0, mp_ptr r1, mp_ptr r2, mp_ptr r3, mp_size_t rn,
+		  mp_srcptr m0, mp_srcptr m1, mp_srcptr m2, mp_srcptr m3, mp_size_t mn,
+		  mp_ptr tp)
+{
+  if (BELOW_THRESHOLD (rn, MATRIX22_STRASSEN_THRESHOLD)
+      || BELOW_THRESHOLD (mn, MATRIX22_STRASSEN_THRESHOLD))
+    {
+      mp_ptr p0, p1;
+      unsigned i;
+
+      /* Temporary storage: 3 rn + 2 mn */
+      p0 = tp + rn;
+      p1 = p0 + rn + mn;
+
+      for (i = 0; i < 2; i++)
+	{
+	  MPN_COPY (tp, r0, rn);
+
+	  if (rn >= mn)
+	    {
+	      mpn_mul (p0, r0, rn, m0, mn);
+	      mpn_mul (p1, r1, rn, m3, mn);
+	      mpn_mul (r0, r1, rn, m2, mn);
+	      mpn_mul (r1, tp, rn, m1, mn);
+	    }
+	  else
+	    {
+	      mpn_mul (p0, m0, mn, r0, rn);
+	      mpn_mul (p1, m3, mn, r1, rn);
+	      mpn_mul (r0, m2, mn, r1, rn);
+	      mpn_mul (r1, m1, mn, tp, rn);
+	    }
+	  r0[rn+mn] = mpn_add_n (r0, r0, p0, rn + mn);
+	  r1[rn+mn] = mpn_add_n (r1, r1, p1, rn + mn);
+
+	  r0 = r2; r1 = r3;
+	}
+    }
+  else
+    mpn_matrix22_mul_strassen (r0, r1, r2, r3, rn,
+			       m0, m1, m2, m3, mn, tp);
+}
diff --git a/mpn/generic/matrix22_mul1_inverse_vector.c b/mpn/generic/matrix22_mul1_inverse_vector.c
new file mode 100644
index 0000000..68d50b7
--- /dev/null
+++ b/mpn/generic/matrix22_mul1_inverse_vector.c
@@ -0,0 +1,64 @@
+/* matrix22_mul1_inverse_vector.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Sets (r;b) = M^{-1}(a;b), with M^{-1} = (u11, -u01; -u10, u00) from
+   the left. Uses three buffers, to avoid a copy. */
+mp_size_t
+mpn_matrix22_mul1_inverse_vector (const struct hgcd_matrix1 *M,
+				  mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
+{
+  mp_limb_t h0, h1;
+
+  /* Compute (r;b) <-- (u11 a - u01 b; -u10 a + u00 b) as
+
+     r  = u11 * a
+     r -= u01 * b
+     b *= u00
+     b -= u10 * a
+  */
+
+  h0 =    mpn_mul_1 (rp, ap, n, M->u[1][1]);
+  h1 = mpn_submul_1 (rp, bp, n, M->u[0][1]);
+  ASSERT (h0 == h1);
+
+  h0 =    mpn_mul_1 (bp, bp, n, M->u[0][0]);
+  h1 = mpn_submul_1 (bp, ap, n, M->u[1][0]);
+  ASSERT (h0 == h1);
+
+  n -= (rp[n-1] | bp[n-1]) == 0;
+  return n;
+}
diff --git a/mpn/generic/mod_1.c b/mpn/generic/mod_1.c
new file mode 100644
index 0000000..f737bc2
--- /dev/null
+++ b/mpn/generic/mod_1.c
@@ -0,0 +1,278 @@
+/* mpn_mod_1(dividend_ptr, dividend_size, divisor_limb) --
+   Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
+   Return the single-limb remainder.
+   There are no constraints on the value of the divisor.
+
+Copyright 1991, 1993, 1994, 1999, 2000, 2002, 2007-2009, 2012, 2020
+Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The size where udiv_qrnnd_preinv should be used rather than udiv_qrnnd,
+   meaning the quotient size where that should happen, the quotient size
+   being how many udiv divisions will be done.
+
+   The default is to use preinv always, CPUs where this doesn't suit have
+   tuned thresholds.  Note in particular that preinv should certainly be
+   used if that's the only division available (USE_PREINV_ALWAYS).  */
+
+#ifndef MOD_1_NORM_THRESHOLD
+#define MOD_1_NORM_THRESHOLD  0
+#endif
+
+#ifndef MOD_1_UNNORM_THRESHOLD
+#define MOD_1_UNNORM_THRESHOLD  0
+#endif
+
+#ifndef MOD_1U_TO_MOD_1_1_THRESHOLD
+#define MOD_1U_TO_MOD_1_1_THRESHOLD  MP_SIZE_T_MAX /* default is not to use mpn_mod_1s */
+#endif
+
+#ifndef MOD_1N_TO_MOD_1_1_THRESHOLD
+#define MOD_1N_TO_MOD_1_1_THRESHOLD  MP_SIZE_T_MAX /* default is not to use mpn_mod_1s */
+#endif
+
+#ifndef MOD_1_1_TO_MOD_1_2_THRESHOLD
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD  10
+#endif
+
+#ifndef MOD_1_2_TO_MOD_1_4_THRESHOLD
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD  20
+#endif
+
+#if TUNE_PROGRAM_BUILD && !HAVE_NATIVE_mpn_mod_1_1p
+/* Duplicates declarations in tune/speed.h */
+mp_limb_t mpn_mod_1_1p_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t [4]);
+mp_limb_t mpn_mod_1_1p_2 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t [4]);
+
+void mpn_mod_1_1p_cps_1 (mp_limb_t [4], mp_limb_t);
+void mpn_mod_1_1p_cps_2 (mp_limb_t [4], mp_limb_t);
+
+#undef mpn_mod_1_1p
+#define mpn_mod_1_1p(ap, n, b, pre)			     \
+  (mod_1_1p_method == 1 ? mpn_mod_1_1p_1 (ap, n, b, pre)     \
+   : (mod_1_1p_method == 2 ? mpn_mod_1_1p_2 (ap, n, b, pre)  \
+      : __gmpn_mod_1_1p (ap, n, b, pre)))
+
+#undef mpn_mod_1_1p_cps
+#define mpn_mod_1_1p_cps(pre, b)				\
+  (mod_1_1p_method == 1 ? mpn_mod_1_1p_cps_1 (pre, b)		\
+   : (mod_1_1p_method == 2 ? mpn_mod_1_1p_cps_2 (pre, b)	\
+      : __gmpn_mod_1_1p_cps (pre, b)))
+#endif /* TUNE_PROGRAM_BUILD && !HAVE_NATIVE_mpn_mod_1_1p */
+
+
+/* The comments in mpn/generic/divrem_1.c apply here too.
+
+   As noted in the algorithms section of the manual, the shifts in the loop
+   for the unnorm case can be avoided by calculating r = a%(d*2^n), followed
+   by a final (r*2^n)%(d*2^n).  In fact if it happens that a%(d*2^n) can
+   skip a division where (a*2^n)%(d*2^n) can't then there's the same number
+   of divide steps, though how often that happens depends on the assumed
+   distributions of dividend and divisor.  In any case this idea is left to
+   CPU specific implementations to consider.  */
+
+static mp_limb_t
+mpn_mod_1_unnorm (mp_srcptr up, mp_size_t un, mp_limb_t d)
+{
+  mp_size_t  i;
+  mp_limb_t  n1, n0, r;
+  mp_limb_t  dummy;
+  int cnt;
+
+  ASSERT (un > 0);
+  ASSERT (d != 0);
+
+  /* Skip a division if high < divisor.  Having the test here before
+     normalizing will still skip as often as possible.  */
+  r = up[un - 1];
+  if (r < d)
+    {
+      if (--un == 0)
+	return r;
+    }
+  else
+    r = 0;
+
+  d <<= GMP_NAIL_BITS;
+
+  /* If udiv_qrnnd doesn't need a normalized divisor, can use the simple
+     code above. */
+  if (! UDIV_NEEDS_NORMALIZATION
+      && BELOW_THRESHOLD (un, MOD_1_UNNORM_THRESHOLD))
+    {
+      for (i = un - 1; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  udiv_qrnnd (dummy, r, r, n0, d);
+	  r >>= GMP_NAIL_BITS;
+	}
+      return r;
+    }
+
+  count_leading_zeros (cnt, d);
+  d <<= cnt;
+
+  n1 = up[un - 1] << GMP_NAIL_BITS;
+  r = (r << cnt) | (n1 >> (GMP_LIMB_BITS - cnt));
+
+  if (UDIV_NEEDS_NORMALIZATION
+      && BELOW_THRESHOLD (un, MOD_1_UNNORM_THRESHOLD))
+    {
+      mp_limb_t nshift;
+      for (i = un - 2; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+	  udiv_qrnnd (dummy, r, r, nshift, d);
+	  r >>= GMP_NAIL_BITS;
+	  n1 = n0;
+	}
+      udiv_qrnnd (dummy, r, r, n1 << cnt, d);
+      r >>= GMP_NAIL_BITS;
+      return r >> cnt;
+    }
+  else
+    {
+      mp_limb_t inv, nshift;
+      invert_limb (inv, d);
+
+      for (i = un - 2; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+	  udiv_rnnd_preinv (r, r, nshift, d, inv);
+	  r >>= GMP_NAIL_BITS;
+	  n1 = n0;
+	}
+      udiv_rnnd_preinv (r, r, n1 << cnt, d, inv);
+      r >>= GMP_NAIL_BITS;
+      return r >> cnt;
+    }
+}
+
+static mp_limb_t
+mpn_mod_1_norm (mp_srcptr up, mp_size_t un, mp_limb_t d)
+{
+  mp_size_t  i;
+  mp_limb_t  n0, r;
+  mp_limb_t  dummy;
+
+  ASSERT (un > 0);
+
+  d <<= GMP_NAIL_BITS;
+
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+
+  /* High limb is initial remainder, possibly with one subtract of
+     d to get r<d.  */
+  r = up[un - 1] << GMP_NAIL_BITS;
+  if (r >= d)
+    r -= d;
+  r >>= GMP_NAIL_BITS;
+  un--;
+  if (un == 0)
+    return r;
+
+  if (BELOW_THRESHOLD (un, MOD_1_NORM_THRESHOLD))
+    {
+      for (i = un - 1; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  udiv_qrnnd (dummy, r, r, n0, d);
+	  r >>= GMP_NAIL_BITS;
+	}
+      return r;
+    }
+  else
+    {
+      mp_limb_t  inv;
+      invert_limb (inv, d);
+      for (i = un - 1; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  udiv_rnnd_preinv (r, r, n0, d, inv);
+	  r >>= GMP_NAIL_BITS;
+	}
+      return r;
+    }
+}
+
+mp_limb_t
+mpn_mod_1 (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  ASSERT (n >= 0);
+  ASSERT (b != 0);
+
+  /* Should this be handled at all?  Rely on callers?  Note un==0 is currently
+     required by mpz/fdiv_r_ui.c and possibly other places.  */
+  if (n == 0)
+    return 0;
+
+  if (UNLIKELY ((b & GMP_NUMB_HIGHBIT) != 0))
+    {
+      if (BELOW_THRESHOLD (n, MOD_1N_TO_MOD_1_1_THRESHOLD))
+	{
+	  return mpn_mod_1_norm (ap, n, b);
+	}
+      else
+	{
+	  mp_limb_t pre[4];
+	  mpn_mod_1_1p_cps (pre, b);
+	  return mpn_mod_1_1p (ap, n, b, pre);
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MOD_1U_TO_MOD_1_1_THRESHOLD))
+	{
+	  return mpn_mod_1_unnorm (ap, n, b);
+	}
+      else if (BELOW_THRESHOLD (n, MOD_1_1_TO_MOD_1_2_THRESHOLD))
+	{
+	  mp_limb_t pre[4];
+	  mpn_mod_1_1p_cps (pre, b);
+	  return mpn_mod_1_1p (ap, n, b << pre[1], pre);
+	}
+      else if (BELOW_THRESHOLD (n, MOD_1_2_TO_MOD_1_4_THRESHOLD) || UNLIKELY (b > GMP_NUMB_MASK / 4))
+	{
+	  mp_limb_t pre[5];
+	  mpn_mod_1s_2p_cps (pre, b);
+	  return mpn_mod_1s_2p (ap, n, b << pre[1], pre);
+	}
+      else
+	{
+	  mp_limb_t pre[7];
+	  mpn_mod_1s_4p_cps (pre, b);
+	  return mpn_mod_1s_4p (ap, n, b << pre[1], pre);
+	}
+    }
+}
diff --git a/mpn/generic/mod_1_1.c b/mpn/generic/mod_1_1.c
new file mode 100644
index 0000000..be199ff
--- /dev/null
+++ b/mpn/generic/mod_1_1.c
@@ -0,0 +1,341 @@
+/* mpn_mod_1_1p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+
+   Contributed to the GNU project by Torbjorn Granlund and Niels Möller.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2011, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef MOD_1_1P_METHOD
+# define MOD_1_1P_METHOD 1    /* need to make sure this is 2 for asm testing */
+#endif
+
+/* Define some longlong.h-style macros, but for wider operations.
+ * add_mssaaaa is like longlong.h's add_ssaaaa, but also generates
+ * carry out, in the form of a mask. */
+
+#if defined (__GNUC__) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %k2\n\t"					\
+	     "adc	%4, %k1\n\t"					\
+	     "sbb	%k0, %k0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_x86_64 && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %q2\n\t"					\
+	     "adc	%4, %q1\n\t"					\
+	     "sbb	%q0, %q0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxcc	%r3, %4, %1\n\t"				\
+	     "subx	%%g0, %%g0, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addccc	%r7, %8, %%g0\n\t"				\
+	     "addccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl),		\
+	     "rJ" ((al) >> 32), "rI" ((bl) >> 32)			\
+	 __CLOBBER_CC)
+#if __VIS__ >= 0x300
+#undef add_mssaaaa
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add%I6c	%2, %5, %6\n\t"					\
+	     "adde	%1, %3, %4\n\t"					\
+	     "subfe	%0, %0, %0\n\t"					\
+	     "nor	%0, %0, %0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)			\
+	     __CLOBBER_CC)
+#endif
+
+#if defined (__s390x__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "algr	%2, %6\n\t"					\
+	     "alcgr	%1, %4\n\t"					\
+	     "lghi	%0, 0\n\t"					\
+	     "alcgr	%0, %0\n\t"					\
+	     "lcgr	%0, %0"						\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "r" ((UDItype)(b1)),			\
+	     "%2" ((UDItype)(a0)), "r" ((UDItype)(b0)) __CLOBBER_CC)
+#endif
+
+#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "adds	%2, %5, %6\n\t"					\
+	     "adcs	%1, %3, %4\n\t"					\
+	     "movcc	%0, #0\n\t"					\
+	     "movcs	%0, #-1"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC)
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "adds	%2, %x5, %6\n\t"				\
+	     "adcs	%1, %x3, %x4\n\t"				\
+	     "csinv	%0, xzr, xzr, cc\n\t"				\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rZ" (ah), "rZ" (bh), "%rZ" (al), "rI" (bl) __CLOBBER_CC)
+#endif
+#endif /* defined (__GNUC__) */
+
+#ifndef add_mssaaaa
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (m) = - (__c1 + (__s1 < __c0));					\
+  } while (0)
+#endif
+
+#if MOD_1_1P_METHOD == 1
+void
+mpn_mod_1_1p_cps (mp_limb_t cps[4], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb;
+  int cnt;
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b;
+  if (LIKELY (cnt != 0))
+    B1modb *= ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  /* In the normalized case, this can be simplified to
+   *
+   *   B2modb = - b * bi;
+   *   ASSERT (B2modb <= b);    // NB: equality iff b = B/2
+   */
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+}
+
+mp_limb_t
+mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t bmodb[4])
+{
+  mp_limb_t rh, rl, bi, ph, pl, r;
+  mp_limb_t B1modb, B2modb;
+  mp_size_t i;
+  int cnt;
+  mp_limb_t mask;
+
+  ASSERT (n >= 2);		/* fix tuneup.c if this is changed */
+
+  B1modb = bmodb[2];
+  B2modb = bmodb[3];
+
+  rl = ap[n - 1];
+  umul_ppmm (ph, pl, rl, B1modb);
+  add_ssaaaa (rh, rl, ph, pl, CNST_LIMB(0), ap[n - 2]);
+
+  for (i = n - 3; i >= 0; i -= 1)
+    {
+      /* rr = ap[i]				< B
+	    + LO(rr)  * (B mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^2 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, rl, B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i]);
+
+      umul_ppmm (rh, rl, rh, B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  cnt = bmodb[1];
+  bi = bmodb[0];
+
+  if (LIKELY (cnt != 0))
+    rh = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+
+  mask = -(mp_limb_t) (rh >= b);
+  rh -= mask & b;
+
+  udiv_rnnd_preinv (r, rh, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
+#endif /* MOD_1_1P_METHOD == 1 */
+
+#if MOD_1_1P_METHOD == 2
+void
+mpn_mod_1_1p_cps (mp_limb_t cps[4], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B2modb;
+  int cnt;
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  if (LIKELY (cnt != 0))
+    {
+      mp_limb_t B1modb = -b;
+      B1modb *= ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+      ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+      cps[2] = B1modb >> cnt;
+    }
+  B2modb = - b * bi;
+  ASSERT (B2modb <= b);    // NB: equality iff b = B/2
+  cps[3] = B2modb;
+}
+
+mp_limb_t
+mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t bmodb[4])
+{
+  int cnt;
+  mp_limb_t bi, B1modb;
+  mp_limb_t r0, r1;
+  mp_limb_t r;
+
+  ASSERT (n >= 2);		/* fix tuneup.c if this is changed */
+
+  r0 = ap[n-2];
+  r1 = ap[n-1];
+
+  if (n > 2)
+    {
+      mp_limb_t B2modb, B2mb;
+      mp_limb_t p0, p1;
+      mp_limb_t r2;
+      mp_size_t j;
+
+      B2modb = bmodb[3];
+      B2mb = B2modb - b;
+
+      umul_ppmm (p1, p0, r1, B2modb);
+      add_mssaaaa (r2, r1, r0, r0, ap[n-3], p1, p0);
+
+      for (j = n-4; j >= 0; j--)
+	{
+	  mp_limb_t cy;
+	  /* mp_limb_t t = r0 + B2mb; */
+	  umul_ppmm (p1, p0, r1, B2modb);
+
+	  ADDC_LIMB (cy, r0, r0, r2 & B2modb);
+	  /* Alternative, for cmov: if (cy) r0 = t; */
+	  r0 -= (-cy) & b;
+	  add_mssaaaa (r2, r1, r0, r0, ap[j], p1, p0);
+	}
+
+      r1 -= (r2 & b);
+    }
+
+  cnt = bmodb[1];
+
+  if (LIKELY (cnt != 0))
+    {
+      mp_limb_t t;
+      mp_limb_t B1modb = bmodb[2];
+
+      umul_ppmm (r1, t, r1, B1modb);
+      r0 += t;
+      r1 += (r0 < t);
+
+      /* Normalize */
+      r1 = (r1 << cnt) | (r0 >> (GMP_LIMB_BITS - cnt));
+      r0 <<= cnt;
+
+      /* NOTE: Might get r1 == b here, but udiv_rnnd_preinv allows that. */
+    }
+  else
+    {
+      mp_limb_t mask = -(mp_limb_t) (r1 >= b);
+      r1 -= mask & b;
+    }
+
+  bi = bmodb[0];
+
+  udiv_rnnd_preinv (r, r1, r0, b, bi);
+  return r >> cnt;
+}
+#endif /* MOD_1_1P_METHOD == 2 */
diff --git a/mpn/generic/mod_1_2.c b/mpn/generic/mod_1_2.c
new file mode 100644
index 0000000..b00d19e
--- /dev/null
+++ b/mpn/generic/mod_1_2.c
@@ -0,0 +1,148 @@
+/* mpn_mod_1s_2p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that b < B / 2.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mod_1s_2p_cps (mp_limb_t cps[5], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 2);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 4; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_2p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[5])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+
+  if ((n & 1) != 0)
+    {
+      if (n == 1)
+	{
+	  rl = ap[n - 1];
+	  bi = cps[0];
+	  cnt = cps[1];
+	  udiv_rnnd_preinv (r, rl >> (GMP_LIMB_BITS - cnt),
+			     rl << cnt, b, bi);
+	  return r >> cnt;
+	}
+
+      umul_ppmm (ph, pl, ap[n - 2], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+      umul_ppmm (rh, rl, ap[n - 1], B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n--;
+    }
+  else
+    {
+      rh = ap[n - 1];
+      rl = ap[n - 2];
+    }
+
+  for (i = n - 4; i >= 0; i -= 2)
+    {
+      /* rr = ap[i]				< B
+	    + ap[i+1] * (B mod b)		<= (B-1)(b-1)
+	    + LO(rr)  * (B^2 mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^3 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, ap[i + 1], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+      umul_ppmm (ch, cl, rl, B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (rh, rl, rh, B3modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  umul_ppmm (rh, cl, rh, B1modb);
+  add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+
+  cnt = cps[1];
+  bi = cps[0];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/mpn/generic/mod_1_3.c b/mpn/generic/mod_1_3.c
new file mode 100644
index 0000000..e4a908d
--- /dev/null
+++ b/mpn/generic/mod_1_3.c
@@ -0,0 +1,155 @@
+/* mpn_mod_1s_3p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that b < B / 3.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mod_1s_3p_cps (mp_limb_t cps[6], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 3);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+  udiv_rnnd_preinv (B4modb, B3modb, CNST_LIMB(0), b, bi);
+  cps[5] = B4modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 5; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_3p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[6])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+  B4modb = cps[5];
+
+  /* We compute n mod 3 in a tricky way, which works except for when n is so
+     close to the maximum size that we don't need to support it.  The final
+     cast to int is a workaround for HP cc.  */
+  switch ((int) ((mp_limb_t) n * MODLIMB_INVERSE_3 >> (GMP_NUMB_BITS - 2)))
+    {
+    case 0:
+      umul_ppmm (ph, pl, ap[n - 2], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+      umul_ppmm (rh, rl, ap[n - 1], B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n -= 3;
+      break;
+    default:	/* n mod 3 = 1; (case 2)*/
+      rh = 0;
+      rl = ap[--n];
+      break;
+    case 1:	/* n mod 3 = 2 */
+      rh = ap[n - 1];
+      rl = ap[n - 2];
+      n -= 2;
+      break;
+    }
+
+  for (i = n - 3; i >= 0; i -= 3)
+    {
+      /* rr = ap[i]				< B
+	    + ap[i+1] * (B mod b)		<= (B-1)(b-1)
+	    + ap[i+2] * (B^2 mod b)		<= (B-1)(b-1)
+	    + LO(rr)  * (B^3 mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^4 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, ap[i + 1], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+      umul_ppmm (ch, cl, ap[i + 2], B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (ch, cl, rl, B3modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (rh, rl, rh, B4modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  umul_ppmm (rh, cl, rh, B1modb);
+  add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+
+  cnt = cps[1];
+  bi = cps[0];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/mpn/generic/mod_1_4.c b/mpn/generic/mod_1_4.c
new file mode 100644
index 0000000..80b42ba
--- /dev/null
+++ b/mpn/generic/mod_1_4.c
@@ -0,0 +1,170 @@
+/* mpn_mod_1s_4p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that b < B / 4.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mod_1s_4p_cps (mp_limb_t cps[7], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 4);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+  udiv_rnnd_preinv (B4modb, B3modb, CNST_LIMB(0), b, bi);
+  cps[5] = B4modb >> cnt;
+
+  udiv_rnnd_preinv (B5modb, B4modb, CNST_LIMB(0), b, bi);
+  cps[6] = B5modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 6; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_4p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[7])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+  B4modb = cps[5];
+  B5modb = cps[6];
+
+  switch (n & 3)
+    {
+    case 0:
+      umul_ppmm (ph, pl, ap[n - 3], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 4]);
+      umul_ppmm (ch, cl, ap[n - 2], B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+      umul_ppmm (rh, rl, ap[n - 1], B3modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n -= 4;
+      break;
+    case 1:
+      rh = 0;
+      rl = ap[n - 1];
+      n -= 1;
+      break;
+    case 2:
+      rh = ap[n - 1];
+      rl = ap[n - 2];
+      n -= 2;
+      break;
+    case 3:
+      umul_ppmm (ph, pl, ap[n - 2], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+      umul_ppmm (rh, rl, ap[n - 1], B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n -= 3;
+      break;
+    }
+
+  for (i = n - 4; i >= 0; i -= 4)
+    {
+      /* rr = ap[i]				< B
+	    + ap[i+1] * (B mod b)		<= (B-1)(b-1)
+	    + ap[i+2] * (B^2 mod b)		<= (B-1)(b-1)
+	    + ap[i+3] * (B^3 mod b)		<= (B-1)(b-1)
+	    + LO(rr)  * (B^4 mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^5 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, ap[i + 1], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+      umul_ppmm (ch, cl, ap[i + 2], B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (ch, cl, ap[i + 3], B3modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (ch, cl, rl, B4modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (rh, rl, rh, B5modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  umul_ppmm (rh, cl, rh, B1modb);
+  add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+
+  cnt = cps[1];
+  bi = cps[0];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/mpn/generic/mod_34lsub1.c b/mpn/generic/mod_34lsub1.c
new file mode 100644
index 0000000..af9c6c6
--- /dev/null
+++ b/mpn/generic/mod_34lsub1.c
@@ -0,0 +1,128 @@
+/* mpn_mod_34lsub1 -- remainder modulo 2^(GMP_NUMB_BITS*3/4)-1.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+/* Calculate a remainder from {p,n} divided by 2^(GMP_NUMB_BITS*3/4)-1.
+   The remainder is not fully reduced, it's any limb value congruent to
+   {p,n} modulo that divisor.
+
+   This implementation is only correct when GMP_NUMB_BITS is a multiple of
+   4.
+
+   FIXME: If GMP_NAIL_BITS is some silly big value during development then
+   it's possible the carry accumulators c0,c1,c2 could overflow.
+
+   General notes:
+
+   The basic idea is to use a set of N accumulators (N=3 in this case) to
+   effectively get a remainder mod 2^(GMP_NUMB_BITS*N)-1 followed at the end
+   by a reduction to GMP_NUMB_BITS*N/M bits (M=4 in this case) for a
+   remainder mod 2^(GMP_NUMB_BITS*N/M)-1.  N and M are chosen to give a good
+   set of small prime factors in 2^(GMP_NUMB_BITS*N/M)-1.
+
+   N=3 M=4 suits GMP_NUMB_BITS==32 and GMP_NUMB_BITS==64 quite well, giving
+   a few more primes than a single accumulator N=1 does, and for no extra
+   cost (assuming the processor has a decent number of registers).
+
+   For strange nailified values of GMP_NUMB_BITS the idea would be to look
+   for what N and M give good primes.  With GMP_NUMB_BITS not a power of 2
+   the choices for M may be opened up a bit.  But such things are probably
+   best done in separate code, not grafted on here.  */
+
+#if GMP_NUMB_BITS % 4 == 0
+
+#define B1  (GMP_NUMB_BITS / 4)
+#define B2  (B1 * 2)
+#define B3  (B1 * 3)
+
+#define M1  ((CNST_LIMB(1) << B1) - 1)
+#define M2  ((CNST_LIMB(1) << B2) - 1)
+#define M3  ((CNST_LIMB(1) << B3) - 1)
+
+#define LOW0(n)      ((n) & M3)
+#define HIGH0(n)     ((n) >> B3)
+
+#define LOW1(n)      (((n) & M2) << B1)
+#define HIGH1(n)     ((n) >> B2)
+
+#define LOW2(n)      (((n) & M1) << B2)
+#define HIGH2(n)     ((n) >> B1)
+
+#define PARTS0(n)    (LOW0(n) + HIGH0(n))
+#define PARTS1(n)    (LOW1(n) + HIGH1(n))
+#define PARTS2(n)    (LOW2(n) + HIGH2(n))
+
+#define ADD(c,a,val)                    \
+  do {                                  \
+    mp_limb_t  new_c;                   \
+    ADDC_LIMB (new_c, a, a, val);       \
+    (c) += new_c;                       \
+  } while (0)
+
+mp_limb_t
+mpn_mod_34lsub1 (mp_srcptr p, mp_size_t n)
+{
+  mp_limb_t  c0, c1, c2;
+  mp_limb_t  a0, a1, a2;
+
+  ASSERT (n >= 1);
+  ASSERT (n/3 < GMP_NUMB_MAX);
+
+  a0 = a1 = a2 = 0;
+  c0 = c1 = c2 = 0;
+
+  while ((n -= 3) >= 0)
+    {
+      ADD (c0, a0, p[0]);
+      ADD (c1, a1, p[1]);
+      ADD (c2, a2, p[2]);
+      p += 3;
+    }
+
+  if (n != -3)
+    {
+      ADD (c0, a0, p[0]);
+      if (n != -2)
+	ADD (c1, a1, p[1]);
+    }
+
+  return
+    PARTS0 (a0) + PARTS1 (a1) + PARTS2 (a2)
+    + PARTS1 (c0) + PARTS2 (c1) + PARTS0 (c2);
+}
+
+#endif
diff --git a/mpn/generic/mode1o.c b/mpn/generic/mode1o.c
new file mode 100644
index 0000000..9ba0ae1
--- /dev/null
+++ b/mpn/generic/mode1o.c
@@ -0,0 +1,235 @@
+/* mpn_modexact_1c_odd -- mpn by limb exact division style remainder.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Calculate an r satisfying
+
+           r*B^k + a - c == q*d
+
+   where B=2^GMP_LIMB_BITS, a is {src,size}, k is either size or size-1
+   (the caller won't know which), and q is the quotient (discarded).  d must
+   be odd, c can be any limb value.
+
+   If c<d then r will be in the range 0<=r<d, or if c>=d then 0<=r<=d.
+
+   This slightly strange function suits the initial Nx1 reduction for GCDs
+   or Jacobi symbols since the factors of 2 in B^k can be ignored, leaving
+   -r == a mod d (by passing c=0).  For a GCD the factor of -1 on r can be
+   ignored, or for the Jacobi symbol it can be accounted for.  The function
+   also suits divisibility and congruence testing since if r=0 (or r=d) is
+   obtained then a==c mod d.
+
+
+   r is a bit like the remainder returned by mpn_divexact_by3c, and is the
+   sort of remainder mpn_divexact_1 might return.  Like mpn_divexact_by3c, r
+   represents a borrow, since effectively quotient limbs are chosen so that
+   subtracting that multiple of d from src at each step will produce a zero
+   limb.
+
+   A long calculation can be done piece by piece from low to high by passing
+   the return value from one part as the carry parameter to the next part.
+   The effective final k becomes anything between size and size-n, if n
+   pieces are used.
+
+
+   A similar sort of routine could be constructed based on adding multiples
+   of d at each limb, much like redc in mpz_powm does.  Subtracting however
+   has a small advantage that when subtracting to cancel out l there's never
+   a borrow into h, whereas using an addition would put a carry into h
+   depending whether l==0 or l!=0.
+
+
+   In terms of efficiency, this function is similar to a mul-by-inverse
+   mpn_mod_1.  Both are essentially two multiplies and are best suited to
+   CPUs with low latency multipliers (in comparison to a divide instruction
+   at least.)  But modexact has a few less supplementary operations, only
+   needs low part and high part multiplies, and has fewer working quantities
+   (helping CPUs with few registers).
+
+
+   In the main loop it will be noted that the new carry (call it r) is the
+   sum of the high product h and any borrow from l=s-c.  If c<d then we will
+   have r<d too, for the following reasons.  Let q=l*inverse be the quotient
+   limb, so that q*d = B*h + l, where B=2^GMP_NUMB_BITS.  Now if h=d-1 then
+
+       l = q*d - B*(d-1) <= (B-1)*d - B*(d-1) = B-d
+
+   But if l=s-c produces a borrow when c<d, then l>=B-d+1 and hence will
+   never have h=d-1 and so r=h+borrow <= d-1.
+
+   When c>=d, on the other hand, h=d-1 can certainly occur together with a
+   borrow, thereby giving only r<=d, as per the function definition above.
+
+   As a design decision it's left to the caller to check for r=d if it might
+   be passing c>=d.  Several applications have c<d initially so the extra
+   test is often unnecessary, for example the GCDs or a plain divisibility
+   d|a test will pass c=0.
+
+
+   The special case for size==1 is so that it can be assumed c<=d in the
+   high<=divisor test at the end.  c<=d is only guaranteed after at least
+   one iteration of the main loop.  There's also a decent chance one % is
+   faster than a binvert_limb, though that will depend on the processor.
+
+   A CPU specific implementation might want to omit the size==1 code or the
+   high<divisor test.  mpn/x86/k6/mode1o.asm for instance finds neither
+   useful.  */
+
+
+mp_limb_t
+mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d,
+                     mp_limb_t orig_c)
+{
+  mp_limb_t  s, h, l, inverse, dummy, dmul, ret;
+  mp_limb_t  c = orig_c;
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+  ASSERT (d & 1);
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (d);
+  ASSERT_LIMB (c);
+
+  if (size == 1)
+    {
+      s = src[0];
+      if (s > c)
+	{
+	  l = s-c;
+	  h = l % d;
+	  if (h != 0)
+	    h = d - h;
+	}
+      else
+	{
+	  l = c-s;
+	  h = l % d;
+	}
+      return h;
+    }
+
+
+  binvert_limb (inverse, d);
+  dmul = d << GMP_NAIL_BITS;
+
+  i = 0;
+  do
+    {
+      s = src[i];
+      SUBC_LIMB (c, l, s, c);
+      l = (l * inverse) & GMP_NUMB_MASK;
+      umul_ppmm (h, dummy, l, dmul);
+      c += h;
+    }
+  while (++i < size-1);
+
+
+  s = src[i];
+  if (s <= d)
+    {
+      /* With high<=d the final step can be a subtract and addback.  If c==0
+	 then the addback will restore to l>=0.  If c==d then will get l==d
+	 if s==0, but that's ok per the function definition.  */
+
+      l = c - s;
+      if (c < s)
+	l += d;
+
+      ret = l;
+    }
+  else
+    {
+      /* Can't skip a divide, just do the loop code once more. */
+
+      SUBC_LIMB (c, l, s, c);
+      l = (l * inverse) & GMP_NUMB_MASK;
+      umul_ppmm (h, dummy, l, dmul);
+      c += h;
+      ret = c;
+    }
+
+  ASSERT (orig_c < d ? ret < d : ret <= d);
+  return ret;
+}
+
+
+
+#if 0
+
+/* The following is an alternate form that might shave one cycle on a
+   superscalar processor since it takes c+=h off the dependent chain,
+   leaving just a low product, high product, and a subtract.
+
+   This is for CPU specific implementations to consider.  A special case for
+   high<divisor and/or size==1 can be added if desired.
+
+   Notice that c is only ever 0 or 1, since if s-c produces a borrow then
+   x=0xFF..FF and x-h cannot produce a borrow.  The c=(x>s) could become
+   c=(x==0xFF..FF) too, if that helped.  */
+
+mp_limb_t
+mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d, mp_limb_t h)
+{
+  mp_limb_t  s, x, y, inverse, dummy, dmul, c1, c2;
+  mp_limb_t  c = 0;
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+  ASSERT (d & 1);
+
+  binvert_limb (inverse, d);
+  dmul = d << GMP_NAIL_BITS;
+
+  for (i = 0; i < size; i++)
+    {
+      ASSERT (c==0 || c==1);
+
+      s = src[i];
+      SUBC_LIMB (c1, x, s, c);
+
+      SUBC_LIMB (c2, y, x, h);
+      c = c1 + c2;
+
+      y = (y * inverse) & GMP_NUMB_MASK;
+      umul_ppmm (h, dummy, y, dmul);
+    }
+
+  h += c;
+  return h;
+}
+
+#endif
diff --git a/mpn/generic/mu_bdiv_q.c b/mpn/generic/mu_bdiv_q.c
new file mode 100644
index 0000000..0ef3bd8
--- /dev/null
+++ b/mpn/generic/mu_bdiv_q.c
@@ -0,0 +1,281 @@
+/* mpn_mu_bdiv_q(qp,np,nn,dp,dn,tp) -- Compute {np,nn} / {dp,dn} mod B^nn.
+   storing the result in {qp,nn}.  Overlap allowed between Q and N; all other
+   overlap disallowed.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+#include "gmp-impl.h"
+
+
+/* N = {np,nn}
+   D = {dp,dn}
+
+   Requirements: N >= D
+		 D >= 1
+		 D odd
+		 dn >= 2
+		 nn >= 2
+		 scratch space as determined by mpn_mu_bdiv_q_itch(nn,dn).
+
+   Write quotient to Q = {qp,nn}.
+
+   FIXME: When iterating, perhaps do the small step before loop, not after.
+   FIXME: Try to avoid the scalar divisions when computing inverse size.
+   FIXME: Trim allocation for (qn > dn) case, 3*dn might be possible.  In
+	  particular, when dn==in, tp and rp could use the same space.
+   FIXME: Trim final quotient calculation to qn limbs of precision.
+*/
+static void
+mpn_mu_bdiv_q_old (mp_ptr qp,
+	       mp_srcptr np, mp_size_t nn,
+	       mp_srcptr dp, mp_size_t dn,
+	       mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_size_t in;
+  int cy, c0;
+  mp_size_t tn, wn;
+
+  qn = nn;
+
+  ASSERT (dn >= 2);
+  ASSERT (qn >= 2);
+
+  if (qn > dn)
+    {
+      mp_size_t b;
+
+      /* |_______________________|   dividend
+			|________|   divisor  */
+
+#define ip           scratch			/* in */
+#define rp           (scratch + in)		/* dn or rest >= binvert_itch(in) */
+#define tp           (scratch + in + dn)	/* dn+in or next_size(dn) */
+#define scratch_out  (scratch + in + dn + tn)	/* mulmod_bnm1_itch(next_size(dn)) */
+
+      /* Compute an inverse size that is a nice partition of the quotient.  */
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+
+      /* Some notes on allocation:
+
+	 When in = dn, R dies when mpn_mullo returns, if in < dn the low in
+	 limbs of R dies at that point.  We could save memory by letting T live
+	 just under R, and let the upper part of T expand into R. These changes
+	 should reduce itch to perhaps 3dn.
+       */
+
+      mpn_binvert (ip, dp, in, rp);
+
+      cy = 0;
+
+      MPN_COPY (rp, np, dn);
+      np += dn;
+      mpn_mullo_n (qp, rp, ip, in);
+      qn -= in;
+
+      while (qn > in)
+	{
+	  if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	    mpn_mul (tp, dp, dn, qp, in);	/* mulhi, need tp[dn+in-1...in] */
+	  else
+	    {
+	      tn = mpn_mulmod_bnm1_next_size (dn);
+	      mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	      wn = dn + in - tn;		/* number of wrapped limbs */
+	      if (wn > 0)
+		{
+		  c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+		  mpn_decr_u (tp + wn, c0);
+		}
+	    }
+
+	  qp += in;
+	  if (dn != in)
+	    {
+	      /* Subtract tp[dn-1...in] from partial remainder.  */
+	      cy += mpn_sub_n (rp, rp + in, tp + in, dn - in);
+	      if (cy == 2)
+		{
+		  mpn_incr_u (tp + dn, 1);
+		  cy = 1;
+		}
+	    }
+	  /* Subtract tp[dn+in-1...dn] from dividend.  */
+	  cy = mpn_sub_nc (rp + dn - in, np, tp + dn, in, cy);
+	  np += in;
+	  mpn_mullo_n (qp, rp, ip, in);
+	  qn -= in;
+	}
+
+      /* Generate last qn limbs.
+	 FIXME: It should be possible to limit precision here, since qn is
+	 typically somewhat smaller than dn.  No big gains expected.  */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* mulhi, need tp[qn+in-1...in] */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      qp += in;
+      if (dn != in)
+	{
+	  cy += mpn_sub_n (rp, rp + in, tp + in, dn - in);
+	  if (cy == 2)
+	    {
+	      mpn_incr_u (tp + dn, 1);
+	      cy = 1;
+	    }
+	}
+
+      mpn_sub_nc (rp + dn - in, np, tp + dn, qn - (dn - in), cy);
+      mpn_mullo_n (qp, rp, ip, qn);
+
+#undef ip
+#undef rp
+#undef tp
+#undef scratch_out
+   }
+  else
+    {
+      /* |_______________________|   dividend
+		|________________|   divisor  */
+
+#define ip           scratch		/* in */
+#define tp           (scratch + in)	/* qn+in or next_size(qn) or rest >= binvert_itch(in) */
+#define scratch_out  (scratch + in + tn)/* mulmod_bnm1_itch(next_size(qn)) */
+
+      /* Compute half-sized inverse.  */
+      in = qn - (qn >> 1);
+
+      mpn_binvert (ip, dp, in, tp);
+
+      mpn_mullo_n (qp, np, ip, in);		/* low `in' quotient limbs */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, qn, qp, in);		/* mulhigh */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (qn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, qn, qp, in, scratch_out);
+	  wn = qn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_cmp (tp, np, wn) < 0;
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      mpn_sub_n (tp, np + in, tp + in, qn - in);
+      mpn_mullo_n (qp + in, tp, ip, qn - in);	/* high qn-in quotient limbs */
+
+#undef ip
+#undef tp
+#undef scratch_out
+    }
+}
+
+void
+mpn_mu_bdiv_q (mp_ptr qp,
+	       mp_srcptr np, mp_size_t nn,
+	       mp_srcptr dp, mp_size_t dn,
+	       mp_ptr scratch)
+{
+  mpn_mu_bdiv_q_old (qp, np, nn, dp, dn, scratch);
+  mpn_neg (qp, qp, nn);
+}
+
+mp_size_t
+mpn_mu_bdiv_q_itch (mp_size_t nn, mp_size_t dn)
+{
+  mp_size_t qn, in, tn, itch_binvert, itch_out, itches;
+  mp_size_t b;
+
+  ASSERT_ALWAYS (DC_BDIV_Q_THRESHOLD < MU_BDIV_Q_THRESHOLD);
+
+  qn = nn;
+
+  if (qn > dn)
+    {
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	{
+	  tn = dn + in;
+	  itch_out = 0;
+	}
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  itch_out = mpn_mulmod_bnm1_itch (tn, dn, in);
+	}
+      itches = dn + tn + itch_out;
+    }
+  else
+    {
+      in = qn - (qn >> 1);
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	{
+	  tn = qn + in;
+	  itch_out = 0;
+	}
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (qn);
+	  itch_out = mpn_mulmod_bnm1_itch (tn, qn, in);
+	}
+      itches = tn + itch_out;
+    }
+
+  itch_binvert = mpn_binvert_itch (in);
+  return in + MAX (itches, itch_binvert);
+}
diff --git a/mpn/generic/mu_bdiv_qr.c b/mpn/generic/mu_bdiv_qr.c
new file mode 100644
index 0000000..540ad73
--- /dev/null
+++ b/mpn/generic/mu_bdiv_qr.c
@@ -0,0 +1,312 @@
+/* mpn_mu_bdiv_qr(qp,rp,np,nn,dp,dn,tp) -- Compute {np,nn} / {dp,dn} mod B^qn,
+   where qn = nn-dn, storing the result in {qp,qn}.  Overlap allowed between Q
+   and N; all other overlap disallowed.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+#include "gmp-impl.h"
+
+
+/* N = {np,nn}
+   D = {dp,dn}
+
+   Requirements: N >= D
+		 D >= 1
+		 D odd
+		 dn >= 2
+		 nn >= 2
+		 scratch space as determined by mpn_mu_bdiv_qr_itch(nn,dn).
+
+   Write quotient to Q = {qp,nn-dn}.
+
+   FIXME: When iterating, perhaps do the small step before loop, not after.
+   FIXME: Try to avoid the scalar divisions when computing inverse size.
+   FIXME: Trim allocation for (qn > dn) case, 3*dn might be possible.  In
+	  particular, when dn==in, tp and rp could use the same space.
+*/
+static mp_limb_t
+mpn_mu_bdiv_qr_old (mp_ptr qp,
+		    mp_ptr rp,
+		    mp_srcptr np, mp_size_t nn,
+		    mp_srcptr dp, mp_size_t dn,
+		    mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_size_t in;
+  mp_limb_t cy, c0;
+  mp_size_t tn, wn;
+
+  qn = nn - dn;
+
+  ASSERT (dn >= 2);
+  ASSERT (qn >= 2);
+
+  if (qn > dn)
+    {
+      mp_size_t b;
+
+      /* |_______________________|   dividend
+			|________|   divisor  */
+
+#define ip           scratch		/* in */
+#define tp           (scratch + in)	/* dn+in or next_size(dn) or rest >= binvert_itch(in) */
+#define scratch_out  (scratch + in + tn)/* mulmod_bnm1_itch(next_size(dn)) */
+
+      /* Compute an inverse size that is a nice partition of the quotient.  */
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+
+      /* Some notes on allocation:
+
+	 When in = dn, R dies when mpn_mullo returns, if in < dn the low in
+	 limbs of R dies at that point.  We could save memory by letting T live
+	 just under R, and let the upper part of T expand into R. These changes
+	 should reduce itch to perhaps 3dn.
+       */
+
+      mpn_binvert (ip, dp, in, tp);
+
+      MPN_COPY (rp, np, dn);
+      np += dn;
+      cy = 0;
+
+      while (qn > in)
+	{
+	  mpn_mullo_n (qp, rp, ip, in);
+
+	  if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	    mpn_mul (tp, dp, dn, qp, in);	/* mulhi, need tp[dn+in-1...in] */
+	  else
+	    {
+	      tn = mpn_mulmod_bnm1_next_size (dn);
+	      mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	      wn = dn + in - tn;		/* number of wrapped limbs */
+	      if (wn > 0)
+		{
+		  c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+		  mpn_decr_u (tp + wn, c0);
+		}
+	    }
+
+	  qp += in;
+	  qn -= in;
+
+	  if (dn != in)
+	    {
+	      /* Subtract tp[dn-1...in] from partial remainder.  */
+	      cy += mpn_sub_n (rp, rp + in, tp + in, dn - in);
+	      if (cy == 2)
+		{
+		  mpn_incr_u (tp + dn, 1);
+		  cy = 1;
+		}
+	    }
+	  /* Subtract tp[dn+in-1...dn] from dividend.  */
+	  cy = mpn_sub_nc (rp + dn - in, np, tp + dn, in, cy);
+	  np += in;
+	}
+
+      /* Generate last qn limbs.  */
+      mpn_mullo_n (qp, rp, ip, qn);
+
+      if (BELOW_THRESHOLD (qn, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, qn);		/* mulhi, need tp[qn+in-1...in] */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, qn, scratch_out);
+	  wn = dn + qn - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      if (dn != qn)
+	{
+	  cy += mpn_sub_n (rp, rp + qn, tp + qn, dn - qn);
+	  if (cy == 2)
+	    {
+	      mpn_incr_u (tp + dn, 1);
+	      cy = 1;
+	    }
+	}
+      return mpn_sub_nc (rp + dn - qn, np, tp + dn, qn, cy);
+
+#undef ip
+#undef tp
+#undef scratch_out
+    }
+  else
+    {
+      /* |_______________________|   dividend
+		|________________|   divisor  */
+
+#define ip           scratch		/* in */
+#define tp           (scratch + in)	/* dn+in or next_size(dn) or rest >= binvert_itch(in) */
+#define scratch_out  (scratch + in + tn)/* mulmod_bnm1_itch(next_size(dn)) */
+
+      /* Compute half-sized inverse.  */
+      in = qn - (qn >> 1);
+
+      mpn_binvert (ip, dp, in, tp);
+
+      mpn_mullo_n (qp, np, ip, in);		/* low `in' quotient limbs */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* mulhigh */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, np, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      qp += in;
+      qn -= in;
+
+      cy = mpn_sub_n (rp, np + in, tp + in, dn);
+      mpn_mullo_n (qp, rp, ip, qn);		/* high qn quotient limbs */
+
+      if (BELOW_THRESHOLD (qn, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, qn);		/* mulhigh */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, qn, scratch_out);
+	  wn = dn + qn - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      cy += mpn_sub_n (rp, rp + qn, tp + qn, dn - qn);
+      if (cy == 2)
+	{
+	  mpn_incr_u (tp + dn, 1);
+	  cy = 1;
+	}
+      return mpn_sub_nc (rp + dn - qn, np + dn + in, tp + dn, qn, cy);
+
+#undef ip
+#undef tp
+#undef scratch_out
+    }
+}
+
+mp_limb_t
+mpn_mu_bdiv_qr (mp_ptr qp,
+		mp_ptr rp,
+		mp_srcptr np, mp_size_t nn,
+		mp_srcptr dp, mp_size_t dn,
+		mp_ptr scratch)
+{
+  mp_limb_t cy = mpn_mu_bdiv_qr_old (qp, rp, np, nn, dp, dn, scratch);
+
+  /* R' B^{qn} = U - Q' D
+   *
+   * Q = B^{qn} - Q' (assuming Q' != 0)
+   *
+   * R B^{qn} = U + Q D = U + B^{qn} D - Q' D
+   *          = B^{qn} D + R'
+   */
+
+  if (UNLIKELY (!mpn_neg (qp, qp, nn - dn)))
+    {
+      /* Zero quotient. */
+      ASSERT (cy == 0);
+      return 0;
+    }
+  else
+    {
+      mp_limb_t cy2 = mpn_add_n (rp, rp, dp, dn);
+      ASSERT (cy2 >= cy);
+
+      return cy2 - cy;
+    }
+}
+
+
+mp_size_t
+mpn_mu_bdiv_qr_itch (mp_size_t nn, mp_size_t dn)
+{
+  mp_size_t qn, in, tn, itch_binvert, itch_out, itches;
+  mp_size_t b;
+
+  ASSERT_ALWAYS (DC_BDIV_Q_THRESHOLD < MU_BDIV_Q_THRESHOLD);
+
+  qn = nn - dn;
+
+  if (qn > dn)
+    {
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+    }
+  else
+    {
+      in = qn - (qn >> 1);
+    }
+
+  if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+    {
+      tn = dn + in;
+      itch_out = 0;
+    }
+  else
+    {
+      tn = mpn_mulmod_bnm1_next_size (dn);
+      itch_out = mpn_mulmod_bnm1_itch (tn, dn, in);
+    }
+
+  itch_binvert = mpn_binvert_itch (in);
+  itches = tn + itch_out;
+  return in + MAX (itches, itch_binvert);
+}
diff --git a/mpn/generic/mu_div_q.c b/mpn/generic/mu_div_q.c
new file mode 100644
index 0000000..44cfb40
--- /dev/null
+++ b/mpn/generic/mu_div_q.c
@@ -0,0 +1,184 @@
+/* mpn_mu_div_q.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+/*
+  Things to work on:
+
+  1. This is a rudimentary implementation of mpn_mu_div_q.  The algorithm is
+     probably close to optimal, except when mpn_mu_divappr_q fails.
+
+  2. We used to fall back to mpn_mu_div_qr when we detect a possible
+     mpn_mu_divappr_q rounding problem, now we multiply and compare.
+     Unfortunately, since mpn_mu_divappr_q does not return the partial
+     remainder, this also doesn't become optimal.  A mpn_mu_divappr_qr could
+     solve that.
+
+  3. The allocations done here should be made from the scratch area, which
+     then would need to be amended.
+*/
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+
+
+mp_limb_t
+mpn_mu_div_q (mp_ptr qp,
+	      mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp, mp_size_t dn,
+	      mp_ptr scratch)
+{
+  mp_ptr tp, rp;
+  mp_size_t qn;
+  mp_limb_t cy, qh;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  qn = nn - dn;
+
+  tp = TMP_BALLOC_LIMBS (qn + 1);
+
+  if (qn >= dn)			/* nn >= 2*dn + 1 */
+    {
+       /* |_______________________|   dividend
+			 |________|   divisor  */
+
+      rp = TMP_BALLOC_LIMBS (nn + 1);
+      MPN_COPY (rp + 1, np, nn);
+      rp[0] = 0;
+
+      qh = mpn_cmp (rp + 1 + nn - dn, dp, dn) >= 0;
+      if (qh != 0)
+	mpn_sub_n (rp + 1 + nn - dn, rp + 1 + nn - dn, dp, dn);
+
+      cy = mpn_mu_divappr_q (tp, rp, nn + 1, dp, dn, scratch);
+
+      if (UNLIKELY (cy != 0))
+	{
+	  /* Since the partial remainder fed to mpn_preinv_mu_divappr_q was
+	     canonically reduced, replace the returned value of B^(qn-dn)+eps
+	     by the largest possible value.  */
+	  mp_size_t i;
+	  for (i = 0; i < qn + 1; i++)
+	    tp[i] = GMP_NUMB_MAX;
+	}
+
+      /* The max error of mpn_mu_divappr_q is +4.  If the low quotient limb is
+	 smaller than the max error, we cannot trust the quotient.  */
+      if (tp[0] > 4)
+	{
+	  MPN_COPY (qp, tp + 1, qn);
+	}
+      else
+	{
+	  mp_limb_t cy;
+	  mp_ptr pp;
+
+	  pp = rp;
+	  mpn_mul (pp, tp + 1, qn, dp, dn);
+
+	  cy = (qh != 0) ? mpn_add_n (pp + qn, pp + qn, dp, dn) : 0;
+
+	  if (cy || mpn_cmp (pp, np, nn) > 0) /* At most is wrong by one, no cycle. */
+	    qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
+	  else /* Same as above */
+	    MPN_COPY (qp, tp + 1, qn);
+	}
+    }
+  else
+    {
+       /* |_______________________|   dividend
+		 |________________|   divisor  */
+
+      /* FIXME: When nn = 2dn-1, qn becomes dn-1, and the numerator size passed
+	 here becomes 2dn, i.e., more than nn.  This shouldn't hurt, since only
+	 the most significant dn-1 limbs will actually be read, but it is not
+	 pretty.  */
+
+      qh = mpn_mu_divappr_q (tp, np + nn - (2 * qn + 2), 2 * qn + 2,
+			     dp + dn - (qn + 1), qn + 1, scratch);
+
+      /* The max error of mpn_mu_divappr_q is +4, but we get an additional
+         error from the divisor truncation.  */
+      if (tp[0] > 6)
+	{
+	  MPN_COPY (qp, tp + 1, qn);
+	}
+      else
+	{
+	  mp_limb_t cy;
+
+	  /* FIXME: a shorter product should be enough; we may use already
+	     allocated space... */
+	  rp = TMP_BALLOC_LIMBS (nn);
+	  mpn_mul (rp, dp, dn, tp + 1, qn);
+
+	  cy = (qh != 0) ? mpn_add_n (rp + qn, rp + qn, dp, dn) : 0;
+
+	  if (cy || mpn_cmp (rp, np, nn) > 0) /* At most is wrong by one, no cycle. */
+	    qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
+	  else /* Same as above */
+	    MPN_COPY (qp, tp + 1, qn);
+	}
+    }
+
+  TMP_FREE;
+  return qh;
+}
+
+mp_size_t
+mpn_mu_div_q_itch (mp_size_t nn, mp_size_t dn, int mua_k)
+{
+  mp_size_t qn;
+
+  qn = nn - dn;
+  if (qn >= dn)
+    {
+      return mpn_mu_divappr_q_itch (nn + 1, dn, mua_k);
+    }
+  else
+    {
+      return mpn_mu_divappr_q_itch (2 * qn + 2, qn + 1, mua_k);
+    }
+}
diff --git a/mpn/generic/mu_div_qr.c b/mpn/generic/mu_div_qr.c
new file mode 100644
index 0000000..8b9c702
--- /dev/null
+++ b/mpn/generic/mu_div_qr.c
@@ -0,0 +1,417 @@
+/* mpn_mu_div_qr, mpn_preinv_mu_div_qr.
+
+   Compute Q = floor(N / D) and R = N-QD.  N is nn limbs and D is dn limbs and
+   must be normalized, and Q must be nn-dn limbs.  The requirement that Q is
+   nn-dn limbs (and not nn-dn+1 limbs) was put in place in order to allow us to
+   let N be unmodified during the operation.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+/* CAUTION: This code and the code in mu_divappr_q.c should be edited in sync.
+
+ Things to work on:
+
+  * This isn't optimal when the quotient isn't needed, as it might take a lot
+    of space.  The computation is always needed, though, so there is no time to
+    save with special code.
+
+  * The itch/scratch scheme isn't perhaps such a good idea as it once seemed,
+    demonstrated by the fact that the mpn_invertappr function's scratch needs
+    mean that we need to keep a large allocation long after it is needed.
+    Things are worse as mpn_mul_fft does not accept any scratch parameter,
+    which means we'll have a large memory hole while in mpn_mul_fft.  In
+    general, a peak scratch need in the beginning of a function isn't
+    well-handled by the itch/scratch scheme.
+*/
+
+#ifdef STAT
+#undef STAT
+#define STAT(x) x
+#else
+#define STAT(x)
+#endif
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+
+
+/* FIXME: The MU_DIV_QR_SKEW_THRESHOLD was not analysed properly.  It gives a
+   speedup according to old measurements, but does the decision mechanism
+   really make sense?  It seem like the quotient between dn and qn might be
+   what we really should be checking.  */
+#ifndef MU_DIV_QR_SKEW_THRESHOLD
+#define MU_DIV_QR_SKEW_THRESHOLD 100
+#endif
+
+#ifdef CHECK				/* FIXME: Enable in minithres */
+#undef  MU_DIV_QR_SKEW_THRESHOLD
+#define MU_DIV_QR_SKEW_THRESHOLD 1
+#endif
+
+
+static mp_limb_t mpn_mu_div_qr2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+static mp_size_t mpn_mu_div_qr_choose_in (mp_size_t, mp_size_t, int);
+
+
+mp_limb_t
+mpn_mu_div_qr (mp_ptr qp,
+	       mp_ptr rp,
+	       mp_srcptr np,
+	       mp_size_t nn,
+	       mp_srcptr dp,
+	       mp_size_t dn,
+	       mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_limb_t cy, qh;
+
+  qn = nn - dn;
+  if (qn + MU_DIV_QR_SKEW_THRESHOLD < dn)
+    {
+      /* |______________|_ign_first__|   dividend			  nn
+		|_______|_ign_first__|   divisor			  dn
+
+		|______|	     quotient (prel)			  qn
+
+		 |___________________|   quotient * ignored-divisor-part  dn-1
+      */
+
+      /* Compute a preliminary quotient and a partial remainder by dividing the
+	 most significant limbs of each operand.  */
+      qh = mpn_mu_div_qr2 (qp, rp + nn - (2 * qn + 1),
+			   np + nn - (2 * qn + 1), 2 * qn + 1,
+			   dp + dn - (qn + 1), qn + 1,
+			   scratch);
+
+      /* Multiply the quotient by the divisor limbs ignored above.  */
+      if (dn - (qn + 1) > qn)
+	mpn_mul (scratch, dp, dn - (qn + 1), qp, qn);  /* prod is dn-1 limbs */
+      else
+	mpn_mul (scratch, qp, qn, dp, dn - (qn + 1));  /* prod is dn-1 limbs */
+
+      if (qh)
+	cy = mpn_add_n (scratch + qn, scratch + qn, dp, dn - (qn + 1));
+      else
+	cy = 0;
+      scratch[dn - 1] = cy;
+
+      cy = mpn_sub_n (rp, np, scratch, nn - (2 * qn + 1));
+      cy = mpn_sub_nc (rp + nn - (2 * qn + 1),
+		       rp + nn - (2 * qn + 1),
+		       scratch + nn - (2 * qn + 1),
+		       qn + 1, cy);
+      if (cy)
+	{
+	  qh -= mpn_sub_1 (qp, qp, qn, 1);
+	  mpn_add_n (rp, rp, dp, dn);
+	}
+    }
+  else
+    {
+      qh = mpn_mu_div_qr2 (qp, rp, np, nn, dp, dn, scratch);
+    }
+
+  return qh;
+}
+
+static mp_limb_t
+mpn_mu_div_qr2 (mp_ptr qp,
+		mp_ptr rp,
+		mp_srcptr np,
+		mp_size_t nn,
+		mp_srcptr dp,
+		mp_size_t dn,
+		mp_ptr scratch)
+{
+  mp_size_t qn, in;
+  mp_limb_t cy, qh;
+  mp_ptr ip, tp;
+
+  ASSERT (dn > 1);
+
+  qn = nn - dn;
+
+  /* Compute the inverse size.  */
+  in = mpn_mu_div_qr_choose_in (qn, dn, 0);
+  ASSERT (in <= dn);
+
+#if 1
+  /* This alternative inverse computation method gets slightly more accurate
+     results.  FIXMEs: (1) Temp allocation needs not analysed (2) itch function
+     not adapted (3) mpn_invertappr scratch needs not met.  */
+  ip = scratch;
+  tp = scratch + in + 1;
+
+  /* compute an approximate inverse on (in+1) limbs */
+  if (dn == in)
+    {
+      MPN_COPY (tp + 1, dp, in);
+      tp[0] = 1;
+      mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+      MPN_COPY_INCR (ip, ip + 1, in);
+    }
+  else
+    {
+      cy = mpn_add_1 (tp, dp + dn - (in + 1), in + 1, 1);
+      if (UNLIKELY (cy != 0))
+	MPN_ZERO (ip, in);
+      else
+	{
+	  mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+	  MPN_COPY_INCR (ip, ip + 1, in);
+	}
+    }
+#else
+  /* This older inverse computation method gets slightly worse results than the
+     one above.  */
+  ip = scratch;
+  tp = scratch + in;
+
+  /* Compute inverse of D to in+1 limbs, then round to 'in' limbs.  Ideally the
+     inversion function should do this automatically.  */
+  if (dn == in)
+    {
+      tp[in + 1] = 0;
+      MPN_COPY (tp + in + 2, dp, in);
+      mpn_invertappr (tp, tp + in + 1, in + 1, NULL);
+    }
+  else
+    {
+      mpn_invertappr (tp, dp + dn - (in + 1), in + 1, NULL);
+    }
+  cy = mpn_sub_1 (tp, tp, in + 1, GMP_NUMB_HIGHBIT);
+  if (UNLIKELY (cy != 0))
+    MPN_ZERO (tp + 1, in);
+  MPN_COPY (ip, tp + 1, in);
+#endif
+
+  qh = mpn_preinv_mu_div_qr (qp, rp, np, nn, dp, dn, ip, in, scratch + in);
+
+  return qh;
+}
+
+mp_limb_t
+mpn_preinv_mu_div_qr (mp_ptr qp,
+		      mp_ptr rp,
+		      mp_srcptr np,
+		      mp_size_t nn,
+		      mp_srcptr dp,
+		      mp_size_t dn,
+		      mp_srcptr ip,
+		      mp_size_t in,
+		      mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_limb_t cy, cx, qh;
+  mp_limb_t r;
+  mp_size_t tn, wn;
+
+#define tp           scratch
+#define scratch_out  (scratch + tn)
+
+  qn = nn - dn;
+
+  np += qn;
+  qp += qn;
+
+  qh = mpn_cmp (np, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (rp, np, dp, dn);
+  else
+    MPN_COPY_INCR (rp, np, dn);
+
+  /* if (qn == 0) */			/* The while below handles this case */
+  /*   return qh; */			/* Degenerate use.  Should we allow this? */
+
+  while (qn > 0)
+    {
+      if (qn < in)
+	{
+	  ip += in - qn;
+	  in = qn;
+	}
+      np -= in;
+      qp -= in;
+
+      /* Compute the next block of quotient limbs by multiplying the inverse I
+	 by the upper part of the partial remainder R.  */
+      mpn_mul_n (tp, rp + dn - in, ip, in);		/* mulhi  */
+      cy = mpn_add_n (qp, tp + in, rp + dn - in, in);	/* I's msb implicit */
+      ASSERT_ALWAYS (cy == 0);
+
+      qn -= in;
+
+      /* Compute the product of the quotient block and the divisor D, to be
+	 subtracted from the partial remainder combined with new limbs from the
+	 dividend N.  We only really need the low dn+1 limbs.  */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* dn+in limbs, high 'in' cancels */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn + 1);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      cy = mpn_sub_n (tp, tp, rp + dn - wn, wn);
+	      cy = mpn_sub_1 (tp + wn, tp + wn, tn - wn, cy);
+	      cx = mpn_cmp (rp + dn - in, tp + dn, tn - dn) < 0;
+	      ASSERT_ALWAYS (cx >= cy);
+	      mpn_incr_u (tp, cx - cy);
+	    }
+	}
+
+      r = rp[dn - in] - tp[dn];
+
+      /* Subtract the product from the partial remainder combined with new
+	 limbs from the dividend N, generating a new partial remainder R.  */
+      if (dn != in)
+	{
+	  cy = mpn_sub_n (tp, np, tp, in);	/* get next 'in' limbs from N */
+	  cy = mpn_sub_nc (tp + in, rp, tp + in, dn - in, cy);
+	  MPN_COPY (rp, tp, dn);		/* FIXME: try to avoid this */
+	}
+      else
+	{
+	  cy = mpn_sub_n (rp, np, tp, in);	/* get next 'in' limbs from N */
+	}
+
+      STAT (int i; int err = 0;
+	    static int errarr[5]; static int err_rec; static int tot);
+
+      /* Check the remainder R and adjust the quotient as needed.  */
+      r -= cy;
+      while (r != 0)
+	{
+	  /* We loop 0 times with about 69% probability, 1 time with about 31%
+	     probability, 2 times with about 0.6% probability, if inverse is
+	     computed as recommended.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  r -= cy;
+	  STAT (err++);
+	}
+      if (mpn_cmp (rp, dp, dn) >= 0)
+	{
+	  /* This is executed with about 76% probability.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  STAT (err++);
+	}
+
+      STAT (
+	    tot++;
+	    errarr[err]++;
+	    if (err > err_rec)
+	      err_rec = err;
+	    if (tot % 0x10000 == 0)
+	      {
+		for (i = 0; i <= err_rec; i++)
+		  printf ("  %d(%.1f%%)", errarr[i], 100.0*errarr[i]/tot);
+		printf ("\n");
+	      }
+	    );
+    }
+
+  return qh;
+}
+
+/* In case k=0 (automatic choice), we distinguish 3 cases:
+   (a) dn < qn:         in = ceil(qn / ceil(qn/dn))
+   (b) dn/3 < qn <= dn: in = ceil(qn / 2)
+   (c) qn < dn/3:       in = qn
+   In all cases we have in <= dn.
+ */
+static mp_size_t
+mpn_mu_div_qr_choose_in (mp_size_t qn, mp_size_t dn, int k)
+{
+  mp_size_t in;
+
+  if (k == 0)
+    {
+      mp_size_t b;
+      if (qn > dn)
+	{
+	  /* Compute an inverse size that is a nice partition of the quotient.  */
+	  b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+	  in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+	}
+      else if (3 * qn > dn)
+	{
+	  in = (qn - 1) / 2 + 1;	/* b = 2 */
+	}
+      else
+	{
+	  in = (qn - 1) / 1 + 1;	/* b = 1 */
+	}
+    }
+  else
+    {
+      mp_size_t xn;
+      xn = MIN (dn, qn);
+      in = (xn - 1) / k + 1;
+    }
+
+  return in;
+}
+
+mp_size_t
+mpn_mu_div_qr_itch (mp_size_t nn, mp_size_t dn, int mua_k)
+{
+  mp_size_t in = mpn_mu_div_qr_choose_in (nn - dn, dn, mua_k);
+  mp_size_t itch_preinv = mpn_preinv_mu_div_qr_itch (nn, dn, in);
+  mp_size_t itch_invapp = mpn_invertappr_itch (in + 1) + in + 2; /* 3in + 4 */
+
+  ASSERT (itch_preinv >= itch_invapp);
+  return in + MAX (itch_invapp, itch_preinv);
+}
+
+mp_size_t
+mpn_preinv_mu_div_qr_itch (mp_size_t nn, mp_size_t dn, mp_size_t in)
+{
+  mp_size_t itch_local = mpn_mulmod_bnm1_next_size (dn + 1);
+  mp_size_t itch_out = mpn_mulmod_bnm1_itch (itch_local, dn, in);
+
+  return itch_local + itch_out;
+}
diff --git a/mpn/generic/mu_divappr_q.c b/mpn/generic/mu_divappr_q.c
new file mode 100644
index 0000000..0ef7e03
--- /dev/null
+++ b/mpn/generic/mu_divappr_q.c
@@ -0,0 +1,368 @@
+/* mpn_mu_divappr_q, mpn_preinv_mu_divappr_q.
+
+   Compute Q = floor(N / D) + e.  N is nn limbs, D is dn limbs and must be
+   normalized, and Q must be nn-dn limbs, 0 <= e <= 4.  The requirement that Q
+   is nn-dn limbs (and not nn-dn+1 limbs) was put in place in order to allow us
+   to let N be unmodified during the operation.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+/* CAUTION: This code and the code in mu_div_qr.c should be edited in sync.
+
+ Things to work on:
+
+  * The itch/scratch scheme isn't perhaps such a good idea as it once seemed,
+    demonstrated by the fact that the mpn_invertappr function's scratch needs
+    mean that we need to keep a large allocation long after it is needed.
+    Things are worse as mpn_mul_fft does not accept any scratch parameter,
+    which means we'll have a large memory hole while in mpn_mul_fft.  In
+    general, a peak scratch need in the beginning of a function isn't
+    well-handled by the itch/scratch scheme.
+*/
+
+#ifdef STAT
+#undef STAT
+#define STAT(x) x
+#else
+#define STAT(x)
+#endif
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+
+static mp_limb_t mpn_preinv_mu_divappr_q (mp_ptr, mp_srcptr, mp_size_t,
+			 mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+static mp_size_t mpn_mu_divappr_q_choose_in (mp_size_t, mp_size_t, int);
+
+mp_limb_t
+mpn_mu_divappr_q (mp_ptr qp,
+		  mp_srcptr np,
+		  mp_size_t nn,
+		  mp_srcptr dp,
+		  mp_size_t dn,
+		  mp_ptr scratch)
+{
+  mp_size_t qn, in;
+  mp_limb_t cy, qh;
+  mp_ptr ip, tp;
+
+  ASSERT (dn > 1);
+
+  qn = nn - dn;
+
+  /* If Q is smaller than D, truncate operands. */
+  if (qn + 1 < dn)
+    {
+      np += dn - (qn + 1);
+      nn -= dn - (qn + 1);
+      dp += dn - (qn + 1);
+      dn = qn + 1;
+    }
+
+  /* Compute the inverse size.  */
+  in = mpn_mu_divappr_q_choose_in (qn, dn, 0);
+  ASSERT (in <= dn);
+
+#if 1
+  /* This alternative inverse computation method gets slightly more accurate
+     results.  FIXMEs: (1) Temp allocation needs not analysed (2) itch function
+     not adapted (3) mpn_invertappr scratch needs not met.  */
+  ip = scratch;
+  tp = scratch + in + 1;
+
+  /* compute an approximate inverse on (in+1) limbs */
+  if (dn == in)
+    {
+      MPN_COPY (tp + 1, dp, in);
+      tp[0] = 1;
+      mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+      MPN_COPY_INCR (ip, ip + 1, in);
+    }
+  else
+    {
+      cy = mpn_add_1 (tp, dp + dn - (in + 1), in + 1, 1);
+      if (UNLIKELY (cy != 0))
+	MPN_ZERO (ip, in);
+      else
+	{
+	  mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+	  MPN_COPY_INCR (ip, ip + 1, in);
+	}
+    }
+#else
+  /* This older inverse computation method gets slightly worse results than the
+     one above.  */
+  ip = scratch;
+  tp = scratch + in;
+
+  /* Compute inverse of D to in+1 limbs, then round to 'in' limbs.  Ideally the
+     inversion function should do this automatically.  */
+  if (dn == in)
+    {
+      tp[in + 1] = 0;
+      MPN_COPY (tp + in + 2, dp, in);
+      mpn_invertappr (tp, tp + in + 1, in + 1, NULL);
+    }
+  else
+    {
+      mpn_invertappr (tp, dp + dn - (in + 1), in + 1, NULL);
+    }
+  cy = mpn_sub_1 (tp, tp, in + 1, GMP_NUMB_HIGHBIT);
+  if (UNLIKELY (cy != 0))
+    MPN_ZERO (tp + 1, in);
+  MPN_COPY (ip, tp + 1, in);
+#endif
+
+  qh = mpn_preinv_mu_divappr_q (qp, np, nn, dp, dn, ip, in, scratch + in);
+
+  return qh;
+}
+
+static mp_limb_t
+mpn_preinv_mu_divappr_q (mp_ptr qp,
+			 mp_srcptr np,
+			 mp_size_t nn,
+			 mp_srcptr dp,
+			 mp_size_t dn,
+			 mp_srcptr ip,
+			 mp_size_t in,
+			 mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_limb_t cy, cx, qh;
+  mp_limb_t r;
+  mp_size_t tn, wn;
+
+#define rp           scratch
+#define tp           (scratch + dn)
+#define scratch_out  (scratch + dn + tn)
+
+  qn = nn - dn;
+
+  np += qn;
+  qp += qn;
+
+  qh = mpn_cmp (np, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (rp, np, dp, dn);
+  else
+    MPN_COPY (rp, np, dn);
+
+  if (UNLIKELY (qn == 0))
+    return qh;			/* Degenerate use.  Should we allow this? */
+
+  for (;;) /* The exit condition (qn == 0) is verified in the loop. */
+    {
+      if (qn < in)
+	{
+	  ip += in - qn;
+	  in = qn;
+	}
+      np -= in;
+      qp -= in;
+
+      /* Compute the next block of quotient limbs by multiplying the inverse I
+	 by the upper part of the partial remainder R.  */
+      mpn_mul_n (tp, rp + dn - in, ip, in);		/* mulhi  */
+      cy = mpn_add_n (qp, tp + in, rp + dn - in, in);	/* I's msb implicit */
+      ASSERT_ALWAYS (cy == 0);
+
+      qn -= in;
+      if (qn == 0)
+	break;
+
+      /* Compute the product of the quotient block and the divisor D, to be
+	 subtracted from the partial remainder combined with new limbs from the
+	 dividend N.  We only really need the low dn limbs.  */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* dn+in limbs, high 'in' cancels */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn + 1);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      cy = mpn_sub_n (tp, tp, rp + dn - wn, wn);
+	      cy = mpn_sub_1 (tp + wn, tp + wn, tn - wn, cy);
+	      cx = mpn_cmp (rp + dn - in, tp + dn, tn - dn) < 0;
+	      ASSERT_ALWAYS (cx >= cy);
+	      mpn_incr_u (tp, cx - cy);
+	    }
+	}
+
+      r = rp[dn - in] - tp[dn];
+
+      /* Subtract the product from the partial remainder combined with new
+	 limbs from the dividend N, generating a new partial remainder R.  */
+      if (dn != in)
+	{
+	  cy = mpn_sub_n (tp, np, tp, in);	/* get next 'in' limbs from N */
+	  cy = mpn_sub_nc (tp + in, rp, tp + in, dn - in, cy);
+	  MPN_COPY (rp, tp, dn);		/* FIXME: try to avoid this */
+	}
+      else
+	{
+	  cy = mpn_sub_n (rp, np, tp, in);	/* get next 'in' limbs from N */
+	}
+
+      STAT (int i; int err = 0;
+	    static int errarr[5]; static int err_rec; static int tot);
+
+      /* Check the remainder R and adjust the quotient as needed.  */
+      r -= cy;
+      while (r != 0)
+	{
+	  /* We loop 0 times with about 69% probability, 1 time with about 31%
+	     probability, 2 times with about 0.6% probability, if inverse is
+	     computed as recommended.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  r -= cy;
+	  STAT (err++);
+	}
+      if (mpn_cmp (rp, dp, dn) >= 0)
+	{
+	  /* This is executed with about 76% probability.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  STAT (err++);
+	}
+
+      STAT (
+	    tot++;
+	    errarr[err]++;
+	    if (err > err_rec)
+	      err_rec = err;
+	    if (tot % 0x10000 == 0)
+	      {
+		for (i = 0; i <= err_rec; i++)
+		  printf ("  %d(%.1f%%)", errarr[i], 100.0*errarr[i]/tot);
+		printf ("\n");
+	      }
+	    );
+    }
+
+  /* FIXME: We should perhaps be somewhat more elegant in our rounding of the
+     quotient.  For now, just make sure the returned quotient is >= the real
+     quotient; add 3 with saturating arithmetic.  */
+  qn = nn - dn;
+  cy += mpn_add_1 (qp, qp, qn, 3);
+  if (cy != 0)
+    {
+      if (qh != 0)
+	{
+	  /* Return a quotient of just 1-bits, with qh set.  */
+	  mp_size_t i;
+	  for (i = 0; i < qn; i++)
+	    qp[i] = GMP_NUMB_MAX;
+	}
+      else
+	{
+	  /* Propagate carry into qh.  */
+	  qh = 1;
+	}
+    }
+
+  return qh;
+}
+
+/* In case k=0 (automatic choice), we distinguish 3 cases:
+   (a) dn < qn:         in = ceil(qn / ceil(qn/dn))
+   (b) dn/3 < qn <= dn: in = ceil(qn / 2)
+   (c) qn < dn/3:       in = qn
+   In all cases we have in <= dn.
+ */
+static mp_size_t
+mpn_mu_divappr_q_choose_in (mp_size_t qn, mp_size_t dn, int k)
+{
+  mp_size_t in;
+
+  if (k == 0)
+    {
+      mp_size_t b;
+      if (qn > dn)
+	{
+	  /* Compute an inverse size that is a nice partition of the quotient.  */
+	  b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+	  in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+	}
+      else if (3 * qn > dn)
+	{
+	  in = (qn - 1) / 2 + 1;	/* b = 2 */
+	}
+      else
+	{
+	  in = (qn - 1) / 1 + 1;	/* b = 1 */
+	}
+    }
+  else
+    {
+      mp_size_t xn;
+      xn = MIN (dn, qn);
+      in = (xn - 1) / k + 1;
+    }
+
+  return in;
+}
+
+mp_size_t
+mpn_mu_divappr_q_itch (mp_size_t nn, mp_size_t dn, int mua_k)
+{
+  mp_size_t qn, in, itch_local, itch_out, itch_invapp;
+
+  qn = nn - dn;
+  if (qn + 1 < dn)
+    {
+      dn = qn + 1;
+    }
+  in = mpn_mu_divappr_q_choose_in (qn, dn, mua_k);
+
+  itch_local = mpn_mulmod_bnm1_next_size (dn + 1);
+  itch_out = mpn_mulmod_bnm1_itch (itch_local, dn, in);
+  itch_invapp = mpn_invertappr_itch (in + 1) + in + 2; /* 3in + 4 */
+
+  ASSERT (dn + itch_local + itch_out >= itch_invapp);
+  return in + MAX (dn + itch_local + itch_out, itch_invapp);
+}
diff --git a/mpn/generic/mul.c b/mpn/generic/mul.c
new file mode 100644
index 0000000..37444e9
--- /dev/null
+++ b/mpn/generic/mul.c
@@ -0,0 +1,441 @@
+/* mpn_mul -- Multiply two natural numbers.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 1999-2003, 2005-2007, 2009, 2010, 2012,
+2014, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifndef MUL_BASECASE_MAX_UN
+#define MUL_BASECASE_MAX_UN 500
+#endif
+
+/* Areas where the different toom algorithms can be called (extracted
+   from the t-toom*.c files, and ignoring small constant offsets):
+
+   1/6  1/5 1/4 4/13 1/3 3/8 2/5 5/11 1/2 3/5 2/3 3/4 4/5   1 vn/un
+                                        4/7              6/7
+				       6/11
+                                       |--------------------| toom22 (small)
+                                                           || toom22 (large)
+                                                       |xxxx| toom22 called
+                      |-------------------------------------| toom32
+                                         |xxxxxxxxxxxxxxxx| | toom32 called
+                                               |------------| toom33
+                                                          |x| toom33 called
+             |---------------------------------|            | toom42
+	              |xxxxxxxxxxxxxxxxxxxxxxxx|            | toom42 called
+                                       |--------------------| toom43
+                                               |xxxxxxxxxx|   toom43 called
+         |-----------------------------|                      toom52 (unused)
+                                                   |--------| toom44
+						   |xxxxxxxx| toom44 called
+                              |--------------------|        | toom53
+                                        |xxxxxx|              toom53 called
+    |-------------------------|                               toom62 (unused)
+                                           |----------------| toom54 (unused)
+                      |--------------------|                  toom63
+	                      |xxxxxxxxx|                   | toom63 called
+                          |---------------------------------| toom6h
+						   |xxxxxxxx| toom6h called
+                                  |-------------------------| toom8h (32 bit)
+                 |------------------------------------------| toom8h (64 bit)
+						   |xxxxxxxx| toom8h called
+*/
+
+#define TOOM33_OK(an,bn) (6 + 2 * an < 3 * bn)
+#define TOOM44_OK(an,bn) (12 + 3 * an < 4 * bn)
+
+/* Multiply the natural numbers u (pointed to by UP, with UN limbs) and v
+   (pointed to by VP, with VN limbs), and store the result at PRODP.  The
+   result is UN + VN limbs.  Return the most significant limb of the result.
+
+   NOTE: The space pointed to by PRODP is overwritten before finished with U
+   and V, so overlap is an error.
+
+   Argument constraints:
+   1. UN >= VN.
+   2. PRODP != UP and PRODP != VP, i.e. the destination must be distinct from
+      the multiplier and the multiplicand.  */
+
+/*
+  * The cutoff lines in the toomX2 and toomX3 code are now exactly between the
+    ideal lines of the surrounding algorithms.  Is that optimal?
+
+  * The toomX3 code now uses a structure similar to the one of toomX2, except
+    that it loops longer in the unbalanced case.  The result is that the
+    remaining area might have un < vn.  Should we fix the toomX2 code in a
+    similar way?
+
+  * The toomX3 code is used for the largest non-FFT unbalanced operands.  It
+    therefore calls mpn_mul recursively for certain cases.
+
+  * Allocate static temp space using THRESHOLD variables (except for toom44
+    when !WANT_FFT).  That way, we can typically have no TMP_ALLOC at all.
+
+  * We sort ToomX2 algorithms together, assuming the toom22, toom32, toom42
+    have the same vn threshold.  This is not true, we should actually use
+    mul_basecase for slightly larger operands for toom32 than for toom22, and
+    even larger for toom42.
+
+  * That problem is even more prevalent for toomX3.  We therefore use special
+    THRESHOLD variables there.
+*/
+
+mp_limb_t
+mpn_mul (mp_ptr prodp,
+	 mp_srcptr up, mp_size_t un,
+	 mp_srcptr vp, mp_size_t vn)
+{
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! MPN_OVERLAP_P (prodp, un+vn, up, un));
+  ASSERT (! MPN_OVERLAP_P (prodp, un+vn, vp, vn));
+
+  if (BELOW_THRESHOLD (un, MUL_TOOM22_THRESHOLD))
+    {
+      /* When un (and thus vn) is below the toom22 range, do mul_basecase.
+	 Test un and not vn here not to thwart the un >> vn code below.
+	 This special case is not necessary, but cuts the overhead for the
+	 smallest operands. */
+      mpn_mul_basecase (prodp, up, un, vp, vn);
+    }
+  else if (un == vn)
+    {
+      mpn_mul_n (prodp, up, vp, un);
+    }
+  else if (vn < MUL_TOOM22_THRESHOLD)
+    { /* plain schoolbook multiplication */
+
+      /* Unless un is very large, or else if have an applicable mpn_mul_N,
+	 perform basecase multiply directly.  */
+      if (un <= MUL_BASECASE_MAX_UN
+#if HAVE_NATIVE_mpn_mul_2
+	  || vn <= 2
+#else
+	  || vn == 1
+#endif
+	  )
+	mpn_mul_basecase (prodp, up, un, vp, vn);
+      else
+	{
+	  /* We have un >> MUL_BASECASE_MAX_UN > vn.  For better memory
+	     locality, split up[] into MUL_BASECASE_MAX_UN pieces and multiply
+	     these pieces with the vp[] operand.  After each such partial
+	     multiplication (but the last) we copy the most significant vn
+	     limbs into a temporary buffer since that part would otherwise be
+	     overwritten by the next multiplication.  After the next
+	     multiplication, we add it back.  This illustrates the situation:
+
+                                                    -->vn<--
+                                                      |  |<------- un ------->|
+                                                         _____________________|
+                                                        X                    /|
+                                                      /XX__________________/  |
+                                    _____________________                     |
+                                   X                    /                     |
+                                 /XX__________________/                       |
+               _____________________                                          |
+              /                    /                                          |
+            /____________________/                                            |
+	    ==================================================================
+
+	    The parts marked with X are the parts whose sums are copied into
+	    the temporary buffer.  */
+
+	  mp_limb_t tp[MUL_TOOM22_THRESHOLD_LIMIT];
+	  mp_limb_t cy;
+	  ASSERT (MUL_TOOM22_THRESHOLD <= MUL_TOOM22_THRESHOLD_LIMIT);
+
+	  mpn_mul_basecase (prodp, up, MUL_BASECASE_MAX_UN, vp, vn);
+	  prodp += MUL_BASECASE_MAX_UN;
+	  MPN_COPY (tp, prodp, vn);		/* preserve high triangle */
+	  up += MUL_BASECASE_MAX_UN;
+	  un -= MUL_BASECASE_MAX_UN;
+	  while (un > MUL_BASECASE_MAX_UN)
+	    {
+	      mpn_mul_basecase (prodp, up, MUL_BASECASE_MAX_UN, vp, vn);
+	      cy = mpn_add_n (prodp, prodp, tp, vn); /* add back preserved triangle */
+	      mpn_incr_u (prodp + vn, cy);
+	      prodp += MUL_BASECASE_MAX_UN;
+	      MPN_COPY (tp, prodp, vn);		/* preserve high triangle */
+	      up += MUL_BASECASE_MAX_UN;
+	      un -= MUL_BASECASE_MAX_UN;
+	    }
+	  if (un > vn)
+	    {
+	      mpn_mul_basecase (prodp, up, un, vp, vn);
+	    }
+	  else
+	    {
+	      ASSERT (un > 0);
+	      mpn_mul_basecase (prodp, vp, vn, up, un);
+	    }
+	  cy = mpn_add_n (prodp, prodp, tp, vn); /* add back preserved triangle */
+	  mpn_incr_u (prodp + vn, cy);
+	}
+    }
+  else if (BELOW_THRESHOLD (vn, MUL_TOOM33_THRESHOLD))
+    {
+      /* Use ToomX2 variants */
+      mp_ptr scratch;
+      TMP_SDECL; TMP_SMARK;
+
+#define ITCH_TOOMX2 (9 * vn / 2 + GMP_NUMB_BITS * 2)
+      scratch = TMP_SALLOC_LIMBS (ITCH_TOOMX2);
+      ASSERT (mpn_toom22_mul_itch ((5*vn-1)/4, vn) <= ITCH_TOOMX2); /* 5vn/2+ */
+      ASSERT (mpn_toom32_mul_itch ((7*vn-1)/4, vn) <= ITCH_TOOMX2); /* 7vn/6+ */
+      ASSERT (mpn_toom42_mul_itch (3 * vn - 1, vn) <= ITCH_TOOMX2); /* 9vn/2+ */
+#undef ITCH_TOOMX2
+
+      /* FIXME: This condition (repeated in the loop below) leaves from a vn*vn
+	 square to a (3vn-1)*vn rectangle.  Leaving such a rectangle is hardly
+	 wise; we would get better balance by slightly moving the bound.  We
+	 will sometimes end up with un < vn, like in the X3 arm below.  */
+      if (un >= 3 * vn)
+	{
+	  mp_limb_t cy;
+	  mp_ptr ws;
+
+	  /* The maximum ws usage is for the mpn_mul result.  */
+	  ws = TMP_SALLOC_LIMBS (4 * vn);
+
+	  mpn_toom42_mul (prodp, up, 2 * vn, vp, vn, scratch);
+	  un -= 2 * vn;
+	  up += 2 * vn;
+	  prodp += 2 * vn;
+
+	  while (un >= 3 * vn)
+	    {
+	      mpn_toom42_mul (ws, up, 2 * vn, vp, vn, scratch);
+	      un -= 2 * vn;
+	      up += 2 * vn;
+	      cy = mpn_add_n (prodp, prodp, ws, vn);
+	      MPN_COPY (prodp + vn, ws + vn, 2 * vn);
+	      mpn_incr_u (prodp + vn, cy);
+	      prodp += 2 * vn;
+	    }
+
+	  /* vn <= un < 3vn */
+
+	  if (4 * un < 5 * vn)
+	    mpn_toom22_mul (ws, up, un, vp, vn, scratch);
+	  else if (4 * un < 7 * vn)
+	    mpn_toom32_mul (ws, up, un, vp, vn, scratch);
+	  else
+	    mpn_toom42_mul (ws, up, un, vp, vn, scratch);
+
+	  cy = mpn_add_n (prodp, prodp, ws, vn);
+	  MPN_COPY (prodp + vn, ws + vn, un);
+	  mpn_incr_u (prodp + vn, cy);
+	}
+      else
+	{
+	  if (4 * un < 5 * vn)
+	    mpn_toom22_mul (prodp, up, un, vp, vn, scratch);
+	  else if (4 * un < 7 * vn)
+	    mpn_toom32_mul (prodp, up, un, vp, vn, scratch);
+	  else
+	    mpn_toom42_mul (prodp, up, un, vp, vn, scratch);
+	}
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD ((un + vn) >> 1, MUL_FFT_THRESHOLD) ||
+	   BELOW_THRESHOLD (3 * vn, MUL_FFT_THRESHOLD))
+    {
+      /* Handle the largest operands that are not in the FFT range.  The 2nd
+	 condition makes very unbalanced operands avoid the FFT code (except
+	 perhaps as coefficient products of the Toom code.  */
+
+      if (BELOW_THRESHOLD (vn, MUL_TOOM44_THRESHOLD) || !TOOM44_OK (un, vn))
+	{
+	  /* Use ToomX3 variants */
+	  mp_ptr scratch;
+	  TMP_DECL; TMP_MARK;
+
+#define ITCH_TOOMX3 (4 * vn + GMP_NUMB_BITS)
+	  scratch = TMP_ALLOC_LIMBS (ITCH_TOOMX3);
+	  ASSERT (mpn_toom33_mul_itch ((7*vn-1)/6, vn) <= ITCH_TOOMX3); /* 7vn/2+ */
+	  ASSERT (mpn_toom43_mul_itch ((3*vn-1)/2, vn) <= ITCH_TOOMX3); /* 9vn/4+ */
+	  ASSERT (mpn_toom32_mul_itch ((7*vn-1)/4, vn) <= ITCH_TOOMX3); /* 7vn/6+ */
+	  ASSERT (mpn_toom53_mul_itch ((11*vn-1)/6, vn) <= ITCH_TOOMX3); /* 11vn/3+ */
+	  ASSERT (mpn_toom42_mul_itch ((5*vn-1)/2, vn) <= ITCH_TOOMX3); /* 15vn/4+ */
+	  ASSERT (mpn_toom63_mul_itch ((5*vn-1)/2, vn) <= ITCH_TOOMX3); /* 15vn/4+ */
+#undef ITCH_TOOMX3
+
+	  if (2 * un >= 5 * vn)
+	    {
+	      mp_limb_t cy;
+	      mp_ptr ws;
+
+	      /* The maximum ws usage is for the mpn_mul result.  */
+	      ws = TMP_ALLOC_LIMBS (7 * vn >> 1);
+
+	      if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM63_THRESHOLD))
+		mpn_toom42_mul (prodp, up, 2 * vn, vp, vn, scratch);
+	      else
+		mpn_toom63_mul (prodp, up, 2 * vn, vp, vn, scratch);
+	      un -= 2 * vn;
+	      up += 2 * vn;
+	      prodp += 2 * vn;
+
+	      while (2 * un >= 5 * vn)	/* un >= 2.5vn */
+		{
+		  if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM63_THRESHOLD))
+		    mpn_toom42_mul (ws, up, 2 * vn, vp, vn, scratch);
+		  else
+		    mpn_toom63_mul (ws, up, 2 * vn, vp, vn, scratch);
+		  un -= 2 * vn;
+		  up += 2 * vn;
+		  cy = mpn_add_n (prodp, prodp, ws, vn);
+		  MPN_COPY (prodp + vn, ws + vn, 2 * vn);
+		  mpn_incr_u (prodp + vn, cy);
+		  prodp += 2 * vn;
+		}
+
+	      /* vn / 2 <= un < 2.5vn */
+
+	      if (un < vn)
+		mpn_mul (ws, vp, vn, up, un);
+	      else
+		mpn_mul (ws, up, un, vp, vn);
+
+	      cy = mpn_add_n (prodp, prodp, ws, vn);
+	      MPN_COPY (prodp + vn, ws + vn, un);
+	      mpn_incr_u (prodp + vn, cy);
+	    }
+	  else
+	    {
+	      if (6 * un < 7 * vn)
+		mpn_toom33_mul (prodp, up, un, vp, vn, scratch);
+	      else if (2 * un < 3 * vn)
+		{
+		  if (BELOW_THRESHOLD (vn, MUL_TOOM32_TO_TOOM43_THRESHOLD))
+		    mpn_toom32_mul (prodp, up, un, vp, vn, scratch);
+		  else
+		    mpn_toom43_mul (prodp, up, un, vp, vn, scratch);
+		}
+	      else if (6 * un < 11 * vn)
+		{
+		  if (4 * un < 7 * vn)
+		    {
+		      if (BELOW_THRESHOLD (vn, MUL_TOOM32_TO_TOOM53_THRESHOLD))
+			mpn_toom32_mul (prodp, up, un, vp, vn, scratch);
+		      else
+			mpn_toom53_mul (prodp, up, un, vp, vn, scratch);
+		    }
+		  else
+		    {
+		      if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM53_THRESHOLD))
+			mpn_toom42_mul (prodp, up, un, vp, vn, scratch);
+		      else
+			mpn_toom53_mul (prodp, up, un, vp, vn, scratch);
+		    }
+		}
+	      else
+		{
+		  if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM63_THRESHOLD))
+		    mpn_toom42_mul (prodp, up, un, vp, vn, scratch);
+		  else
+		    mpn_toom63_mul (prodp, up, un, vp, vn, scratch);
+		}
+	    }
+	  TMP_FREE;
+	}
+      else
+	{
+	  mp_ptr scratch;
+	  TMP_DECL; TMP_MARK;
+
+	  if (BELOW_THRESHOLD (vn, MUL_TOOM6H_THRESHOLD))
+	    {
+	      scratch = TMP_SALLOC_LIMBS (mpn_toom44_mul_itch (un, vn));
+	      mpn_toom44_mul (prodp, up, un, vp, vn, scratch);
+	    }
+	  else if (BELOW_THRESHOLD (vn, MUL_TOOM8H_THRESHOLD))
+	    {
+	      scratch = TMP_SALLOC_LIMBS (mpn_toom6h_mul_itch (un, vn));
+	      mpn_toom6h_mul (prodp, up, un, vp, vn, scratch);
+	    }
+	  else
+	    {
+	      scratch = TMP_ALLOC_LIMBS (mpn_toom8h_mul_itch (un, vn));
+	      mpn_toom8h_mul (prodp, up, un, vp, vn, scratch);
+	    }
+	  TMP_FREE;
+	}
+    }
+  else
+    {
+      if (un >= 8 * vn)
+	{
+	  mp_limb_t cy;
+	  mp_ptr ws;
+	  TMP_DECL; TMP_MARK;
+
+	  /* The maximum ws usage is for the mpn_mul result.  */
+	  ws = TMP_BALLOC_LIMBS (9 * vn >> 1);
+
+	  mpn_fft_mul (prodp, up, 3 * vn, vp, vn);
+	  un -= 3 * vn;
+	  up += 3 * vn;
+	  prodp += 3 * vn;
+
+	  while (2 * un >= 7 * vn)	/* un >= 3.5vn  */
+	    {
+	      mpn_fft_mul (ws, up, 3 * vn, vp, vn);
+	      un -= 3 * vn;
+	      up += 3 * vn;
+	      cy = mpn_add_n (prodp, prodp, ws, vn);
+	      MPN_COPY (prodp + vn, ws + vn, 3 * vn);
+	      mpn_incr_u (prodp + vn, cy);
+	      prodp += 3 * vn;
+	    }
+
+	  /* vn / 2 <= un < 3.5vn */
+
+	  if (un < vn)
+	    mpn_mul (ws, vp, vn, up, un);
+	  else
+	    mpn_mul (ws, up, un, vp, vn);
+
+	  cy = mpn_add_n (prodp, prodp, ws, vn);
+	  MPN_COPY (prodp + vn, ws + vn, un);
+	  mpn_incr_u (prodp + vn, cy);
+
+	  TMP_FREE;
+	}
+      else
+	mpn_fft_mul (prodp, up, un, vp, vn);
+    }
+
+  return prodp[un + vn - 1];	/* historic */
+}
diff --git a/mpn/generic/mul_1.c b/mpn/generic/mul_1.c
new file mode 100644
index 0000000..52d46da
--- /dev/null
+++ b/mpn/generic/mul_1.c
@@ -0,0 +1,96 @@
+/* mpn_mul_1 -- Multiply a limb vector with a single limb and store the
+   product in a second limb vector.
+
+Copyright 1991-1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 1
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t shifted_vl, ul, lpl, hpl, prev_hpl, xw, cl, xl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (vl);
+
+  shifted_vl = vl << GMP_NAIL_BITS;
+  cl = 0;
+  prev_hpl = 0;
+  do
+    {
+      ul = *up++;
+
+      umul_ppmm (hpl, lpl, ul, shifted_vl);
+      lpl >>= GMP_NAIL_BITS;
+      xw = prev_hpl + lpl + cl;
+      cl = xw >> GMP_NUMB_BITS;
+      xl = xw & GMP_NUMB_MASK;
+      *rp++ = xl;
+      prev_hpl = hpl;
+    }
+  while (--n != 0);
+
+  return prev_hpl + cl;
+}
+
+#endif
diff --git a/mpn/generic/mul_basecase.c b/mpn/generic/mul_basecase.c
new file mode 100644
index 0000000..2487fba
--- /dev/null
+++ b/mpn/generic/mul_basecase.c
@@ -0,0 +1,165 @@
+/* mpn_mul_basecase -- Internal routine to multiply two natural numbers
+   of length m and n.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright 1991-1994, 1996, 1997, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Multiply {up,usize} by {vp,vsize} and write the result to
+   {prodp,usize+vsize}.  Must have usize>=vsize.
+
+   Note that prodp gets usize+vsize limbs stored, even if the actual result
+   only needs usize+vsize-1.
+
+   There's no good reason to call here with vsize>=MUL_TOOM22_THRESHOLD.
+   Currently this is allowed, but it might not be in the future.
+
+   This is the most critical code for multiplication.  All multiplies rely
+   on this, both small and huge.  Small ones arrive here immediately, huge
+   ones arrive here as this is the base case for Karatsuba's recursive
+   algorithm.  */
+
+void
+mpn_mul_basecase (mp_ptr rp,
+		  mp_srcptr up, mp_size_t un,
+		  mp_srcptr vp, mp_size_t vn)
+{
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, un+vn, up, un));
+  ASSERT (! MPN_OVERLAP_P (rp, un+vn, vp, vn));
+
+  /* We first multiply by the low order limb (or depending on optional function
+     availability, limbs).  This result can be stored, not added, to rp.  We
+     also avoid a loop for zeroing this way.  */
+
+#if HAVE_NATIVE_mpn_mul_2
+  if (vn >= 2)
+    {
+      rp[un + 1] = mpn_mul_2 (rp, up, un, vp);
+      rp += 2, vp += 2, vn -= 2;
+    }
+  else
+    {
+      rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+      return;
+    }
+#else
+  rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+  rp += 1, vp += 1, vn -= 1;
+#endif
+
+  /* Now accumulate the product of up[] and the next higher limb (or depending
+     on optional function availability, limbs) from vp[].  */
+
+#define MAX_LEFT MP_SIZE_T_MAX	/* Used to simplify loops into if statements */
+
+
+#if HAVE_NATIVE_mpn_addmul_6
+  while (vn >= 6)
+    {
+      rp[un + 6 - 1] = mpn_addmul_6 (rp, up, un, vp);
+      if (MAX_LEFT == 6)
+	return;
+      rp += 6, vp += 6, vn -= 6;
+      if (MAX_LEFT < 2 * 6)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (6 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_5
+  while (vn >= 5)
+    {
+      rp[un + 5 - 1] = mpn_addmul_5 (rp, up, un, vp);
+      if (MAX_LEFT == 5)
+	return;
+      rp += 5, vp += 5, vn -= 5;
+      if (MAX_LEFT < 2 * 5)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (5 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_4
+  while (vn >= 4)
+    {
+      rp[un + 4 - 1] = mpn_addmul_4 (rp, up, un, vp);
+      if (MAX_LEFT == 4)
+	return;
+      rp += 4, vp += 4, vn -= 4;
+      if (MAX_LEFT < 2 * 4)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (4 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_3
+  while (vn >= 3)
+    {
+      rp[un + 3 - 1] = mpn_addmul_3 (rp, up, un, vp);
+      if (MAX_LEFT == 3)
+	return;
+      rp += 3, vp += 3, vn -= 3;
+      if (MAX_LEFT < 2 * 3)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (3 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2
+  while (vn >= 2)
+    {
+      rp[un + 2 - 1] = mpn_addmul_2 (rp, up, un, vp);
+      if (MAX_LEFT == 2)
+	return;
+      rp += 2, vp += 2, vn -= 2;
+      if (MAX_LEFT < 2 * 2)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (2 - 1)
+#endif
+
+  while (vn >= 1)
+    {
+      rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
+      if (MAX_LEFT == 1)
+	return;
+      rp += 1, vp += 1, vn -= 1;
+    }
+}
diff --git a/mpn/generic/mul_fft.c b/mpn/generic/mul_fft.c
new file mode 100644
index 0000000..76a2106
--- /dev/null
+++ b/mpn/generic/mul_fft.c
@@ -0,0 +1,1105 @@
+/* Schoenhage's fast multiplication modulo 2^N+1.
+
+   Contributed by Paul Zimmermann.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1998-2010, 2012, 2013, 2018, 2020, 2022 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* References:
+
+   Schnelle Multiplikation grosser Zahlen, by Arnold Schoenhage and Volker
+   Strassen, Computing 7, p. 281-292, 1971.
+
+   Asymptotically fast algorithms for the numerical multiplication and division
+   of polynomials with complex coefficients, by Arnold Schoenhage, Computer
+   Algebra, EUROCAM'82, LNCS 144, p. 3-15, 1982.
+
+   Tapes versus Pointers, a study in implementing fast algorithms, by Arnold
+   Schoenhage, Bulletin of the EATCS, 30, p. 23-32, 1986.
+
+   TODO:
+
+   Implement some of the tricks published at ISSAC'2007 by Gaudry, Kruppa, and
+   Zimmermann.
+
+   It might be possible to avoid a small number of MPN_COPYs by using a
+   rotating temporary or two.
+
+   Cleanup and simplify the code!
+*/
+
+#ifdef TRACE
+#undef TRACE
+#define TRACE(x) x
+#include <stdio.h>
+#else
+#define TRACE(x)
+#endif
+
+#include "gmp-impl.h"
+
+#ifdef WANT_ADDSUB
+#include "generic/add_n_sub_n.c"
+#define HAVE_NATIVE_mpn_add_n_sub_n 1
+#endif
+
+static mp_limb_t mpn_mul_fft_internal (mp_ptr, mp_size_t, int, mp_ptr *,
+				       mp_ptr *, mp_ptr, mp_ptr, mp_size_t,
+				       mp_size_t, mp_size_t, int **, mp_ptr, int);
+static void mpn_mul_fft_decompose (mp_ptr, mp_ptr *, mp_size_t, mp_size_t, mp_srcptr,
+				   mp_size_t, mp_size_t, mp_size_t, mp_ptr);
+
+
+/* Find the best k to use for a mod 2^(m*GMP_NUMB_BITS)+1 FFT for m >= n.
+   We have sqr=0 if for a multiply, sqr=1 for a square.
+   There are three generations of this code; we keep the old ones as long as
+   some gmp-mparam.h is not updated.  */
+
+
+/*****************************************************************************/
+
+#if TUNE_PROGRAM_BUILD || (defined (MUL_FFT_TABLE3) && defined (SQR_FFT_TABLE3))
+
+#ifndef FFT_TABLE3_SIZE		/* When tuning this is defined in gmp-impl.h */
+#if defined (MUL_FFT_TABLE3_SIZE) && defined (SQR_FFT_TABLE3_SIZE)
+#if MUL_FFT_TABLE3_SIZE > SQR_FFT_TABLE3_SIZE
+#define FFT_TABLE3_SIZE MUL_FFT_TABLE3_SIZE
+#else
+#define FFT_TABLE3_SIZE SQR_FFT_TABLE3_SIZE
+#endif
+#endif
+#endif
+
+#ifndef FFT_TABLE3_SIZE
+#define FFT_TABLE3_SIZE 200
+#endif
+
+FFT_TABLE_ATTRS struct fft_table_nk mpn_fft_table3[2][FFT_TABLE3_SIZE] =
+{
+  MUL_FFT_TABLE3,
+  SQR_FFT_TABLE3
+};
+
+int
+mpn_fft_best_k (mp_size_t n, int sqr)
+{
+  const struct fft_table_nk *fft_tab, *tab;
+  mp_size_t tab_n, thres;
+  int last_k;
+
+  fft_tab = mpn_fft_table3[sqr];
+  last_k = fft_tab->k;
+  for (tab = fft_tab + 1; ; tab++)
+    {
+      tab_n = tab->n;
+      thres = tab_n << last_k;
+      if (n <= thres)
+	break;
+      last_k = tab->k;
+    }
+  return last_k;
+}
+
+#define MPN_FFT_BEST_READY 1
+#endif
+
+/*****************************************************************************/
+
+#if ! defined (MPN_FFT_BEST_READY)
+FFT_TABLE_ATTRS mp_size_t mpn_fft_table[2][MPN_FFT_TABLE_SIZE] =
+{
+  MUL_FFT_TABLE,
+  SQR_FFT_TABLE
+};
+
+int
+mpn_fft_best_k (mp_size_t n, int sqr)
+{
+  int i;
+
+  for (i = 0; mpn_fft_table[sqr][i] != 0; i++)
+    if (n < mpn_fft_table[sqr][i])
+      return i + FFT_FIRST_K;
+
+  /* treat 4*last as one further entry */
+  if (i == 0 || n < 4 * mpn_fft_table[sqr][i - 1])
+    return i + FFT_FIRST_K;
+  else
+    return i + FFT_FIRST_K + 1;
+}
+#endif
+
+/*****************************************************************************/
+
+
+/* Returns smallest possible number of limbs >= pl for a fft of size 2^k,
+   i.e. smallest multiple of 2^k >= pl.
+
+   Don't declare static: needed by tuneup.
+*/
+
+mp_size_t
+mpn_fft_next_size (mp_size_t pl, int k)
+{
+  pl = 1 + ((pl - 1) >> k); /* ceil (pl/2^k) */
+  return pl << k;
+}
+
+
+/* Initialize l[i][j] with bitrev(j) */
+static void
+mpn_fft_initl (int **l, int k)
+{
+  int i, j, K;
+  int *li;
+
+  l[0][0] = 0;
+  for (i = 1, K = 1; i <= k; i++, K *= 2)
+    {
+      li = l[i];
+      for (j = 0; j < K; j++)
+	{
+	  li[j] = 2 * l[i - 1][j];
+	  li[K + j] = 1 + li[j];
+	}
+    }
+}
+
+
+/* r <- a*2^d mod 2^(n*GMP_NUMB_BITS)+1 with a = {a, n+1}
+   Assumes a is semi-normalized, i.e. a[n] <= 1.
+   r and a must have n+1 limbs, and not overlap.
+*/
+static void
+mpn_fft_mul_2exp_modF (mp_ptr r, mp_srcptr a, mp_bitcnt_t d, mp_size_t n)
+{
+  unsigned int sh;
+  mp_size_t m;
+  mp_limb_t cc, rd;
+
+  sh = d % GMP_NUMB_BITS;
+  m = d / GMP_NUMB_BITS;
+
+  if (m >= n)			/* negate */
+    {
+      /* r[0..m-1]  <-- lshift(a[n-m]..a[n-1], sh)
+	 r[m..n-1]  <-- -lshift(a[0]..a[n-m-1],  sh) */
+
+      m -= n;
+      if (sh != 0)
+	{
+	  /* no out shift below since a[n] <= 1 */
+	  mpn_lshift (r, a + n - m, m + 1, sh);
+	  rd = r[m];
+	  cc = mpn_lshiftc (r + m, a, n - m, sh);
+	}
+      else
+	{
+	  MPN_COPY (r, a + n - m, m);
+	  rd = a[n];
+	  mpn_com (r + m, a, n - m);
+	  cc = 0;
+	}
+
+      /* add cc to r[0], and add rd to r[m] */
+
+      /* now add 1 in r[m], subtract 1 in r[n], i.e. add 1 in r[0] */
+
+      r[n] = 0;
+      /* cc < 2^sh <= 2^(GMP_NUMB_BITS-1) thus no overflow here */
+      ++cc;
+      MPN_INCR_U (r, n + 1, cc);
+
+      ++rd;
+      /* rd might overflow when sh=GMP_NUMB_BITS-1 */
+      cc = rd + (rd == 0);
+      r = r + m + (rd == 0);
+      MPN_INCR_U (r, n + 1 - m - (rd == 0), cc);
+    }
+  else
+    {
+      /* r[0..m-1]  <-- -lshift(a[n-m]..a[n-1], sh)
+	 r[m..n-1]  <-- lshift(a[0]..a[n-m-1],  sh)  */
+      if (sh != 0)
+	{
+	  /* no out bits below since a[n] <= 1 */
+	  mpn_lshiftc (r, a + n - m, m + 1, sh);
+	  rd = ~r[m];
+	  /* {r, m+1} = {a+n-m, m+1} << sh */
+	  cc = mpn_lshift (r + m, a, n - m, sh); /* {r+m, n-m} = {a, n-m}<<sh */
+	}
+      else
+	{
+	  /* r[m] is not used below, but we save a test for m=0 */
+	  mpn_com (r, a + n - m, m + 1);
+	  rd = a[n];
+	  MPN_COPY (r + m, a, n - m);
+	  cc = 0;
+	}
+
+      /* now complement {r, m}, subtract cc from r[0], subtract rd from r[m] */
+
+      /* if m=0 we just have r[0]=a[n] << sh */
+      if (m != 0)
+	{
+	  /* now add 1 in r[0], subtract 1 in r[m] */
+	  if (cc-- == 0) /* then add 1 to r[0] */
+	    cc = mpn_add_1 (r, r, n, CNST_LIMB(1));
+	  cc = mpn_sub_1 (r, r, m, cc) + 1;
+	  /* add 1 to cc instead of rd since rd might overflow */
+	}
+
+      /* now subtract cc and rd from r[m..n] */
+
+      r[n] = 2; /* Add a value, to avoid borrow propagation */
+      MPN_DECR_U (r + m, n - m + 1, cc);
+      MPN_DECR_U (r + m, n - m + 1, rd);
+      /* Remove the added value, and check for a possible borrow. */
+      if (UNLIKELY ((r[n] -= 2) != 0))
+	{
+	  mp_limb_t cy = -r[n];
+	  /* cy should always be 1, except in the very unlikely case
+	     m=n-1, r[m]=0, cc+rd>GMP_NUMB_MAX+1. Never triggered.
+	     Is it actually possible? */
+	  r[n] = 0;
+	  MPN_INCR_U (r, n + 1, cy);
+	}
+    }
+}
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+static inline void
+mpn_fft_add_sub_modF (mp_ptr A0, mp_ptr Ai, mp_srcptr tp, mp_size_t n)
+{
+  mp_limb_t cyas, c, x;
+
+  cyas = mpn_add_n_sub_n (A0, Ai, A0, tp, n);
+
+  c = A0[n] - tp[n] - (cyas & 1);
+  x = (-c) & -((c & GMP_LIMB_HIGHBIT) != 0);
+  Ai[n] = x + c;
+  MPN_INCR_U (Ai, n + 1, x);
+
+  c = A0[n] + tp[n] + (cyas >> 1);
+  x = (c - 1) & -(c != 0);
+  A0[n] = c - x;
+  MPN_DECR_U (A0, n + 1, x);
+}
+
+#else /* ! HAVE_NATIVE_mpn_add_n_sub_n  */
+
+/* r <- a+b mod 2^(n*GMP_NUMB_BITS)+1.
+   Assumes a and b are semi-normalized.
+*/
+static inline void
+mpn_fft_add_modF (mp_ptr r, mp_srcptr a, mp_srcptr b, mp_size_t n)
+{
+  mp_limb_t c, x;
+
+  c = a[n] + b[n] + mpn_add_n (r, a, b, n);
+  /* 0 <= c <= 3 */
+
+#if 1
+  /* GCC 4.1 outsmarts most expressions here, and generates a 50% branch.  The
+     result is slower code, of course.  But the following outsmarts GCC.  */
+  x = (c - 1) & -(c != 0);
+  r[n] = c - x;
+  MPN_DECR_U (r, n + 1, x);
+#endif
+#if 0
+  if (c > 1)
+    {
+      r[n] = 1;                       /* r[n] - c = 1 */
+      MPN_DECR_U (r, n + 1, c - 1);
+    }
+  else
+    {
+      r[n] = c;
+    }
+#endif
+}
+
+/* r <- a-b mod 2^(n*GMP_NUMB_BITS)+1.
+   Assumes a and b are semi-normalized.
+*/
+static inline void
+mpn_fft_sub_modF (mp_ptr r, mp_srcptr a, mp_srcptr b, mp_size_t n)
+{
+  mp_limb_t c, x;
+
+  c = a[n] - b[n] - mpn_sub_n (r, a, b, n);
+  /* -2 <= c <= 1 */
+
+#if 1
+  /* GCC 4.1 outsmarts most expressions here, and generates a 50% branch.  The
+     result is slower code, of course.  But the following outsmarts GCC.  */
+  x = (-c) & -((c & GMP_LIMB_HIGHBIT) != 0);
+  r[n] = x + c;
+  MPN_INCR_U (r, n + 1, x);
+#endif
+#if 0
+  if ((c & GMP_LIMB_HIGHBIT) != 0)
+    {
+      r[n] = 0;
+      MPN_INCR_U (r, n + 1, -c);
+    }
+  else
+    {
+      r[n] = c;
+    }
+#endif
+}
+#endif /* HAVE_NATIVE_mpn_add_n_sub_n */
+
+/* input: A[0] ... A[inc*(K-1)] are residues mod 2^N+1 where
+	  N=n*GMP_NUMB_BITS, and 2^omega is a primitive root mod 2^N+1
+   output: A[inc*l[k][i]] <- \sum (2^omega)^(ij) A[inc*j] mod 2^N+1 */
+
+static void
+mpn_fft_fft (mp_ptr *Ap, mp_size_t K, int **ll,
+	     mp_size_t omega, mp_size_t n, mp_size_t inc, mp_ptr tp)
+{
+  if (K == 2)
+    {
+      mp_limb_t cy;
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      cy = mpn_add_n_sub_n (Ap[0], Ap[inc], Ap[0], Ap[inc], n + 1) & 1;
+#else
+      MPN_COPY (tp, Ap[0], n + 1);
+      mpn_add_n (Ap[0], Ap[0], Ap[inc], n + 1);
+      cy = mpn_sub_n (Ap[inc], tp, Ap[inc], n + 1);
+#endif
+      if (Ap[0][n] > 1) /* can be 2 or 3 */
+	{ /* Ap[0][n] = 1 - mpn_sub_1 (Ap[0], Ap[0], n, Ap[0][n] - 1); */
+	  mp_limb_t cc = Ap[0][n] - 1;
+	  Ap[0][n] = 1;
+	  MPN_DECR_U (Ap[0], n + 1, cc);
+	}
+      if (cy) /* Ap[inc][n] can be -1 or -2 */
+	{ /* Ap[inc][n] = mpn_add_1 (Ap[inc], Ap[inc], n, ~Ap[inc][n] + 1); */
+	  mp_limb_t cc = ~Ap[inc][n] + 1;
+	  Ap[inc][n] = 0;
+	  MPN_INCR_U (Ap[inc], n + 1, cc);
+	}
+    }
+  else
+    {
+      mp_size_t j, K2 = K >> 1;
+      int *lk = *ll;
+
+      mpn_fft_fft (Ap,     K2, ll-1, 2 * omega, n, inc * 2, tp);
+      mpn_fft_fft (Ap+inc, K2, ll-1, 2 * omega, n, inc * 2, tp);
+      /* A[2*j*inc]   <- A[2*j*inc] + omega^l[k][2*j*inc] A[(2j+1)inc]
+	 A[(2j+1)inc] <- A[2*j*inc] + omega^l[k][(2j+1)inc] A[(2j+1)inc] */
+      for (j = 0; j < K2; j++, lk += 2, Ap += 2 * inc)
+	{
+	  /* Ap[inc] <- Ap[0] + Ap[inc] * 2^(lk[1] * omega)
+	     Ap[0]   <- Ap[0] + Ap[inc] * 2^(lk[0] * omega) */
+	  mpn_fft_mul_2exp_modF (tp, Ap[inc], lk[0] * omega, n);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+	  mpn_fft_add_sub_modF (Ap[0], Ap[inc], tp, n);
+#else
+	  mpn_fft_sub_modF (Ap[inc], Ap[0], tp, n);
+	  mpn_fft_add_modF (Ap[0],   Ap[0], tp, n);
+#endif
+	}
+    }
+}
+
+/* input: A[0] ... A[inc*(K-1)] are residues mod 2^N+1 where
+	  N=n*GMP_NUMB_BITS, and 2^omega is a primitive root mod 2^N+1
+   output: A[inc*l[k][i]] <- \sum (2^omega)^(ij) A[inc*j] mod 2^N+1
+   tp must have space for 2*(n+1) limbs.
+*/
+
+
+/* Given ap[0..n] with ap[n]<=1, reduce it modulo 2^(n*GMP_NUMB_BITS)+1,
+   by subtracting that modulus if necessary.
+
+   If ap[0..n] is exactly 2^(n*GMP_NUMB_BITS) then mpn_sub_1 produces a
+   borrow and the limbs must be zeroed out again.  This will occur very
+   infrequently.  */
+
+static inline void
+mpn_fft_normalize (mp_ptr ap, mp_size_t n)
+{
+  if (ap[n] != 0)
+    {
+      MPN_DECR_U (ap, n + 1, CNST_LIMB(1));
+      if (ap[n] == 0)
+	{
+	  /* This happens with very low probability; we have yet to trigger it,
+	     and thereby make sure this code is correct.  */
+	  MPN_ZERO (ap, n);
+	  ap[n] = 1;
+	}
+      else
+	ap[n] = 0;
+    }
+}
+
+/* a[i] <- a[i]*b[i] mod 2^(n*GMP_NUMB_BITS)+1 for 0 <= i < K */
+static void
+mpn_fft_mul_modF_K (mp_ptr *ap, mp_ptr *bp, mp_size_t n, mp_size_t K)
+{
+  int i;
+  unsigned k;
+  int sqr = (ap == bp);
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (n >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_size_t K2, nprime2, Nprime2, M2, maxLK, l, Mp2;
+      int k;
+      int **fft_l, *tmp;
+      mp_ptr *Ap, *Bp, A, B, T;
+
+      k = mpn_fft_best_k (n, sqr);
+      K2 = (mp_size_t) 1 << k;
+      ASSERT_ALWAYS((n & (K2 - 1)) == 0);
+      maxLK = (K2 > GMP_NUMB_BITS) ? K2 : GMP_NUMB_BITS;
+      M2 = n * GMP_NUMB_BITS >> k;
+      l = n >> k;
+      Nprime2 = ((2 * M2 + k + 2 + maxLK) / maxLK) * maxLK;
+      /* Nprime2 = ceil((2*M2+k+3)/maxLK)*maxLK*/
+      nprime2 = Nprime2 / GMP_NUMB_BITS;
+
+      /* we should ensure that nprime2 is a multiple of the next K */
+      if (nprime2 >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+	{
+	  mp_size_t K3;
+	  for (;;)
+	    {
+	      K3 = (mp_size_t) 1 << mpn_fft_best_k (nprime2, sqr);
+	      if ((nprime2 & (K3 - 1)) == 0)
+		break;
+	      nprime2 = (nprime2 + K3 - 1) & -K3;
+	      Nprime2 = nprime2 * GMP_LIMB_BITS;
+	      /* warning: since nprime2 changed, K3 may change too! */
+	    }
+	}
+      ASSERT_ALWAYS(nprime2 < n); /* otherwise we'll loop */
+
+      Mp2 = Nprime2 >> k;
+
+      Ap = TMP_BALLOC_MP_PTRS (K2);
+      Bp = TMP_BALLOC_MP_PTRS (K2);
+      A = TMP_BALLOC_LIMBS (2 * (nprime2 + 1) << k);
+      T = TMP_BALLOC_LIMBS (2 * (nprime2 + 1));
+      B = A + ((nprime2 + 1) << k);
+      fft_l = TMP_BALLOC_TYPE (k + 1, int *);
+      tmp = TMP_BALLOC_TYPE ((size_t) 2 << k, int);
+      for (i = 0; i <= k; i++)
+	{
+	  fft_l[i] = tmp;
+	  tmp += (mp_size_t) 1 << i;
+	}
+
+      mpn_fft_initl (fft_l, k);
+
+      TRACE (printf ("recurse: %ldx%ld limbs -> %ld times %ldx%ld (%1.2f)\n", n,
+		    n, K2, nprime2, nprime2, 2.0*(double)n/nprime2/K2));
+      for (i = 0; i < K; i++, ap++, bp++)
+	{
+	  mp_limb_t cy;
+	  mpn_fft_normalize (*ap, n);
+	  if (!sqr)
+	    mpn_fft_normalize (*bp, n);
+
+	  mpn_mul_fft_decompose (A, Ap, K2, nprime2, *ap, (l << k) + 1, l, Mp2, T);
+	  if (!sqr)
+	    mpn_mul_fft_decompose (B, Bp, K2, nprime2, *bp, (l << k) + 1, l, Mp2, T);
+
+	  cy = mpn_mul_fft_internal (*ap, n, k, Ap, Bp, A, B, nprime2,
+				     l, Mp2, fft_l, T, sqr);
+	  (*ap)[n] = cy;
+	}
+    }
+#if ! TUNE_PROGRAM_BUILD
+  else if (MPN_MULMOD_BKNP1_USABLE (n, k, MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_ptr a;
+      mp_size_t n_k = n / k;
+
+      if (sqr)
+       {
+	 mp_ptr tp = TMP_SALLOC_LIMBS (mpn_sqrmod_bknp1_itch (n));
+         for (i = 0; i < K; i++)
+           {
+             a = *ap++;
+             mpn_sqrmod_bknp1 (a, a, n_k, k, tp);
+           }
+       }
+      else
+       {
+	 mp_ptr b, tp = TMP_SALLOC_LIMBS (mpn_mulmod_bknp1_itch (n));
+         for (i = 0; i < K; i++)
+           {
+             a = *ap++;
+             b = *bp++;
+             mpn_mulmod_bknp1 (a, a, b, n_k, k, tp);
+           }
+       }
+    }
+#endif
+  else
+    {
+      mp_ptr a, b, tp, tpn;
+      mp_limb_t cc;
+      mp_size_t n2 = 2 * n;
+      tp = TMP_BALLOC_LIMBS (n2);
+      tpn = tp + n;
+      TRACE (printf ("  mpn_mul_n %ld of %ld limbs\n", K, n));
+      for (i = 0; i < K; i++)
+	{
+	  a = *ap++;
+	  b = *bp++;
+	  if (sqr)
+	    mpn_sqr (tp, a, n);
+	  else
+	    mpn_mul_n (tp, b, a, n);
+	  if (a[n] != 0)
+	    cc = mpn_add_n (tpn, tpn, b, n);
+	  else
+	    cc = 0;
+	  if (b[n] != 0)
+	    cc += mpn_add_n (tpn, tpn, a, n) + a[n];
+	  if (cc != 0)
+	    {
+	      cc = mpn_add_1 (tp, tp, n2, cc);
+	      /* If mpn_add_1 give a carry (cc != 0),
+		 the result (tp) is at most GMP_NUMB_MAX - 1,
+		 so the following addition can't overflow.
+	      */
+	      tp[0] += cc;
+	    }
+	  cc = mpn_sub_n (a, tp, tpn, n);
+	  a[n] = 0;
+	  MPN_INCR_U (a, n + 1, cc);
+	}
+    }
+  TMP_FREE;
+}
+
+
+/* input: A^[l[k][0]] A^[l[k][1]] ... A^[l[k][K-1]]
+   output: K*A[0] K*A[K-1] ... K*A[1].
+   Assumes the Ap[] are pseudo-normalized, i.e. 0 <= Ap[][n] <= 1.
+   This condition is also fulfilled at exit.
+*/
+static void
+mpn_fft_fftinv (mp_ptr *Ap, mp_size_t K, mp_size_t omega, mp_size_t n, mp_ptr tp)
+{
+  if (K == 2)
+    {
+      mp_limb_t cy;
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      cy = mpn_add_n_sub_n (Ap[0], Ap[1], Ap[0], Ap[1], n + 1) & 1;
+#else
+      MPN_COPY (tp, Ap[0], n + 1);
+      mpn_add_n (Ap[0], Ap[0], Ap[1], n + 1);
+      cy = mpn_sub_n (Ap[1], tp, Ap[1], n + 1);
+#endif
+      if (Ap[0][n] > 1) /* can be 2 or 3 */
+	{ /* Ap[0][n] = 1 - mpn_sub_1 (Ap[0], Ap[0], n, Ap[0][n] - 1); */
+	  mp_limb_t cc = Ap[0][n] - 1;
+	  Ap[0][n] = 1;
+	  MPN_DECR_U (Ap[0], n + 1, cc);
+	}
+      if (cy) /* Ap[1][n] can be -1 or -2 */
+	{ /* Ap[1][n] = mpn_add_1 (Ap[1], Ap[1], n, ~Ap[1][n] + 1); */
+	  mp_limb_t cc = ~Ap[1][n] + 1;
+	  Ap[1][n] = 0;
+	  MPN_INCR_U (Ap[1], n + 1, cc);
+	}
+    }
+  else
+    {
+      mp_size_t j, K2 = K >> 1;
+
+      mpn_fft_fftinv (Ap,      K2, 2 * omega, n, tp);
+      mpn_fft_fftinv (Ap + K2, K2, 2 * omega, n, tp);
+      /* A[j]     <- A[j] + omega^j A[j+K/2]
+	 A[j+K/2] <- A[j] + omega^(j+K/2) A[j+K/2] */
+      for (j = 0; j < K2; j++, Ap++)
+	{
+	  /* Ap[K2] <- Ap[0] + Ap[K2] * 2^((j + K2) * omega)
+	     Ap[0]  <- Ap[0] + Ap[K2] * 2^(j * omega) */
+	  mpn_fft_mul_2exp_modF (tp, Ap[K2], j * omega, n);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+	  mpn_fft_add_sub_modF (Ap[0], Ap[K2], tp, n);
+#else
+	  mpn_fft_sub_modF (Ap[K2], Ap[0], tp, n);
+	  mpn_fft_add_modF (Ap[0],  Ap[0], tp, n);
+#endif
+	}
+    }
+}
+
+
+/* R <- A/2^k mod 2^(n*GMP_NUMB_BITS)+1 */
+static void
+mpn_fft_div_2exp_modF (mp_ptr r, mp_srcptr a, mp_bitcnt_t k, mp_size_t n)
+{
+  mp_bitcnt_t i;
+
+  ASSERT (r != a);
+  i = (mp_bitcnt_t) 2 * n * GMP_NUMB_BITS - k;
+  mpn_fft_mul_2exp_modF (r, a, i, n);
+  /* 1/2^k = 2^(2nL-k) mod 2^(n*GMP_NUMB_BITS)+1 */
+  /* normalize so that R < 2^(n*GMP_NUMB_BITS)+1 */
+  mpn_fft_normalize (r, n);
+}
+
+
+/* {rp,n} <- {ap,an} mod 2^(n*GMP_NUMB_BITS)+1, n <= an <= 3*n.
+   Returns carry out, i.e. 1 iff {ap,an} = -1 mod 2^(n*GMP_NUMB_BITS)+1,
+   then {rp,n}=0.
+*/
+static mp_size_t
+mpn_fft_norm_modF (mp_ptr rp, mp_size_t n, mp_ptr ap, mp_size_t an)
+{
+  mp_size_t l, m, rpn;
+  mp_limb_t cc;
+
+  ASSERT ((n <= an) && (an <= 3 * n));
+  m = an - 2 * n;
+  if (m > 0)
+    {
+      l = n;
+      /* add {ap, m} and {ap+2n, m} in {rp, m} */
+      cc = mpn_add_n (rp, ap, ap + 2 * n, m);
+      /* copy {ap+m, n-m} to {rp+m, n-m} */
+      rpn = mpn_add_1 (rp + m, ap + m, n - m, cc);
+    }
+  else
+    {
+      l = an - n; /* l <= n */
+      MPN_COPY (rp, ap, n);
+      rpn = 0;
+    }
+
+  /* remains to subtract {ap+n, l} from {rp, n+1} */
+  rpn -= mpn_sub (rp, rp, n, ap + n, l);
+  if (rpn < 0) /* necessarily rpn = -1 */
+    rpn = mpn_add_1 (rp, rp, n, CNST_LIMB(1));
+  return rpn;
+}
+
+/* store in A[0..nprime] the first M bits from {n, nl},
+   in A[nprime+1..] the following M bits, ...
+   Assumes M is a multiple of GMP_NUMB_BITS (M = l * GMP_NUMB_BITS).
+   T must have space for at least (nprime + 1) limbs.
+   We must have nl <= 2*K*l.
+*/
+static void
+mpn_mul_fft_decompose (mp_ptr A, mp_ptr *Ap, mp_size_t K, mp_size_t nprime,
+		       mp_srcptr n, mp_size_t nl, mp_size_t l, mp_size_t Mp,
+		       mp_ptr T)
+{
+  mp_size_t i, j;
+  mp_ptr tmp;
+  mp_size_t Kl = K * l;
+  TMP_DECL;
+  TMP_MARK;
+
+  if (nl > Kl) /* normalize {n, nl} mod 2^(Kl*GMP_NUMB_BITS)+1 */
+    {
+      mp_size_t dif = nl - Kl;
+
+      tmp = TMP_BALLOC_LIMBS(Kl + 1);
+      tmp[Kl] = 0;
+
+#if ! WANT_OLD_FFT_FULL
+      ASSERT_ALWAYS (dif <= Kl);
+#else
+      /* The comment "We must have nl <= 2*K*l." says that
+	 ((dif = nl - Kl) > Kl) should never happen. */
+      if (UNLIKELY (dif > Kl))
+	{
+	  mp_limb_signed_t cy;
+	  int subp = 0;
+
+	  cy = mpn_sub_n (tmp, n, n + Kl, Kl);
+	  n += 2 * Kl;
+	  dif -= Kl;
+
+	  /* now dif > 0 */
+	  while (dif > Kl)
+	    {
+	      if (subp)
+		cy += mpn_sub_n (tmp, tmp, n, Kl);
+	      else
+		cy -= mpn_add_n (tmp, tmp, n, Kl);
+	      subp ^= 1;
+	      n += Kl;
+	      dif -= Kl;
+	    }
+	  /* now dif <= Kl */
+	  if (subp)
+	    cy += mpn_sub (tmp, tmp, Kl, n, dif);
+	  else
+	    cy -= mpn_add (tmp, tmp, Kl, n, dif);
+	  if (cy >= 0)
+	    MPN_INCR_U (tmp, Kl + 1, cy);
+	  else
+	    {
+	      tmp[Kl] = 1;
+	      MPN_DECR_U (tmp, Kl + 1, -cy - 1);
+	    }
+	}
+      else /* dif <= Kl, i.e. nl <= 2 * Kl */
+#endif
+	{
+	  mp_limb_t cy;
+	  cy = mpn_sub (tmp, n, Kl, n + Kl, dif);
+	  MPN_INCR_U (tmp, Kl + 1, cy);
+	}
+      nl = Kl + 1;
+      n = tmp;
+    }
+  for (i = 0; i < K; i++)
+    {
+      Ap[i] = A;
+      /* store the next M bits of n into A[0..nprime] */
+      if (nl > 0) /* nl is the number of remaining limbs */
+	{
+	  j = (l <= nl && i < K - 1) ? l : nl; /* store j next limbs */
+	  nl -= j;
+	  MPN_COPY (T, n, j);
+	  MPN_ZERO (T + j, nprime + 1 - j);
+	  n += l;
+	  mpn_fft_mul_2exp_modF (A, T, i * Mp, nprime);
+	}
+      else
+	MPN_ZERO (A, nprime + 1);
+      A += nprime + 1;
+    }
+  ASSERT_ALWAYS (nl == 0);
+  TMP_FREE;
+}
+
+/* op <- n*m mod 2^N+1 with fft of size 2^k where N=pl*GMP_NUMB_BITS
+   op is pl limbs, its high bit is returned.
+   One must have pl = mpn_fft_next_size (pl, k).
+   T must have space for 2 * (nprime + 1) limbs.
+*/
+
+static mp_limb_t
+mpn_mul_fft_internal (mp_ptr op, mp_size_t pl, int k,
+		      mp_ptr *Ap, mp_ptr *Bp, mp_ptr unusedA, mp_ptr B,
+		      mp_size_t nprime, mp_size_t l, mp_size_t Mp,
+		      int **fft_l, mp_ptr T, int sqr)
+{
+  mp_size_t K, i, pla, lo, sh, j;
+  mp_ptr p;
+  mp_limb_t cc;
+
+  K = (mp_size_t) 1 << k;
+
+  /* direct fft's */
+  mpn_fft_fft (Ap, K, fft_l + k, 2 * Mp, nprime, 1, T);
+  if (!sqr)
+    mpn_fft_fft (Bp, K, fft_l + k, 2 * Mp, nprime, 1, T);
+
+  /* term to term multiplications */
+  mpn_fft_mul_modF_K (Ap, sqr ? Ap : Bp, nprime, K);
+
+  /* inverse fft's */
+  mpn_fft_fftinv (Ap, K, 2 * Mp, nprime, T);
+
+  /* division of terms after inverse fft */
+  Bp[0] = T + nprime + 1;
+  mpn_fft_div_2exp_modF (Bp[0], Ap[0], k, nprime);
+  for (i = 1; i < K; i++)
+    {
+      Bp[i] = Ap[i - 1];
+      mpn_fft_div_2exp_modF (Bp[i], Ap[i], k + (K - i) * Mp, nprime);
+    }
+
+  /* addition of terms in result p */
+  MPN_ZERO (T, nprime + 1);
+  pla = l * (K - 1) + nprime + 1; /* number of required limbs for p */
+  p = B; /* B has K*(n' + 1) limbs, which is >= pla, i.e. enough */
+  MPN_ZERO (p, pla);
+  cc = 0; /* will accumulate the (signed) carry at p[pla] */
+  for (i = K - 1, lo = l * i + nprime,sh = l * i; i >= 0; i--,lo -= l,sh -= l)
+    {
+      mp_ptr n = p + sh;
+
+      j = (K - i) & (K - 1);
+
+      cc += mpn_add (n, n, pla - sh, Bp[j], nprime + 1);
+      T[2 * l] = i + 1; /* T = (i + 1)*2^(2*M) */
+      if (mpn_cmp (Bp[j], T, nprime + 1) > 0)
+	{ /* subtract 2^N'+1 */
+	  cc -= mpn_sub_1 (n, n, pla - sh, CNST_LIMB(1));
+	  cc -= mpn_sub_1 (p + lo, p + lo, pla - lo, CNST_LIMB(1));
+	}
+    }
+  if (cc == -CNST_LIMB(1))
+    {
+      if ((cc = mpn_add_1 (p + pla - pl, p + pla - pl, pl, CNST_LIMB(1))))
+	{
+	  /* p[pla-pl]...p[pla-1] are all zero */
+	  mpn_sub_1 (p + pla - pl - 1, p + pla - pl - 1, pl + 1, CNST_LIMB(1));
+	  mpn_sub_1 (p + pla - 1, p + pla - 1, 1, CNST_LIMB(1));
+	}
+    }
+  else if (cc == 1)
+    {
+      if (pla >= 2 * pl)
+	{
+	  while ((cc = mpn_add_1 (p + pla - 2 * pl, p + pla - 2 * pl, 2 * pl, cc)))
+	    ;
+	}
+      else
+	{
+	  MPN_DECR_U (p + pla - pl, pl, cc);
+	}
+    }
+  else
+    ASSERT (cc == 0);
+
+  /* here p < 2^(2M) [K 2^(M(K-1)) + (K-1) 2^(M(K-2)) + ... ]
+     < K 2^(2M) [2^(M(K-1)) + 2^(M(K-2)) + ... ]
+     < K 2^(2M) 2^(M(K-1))*2 = 2^(M*K+M+k+1) */
+  return mpn_fft_norm_modF (op, pl, p, pla);
+}
+
+/* return the lcm of a and 2^k */
+static mp_bitcnt_t
+mpn_mul_fft_lcm (mp_bitcnt_t a, int k)
+{
+  mp_bitcnt_t l = k;
+
+  while (a % 2 == 0 && k > 0)
+    {
+      a >>= 1;
+      k --;
+    }
+  return a << l;
+}
+
+
+mp_limb_t
+mpn_mul_fft (mp_ptr op, mp_size_t pl,
+	     mp_srcptr n, mp_size_t nl,
+	     mp_srcptr m, mp_size_t ml,
+	     int k)
+{
+  int i;
+  mp_size_t K, maxLK;
+  mp_size_t N, Nprime, nprime, M, Mp, l;
+  mp_ptr *Ap, *Bp, A, T, B;
+  int **fft_l, *tmp;
+  int sqr = (n == m && nl == ml);
+  mp_limb_t h;
+  TMP_DECL;
+
+  TRACE (printf ("\nmpn_mul_fft pl=%ld nl=%ld ml=%ld k=%d\n", pl, nl, ml, k));
+  ASSERT_ALWAYS (mpn_fft_next_size (pl, k) == pl);
+
+  TMP_MARK;
+  N = pl * GMP_NUMB_BITS;
+  fft_l = TMP_BALLOC_TYPE (k + 1, int *);
+  tmp = TMP_BALLOC_TYPE ((size_t) 2 << k, int);
+  for (i = 0; i <= k; i++)
+    {
+      fft_l[i] = tmp;
+      tmp += (mp_size_t) 1 << i;
+    }
+
+  mpn_fft_initl (fft_l, k);
+  K = (mp_size_t) 1 << k;
+  M = N >> k;	/* N = 2^k M */
+  l = 1 + (M - 1) / GMP_NUMB_BITS;
+  maxLK = mpn_mul_fft_lcm (GMP_NUMB_BITS, k); /* lcm (GMP_NUMB_BITS, 2^k) */
+
+  Nprime = (1 + (2 * M + k + 2) / maxLK) * maxLK;
+  /* Nprime = ceil((2*M+k+3)/maxLK)*maxLK; */
+  nprime = Nprime / GMP_NUMB_BITS;
+  TRACE (printf ("N=%ld K=%ld, M=%ld, l=%ld, maxLK=%ld, Np=%ld, np=%ld\n",
+		 N, K, M, l, maxLK, Nprime, nprime));
+  /* we should ensure that recursively, nprime is a multiple of the next K */
+  if (nprime >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_size_t K2;
+      for (;;)
+	{
+	  K2 = (mp_size_t) 1 << mpn_fft_best_k (nprime, sqr);
+	  if ((nprime & (K2 - 1)) == 0)
+	    break;
+	  nprime = (nprime + K2 - 1) & -K2;
+	  Nprime = nprime * GMP_LIMB_BITS;
+	  /* warning: since nprime changed, K2 may change too! */
+	}
+      TRACE (printf ("new maxLK=%ld, Np=%ld, np=%ld\n", maxLK, Nprime, nprime));
+    }
+  ASSERT_ALWAYS (nprime < pl); /* otherwise we'll loop */
+
+  T = TMP_BALLOC_LIMBS (2 * (nprime + 1));
+  Mp = Nprime >> k;
+
+  TRACE (printf ("%ldx%ld limbs -> %ld times %ldx%ld limbs (%1.2f)\n",
+		pl, pl, K, nprime, nprime, 2.0 * (double) N / Nprime / K);
+	 printf ("   temp space %ld\n", 2 * K * (nprime + 1)));
+
+  A = TMP_BALLOC_LIMBS (K * (nprime + 1));
+  Ap = TMP_BALLOC_MP_PTRS (K);
+  Bp = TMP_BALLOC_MP_PTRS (K);
+  mpn_mul_fft_decompose (A, Ap, K, nprime, n, nl, l, Mp, T);
+  if (sqr)
+    {
+      mp_size_t pla;
+      pla = l * (K - 1) + nprime + 1; /* number of required limbs for p */
+      B = TMP_BALLOC_LIMBS (pla);
+    }
+  else
+    {
+      B = TMP_BALLOC_LIMBS (K * (nprime + 1));
+      mpn_mul_fft_decompose (B, Bp, K, nprime, m, ml, l, Mp, T);
+    }
+  h = mpn_mul_fft_internal (op, pl, k, Ap, Bp, A, B, nprime, l, Mp, fft_l, T, sqr);
+
+  TMP_FREE;
+  return h;
+}
+
+#if WANT_OLD_FFT_FULL
+/* multiply {n, nl} by {m, ml}, and put the result in {op, nl+ml} */
+void
+mpn_mul_fft_full (mp_ptr op,
+		  mp_srcptr n, mp_size_t nl,
+		  mp_srcptr m, mp_size_t ml)
+{
+  mp_ptr pad_op;
+  mp_size_t pl, pl2, pl3, l;
+  mp_size_t cc, c2, oldcc;
+  int k2, k3;
+  int sqr = (n == m && nl == ml);
+
+  pl = nl + ml; /* total number of limbs of the result */
+
+  /* perform a fft mod 2^(2N)+1 and one mod 2^(3N)+1.
+     We must have pl3 = 3/2 * pl2, with pl2 a multiple of 2^k2, and
+     pl3 a multiple of 2^k3. Since k3 >= k2, both are multiples of 2^k2,
+     and pl2 must be an even multiple of 2^k2. Thus (pl2,pl3) =
+     (2*j*2^k2,3*j*2^k2), which works for 3*j <= pl/2^k2 <= 5*j.
+     We need that consecutive intervals overlap, i.e. 5*j >= 3*(j+1),
+     which requires j>=2. Thus this scheme requires pl >= 6 * 2^FFT_FIRST_K. */
+
+  /*  ASSERT_ALWAYS(pl >= 6 * (1 << FFT_FIRST_K)); */
+
+  pl2 = (2 * pl - 1) / 5; /* ceil (2pl/5) - 1 */
+  do
+    {
+      pl2++;
+      k2 = mpn_fft_best_k (pl2, sqr); /* best fft size for pl2 limbs */
+      pl2 = mpn_fft_next_size (pl2, k2);
+      pl3 = 3 * pl2 / 2; /* since k>=FFT_FIRST_K=4, pl2 is a multiple of 2^4,
+			    thus pl2 / 2 is exact */
+      k3 = mpn_fft_best_k (pl3, sqr);
+    }
+  while (mpn_fft_next_size (pl3, k3) != pl3);
+
+  TRACE (printf ("mpn_mul_fft_full nl=%ld ml=%ld -> pl2=%ld pl3=%ld k=%d\n",
+		 nl, ml, pl2, pl3, k2));
+
+  ASSERT_ALWAYS(pl3 <= pl);
+  cc = mpn_mul_fft (op, pl3, n, nl, m, ml, k3);     /* mu */
+  ASSERT(cc == 0);
+  pad_op = __GMP_ALLOCATE_FUNC_LIMBS (pl2);
+  cc = mpn_mul_fft (pad_op, pl2, n, nl, m, ml, k2); /* lambda */
+  cc = -cc + mpn_sub_n (pad_op, pad_op, op, pl2);    /* lambda - low(mu) */
+  /* 0 <= cc <= 1 */
+  ASSERT(0 <= cc && cc <= 1);
+  l = pl3 - pl2; /* l = pl2 / 2 since pl3 = 3/2 * pl2 */
+  c2 = mpn_add_n (pad_op, pad_op, op + pl2, l);
+  cc = mpn_add_1 (pad_op + l, pad_op + l, l, (mp_limb_t) c2) - cc;
+  ASSERT(-1 <= cc && cc <= 1);
+  if (cc < 0)
+    cc = mpn_add_1 (pad_op, pad_op, pl2, (mp_limb_t) -cc);
+  ASSERT(0 <= cc && cc <= 1);
+  /* now lambda-mu = {pad_op, pl2} - cc mod 2^(pl2*GMP_NUMB_BITS)+1 */
+  oldcc = cc;
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  c2 = mpn_add_n_sub_n (pad_op + l, pad_op, pad_op, pad_op + l, l);
+  cc += c2 >> 1; /* carry out from high <- low + high */
+  c2 = c2 & 1; /* borrow out from low <- low - high */
+#else
+  {
+    mp_ptr tmp;
+    TMP_DECL;
+
+    TMP_MARK;
+    tmp = TMP_BALLOC_LIMBS (l);
+    MPN_COPY (tmp, pad_op, l);
+    c2 = mpn_sub_n (pad_op,      pad_op, pad_op + l, l);
+    cc += mpn_add_n (pad_op + l, tmp,    pad_op + l, l);
+    TMP_FREE;
+  }
+#endif
+  c2 += oldcc;
+  /* first normalize {pad_op, pl2} before dividing by 2: c2 is the borrow
+     at pad_op + l, cc is the carry at pad_op + pl2 */
+  /* 0 <= cc <= 2 */
+  cc -= mpn_sub_1 (pad_op + l, pad_op + l, l, (mp_limb_t) c2);
+  /* -1 <= cc <= 2 */
+  if (cc > 0)
+    cc = -mpn_sub_1 (pad_op, pad_op, pl2, (mp_limb_t) cc);
+  /* now -1 <= cc <= 0 */
+  if (cc < 0)
+    cc = mpn_add_1 (pad_op, pad_op, pl2, (mp_limb_t) -cc);
+  /* now {pad_op, pl2} is normalized, with 0 <= cc <= 1 */
+  if (pad_op[0] & 1) /* if odd, add 2^(pl2*GMP_NUMB_BITS)+1 */
+    cc += 1 + mpn_add_1 (pad_op, pad_op, pl2, CNST_LIMB(1));
+  /* now 0 <= cc <= 2, but cc=2 cannot occur since it would give a carry
+     out below */
+  mpn_rshift (pad_op, pad_op, pl2, 1); /* divide by two */
+  if (cc) /* then cc=1 */
+    pad_op [pl2 - 1] |= (mp_limb_t) 1 << (GMP_NUMB_BITS - 1);
+  /* now {pad_op,pl2}-cc = (lambda-mu)/(1-2^(l*GMP_NUMB_BITS))
+     mod 2^(pl2*GMP_NUMB_BITS) + 1 */
+  c2 = mpn_add_n (op, op, pad_op, pl2); /* no need to add cc (is 0) */
+  /* since pl2+pl3 >= pl, necessary the extra limbs (including cc) are zero */
+  MPN_COPY (op + pl3, pad_op, pl - pl3);
+  ASSERT_MPN_ZERO_P (pad_op + pl - pl3, pl2 + pl3 - pl);
+  __GMP_FREE_FUNC_LIMBS (pad_op, pl2);
+  /* since the final result has at most pl limbs, no carry out below */
+  MPN_INCR_U (op + pl2, pl - pl2, (mp_limb_t) c2);
+}
+#endif
diff --git a/mpn/generic/mul_n.c b/mpn/generic/mul_n.c
new file mode 100644
index 0000000..36bd923
--- /dev/null
+++ b/mpn/generic/mul_n.c
@@ -0,0 +1,96 @@
+/* mpn_mul_n -- multiply natural numbers.
+
+Copyright 1991, 1993, 1994, 1996-2003, 2005, 2008, 2009 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mul_n (mp_ptr p, mp_srcptr a, mp_srcptr b, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (p, 2 * n, a, n));
+  ASSERT (! MPN_OVERLAP_P (p, 2 * n, b, n));
+
+  if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+    {
+      mpn_mul_basecase (p, a, n, b, n);
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))
+    {
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t ws[mpn_toom22_mul_itch (MUL_TOOM33_THRESHOLD_LIMIT-1,
+					MUL_TOOM33_THRESHOLD_LIMIT-1)];
+      ASSERT (MUL_TOOM33_THRESHOLD <= MUL_TOOM33_THRESHOLD_LIMIT);
+      mpn_toom22_mul (p, a, n, b, n, ws);
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom33_mul_itch (n, n));
+      mpn_toom33_mul (p, a, n, b, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom44_mul_itch (n, n));
+      mpn_toom44_mul (p, a, n, b, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM8H_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom6_mul_n_itch (n));
+      mpn_toom6h_mul (p, a, n, b, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, MUL_FFT_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_DECL;
+      TMP_MARK;
+      ws = TMP_ALLOC_LIMBS (mpn_toom8_mul_n_itch (n));
+      mpn_toom8h_mul (p, a, n, b, n, ws);
+      TMP_FREE;
+    }
+  else
+    {
+      /* The current FFT code allocates its own space.  That should probably
+	 change.  */
+      mpn_fft_mul (p, a, n, b, n);
+    }
+}
diff --git a/mpn/generic/mullo_basecase.c b/mpn/generic/mullo_basecase.c
new file mode 100644
index 0000000..9a4cd3d
--- /dev/null
+++ b/mpn/generic/mullo_basecase.c
@@ -0,0 +1,90 @@
+/* mpn_mullo_basecase -- Internal routine to multiply two natural
+   numbers of length n and return the low part.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+
+Copyright (C) 2000, 2002, 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* FIXME: Should optionally use mpn_mul_2/mpn_addmul_2.  */
+
+#ifndef MULLO_VARIANT
+#define MULLO_VARIANT 2
+#endif
+
+
+#if MULLO_VARIANT == 1
+void
+mpn_mullo_basecase (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_size_t i;
+
+  mpn_mul_1 (rp, up, n, vp[0]);
+
+  for (i = n - 1; i > 0; i--)
+    {
+      vp++;
+      rp++;
+      mpn_addmul_1 (rp, up, i, vp[0]);
+    }
+}
+#endif
+
+
+#if MULLO_VARIANT == 2
+void
+mpn_mullo_basecase (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t h;
+
+  h = up[0] * vp[n - 1];
+
+  if (n != 1)
+    {
+      mp_size_t i;
+      mp_limb_t v0;
+
+      v0 = *vp++;
+      h += up[n - 1] * v0 + mpn_mul_1 (rp, up, n - 1, v0);
+      rp++;
+
+      for (i = n - 2; i > 0; i--)
+	{
+	  v0 = *vp++;
+	  h += up[i] * v0 + mpn_addmul_1 (rp, up, i, v0);
+	  rp++;
+	}
+    }
+
+  rp[0] = h;
+}
+#endif
diff --git a/mpn/generic/mullo_n.c b/mpn/generic/mullo_n.c
new file mode 100644
index 0000000..6f4e7ae
--- /dev/null
+++ b/mpn/generic/mullo_n.c
@@ -0,0 +1,243 @@
+/* mpn_mullo_n -- multiply two n-limb numbers and return the low n limbs
+   of their products.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THIS IS (FOR NOW) AN INTERNAL FUNCTION.  IT IS ONLY SAFE TO REACH THIS
+   FUNCTION THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST GUARANTEED
+   THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2004, 2005, 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_range_basecase 1
+#define MAYBE_range_toom22   1
+#else
+#define MAYBE_range_basecase                                           \
+  ((MULLO_DC_THRESHOLD == 0 ? MULLO_BASECASE_THRESHOLD : MULLO_DC_THRESHOLD) < MUL_TOOM22_THRESHOLD*36/(36-11))
+#define MAYBE_range_toom22                                             \
+  ((MULLO_DC_THRESHOLD == 0 ? MULLO_BASECASE_THRESHOLD : MULLO_DC_THRESHOLD) < MUL_TOOM33_THRESHOLD*36/(36-11) )
+#endif
+
+/*  THINK: The DC strategy uses different constants in different Toom's
+	 ranges. Something smoother?
+*/
+
+/*
+  Compute the least significant half of the product {xy,n}*{yp,n}, or
+  formally {rp,n} = {xy,n}*{yp,n} Mod (B^n).
+
+  Above the given threshold, the Divide and Conquer strategy is used.
+  The operands are split in two, and a full product plus two mullo
+  are used to obtain the final result. The more natural strategy is to
+  split in two halves, but this is far from optimal when a
+  sub-quadratic multiplication is used.
+
+  Mulders suggests an unbalanced split in favour of the full product,
+  split n = n1 + n2, where an = n1 <= n2 = (1-a)n; i.e. 0 < a <= 1/2.
+
+  To compute the value of a, we assume that the cost of mullo for a
+  given size ML(n) is a fraction of the cost of a full product with
+  same size M(n), and the cost M(n)=n^e for some exponent 1 < e <= 2;
+  then we can write:
+
+  ML(n) = 2*ML(an) + M((1-a)n) => k*M(n) = 2*k*M(n)*a^e + M(n)*(1-a)^e
+
+  Given a value for e, want to minimise the value of k, i.e. the
+  function k=(1-a)^e/(1-2*a^e).
+
+  With e=2, the exponent for schoolbook multiplication, the minimum is
+  given by the values a=1-a=1/2.
+
+  With e=log(3)/log(2), the exponent for Karatsuba (aka toom22),
+  Mulders compute (1-a) = 0.694... and we approximate a with 11/36.
+
+  Other possible approximations follow:
+  e=log(5)/log(3) [Toom-3] -> a ~= 9/40
+  e=log(7)/log(4) [Toom-4] -> a ~= 7/39
+  e=log(11)/log(6) [Toom-6] -> a ~= 1/8
+  e=log(15)/log(8) [Toom-8] -> a ~= 1/10
+
+  The values above where obtained with the following trivial commands
+  in the gp-pari shell:
+
+fun(e,a)=(1-a)^e/(1-2*a^e)
+mul(a,b,c)={local(m,x,p);if(b-c<1/10000,(b+c)/2,m=1;x=b;forstep(p=c,b,(b-c)/8,if(fun(a,p)<m,m=fun(a,p);x=p));mul(a,(b+x)/2,(c+x)/2))}
+contfracpnqn(contfrac(mul(log(2*2-1)/log(2),1/2,0),5))
+contfracpnqn(contfrac(mul(log(3*2-1)/log(3),1/2,0),5))
+contfracpnqn(contfrac(mul(log(4*2-1)/log(4),1/2,0),5))
+contfracpnqn(contfrac(mul(log(6*2-1)/log(6),1/2,0),3))
+contfracpnqn(contfrac(mul(log(8*2-1)/log(8),1/2,0),3))
+
+  ,
+  |\
+  | \
+  +----,
+  |    |
+  |    |
+  |    |\
+  |    | \
+  +----+--`
+  ^ n2 ^n1^
+
+  For an actual implementation, the assumption that M(n)=n^e is
+  incorrect, as a consequence also the assumption that ML(n)=k*M(n)
+  with a constant k is wrong.
+
+  But theory suggest us two things:
+  - the best the multiplication product is (lower e), the more k
+    approaches 1, and a approaches 0.
+
+  - A value for a smaller than optimal is probably less bad than a
+    bigger one: e.g. let e=log(3)/log(2), a=0.3058_ the optimal
+    value, and k(a)=0.808_ the mul/mullo speed ratio. We get
+    k(a+1/6)=0.929_ but k(a-1/6)=0.865_.
+*/
+
+static mp_size_t
+mpn_mullo_n_itch (mp_size_t n)
+{
+  return 2*n;
+}
+
+/*
+    mpn_dc_mullo_n requires a scratch space of 2*n limbs at tp.
+    It accepts tp == rp.
+*/
+static void
+mpn_dc_mullo_n (mp_ptr rp, mp_srcptr xp, mp_srcptr yp, mp_size_t n, mp_ptr tp)
+{
+  mp_size_t n2, n1;
+  ASSERT (n >= 2);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+  ASSERT (MPN_SAME_OR_SEPARATE2_P(rp, n, tp, 2*n));
+
+  /* Divide-and-conquer */
+
+  /* We need fractional approximation of the value 0 < a <= 1/2
+     giving the minimum in the function k=(1-a)^e/(1-2*a^e).
+  */
+  if (MAYBE_range_basecase && BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD*36/(36-11)))
+    n1 = n >> 1;
+  else if (MAYBE_range_toom22 && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD*36/(36-11)))
+    n1 = n * 11 / (size_t) 36;	/* n1 ~= n*(1-.694...) */
+  else if (BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD*40/(40-9)))
+    n1 = n * 9 / (size_t) 40;	/* n1 ~= n*(1-.775...) */
+  else if (BELOW_THRESHOLD (n, MUL_TOOM8H_THRESHOLD*10/9))
+    n1 = n * 7 / (size_t) 39;	/* n1 ~= n*(1-.821...) */
+  /* n1 = n * 4 / (size_t) 31;	// n1 ~= n*(1-.871...) [TOOM66] */
+  else
+    n1 = n / (size_t) 10;		/* n1 ~= n*(1-.899...) [TOOM88] */
+
+  n2 = n - n1;
+
+  /* Split as x = x1 2^(n2 GMP_NUMB_BITS) + x0,
+	      y = y1 2^(n2 GMP_NUMB_BITS) + y0 */
+
+  /* x0 * y0 */
+  mpn_mul_n (tp, xp, yp, n2);
+  MPN_COPY (rp, tp, n2);
+
+  /* x1 * y0 * 2^(n2 GMP_NUMB_BITS) */
+  if (BELOW_THRESHOLD (n1, MULLO_BASECASE_THRESHOLD))
+    mpn_mul_basecase (tp + n, xp + n2, n1, yp, n1);
+  else if (BELOW_THRESHOLD (n1, MULLO_DC_THRESHOLD))
+    mpn_mullo_basecase (tp + n, xp + n2, yp, n1);
+  else
+    mpn_dc_mullo_n (tp + n, xp + n2, yp, n1, tp + n);
+  mpn_add_n (rp + n2, tp + n2, tp + n, n1);
+
+  /* x0 * y1 * 2^(n2 GMP_NUMB_BITS) */
+  if (BELOW_THRESHOLD (n1, MULLO_BASECASE_THRESHOLD))
+    mpn_mul_basecase (tp + n, xp, n1, yp + n2, n1);
+  else if (BELOW_THRESHOLD (n1, MULLO_DC_THRESHOLD))
+    mpn_mullo_basecase (tp + n, xp, yp + n2, n1);
+  else
+    mpn_dc_mullo_n (tp + n, xp, yp + n2, n1, tp + n);
+  mpn_add_n (rp + n2, rp + n2, tp + n, n1);
+}
+
+/* Avoid zero allocations when MULLO_BASECASE_THRESHOLD is 0.  */
+#define MUL_BASECASE_ALLOC \
+ (MULLO_BASECASE_THRESHOLD_LIMIT == 0 ? 1 : 2*MULLO_BASECASE_THRESHOLD_LIMIT)
+
+/* FIXME: This function should accept a temporary area; dc_mullow_n
+   accepts a pointer tp, and handle the case tp == rp, do the same here.
+   Maybe recombine the two functions.
+   THINK: If mpn_mul_basecase is always faster than mpn_mullo_basecase
+	  (typically thanks to mpn_addmul_2) should we unconditionally use
+	  mpn_mul_n?
+*/
+
+void
+mpn_mullo_n (mp_ptr rp, mp_srcptr xp, mp_srcptr yp, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+
+  if (BELOW_THRESHOLD (n, MULLO_BASECASE_THRESHOLD))
+    {
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t tp[MUL_BASECASE_ALLOC];
+      mpn_mul_basecase (tp, xp, n, yp, n);
+      MPN_COPY (rp, tp, n);
+    }
+  else if (BELOW_THRESHOLD (n, MULLO_DC_THRESHOLD))
+    {
+      mpn_mullo_basecase (rp, xp, yp, n);
+    }
+  else
+    {
+      mp_ptr tp;
+      TMP_DECL;
+      TMP_MARK;
+      tp = TMP_ALLOC_LIMBS (mpn_mullo_n_itch (n));
+      if (BELOW_THRESHOLD (n, MULLO_MUL_N_THRESHOLD))
+	{
+	  mpn_dc_mullo_n (rp, xp, yp, n, tp);
+	}
+      else
+	{
+	  /* For really large operands, use plain mpn_mul_n but throw away upper n
+	     limbs of result.  */
+#if !TUNE_PROGRAM_BUILD && (MULLO_MUL_N_THRESHOLD > MUL_FFT_THRESHOLD)
+	  mpn_fft_mul (tp, xp, n, yp, n);
+#else
+	  mpn_mul_n (tp, xp, yp, n);
+#endif
+	  MPN_COPY (rp, tp, n);
+	}
+      TMP_FREE;
+    }
+}
diff --git a/mpn/generic/mulmid.c b/mpn/generic/mulmid.c
new file mode 100644
index 0000000..f35c5fb
--- /dev/null
+++ b/mpn/generic/mulmid.c
@@ -0,0 +1,255 @@
+/* mpn_mulmid -- middle product
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#define CHUNK (200 + MULMID_TOOM42_THRESHOLD)
+
+
+void
+mpn_mulmid (mp_ptr rp,
+            mp_srcptr ap, mp_size_t an,
+            mp_srcptr bp, mp_size_t bn)
+{
+  mp_size_t rn, k;
+  mp_ptr scratch, temp;
+
+  ASSERT (an >= bn);
+  ASSERT (bn >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, ap, an));
+  ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, bp, bn));
+
+  if (bn < MULMID_TOOM42_THRESHOLD)
+    {
+      /* region not tall enough to make toom42 worthwhile for any portion */
+
+      if (an < CHUNK)
+	{
+	  /* region not too wide either, just call basecase directly */
+	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
+	  return;
+	}
+
+      /* Region quite wide. For better locality, use basecase on chunks:
+
+	 AAABBBCC..
+	 .AAABBBCC.
+	 ..AAABBBCC
+      */
+
+      k = CHUNK - bn + 1;    /* number of diagonals per chunk */
+
+      /* first chunk (marked A in the above diagram) */
+      mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
+
+      /* remaining chunks (B, C, etc) */
+      an -= k;
+
+      while (an >= CHUNK)
+	{
+	  mp_limb_t t0, t1, cy;
+	  ap += k, rp += k;
+	  t0 = rp[0], t1 = rp[1];
+	  mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);    /* add back saved limbs */
+	  MPN_INCR_U (rp + 1, k + 1, t1 + cy);
+	  an -= k;
+	}
+
+      if (an >= bn)
+	{
+	  /* last remaining chunk */
+	  mp_limb_t t0, t1, cy;
+	  ap += k, rp += k;
+	  t0 = rp[0], t1 = rp[1];
+	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);
+	  MPN_INCR_U (rp + 1, an - bn + 2, t1 + cy);
+	}
+
+      return;
+    }
+
+  /* region is tall enough for toom42 */
+
+  rn = an - bn + 1;
+
+  if (rn < MULMID_TOOM42_THRESHOLD)
+    {
+      /* region not wide enough to make toom42 worthwhile for any portion */
+
+      TMP_DECL;
+
+      if (bn < CHUNK)
+	{
+	  /* region not too tall either, just call basecase directly */
+	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
+	  return;
+	}
+
+      /* Region quite tall. For better locality, use basecase on chunks:
+
+	 AAAAA....
+	 .AAAAA...
+	 ..BBBBB..
+	 ...BBBBB.
+	 ....CCCCC
+      */
+
+      TMP_MARK;
+
+      temp = TMP_ALLOC_LIMBS (rn + 2);
+
+      /* first chunk (marked A in the above diagram) */
+      bp += bn - CHUNK, an -= bn - CHUNK;
+      mpn_mulmid_basecase (rp, ap, an, bp, CHUNK);
+
+      /* remaining chunks (B, C, etc) */
+      bn -= CHUNK;
+
+      while (bn >= CHUNK)
+	{
+	  ap += CHUNK, bp -= CHUNK;
+	  mpn_mulmid_basecase (temp, ap, an, bp, CHUNK);
+	  mpn_add_n (rp, rp, temp, rn + 2);
+	  bn -= CHUNK;
+	}
+
+      if (bn)
+	{
+	  /* last remaining chunk */
+	  ap += CHUNK, bp -= bn;
+	  mpn_mulmid_basecase (temp, ap, rn + bn - 1, bp, bn);
+	  mpn_add_n (rp, rp, temp, rn + 2);
+	}
+
+      TMP_FREE;
+      return;
+    }
+
+  /* we're definitely going to use toom42 somewhere */
+
+  if (bn > rn)
+    {
+      /* slice region into chunks, use toom42 on all chunks except possibly
+	 the last:
+
+         AA....
+         .AA...
+         ..BB..
+         ...BB.
+         ....CC
+      */
+
+      TMP_DECL;
+      TMP_MARK;
+
+      temp = TMP_ALLOC_LIMBS (rn + 2 + mpn_toom42_mulmid_itch (rn));
+      scratch = temp + rn + 2;
+
+      /* first chunk (marked A in the above diagram) */
+      bp += bn - rn;
+      mpn_toom42_mulmid (rp, ap, bp, rn, scratch);
+
+      /* remaining chunks (B, C, etc) */
+      bn -= rn;
+
+      while (bn >= rn)
+        {
+          ap += rn, bp -= rn;
+	  mpn_toom42_mulmid (temp, ap, bp, rn, scratch);
+          mpn_add_n (rp, rp, temp, rn + 2);
+          bn -= rn;
+        }
+
+      if (bn)
+        {
+          /* last remaining chunk */
+          ap += rn, bp -= bn;
+	  mpn_mulmid (temp, ap, rn + bn - 1, bp, bn);
+          mpn_add_n (rp, rp, temp, rn + 2);
+        }
+
+      TMP_FREE;
+    }
+  else
+    {
+      /* slice region into chunks, use toom42 on all chunks except possibly
+	 the last:
+
+         AAABBBCC..
+         .AAABBBCC.
+         ..AAABBBCC
+      */
+
+      TMP_DECL;
+      TMP_MARK;
+
+      scratch = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (bn));
+
+      /* first chunk (marked A in the above diagram) */
+      mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
+
+      /* remaining chunks (B, C, etc) */
+      rn -= bn;
+
+      while (rn >= bn)
+        {
+	  mp_limb_t t0, t1, cy;
+          ap += bn, rp += bn;
+          t0 = rp[0], t1 = rp[1];
+          mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);     /* add back saved limbs */
+	  MPN_INCR_U (rp + 1, bn + 1, t1 + cy);
+	  rn -= bn;
+        }
+
+      TMP_FREE;
+
+      if (rn)
+        {
+          /* last remaining chunk */
+	  mp_limb_t t0, t1, cy;
+          ap += bn, rp += bn;
+          t0 = rp[0], t1 = rp[1];
+          mpn_mulmid (rp, ap, rn + bn - 1, bp, bn);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);
+	  MPN_INCR_U (rp + 1, rn + 1, t1 + cy);
+        }
+    }
+}
diff --git a/mpn/generic/mulmid_basecase.c b/mpn/generic/mulmid_basecase.c
new file mode 100644
index 0000000..d5434ea
--- /dev/null
+++ b/mpn/generic/mulmid_basecase.c
@@ -0,0 +1,82 @@
+/* mpn_mulmid_basecase -- classical middle product algorithm
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Middle product of {up,un} and {vp,vn}, write result to {rp,un-vn+3}.
+   Must have un >= vn >= 1.
+
+   Neither input buffer may overlap with the output buffer. */
+
+void
+mpn_mulmid_basecase (mp_ptr rp,
+                     mp_srcptr up, mp_size_t un,
+                     mp_srcptr vp, mp_size_t vn)
+{
+  mp_limb_t lo, hi;  /* last two limbs of output */
+  mp_limb_t cy;
+
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, un - vn + 3, up, un));
+  ASSERT (! MPN_OVERLAP_P (rp, un - vn + 3, vp, vn));
+
+  up += vn - 1;
+  un -= vn - 1;
+
+  /* multiply by first limb, store result */
+  lo = mpn_mul_1 (rp, up, un, vp[0]);
+  hi = 0;
+
+  /* accumulate remaining rows */
+  for (vn--; vn; vn--)
+    {
+      up--, vp++;
+      cy = mpn_addmul_1 (rp, up, un, vp[0]);
+      add_ssaaaa (hi, lo, hi, lo, CNST_LIMB(0), cy);
+    }
+
+  /* store final limbs */
+#if GMP_NAIL_BITS != 0
+  hi = (hi << GMP_NAIL_BITS) + (lo >> GMP_NUMB_BITS);
+  lo &= GMP_NUMB_MASK;
+#endif
+
+  rp[un] = lo;
+  rp[un + 1] = hi;
+}
diff --git a/mpn/generic/mulmid_n.c b/mpn/generic/mulmid_n.c
new file mode 100644
index 0000000..ac7e8f1
--- /dev/null
+++ b/mpn/generic/mulmid_n.c
@@ -0,0 +1,61 @@
+/* mpn_mulmid_n -- balanced middle product
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+void
+mpn_mulmid_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, ap, 2*n - 1));
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, bp, n));
+
+  if (n < MULMID_TOOM42_THRESHOLD)
+    {
+      mpn_mulmid_basecase (rp, ap, 2*n - 1, bp, n);
+    }
+  else
+    {
+      mp_ptr scratch;
+      TMP_DECL;
+      TMP_MARK;
+      scratch = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (n));
+      mpn_toom42_mulmid (rp, ap, bp, n, scratch);
+      TMP_FREE;
+    }
+}
diff --git a/mpn/generic/mulmod_bknp1.c b/mpn/generic/mulmod_bknp1.c
new file mode 100644
index 0000000..feb10eb
--- /dev/null
+++ b/mpn/generic/mulmod_bknp1.c
@@ -0,0 +1,502 @@
+/* Mulptiplication mod B^n+1, for small operands.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2020-2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifndef MOD_BKNP1_USE11
+#define MOD_BKNP1_USE11 ((GMP_NUMB_BITS % 8 != 0) && (GMP_NUMB_BITS % 2 == 0))
+#endif
+#ifndef MOD_BKNP1_ONLY3
+#define MOD_BKNP1_ONLY3 0
+#endif
+
+/* {rp, (k - 1) * n} = {op, k * n + 1} % (B^{k*n}+1) / (B^n+1) */
+static void
+_mpn_modbknp1dbnp1_n (mp_ptr rp, mp_srcptr op, mp_size_t n, unsigned k)
+{
+  mp_limb_t hl;
+  mp_srcptr hp;
+  unsigned i;
+
+#if MOD_BKNP1_ONLY3
+  ASSERT (k == 3);
+  k = 3;
+#endif
+  ASSERT (k > 2);
+  ASSERT (k % 2 == 1);
+
+  --k;
+
+  rp += k * n;
+  op += k * n;
+  hp = op;
+  hl = hp[n]; /* initial op[k*n]. */
+  ASSERT (hl < GMP_NUMB_MAX - 1);
+
+#if MOD_BKNP1_ONLY3 == 0
+  /* The first MPN_INCR_U (rp + n, 1, cy); in the loop should be
+     rp[n] = cy;						*/
+  *rp = 0;
+#endif
+
+  i = k >> 1;
+  do
+   {
+     mp_limb_t cy, bw;
+     rp -= n;
+     op -= n;
+     cy = hl + mpn_add_n (rp, op, hp, n);
+#if MOD_BKNP1_ONLY3
+     rp[n] = cy;
+#else
+     MPN_INCR_U (rp + n, (k - i * 2) * n + 1, cy);
+#endif
+     rp -= n;
+     op -= n;
+     bw = hl + mpn_sub_n (rp, op, hp, n);
+     MPN_DECR_U (rp + n, (k - i * 2 + 1) * n + 1, bw);
+   }
+  while (--i != 0);
+
+  for (; (hl = *(rp += k * n)) != 0; ) /* Should run only once... */
+    {
+      *rp = 0;
+      i = k >> 1;
+      do
+	{
+	  rp -= n;
+	  MPN_INCR_U (rp, (k - i * 2 + 1) * n + 1, hl);
+	  rp -= n;
+	  MPN_DECR_U (rp, (k - i * 2 + 2) * n + 1, hl);
+	}
+      while (--i != 0);
+    }
+}
+
+static void
+_mpn_modbnp1_pn_ip (mp_ptr r, mp_size_t n, mp_limb_t h)
+{
+  ASSERT (r[n] == h);
+
+  /* Fully normalise */
+  MPN_DECR_U (r, n + 1, h);
+  h -= r[n];
+  r[n] = 0;
+  MPN_INCR_U (r, n + 1, h);
+}
+
+static void
+_mpn_modbnp1_neg_ip (mp_ptr r, mp_size_t n, mp_limb_t h)
+{
+  r[n] = 0;
+  MPN_INCR_U (r, n + 1, -h);
+  if (UNLIKELY (r[n] != 0))
+    _mpn_modbnp1_pn_ip (r, n, 1);
+}
+
+static void
+_mpn_modbnp1_nc_ip (mp_ptr r, mp_size_t n, mp_limb_t h)
+{
+  if (h & GMP_NUMB_HIGHBIT) /* This means h < 0 */
+    {
+      _mpn_modbnp1_neg_ip (r, n, h);
+    }
+  else
+    {
+      r[n] = h;
+      if (h)
+	_mpn_modbnp1_pn_ip(r, n, h);
+    }
+}
+
+/* {rp, rn + 1} = {op, on} mod (B^{rn}+1) */
+/* Used when rn < on < 2*rn. */
+static void
+_mpn_modbnp1 (mp_ptr rp, mp_size_t rn, mp_srcptr op, mp_size_t on)
+{
+  mp_limb_t bw;
+
+#if 0
+  if (UNLIKELY (on <= rn))
+    {
+      MPN_COPY (rp, op, on);
+      MPN_ZERO (rp + on, rn - on);
+      return;
+    }
+#endif
+
+  ASSERT (on > rn);
+  ASSERT (on <= 2 * rn);
+
+  bw = mpn_sub (rp, op, rn, op + rn, on - rn);
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, bw);
+}
+
+/* {rp, rn + 1} = {op, k * rn + 1} % (B^{rn}+1) */
+/* With odd k >= 3. */
+static void
+_mpn_modbnp1_kn (mp_ptr rp, mp_srcptr op, mp_size_t rn, unsigned k)
+{
+  mp_limb_t cy;
+
+#if MOD_BKNP1_ONLY3
+  ASSERT (k == 3);
+  k = 3;
+#endif
+  ASSERT (k & 1);
+  k >>= 1;
+  ASSERT (0 < k && k < GMP_NUMB_HIGHBIT - 3);
+  ASSERT (op[(1 + 2 * k) * rn] < GMP_NUMB_HIGHBIT - 2 - k);
+
+  cy = - mpn_sub_n (rp, op, op + rn, rn);
+  for (;;) {
+    op += 2 * rn;
+    cy += mpn_add_n (rp, rp, op, rn);
+    if (--k == 0)
+      break;
+    cy -= mpn_sub_n (rp, rp, op + rn, rn);
+  };
+
+  cy += op[rn];
+  _mpn_modbnp1_nc_ip (rp, rn, cy);
+}
+
+/* For the various mpn_divexact_byN here, fall back to using either
+   mpn_pi1_bdiv_q_1 or mpn_divexact_1.  The former has less overhead and is
+   faster if it is native.  For now, since mpn_divexact_1 is native on
+   platforms where mpn_pi1_bdiv_q_1 does not yet exist, do not use
+   mpn_pi1_bdiv_q_1 unconditionally.  FIXME.  */
+
+#ifndef mpn_divexact_by5
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define BINVERT_5 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 4)) / 5 * 3 << 3) + 5) & GMP_NUMB_MAX)
+#define mpn_divexact_by5(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,5,BINVERT_5,0)
+#else
+#define mpn_divexact_by5(dst,src,size) mpn_divexact_1(dst,src,size,5)
+#endif
+#endif
+
+#ifndef mpn_divexact_by7
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define BINVERT_7 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 3)) / 7 * 3 << 4) + 7) & GMP_NUMB_MAX)
+#define mpn_divexact_by7(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,7,BINVERT_7,0)
+#else
+#define mpn_divexact_by7(dst,src,size) mpn_divexact_1(dst,src,size,7)
+#endif
+#endif
+
+#ifndef mpn_divexact_by11
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define BINVERT_11 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 10)) / 11 << 5) + 3) & GMP_NUMB_MAX)
+#define mpn_divexact_by11(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,11,BINVERT_11,0)
+#else
+#define mpn_divexact_by11(dst,src,size) mpn_divexact_1(dst,src,size,11)
+#endif
+#endif
+
+#ifndef mpn_divexact_by13
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define BINVERT_13 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 12)) / 13 * 3 << 14) + 3781) & GMP_NUMB_MAX)
+#define mpn_divexact_by13(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,13,BINVERT_13,0)
+#else
+#define mpn_divexact_by13(dst,src,size) mpn_divexact_1(dst,src,size,13)
+#endif
+#endif
+
+#ifndef mpn_divexact_by17
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define BINVERT_17 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 8)) / 17 * 15 << 7) + 113) & GMP_NUMB_MAX)
+#define mpn_divexact_by17(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,17,BINVERT_17,0)
+#else
+#define mpn_divexact_by17(dst,src,size) mpn_divexact_1(dst,src,size,17)
+#endif
+#endif
+
+/* Thanks to Chinese remainder theorem, store
+   in {rp, k*n+1} the value mod (B^(k*n)+1), given
+   {ap, k*n+1} mod ((B^(k*n)+1)/(B^n+1)) and
+   {bp, n+1} mod (B^n+1) .
+   {tp, n+1} is a scratch area.
+   tp == rp or rp == ap are possible.
+*/
+static void
+_mpn_crt (mp_ptr rp, mp_srcptr ap, mp_srcptr bp,
+	  mp_size_t n, unsigned k, mp_ptr tp)
+{
+  mp_limb_t mod;
+  unsigned i;
+
+#if MOD_BKNP1_ONLY3
+  ASSERT (k == 3);
+  k = 3;
+#endif
+  _mpn_modbnp1_kn (tp, ap, n, k);
+  if (mpn_sub_n (tp, bp, tp, n + 1))
+    _mpn_modbnp1_neg_ip (tp, n, tp[n]);
+
+#if MOD_BKNP1_USE11
+  if (UNLIKELY (k == 11))
+    {
+      ASSERT (GMP_NUMB_BITS % 2 == 0);
+      /* mod <- -Mod(B^n+1,11)^-1 */
+      mod = n * (GMP_NUMB_BITS % 5) % 5;
+      if ((mod > 2) || UNLIKELY (mod == 0))
+	mod += 5;
+
+      mod *= mpn_mod_1 (tp, n + 1, 11);
+    }
+  else
+#endif
+    {
+#if GMP_NUMB_BITS % 8 == 0
+  /* (2^6 - 1) | (2^{GMP_NUMB_BITS*3/4} - 1)	*/
+  /* (2^6 - 1) = 3^2 * 7			*/
+  mod = mpn_mod_34lsub1 (tp, n + 1);
+  ASSERT ((GMP_NUMB_MAX >> (GMP_NUMB_BITS >> 2)) % k == 0);
+  /* (2^12 - 1) = 3^2 * 5 * 7 * 13		*/
+  /* (2^24 - 1) = 3^2 * 5 * 7 * 13 * 17 * 241	*/
+  ASSERT (k == 3 || k == 5 || k == 7 || k == 13 || k == 17);
+
+#if GMP_NUMB_BITS % 3 != 0
+  if (UNLIKELY (k != 3))
+    {
+      ASSERT ((GMP_NUMB_MAX % k == 0) || (n % 3 != 0));
+      if ((GMP_NUMB_BITS % 16 == 0) && LIKELY (k == 5))
+	mod <<= 1; /* k >> 1 = 1 << 1 */
+      else if ((GMP_NUMB_BITS % 16 != 0) || LIKELY (k == 7))
+	mod <<= (n << (GMP_NUMB_BITS % 3 >> 1)) % 3;
+      else if ((GMP_NUMB_BITS % 32 != 0) || LIKELY (k == 13))
+	mod *= ((n << (GMP_NUMB_BITS % 3 >> 1)) % 3 == 1) ? 3 : 9;
+      else /* k == 17 */
+	mod <<= 3; /* k >> 1 = 1 << 3 */
+#if 0
+      if ((GMP_NUMB_BITS == 8) /* && (k == 7) */ ||
+	  (GMP_NUMB_BITS == 16) && (k == 13))
+	mod = ((mod & (GMP_NUMB_MAX >> (GMP_NUMB_BITS >> 2))) +
+	       (mod >> (3 * GMP_NUMB_BITS >> 2)));
+#endif
+    }
+#else
+  ASSERT (GMP_NUMB_MAX % k == 0);
+  /* 2^{GMP_NUMB_BITS} - 1	= 0 (mod k) */
+  /* 2^{GMP_NUMB_BITS}		= 1 (mod k) */
+  /* 2^{n*GMP_NUMB_BITS} + 1	= 2 (mod k) */
+  /* -2^{-1}	= k >> 1 (mod k) */
+  mod *= k >> 1;
+#endif
+#else
+  ASSERT_ALWAYS (k == 0); /* Not implemented, should not be used. */
+#endif
+    }
+
+  MPN_INCR_U (tp, n + 1, mod);
+  tp[n] += mod;
+
+  if (LIKELY (k == 3))
+    ASSERT_NOCARRY (mpn_divexact_by3 (tp, tp, n + 1));
+  else if ((GMP_NUMB_BITS % 16 == 0) && LIKELY (k == 5))
+    mpn_divexact_by5 (tp, tp, n + 1);
+  else if (((! MOD_BKNP1_USE11) && (GMP_NUMB_BITS % 16 != 0))
+	   || LIKELY (k == 7))
+    mpn_divexact_by7 (tp, tp, n + 1);
+#if MOD_BKNP1_USE11
+  else if (k == 11)
+    mpn_divexact_by11 (tp, tp, n + 1);
+#endif
+  else if ((GMP_NUMB_BITS % 32 != 0) || LIKELY (k == 13))
+    mpn_divexact_by13 (tp, tp, n + 1);
+  else /* (k == 17) */
+    mpn_divexact_by17 (tp, tp, n + 1);
+
+  rp += k * n;
+  ap += k * n; /* tp - 1 */
+
+  rp -= n;
+  ap -= n;
+  ASSERT_NOCARRY (mpn_add_n (rp, ap, tp, n + 1));
+
+  i = k >> 1;
+  do
+   {
+      mp_limb_t cy, bw;
+      rp -= n;
+      ap -= n;
+      bw = mpn_sub_n (rp, ap, tp, n) + tp[n];
+      MPN_DECR_U (rp + n, (k - i * 2) * n + 1, bw);
+      rp -= n;
+      ap -= n;
+      cy = mpn_add_n (rp, ap, tp, n) + tp[n];
+      MPN_INCR_U (rp + n, (k - i * 2 + 1) * n + 1, cy);
+    }
+  while (--i != 0);
+
+  /* if (LIKELY (rp[k * n])) */
+    _mpn_modbnp1_pn_ip (rp, k * n, rp[k * n]);
+}
+
+
+static void
+_mpn_mulmod_bnp1_tp (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t rn,
+		    mp_ptr tp)
+{
+  mp_limb_t cy;
+  unsigned k;
+
+  ASSERT (0 < rn);
+  ASSERT ((ap[rn] | bp[rn]) <= 1);
+
+  if (UNLIKELY (ap[rn] | bp[rn]))
+    {
+      if (ap[rn])
+	cy = bp[rn] + mpn_neg (rp, bp, rn);
+      else /* ap[rn] == 0 */
+	cy = mpn_neg (rp, ap, rn);
+    }
+  else if (MPN_MULMOD_BKNP1_USABLE(rn, k, MUL_FFT_MODF_THRESHOLD / 3))
+    {
+      rn /= k;
+      mpn_mulmod_bknp1 (rp, ap, bp, rn, k, tp);
+      return;
+    }
+  else
+    {
+      mpn_mul_n (tp, ap, bp, rn);
+      cy = mpn_sub_n (rp, tp, tp + rn, rn);
+    }
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, cy);
+}
+
+/* {rp, kn + 1} = {ap, kn + 1} * {bp, kn + 1} % (B^kn + 1) */
+/* tp must point to at least 4*(k-1)*n+1 limbs*/
+void
+mpn_mulmod_bknp1 (mp_ptr rp, mp_srcptr ap, mp_srcptr bp,
+		  mp_size_t n, unsigned k, mp_ptr tp)
+{
+  mp_ptr hp;
+
+#if MOD_BKNP1_ONLY3
+  ASSERT (k == 3);
+  k = 3;
+#endif
+  ASSERT (k > 2);
+  ASSERT (k % 2 == 1);
+
+  /* a % (B^{nn}+1)/(B^{nn/k}+1) */
+  _mpn_modbknp1dbnp1_n (tp + (k - 1) * n * 2, ap, n, k);
+  /* b % (B^{nn}+1)/(B^{nn/k}+1) */
+  _mpn_modbknp1dbnp1_n (tp + (k - 1) * n * 3, bp, n, k);
+  mpn_mul_n (tp, tp + (k - 1) * n * 2, tp + (k - 1) * n * 3, (k - 1) * n);
+  _mpn_modbnp1 (tp, k * n, tp, (k - 1) * n * 2);
+
+  hp = tp + k * n + 1;
+  /* a % (B^{nn/k}+1) */
+  ASSERT (ap[k * n] <= 1);
+  _mpn_modbnp1_kn (hp, ap, n, k);
+  /* b % (B^{nn/k}+1) */
+  ASSERT (bp[k * n] <= 1);
+  _mpn_modbnp1_kn (hp + n + 1, bp, n, k);
+  _mpn_mulmod_bnp1_tp (hp + (n + 1) * 2, hp, hp + n + 1, n, hp + (n + 1) * 2);
+
+  _mpn_crt (rp, tp, hp + (n + 1) * 2, n, k, hp);
+}
+
+
+static void
+_mpn_sqrmod_bnp1_tp (mp_ptr rp, mp_srcptr ap, mp_size_t rn,
+		    mp_ptr tp)
+{
+  mp_limb_t cy;
+  unsigned k;
+
+  ASSERT (0 < rn);
+
+  if (UNLIKELY (ap[rn]))
+    {
+      ASSERT (ap[rn] == 1);
+      *rp = 1;
+      MPN_FILL (rp + 1, rn, 0);
+      return;
+    }
+  else if (MPN_SQRMOD_BKNP1_USABLE(rn, k, MUL_FFT_MODF_THRESHOLD / 3))
+    {
+      rn /= k;
+      mpn_sqrmod_bknp1 (rp, ap, rn, k, tp);
+      return;
+    }
+  else
+    {
+      mpn_sqr (tp, ap, rn);
+      cy = mpn_sub_n (rp, tp, tp + rn, rn);
+    }
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, cy);
+}
+
+/* {rp, kn + 1} = {ap, kn + 1}^2 % (B^kn + 1) */
+/* tp must point to at least 3*(k-1)*n+1 limbs*/
+void
+mpn_sqrmod_bknp1 (mp_ptr rp, mp_srcptr ap,
+		  mp_size_t n, unsigned k, mp_ptr tp)
+{
+  mp_ptr hp;
+
+#if MOD_BKNP1_ONLY3
+  ASSERT (k == 3);
+  k = 3;
+#endif
+  ASSERT (k > 2);
+  ASSERT (k % 2 == 1);
+
+  /* a % (B^{nn}+1)/(B^{nn/k}+1) */
+  _mpn_modbknp1dbnp1_n (tp + (k - 1) * n * 2, ap, n, k);
+  mpn_sqr (tp, tp + (k - 1) * n * 2, (k - 1) * n);
+  _mpn_modbnp1 (tp, k * n, tp, (k - 1) * n * 2);
+
+  hp = tp + k * n + 1;
+  /* a % (B^{nn/k}+1) */
+  ASSERT (ap[k * n] <= 1);
+  _mpn_modbnp1_kn (hp, ap, n, k);
+  _mpn_sqrmod_bnp1_tp (hp + (n + 1), hp, n, hp + (n + 1));
+
+  _mpn_crt (rp, tp, hp + (n + 1), n, k, hp);
+}
diff --git a/mpn/generic/mulmod_bnm1.c b/mpn/generic/mulmod_bnm1.c
new file mode 100644
index 0000000..8229ede
--- /dev/null
+++ b/mpn/generic/mulmod_bnm1.c
@@ -0,0 +1,374 @@
+/* mulmod_bnm1.c -- multiplication mod B^n-1.
+
+   Contributed to the GNU project by Niels Möller, Torbjorn Granlund and
+   Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2013, 2020, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Inputs are {ap,rn} and {bp,rn}; output is {rp,rn}, computation is
+   mod B^rn - 1, and values are semi-normalised; zero is represented
+   as either 0 or B^n - 1.  Needs a scratch of 2rn limbs at tp.
+   tp==rp is allowed. */
+void
+mpn_bc_mulmod_bnm1 (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t rn,
+		    mp_ptr tp)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < rn);
+
+  mpn_mul_n (tp, ap, bp, rn);
+  cy = mpn_add_n (rp, tp, tp + rn, rn);
+  /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+   * be no overflow when adding in the carry. */
+  MPN_INCR_U (rp, rn, cy);
+}
+
+
+/* Inputs are {ap,rn+1} and {bp,rn+1}; output is {rp,rn+1}, in
+   normalised representation, computation is mod B^rn + 1. Needs
+   a scratch area of 2rn limbs at tp; tp == rp is allowed.
+   Output is normalised. */
+static void
+mpn_bc_mulmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t rn,
+		    mp_ptr tp)
+{
+  mp_limb_t cy;
+  unsigned k;
+
+  ASSERT (0 < rn);
+
+  if (UNLIKELY (ap[rn] | bp [rn]))
+    {
+      if (ap[rn])
+	cy = bp [rn] + mpn_neg (rp, bp, rn);
+      else /* ap[rn] == 0 */
+	cy = mpn_neg (rp, ap, rn);
+    }
+  else if (MPN_MULMOD_BKNP1_USABLE (rn, k, MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_size_t n_k = rn / k;
+      TMP_DECL;
+
+      TMP_MARK;
+      mpn_mulmod_bknp1 (rp, ap, bp, n_k, k,
+                       TMP_ALLOC_LIMBS (mpn_mulmod_bknp1_itch (rn)));
+      TMP_FREE;
+      return;
+    }
+  else
+    {
+      mpn_mul_n (tp, ap, bp, rn);
+      cy = mpn_sub_n (rp, tp, tp + rn, rn);
+    }
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, cy);
+}
+
+
+/* Computes {rp,MIN(rn,an+bn)} <- {ap,an}*{bp,bn} Mod(B^rn-1)
+ *
+ * The result is expected to be ZERO if and only if one of the operand
+ * already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+ * B^rn-1. This should not be a problem if mulmod_bnm1 is used to
+ * combine results and obtain a natural number when one knows in
+ * advance that the final value is less than (B^rn-1).
+ * Moreover it should not be a problem if mulmod_bnm1 is used to
+ * compute the full product with an+bn <= rn, because this condition
+ * implies (B^an-1)(B^bn-1) < (B^rn-1) .
+ *
+ * Requires 0 < bn <= an <= rn and an + bn > rn/2
+ * Scratch need: rn + (need for recursive call OR rn + 4). This gives
+ *
+ * S(n) <= rn + MAX (rn + 4, S(n/2)) <= 2rn + 4
+ */
+void
+mpn_mulmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn, mp_ptr tp)
+{
+  ASSERT (0 < bn);
+  ASSERT (bn <= an);
+  ASSERT (an <= rn);
+
+  if ((rn & 1) != 0 || BELOW_THRESHOLD (rn, MULMOD_BNM1_THRESHOLD))
+    {
+      if (UNLIKELY (bn < rn))
+	{
+	  if (UNLIKELY (an + bn <= rn))
+	    {
+	      mpn_mul (rp, ap, an, bp, bn);
+	    }
+	  else
+	    {
+	      mp_limb_t cy;
+	      mpn_mul (tp, ap, an, bp, bn);
+	      cy = mpn_add (rp, tp, rn, tp + rn, an + bn - rn);
+	      MPN_INCR_U (rp, rn, cy);
+	    }
+	}
+      else
+	mpn_bc_mulmod_bnm1 (rp, ap, bp, rn, tp);
+    }
+  else
+    {
+      mp_size_t n;
+      mp_limb_t cy;
+      mp_limb_t hi;
+
+      n = rn >> 1;
+
+      /* We need at least an + bn >= n, to be able to fit one of the
+	 recursive products at rp. Requiring strict inequality makes
+	 the code slightly simpler. If desired, we could avoid this
+	 restriction by initially halving rn as long as rn is even and
+	 an + bn <= rn/2. */
+
+      ASSERT (an + bn > n);
+
+      /* Compute xm = a*b mod (B^n - 1), xp = a*b mod (B^n + 1)
+	 and crt together as
+
+	 x = -xp * B^n + (B^n + 1) * [ (xp + xm)/2 mod (B^n-1)]
+      */
+
+#define a0 ap
+#define a1 (ap + n)
+#define b0 bp
+#define b1 (bp + n)
+
+#define xp  tp	/* 2n + 2 */
+      /* am1  maybe in {xp, n} */
+      /* bm1  maybe in {xp + n, n} */
+#define sp1 (tp + 2*n + 2)
+      /* ap1  maybe in {sp1, n + 1} */
+      /* bp1  maybe in {sp1 + n + 1, n + 1} */
+
+      {
+	mp_srcptr am1, bm1;
+	mp_size_t anm, bnm;
+	mp_ptr so;
+
+	bm1 = b0;
+	bnm = bn;
+	if (LIKELY (an > n))
+	  {
+	    am1 = xp;
+	    cy = mpn_add (xp, a0, n, a1, an - n);
+	    MPN_INCR_U (xp, n, cy);
+	    anm = n;
+	    so = xp + n;
+	    if (LIKELY (bn > n))
+	      {
+		bm1 = so;
+		cy = mpn_add (so, b0, n, b1, bn - n);
+		MPN_INCR_U (so, n, cy);
+		bnm = n;
+		so += n;
+	      }
+	  }
+	else
+	  {
+	    so = xp;
+	    am1 = a0;
+	    anm = an;
+	  }
+
+	mpn_mulmod_bnm1 (rp, n, am1, anm, bm1, bnm, so);
+      }
+
+      {
+	int       k;
+	mp_srcptr ap1, bp1;
+	mp_size_t anp, bnp;
+
+	bp1 = b0;
+	bnp = bn;
+	if (LIKELY (an > n)) {
+	  ap1 = sp1;
+	  cy = mpn_sub (sp1, a0, n, a1, an - n);
+	  sp1[n] = 0;
+	  MPN_INCR_U (sp1, n + 1, cy);
+	  anp = n + ap1[n];
+	  if (LIKELY (bn > n)) {
+	    bp1 = sp1 + n + 1;
+	    cy = mpn_sub (sp1 + n + 1, b0, n, b1, bn - n);
+	    sp1[2*n+1] = 0;
+	    MPN_INCR_U (sp1 + n + 1, n + 1, cy);
+	    bnp = n + bp1[n];
+	  }
+	} else {
+	  ap1 = a0;
+	  anp = an;
+	}
+
+	if (BELOW_THRESHOLD (n, MUL_FFT_MODF_THRESHOLD))
+	  k=0;
+	else
+	  {
+	    int mask;
+	    k = mpn_fft_best_k (n, 0);
+	    mask = (1<<k) - 1;
+	    while (n & mask) {k--; mask >>=1;};
+	  }
+	if (k >= FFT_FIRST_K)
+	  xp[n] = mpn_mul_fft (xp, n, ap1, anp, bp1, bnp, k);
+	else if (UNLIKELY (bp1 == b0))
+	  {
+	    ASSERT (anp + bnp <= 2*n+1);
+	    ASSERT (anp + bnp > n);
+	    ASSERT (anp >= bnp);
+	    mpn_mul (xp, ap1, anp, bp1, bnp);
+	    anp = anp + bnp - n;
+	    ASSERT (anp <= n || xp[2*n]==0);
+	    anp-= anp > n;
+	    cy = mpn_sub (xp, xp, n, xp + n, anp);
+	    xp[n] = 0;
+	    MPN_INCR_U (xp, n+1, cy);
+	  }
+	else
+	  mpn_bc_mulmod_bnp1 (xp, ap1, bp1, n, xp);
+      }
+
+      /* Here the CRT recomposition begins.
+
+	 xm <- (xp + xm)/2 = (xp + xm)B^n/2 mod (B^n-1)
+	 Division by 2 is a bitwise rotation.
+
+	 Assumes xp normalised mod (B^n+1).
+
+	 The residue class [0] is represented by [B^n-1]; except when
+	 both input are ZERO.
+      */
+
+#if HAVE_NATIVE_mpn_rsh1add_n || HAVE_NATIVE_mpn_rsh1add_nc
+#if HAVE_NATIVE_mpn_rsh1add_nc
+      cy = mpn_rsh1add_nc(rp, rp, xp, n, xp[n]); /* B^n = 1 */
+      hi = cy << (GMP_NUMB_BITS - 1);
+      cy = 0;
+      /* next update of rp[n-1] will set cy = 1 only if rp[n-1]+=hi
+	 overflows, i.e. a further increment will not overflow again. */
+#else /* ! _nc */
+      cy = xp[n] + mpn_rsh1add_n(rp, rp, xp, n); /* B^n = 1 */
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* cy = 1 only if xp[n] = 1 i.e. {xp,n} = ZERO, this implies that
+	 the rsh1add was a simple rshift: the top bit is 0. cy=1 => hi=0. */
+#endif
+#if GMP_NAIL_BITS == 0
+      add_ssaaaa(cy, rp[n-1], cy, rp[n-1], 0, hi);
+#else
+      cy += (hi & rp[n-1]) >> (GMP_NUMB_BITS-1);
+      rp[n-1] ^= hi;
+#endif
+#else /* ! HAVE_NATIVE_mpn_rsh1add_n */
+#if HAVE_NATIVE_mpn_add_nc
+      cy = mpn_add_nc(rp, rp, xp, n, xp[n]);
+#else /* ! _nc */
+      cy = xp[n] + mpn_add_n(rp, rp, xp, n); /* xp[n] == 1 implies {xp,n} == ZERO */
+#endif
+      cy += (rp[0]&1);
+      mpn_rshift(rp, rp, n, 1);
+      ASSERT (cy <= 2);
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* We can have cy != 0 only if hi = 0... */
+      ASSERT ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0);
+      rp[n-1] |= hi;
+      /* ... rp[n-1] + cy can not overflow, the following INCR is correct. */
+#endif
+      ASSERT (cy <= 1);
+      /* Next increment can not overflow, read the previous comments about cy. */
+      ASSERT ((cy == 0) || ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0));
+      MPN_INCR_U(rp, n, cy);
+
+      /* Compute the highest half:
+	 ([(xp + xm)/2 mod (B^n-1)] - xp ) * B^n
+       */
+      if (UNLIKELY (an + bn < rn))
+	{
+	  /* Note that in this case, the only way the result can equal
+	     zero mod B^{rn} - 1 is if one of the inputs is zero, and
+	     then the output of both the recursive calls and this CRT
+	     reconstruction is zero, not B^{rn} - 1. Which is good,
+	     since the latter representation doesn't fit in the output
+	     area.*/
+	  cy = mpn_sub_n (rp + n, rp, xp, an + bn - n);
+
+	  /* FIXME: This subtraction of the high parts is not really
+	     necessary, we do it to get the carry out, and for sanity
+	     checking. */
+	  cy = xp[n] + mpn_sub_nc (xp + an + bn - n, rp + an + bn - n,
+				   xp + an + bn - n, rn - (an + bn), cy);
+	  ASSERT (an + bn == rn - 1 ||
+		  mpn_zero_p (xp + an + bn - n + 1, rn - 1 - (an + bn)));
+	  cy = mpn_sub_1 (rp, rp, an + bn, cy);
+	  ASSERT (cy == (xp + an + bn - n)[0]);
+	}
+      else
+	{
+	  cy = xp[n] + mpn_sub_n (rp + n, rp, xp, n);
+	  /* cy = 1 only if {xp,n+1} is not ZERO, i.e. {rp,n} is not ZERO.
+	     DECR will affect _at most_ the lowest n limbs. */
+	  MPN_DECR_U (rp, 2*n, cy);
+	}
+#undef a0
+#undef a1
+#undef b0
+#undef b1
+#undef xp
+#undef sp1
+    }
+}
+
+mp_size_t
+mpn_mulmod_bnm1_next_size (mp_size_t n)
+{
+  mp_size_t nh;
+
+  if (BELOW_THRESHOLD (n,     MULMOD_BNM1_THRESHOLD))
+    return n;
+  if (BELOW_THRESHOLD (n, 4 * (MULMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (2-1)) & (-2);
+  if (BELOW_THRESHOLD (n, 8 * (MULMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (4-1)) & (-4);
+
+  nh = (n + 1) >> 1;
+
+  if (BELOW_THRESHOLD (nh, MUL_FFT_MODF_THRESHOLD))
+    return (n + (8-1)) & (-8);
+
+  return 2 * mpn_fft_next_size (nh, mpn_fft_best_k (nh, 0));
+}
diff --git a/mpn/generic/neg.c b/mpn/generic/neg.c
new file mode 100644
index 0000000..bec2a32
--- /dev/null
+++ b/mpn/generic/neg.c
@@ -0,0 +1,33 @@
+/* mpn_neg - negate an mpn.
+
+Copyright 2001, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_neg 1
+
+#include "gmp-impl.h"
diff --git a/mpn/generic/nussbaumer_mul.c b/mpn/generic/nussbaumer_mul.c
new file mode 100644
index 0000000..3e0cf27
--- /dev/null
+++ b/mpn/generic/nussbaumer_mul.c
@@ -0,0 +1,70 @@
+/* mpn_nussbaumer_mul -- Multiply {ap,an} and {bp,bn} using
+   Nussbaumer's negacyclic convolution.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Multiply {ap,an} by {bp,bn}, and put the result in {pp, an+bn} */
+void
+mpn_nussbaumer_mul (mp_ptr pp,
+		    mp_srcptr ap, mp_size_t an,
+		    mp_srcptr bp, mp_size_t bn)
+{
+  mp_size_t rn;
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (an >= bn);
+  ASSERT (bn > 0);
+
+  TMP_MARK;
+
+  if ((ap == bp) && (an == bn))
+    {
+      rn = mpn_sqrmod_bnm1_next_size (2*an);
+      tp = TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (rn, an));
+      mpn_sqrmod_bnm1 (pp, rn, ap, an, tp);
+    }
+  else
+    {
+      rn = mpn_mulmod_bnm1_next_size (an + bn);
+      tp = TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (rn, an, bn));
+      mpn_mulmod_bnm1 (pp, rn, ap, an, bp, bn, tp);
+    }
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/perfpow.c b/mpn/generic/perfpow.c
new file mode 100644
index 0000000..9d46477
--- /dev/null
+++ b/mpn/generic/perfpow.c
@@ -0,0 +1,342 @@
+/* mpn_perfect_power_p -- mpn perfect power detection.
+
+   Contributed to the GNU project by Martin Boij.
+
+Copyright 2009, 2010, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define SMALL 20
+#define MEDIUM 100
+
+/* Return non-zero if {np,nn} == {xp,xn} ^ k.
+   Algorithm:
+       For s = 1, 2, 4, ..., s_max, compute the s least significant limbs of
+       {xp,xn}^k. Stop if they don't match the s least significant limbs of
+       {np,nn}.
+
+   FIXME: Low xn limbs can be expected to always match, if computed as a mod
+   B^{xn} root. So instead of using mpn_powlo, compute an approximation of the
+   most significant (normalized) limb of {xp,xn} ^ k (and an error bound), and
+   compare to {np, nn}. Or use an even cruder approximation based on fix-point
+   base 2 logarithm.  */
+static int
+pow_equals (mp_srcptr np, mp_size_t n,
+	    mp_srcptr xp,mp_size_t xn,
+	    mp_limb_t k, mp_bitcnt_t f,
+	    mp_ptr tp)
+{
+  mp_bitcnt_t y, z;
+  mp_size_t bn;
+  mp_limb_t h, l;
+
+  ASSERT (n > 1 || (n == 1 && np[0] > 1));
+  ASSERT (np[n - 1] > 0);
+  ASSERT (xn > 0);
+
+  if (xn == 1 && xp[0] == 1)
+    return 0;
+
+  z = 1 + (n >> 1);
+  for (bn = 1; bn < z; bn <<= 1)
+    {
+      mpn_powlo (tp, xp, &k, 1, bn, tp + bn);
+      if (mpn_cmp (tp, np, bn) != 0)
+	return 0;
+    }
+
+  /* Final check. Estimate the size of {xp,xn}^k before computing the power
+     with full precision.  Optimization: It might pay off to make a more
+     accurate estimation of the logarithm of {xp,xn}, rather than using the
+     index of the MSB.  */
+
+  MPN_SIZEINBASE_2EXP(y, xp, xn, 1);
+  y -= 1;  /* msb_index (xp, xn) */
+
+  umul_ppmm (h, l, k, y);
+  h -= l == 0;  --l;	/* two-limb decrement */
+
+  z = f - 1; /* msb_index (np, n) */
+  if (h == 0 && l <= z)
+    {
+      mp_limb_t *tp2;
+      mp_size_t i;
+      int ans;
+      mp_limb_t size;
+      TMP_DECL;
+
+      size = l + k;
+      ASSERT_ALWAYS (size >= k);
+
+      TMP_MARK;
+      y = 2 + size / GMP_LIMB_BITS;
+      tp2 = TMP_ALLOC_LIMBS (y);
+
+      i = mpn_pow_1 (tp, xp, xn, k, tp2);
+      if (i == n && mpn_cmp (tp, np, n) == 0)
+	ans = 1;
+      else
+	ans = 0;
+      TMP_FREE;
+      return ans;
+    }
+
+  return 0;
+}
+
+
+/* Return non-zero if N = {np,n} is a kth power.
+   I = {ip,n} = N^(-1) mod B^n.  */
+static int
+is_kth_power (mp_ptr rp, mp_srcptr np,
+	      mp_limb_t k, mp_srcptr ip,
+	      mp_size_t n, mp_bitcnt_t f,
+	      mp_ptr tp)
+{
+  mp_bitcnt_t b;
+  mp_size_t rn, xn;
+
+  ASSERT (n > 0);
+  ASSERT ((k & 1) != 0 || k == 2);
+  ASSERT ((np[0] & 1) != 0);
+
+  if (k == 2)
+    {
+      b = (f + 1) >> 1;
+      rn = 1 + b / GMP_LIMB_BITS;
+      if (mpn_bsqrtinv (rp, ip, b, tp) != 0)
+	{
+	  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+	  xn = rn;
+	  MPN_NORMALIZE (rp, xn);
+	  if (pow_equals (np, n, rp, xn, k, f, tp) != 0)
+	    return 1;
+
+	  /* Check if (2^b - r)^2 == n */
+	  mpn_neg (rp, rp, rn);
+	  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+	  MPN_NORMALIZE (rp, rn);
+	  if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
+	    return 1;
+	}
+    }
+  else
+    {
+      b = 1 + (f - 1) / k;
+      rn = 1 + (b - 1) / GMP_LIMB_BITS;
+      mpn_brootinv (rp, ip, rn, k, tp);
+      if ((b % GMP_LIMB_BITS) != 0)
+	rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+      MPN_NORMALIZE (rp, rn);
+      if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
+	return 1;
+    }
+  MPN_ZERO (rp, rn); /* Untrash rp */
+  return 0;
+}
+
+static int
+perfpow (mp_srcptr np, mp_size_t n,
+	 mp_limb_t ub, mp_limb_t g,
+	 mp_bitcnt_t f, int neg)
+{
+  mp_ptr ip, tp, rp;
+  mp_limb_t k;
+  int ans;
+  mp_bitcnt_t b;
+  gmp_primesieve_t ps;
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT ((np[0] & 1) != 0);
+  ASSERT (ub > 0);
+
+  TMP_MARK;
+  gmp_init_primesieve (&ps);
+  b = (f + 3) >> 1;
+
+  TMP_ALLOC_LIMBS_3 (ip, n, rp, n, tp, 5 * n);
+
+  MPN_ZERO (rp, n);
+
+  /* FIXME: It seems the inverse in ninv is needed only to get non-inverted
+     roots. I.e., is_kth_power computes n^{1/2} as (n^{-1})^{-1/2} and
+     similarly for nth roots. It should be more efficient to compute n^{1/2} as
+     n * n^{-1/2}, with a mullo instead of a binvert. And we can do something
+     similar for kth roots if we switch to an iteration converging to n^{1/k -
+     1}, and we can then eliminate this binvert call. */
+  mpn_binvert (ip, np, 1 + (b - 1) / GMP_LIMB_BITS, tp);
+  if (b % GMP_LIMB_BITS)
+    ip[(b - 1) / GMP_LIMB_BITS] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+
+  if (neg)
+    gmp_nextprime (&ps);
+
+  ans = 0;
+  if (g > 0)
+    {
+      ub = MIN (ub, g + 1);
+      while ((k = gmp_nextprime (&ps)) < ub)
+	{
+	  if ((g % k) == 0)
+	    {
+	      if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
+		{
+		  ans = 1;
+		  goto ret;
+		}
+	    }
+	}
+    }
+  else
+    {
+      while ((k = gmp_nextprime (&ps)) < ub)
+	{
+	  if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
+	    {
+	      ans = 1;
+	      goto ret;
+	    }
+	}
+    }
+ ret:
+  TMP_FREE;
+  return ans;
+}
+
+static const unsigned short nrtrial[] = { 100, 500, 1000 };
+
+/* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime
+   number.  */
+static const double logs[] =
+  { 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 };
+
+int
+mpn_perfect_power_p (mp_srcptr np, mp_size_t n)
+{
+  mp_limb_t *nc, factor, g;
+  mp_limb_t exp, d;
+  mp_bitcnt_t twos, count;
+  int ans, where, neg, trial;
+  TMP_DECL;
+
+  neg = n < 0;
+  if (neg)
+    {
+      n = -n;
+    }
+
+  if (n == 0 || (n == 1 && np[0] == 1)) /* Valgrind doesn't like
+					   (n <= (np[0] == 1)) */
+    return 1;
+
+  TMP_MARK;
+
+  count = 0;
+
+  twos = mpn_scan1 (np, 0);
+  if (twos != 0)
+    {
+      mp_size_t s;
+      if (twos == 1)
+	{
+	  return 0;
+	}
+      s = twos / GMP_LIMB_BITS;
+      if (s + 1 == n && POW2_P (np[s]))
+	{
+	  return ! (neg && POW2_P (twos));
+	}
+      count = twos % GMP_LIMB_BITS;
+      n -= s;
+      np += s;
+      if (count > 0)
+	{
+	  nc = TMP_ALLOC_LIMBS (n);
+	  mpn_rshift (nc, np, n, count);
+	  n -= (nc[n - 1] == 0);
+	  np = nc;
+	}
+    }
+  g = twos;
+
+  trial = (n > SMALL) + (n > MEDIUM);
+
+  where = 0;
+  factor = mpn_trialdiv (np, n, nrtrial[trial], &where);
+
+  if (factor != 0)
+    {
+      if (count == 0) /* We did not allocate nc yet. */
+	{
+	  nc = TMP_ALLOC_LIMBS (n);
+	}
+
+      /* Remove factors found by trialdiv.  Optimization: If remove
+	 define _itch, we can allocate its scratch just once */
+
+      do
+	{
+	  binvert_limb (d, factor);
+
+	  /* After the first round we always have nc == np */
+	  exp = mpn_remove (nc, &n, np, n, &d, 1, ~(mp_bitcnt_t)0);
+
+	  if (g == 0)
+	    g = exp;
+	  else
+	    g = mpn_gcd_1 (&g, 1, exp);
+
+	  if (g == 1)
+	    {
+	      ans = 0;
+	      goto ret;
+	    }
+
+	  if ((n == 1) & (nc[0] == 1))
+	    {
+	      ans = ! (neg && POW2_P (g));
+	      goto ret;
+	    }
+
+	  np = nc;
+	  factor = mpn_trialdiv (np, n, nrtrial[trial], &where);
+	}
+      while (factor != 0);
+    }
+
+  MPN_SIZEINBASE_2EXP(count, np, n, 1);   /* log (np) + 1 */
+  d = (mp_limb_t) (count * logs[trial] + 1e-9) + 1;
+  ans = perfpow (np, n, d, g, count, neg);
+
+ ret:
+  TMP_FREE;
+  return ans;
+}
diff --git a/mpn/generic/perfsqr.c b/mpn/generic/perfsqr.c
new file mode 100644
index 0000000..1ea5c84
--- /dev/null
+++ b/mpn/generic/perfsqr.c
@@ -0,0 +1,238 @@
+/* mpn_perfect_square_p(u,usize) -- Return non-zero if U is a perfect square,
+   zero otherwise.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "perfsqr.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+
+/* PERFSQR_MOD_* detects non-squares using residue tests.
+
+   A macro PERFSQR_MOD_TEST is setup by gen-psqr.c in perfsqr.h.  It takes
+   {up,usize} modulo a selected modulus to get a remainder r.  For 32-bit or
+   64-bit limbs this modulus will be 2^24-1 or 2^48-1 using PERFSQR_MOD_34,
+   or for other limb or nail sizes a PERFSQR_PP is chosen and PERFSQR_MOD_PP
+   used.  PERFSQR_PP_NORM and PERFSQR_PP_INVERTED are pre-calculated in this
+   case too.
+
+   PERFSQR_MOD_TEST then makes various calls to PERFSQR_MOD_1 or
+   PERFSQR_MOD_2 with divisors d which are factors of the modulus, and table
+   data indicating residues and non-residues modulo those divisors.  The
+   table data is in 1 or 2 limbs worth of bits respectively, per the size of
+   each d.
+
+   A "modexact" style remainder is taken to reduce r modulo d.
+   PERFSQR_MOD_IDX implements this, producing an index "idx" for use with
+   the table data.  Notice there's just one multiplication by a constant
+   "inv", for each d.
+
+   The modexact doesn't produce a true r%d remainder, instead idx satisfies
+   "-(idx<<PERFSQR_MOD_BITS) == r mod d".  Because d is odd, this factor
+   -2^PERFSQR_MOD_BITS is a one-to-one mapping between r and idx, and is
+   accounted for by having the table data suitably permuted.
+
+   The remainder r fits within PERFSQR_MOD_BITS which is less than a limb.
+   In fact the GMP_LIMB_BITS - PERFSQR_MOD_BITS spare bits are enough to fit
+   each divisor d meaning the modexact multiply can take place entirely
+   within one limb, giving the compiler the chance to optimize it, in a way
+   that say umul_ppmm would not give.
+
+   There's no need for the divisors d to be prime, in fact gen-psqr.c makes
+   a deliberate effort to combine factors so as to reduce the number of
+   separate tests done on r.  But such combining is limited to d <=
+   2*GMP_LIMB_BITS so that the table data fits in at most 2 limbs.
+
+   Alternatives:
+
+   It'd be possible to use bigger divisors d, and more than 2 limbs of table
+   data, but this doesn't look like it would be of much help to the prime
+   factors in the usual moduli 2^24-1 or 2^48-1.
+
+   The moduli 2^24-1 or 2^48-1 are nothing particularly special, they're
+   just easy to calculate (see mpn_mod_34lsub1) and have a nice set of prime
+   factors.  2^32-1 and 2^64-1 would be equally easy to calculate, but have
+   fewer prime factors.
+
+   The nails case usually ends up using mpn_mod_1, which is a lot slower
+   than mpn_mod_34lsub1.  Perhaps other such special moduli could be found
+   for the nails case.  Two-term things like 2^30-2^15-1 might be
+   candidates.  Or at worst some on-the-fly de-nailing would allow the plain
+   2^24-1 to be used.  Currently nails are too preliminary to be worried
+   about.
+
+*/
+
+#define PERFSQR_MOD_MASK       ((CNST_LIMB(1) << PERFSQR_MOD_BITS) - 1)
+
+#define MOD34_BITS  (GMP_NUMB_BITS / 4 * 3)
+#define MOD34_MASK  ((CNST_LIMB(1) << MOD34_BITS) - 1)
+
+#define PERFSQR_MOD_34(r, up, usize)				\
+  do {								\
+    (r) = mpn_mod_34lsub1 (up, usize);				\
+    (r) = ((r) & MOD34_MASK) + ((r) >> MOD34_BITS);		\
+  } while (0)
+
+/* FIXME: The %= here isn't good, and might destroy any savings from keeping
+   the PERFSQR_MOD_IDX stuff within a limb (rather than needing umul_ppmm).
+   Maybe a new sort of mpn_preinv_mod_1 could accept an unnormalized divisor
+   and a shift count, like mpn_preinv_divrem_1.  But mod_34lsub1 is our
+   normal case, so lets not worry too much about mod_1.  */
+#define PERFSQR_MOD_PP(r, up, usize)					\
+  do {									\
+    if (BELOW_THRESHOLD (usize, PREINV_MOD_1_TO_MOD_1_THRESHOLD))	\
+      {									\
+	(r) = mpn_preinv_mod_1 (up, usize, PERFSQR_PP_NORM,		\
+				PERFSQR_PP_INVERTED);			\
+	(r) %= PERFSQR_PP;						\
+      }									\
+    else								\
+      {									\
+	(r) = mpn_mod_1 (up, usize, PERFSQR_PP);			\
+      }									\
+  } while (0)
+
+#define PERFSQR_MOD_IDX(idx, r, d, inv)				\
+  do {								\
+    mp_limb_t  q;						\
+    ASSERT ((r) <= PERFSQR_MOD_MASK);				\
+    ASSERT ((((inv) * (d)) & PERFSQR_MOD_MASK) == 1);		\
+    ASSERT (MP_LIMB_T_MAX / (d) >= PERFSQR_MOD_MASK);		\
+								\
+    q = ((r) * (inv)) & PERFSQR_MOD_MASK;			\
+    ASSERT (r == ((q * (d)) & PERFSQR_MOD_MASK));		\
+    (idx) = (q * (d)) >> PERFSQR_MOD_BITS;			\
+  } while (0)
+
+#define PERFSQR_MOD_1(r, d, inv, mask)				\
+  do {								\
+    unsigned   idx;						\
+    ASSERT ((d) <= GMP_LIMB_BITS);				\
+    PERFSQR_MOD_IDX(idx, r, d, inv);				\
+    TRACE (printf ("  PERFSQR_MOD_1 d=%u r=%lu idx=%u\n",	\
+		   d, r%d, idx));				\
+    if ((((mask) >> idx) & 1) == 0)				\
+      {								\
+	TRACE (printf ("  non-square\n"));			\
+	return 0;						\
+      }								\
+  } while (0)
+
+/* The expression "(int) idx - GMP_LIMB_BITS < 0" lets the compiler use the
+   sign bit from "idx-GMP_LIMB_BITS", which might help avoid a branch.  */
+#define PERFSQR_MOD_2(r, d, inv, mhi, mlo)			\
+  do {								\
+    mp_limb_t  m;						\
+    unsigned   idx;						\
+    ASSERT ((d) <= 2*GMP_LIMB_BITS);				\
+								\
+    PERFSQR_MOD_IDX (idx, r, d, inv);				\
+    TRACE (printf ("  PERFSQR_MOD_2 d=%u r=%lu idx=%u\n",	\
+		   d, r%d, idx));				\
+    m = ((int) idx - GMP_LIMB_BITS < 0 ? (mlo) : (mhi));	\
+    idx %= GMP_LIMB_BITS;					\
+    if (((m >> idx) & 1) == 0)					\
+      {								\
+	TRACE (printf ("  non-square\n"));			\
+	return 0;						\
+      }								\
+  } while (0)
+
+
+int
+mpn_perfect_square_p (mp_srcptr up, mp_size_t usize)
+{
+  ASSERT (usize >= 1);
+
+  TRACE (gmp_printf ("mpn_perfect_square_p %Nd\n", up, usize));
+
+  /* The first test excludes 212/256 (82.8%) of the perfect square candidates
+     in O(1) time.  */
+  {
+    unsigned  idx = up[0] % 0x100;
+    if (((sq_res_0x100[idx / GMP_LIMB_BITS]
+	  >> (idx % GMP_LIMB_BITS)) & 1) == 0)
+      return 0;
+  }
+
+#if 0
+  /* Check that we have even multiplicity of 2, and then check that the rest is
+     a possible perfect square.  Leave disabled until we can determine this
+     really is an improvement.  If it is, it could completely replace the
+     simple probe above, since this should throw out more non-squares, but at
+     the expense of somewhat more cycles.  */
+  {
+    mp_limb_t lo;
+    int cnt;
+    lo = up[0];
+    while (lo == 0)
+      up++, lo = up[0], usize--;
+    count_trailing_zeros (cnt, lo);
+    if ((cnt & 1) != 0)
+      return 0;			/* return of not even multiplicity of 2 */
+    lo >>= cnt;			/* shift down to align lowest non-zero bit */
+    if ((lo & 6) != 0)
+      return 0;
+  }
+#endif
+
+
+  /* The second test uses mpn_mod_34lsub1 or mpn_mod_1 to detect non-squares
+     according to their residues modulo small primes (or powers of
+     primes).  See perfsqr.h.  */
+  PERFSQR_MOD_TEST (up, usize);
+
+
+  /* For the third and last test, we finally compute the square root,
+     to make sure we've really got a perfect square.  */
+  {
+    mp_ptr root_ptr;
+    int res;
+    TMP_DECL;
+
+    TMP_MARK;
+    root_ptr = TMP_ALLOC_LIMBS ((usize + 1) / 2);
+
+    /* Iff mpn_sqrtrem returns zero, the square is perfect.  */
+    res = ! mpn_sqrtrem (root_ptr, NULL, up, usize);
+    TMP_FREE;
+
+    return res;
+  }
+}
diff --git a/mpn/generic/popham.c b/mpn/generic/popham.c
new file mode 100644
index 0000000..87974d7
--- /dev/null
+++ b/mpn/generic/popham.c
@@ -0,0 +1,125 @@
+/* mpn_popcount, mpn_hamdist -- mpn bit population count/hamming distance.
+
+Copyright 1994, 1996, 2000-2002, 2005, 2011, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if OPERATION_popcount
+#define FNAME mpn_popcount
+#define POPHAM(u,v) u
+#endif
+
+#if OPERATION_hamdist
+#define FNAME mpn_hamdist
+#define POPHAM(u,v) u ^ v
+#endif
+
+mp_bitcnt_t
+FNAME (mp_srcptr up,
+#if OPERATION_hamdist
+       mp_srcptr vp,
+#endif
+       mp_size_t n) __GMP_NOTHROW
+{
+  mp_bitcnt_t result = 0;
+  mp_limb_t p0, p1, p2, p3, x, p01, p23;
+  mp_size_t i;
+
+  ASSERT (n >= 1);		/* Actually, this code handles any n, but some
+				   assembly implementations do not.  */
+
+  for (i = n >> 2; i != 0; i--)
+    {
+      p0 = POPHAM (up[0], vp[0]);
+      p0 -= (p0 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p0 = ((p0 >> 2) & MP_LIMB_T_MAX/5) + (p0 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p1 = POPHAM (up[1], vp[1]);
+      p1 -= (p1 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p1 = ((p1 >> 2) & MP_LIMB_T_MAX/5) + (p1 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p01 = p0 + p1;							/* 8 0-8 */
+      p01 = ((p01 >> 4) & MP_LIMB_T_MAX/17) + (p01 & MP_LIMB_T_MAX/17);	/* 8 0-16 */
+
+      p2 = POPHAM (up[2], vp[2]);
+      p2 -= (p2 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p2 = ((p2 >> 2) & MP_LIMB_T_MAX/5) + (p2 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p3 = POPHAM (up[3], vp[3]);
+      p3 -= (p3 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p3 = ((p3 >> 2) & MP_LIMB_T_MAX/5) + (p3 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p23 = p2 + p3;							/* 8 0-8 */
+      p23 = ((p23 >> 4) & MP_LIMB_T_MAX/17) + (p23 & MP_LIMB_T_MAX/17);	/* 8 0-16 */
+
+      x = p01 + p23;							/* 8 0-32 */
+      x = (x >> 8) + x;							/* 8 0-64 */
+      x = (x >> 16) + x;						/* 8 0-128 */
+#if GMP_LIMB_BITS > 32
+      x = ((x >> 32) & 0xff) + (x & 0xff);				/* 8 0-256 */
+      result += x;
+#else
+      result += x & 0xff;
+#endif
+      up += 4;
+#if OPERATION_hamdist
+      vp += 4;
+#endif
+    }
+
+  n &= 3;
+  if (n != 0)
+    {
+      x = 0;
+      do
+	{
+	  p0 = POPHAM (up[0], vp[0]);
+	  p0 -= (p0 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+	  p0 = ((p0 >> 2) & MP_LIMB_T_MAX/5) + (p0 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+	  p0 = ((p0 >> 4) + p0) & MP_LIMB_T_MAX/17;			/* 8 0-8 */
+
+	  x += p0;
+	  up += 1;
+#if OPERATION_hamdist
+	  vp += 1;
+#endif
+	}
+      while (--n);
+
+      x = (x >> 8) + x;
+      x = (x >> 16) + x;
+#if GMP_LIMB_BITS > 32
+      x = (x >> 32) + x;
+#endif
+      result += x & 0xff;
+    }
+
+  return result;
+}
diff --git a/mpn/generic/pow_1.c b/mpn/generic/pow_1.c
new file mode 100644
index 0000000..de11cd2
--- /dev/null
+++ b/mpn/generic/pow_1.c
@@ -0,0 +1,135 @@
+/* mpn_pow_1 -- Compute powers R = U^exp.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_size_t
+mpn_pow_1 (mp_ptr rp, mp_srcptr bp, mp_size_t bn, mp_limb_t exp, mp_ptr tp)
+{
+  mp_limb_t x;
+  int cnt, i;
+  mp_size_t rn;
+  int par;
+
+  ASSERT (bn >= 1);
+  /* FIXME: Add operand overlap criteria */
+
+  if (exp <= 1)
+    {
+      if (exp == 0)
+	{
+	  rp[0] = 1;
+	  return 1;
+	}
+      else
+	{
+	  MPN_COPY (rp, bp, bn);
+	  return bn;
+	}
+    }
+
+  /* Count number of bits in exp, and compute where to put initial square in
+     order to magically get results in the entry rp.  Use simple code,
+     optimized for small exp.  For large exp, the bignum operations will take
+     so much time that the slowness of this code will be negligible.  */
+  par = 0;
+  cnt = GMP_LIMB_BITS;
+  x = exp;
+  do
+    {
+      par ^= x;
+      cnt--;
+      x >>= 1;
+    } while (x != 0);
+  exp <<= cnt;
+
+  if (bn == 1)
+    {
+      mp_limb_t rl, rh, bl = bp[0];
+
+      if ((cnt & 1) != 0)
+	MP_PTR_SWAP (rp, tp);
+
+      umul_ppmm (rh, rl, bl, bl << GMP_NAIL_BITS);
+      rp[0] = rl >> GMP_NAIL_BITS;
+      rp[1] = rh;
+      rn = 1 + (rh != 0);
+
+      for (i = GMP_LIMB_BITS - cnt - 1;;)
+	{
+	  exp <<= 1;
+	  if ((exp & GMP_LIMB_HIGHBIT) != 0)
+	    {
+	      rp[rn] = rh = mpn_mul_1 (rp, rp, rn, bl);
+	      rn += rh != 0;
+	    }
+
+	  if (--i == 0)
+	    break;
+
+	  mpn_sqr (tp, rp, rn);
+	  rn = 2 * rn; rn -= tp[rn - 1] == 0;
+	  MP_PTR_SWAP (rp, tp);
+	}
+    }
+  else
+    {
+      if (((par ^ cnt) & 1) == 0)
+	MP_PTR_SWAP (rp, tp);
+
+      mpn_sqr (rp, bp, bn);
+      rn = 2 * bn; rn -= rp[rn - 1] == 0;
+
+      for (i = GMP_LIMB_BITS - cnt - 1;;)
+	{
+	  exp <<= 1;
+	  if ((exp & GMP_LIMB_HIGHBIT) != 0)
+	    {
+	      rn = rn + bn - (mpn_mul (tp, rp, rn, bp, bn) == 0);
+	      MP_PTR_SWAP (rp, tp);
+	    }
+
+	  if (--i == 0)
+	    break;
+
+	  mpn_sqr (tp, rp, rn);
+	  rn = 2 * rn; rn -= tp[rn - 1] == 0;
+	  MP_PTR_SWAP (rp, tp);
+	}
+    }
+
+  return rn;
+}
diff --git a/mpn/generic/powlo.c b/mpn/generic/powlo.c
new file mode 100644
index 0000000..c109512
--- /dev/null
+++ b/mpn/generic/powlo.c
@@ -0,0 +1,188 @@
+/* mpn_powlo -- Compute R = U^E mod B^n, where B is the limb base.
+
+Copyright 2007-2009, 2012, 2015, 2016, 2018, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#define getbit(p,bi) \
+  ((p[(bi - 1) / GMP_LIMB_BITS] >> (bi - 1) % GMP_LIMB_BITS) & 1)
+
+static inline mp_limb_t
+getbits (const mp_limb_t *p, mp_bitcnt_t bi, unsigned nbits)
+{
+  unsigned nbits_in_r;
+  mp_limb_t r;
+  mp_size_t i;
+
+  if (bi <= nbits)
+    {
+      return p[0] & (((mp_limb_t) 1 << bi) - 1);
+    }
+  else
+    {
+      bi -= nbits;			/* bit index of low bit to extract */
+      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
+      bi %= GMP_NUMB_BITS;		/* bit index in low word */
+      r = p[i] >> bi;			/* extract (low) bits */
+      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
+      if (nbits_in_r < nbits)		/* did we get enough bits? */
+	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
+      return r & (((mp_limb_t) 1 << nbits) - 1);
+    }
+}
+
+static inline unsigned
+win_size (mp_bitcnt_t eb)
+{
+  unsigned k;
+  static mp_bitcnt_t x[] = {7,25,81,241,673,1793,4609,11521,28161,~(mp_bitcnt_t)0};
+  ASSERT (eb > 1);
+  for (k = 0; eb > x[k++];)
+    ;
+  return k;
+}
+
+/* rp[n-1..0] = bp[n-1..0] ^ ep[en-1..0] mod B^n, B is the limb base.
+   Requires that ep[en-1] is non-zero.
+   Uses scratch space tp[3n-1..0], i.e., 3n words.  */
+/* We only use n words in the scratch space, we should pass tp + n to
+   mullo/sqrlo as a temporary area, it is needed. */
+void
+mpn_powlo (mp_ptr rp, mp_srcptr bp,
+	   mp_srcptr ep, mp_size_t en,
+	   mp_size_t n, mp_ptr tp)
+{
+  unsigned cnt;
+  mp_bitcnt_t ebi;
+  unsigned windowsize, this_windowsize;
+  mp_limb_t expbits;
+  mp_limb_t *pp;
+  long i;
+  int flipflop;
+  TMP_DECL;
+
+  ASSERT (en > 1 || (en == 1 && ep[0] > 1));
+
+  TMP_MARK;
+
+  MPN_SIZEINBASE_2EXP(ebi, ep, en, 1);
+
+  windowsize = win_size (ebi);
+  if (windowsize > 1)
+    {
+      mp_limb_t *this_pp, *last_pp;
+      ASSERT (windowsize < ebi);
+
+      pp = TMP_ALLOC_LIMBS ((n << (windowsize - 1)));
+
+      this_pp = pp;
+
+      MPN_COPY (this_pp, bp, n);
+
+      /* Store b^2 in tp.  */
+      mpn_sqrlo (tp, bp, n);
+
+      /* Precompute odd powers of b and put them in the temporary area at pp.  */
+      i = (1 << (windowsize - 1)) - 1;
+      do
+	{
+	  last_pp = this_pp;
+	  this_pp += n;
+	  mpn_mullo_n (this_pp, last_pp, tp, n);
+	} while (--i != 0);
+
+      expbits = getbits (ep, ebi, windowsize);
+      ebi -= windowsize;
+
+      /* THINK: Should we initialise the case expbits % 4 == 0 with a mullo? */
+      count_trailing_zeros (cnt, expbits);
+      ebi += cnt;
+      expbits >>= cnt;
+
+      MPN_COPY (rp, pp + n * (expbits >> 1), n);
+    }
+  else
+    {
+      pp = tp + n;
+      MPN_COPY (pp, bp, n);
+      MPN_COPY (rp, bp, n);
+      --ebi;
+    }
+
+  flipflop = 0;
+
+  do
+    {
+      while (getbit (ep, ebi) == 0)
+	{
+	  mpn_sqrlo (tp, rp, n);
+	  MP_PTR_SWAP (rp, tp);
+	  flipflop = ! flipflop;
+	  if (--ebi == 0)
+	    goto done;
+	}
+
+      /* The next bit of the exponent is 1.  Now extract the largest block of
+	 bits <= windowsize, and such that the least significant bit is 1.  */
+
+      expbits = getbits (ep, ebi, windowsize);
+      this_windowsize = MIN (windowsize, ebi);
+
+      count_trailing_zeros (cnt, expbits);
+      this_windowsize -= cnt;
+      ebi -= this_windowsize;
+      expbits >>= cnt;
+
+      while (this_windowsize > 1)
+	{
+	  mpn_sqrlo (tp, rp, n);
+	  mpn_sqrlo (rp, tp, n);
+	  this_windowsize -= 2;
+	}
+
+      if (this_windowsize != 0)
+	mpn_sqrlo (tp, rp, n);
+      else
+	{
+	  MP_PTR_SWAP (rp, tp);
+	  flipflop = ! flipflop;
+	}
+
+      mpn_mullo_n (rp, tp, pp + n * (expbits >> 1), n);
+    } while (ebi != 0);
+
+ done:
+  if (flipflop)
+    MPN_COPY (tp, rp, n);
+  TMP_FREE;
+}
diff --git a/mpn/generic/powm.c b/mpn/generic/powm.c
new file mode 100644
index 0000000..1e30f2f
--- /dev/null
+++ b/mpn/generic/powm.c
@@ -0,0 +1,1003 @@
+/* mpn_powm -- Compute R = U^E mod M.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2007-2012, 2019-2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+  BASIC ALGORITHM, Compute U^E mod M, where M < B^n is odd.
+
+  1. W <- U
+
+  2. T <- (B^n * U) mod M                Convert to REDC form
+
+  3. Compute table U^1, U^3, U^5... of E-dependent size
+
+  4. While there are more bits in E
+       W <- power left-to-right base-k
+
+
+  TODO:
+
+   * Make getbits a macro, thereby allowing it to update the index operand.
+     That will simplify the code using getbits.  (Perhaps make getbits' sibling
+     getbit then have similar form, for symmetry.)
+
+   * Write an itch function.  Or perhaps get rid of tp parameter since the huge
+     pp area is allocated locally anyway?
+
+   * Choose window size without looping.  (Superoptimize or think(tm).)
+
+   * Handle small bases with initial, reduction-free exponentiation.
+
+   * Call new division functions, not mpn_tdiv_qr.
+
+   * Consider special code for one-limb M.
+
+   * How should we handle the redc1/redc2/redc_n choice?
+     - redc1:  T(binvert_1limb)  + e * (n)   * (T(mullo-1x1) + n*T(addmul_1))
+     - redc2:  T(binvert_2limbs) + e * (n/2) * (T(mullo-2x2) + n*T(addmul_2))
+     - redc_n: T(binvert_nlimbs) + e * (T(mullo-nxn) + T(M(n)))
+     This disregards the addmul_N constant term, but we could think of
+     that as part of the respective mullo.
+
+   * When U (the base) is small, we should start the exponentiation with plain
+     operations, then convert that partial result to REDC form.
+
+   * When U is just one limb, should it be handled without the k-ary tricks?
+     We could keep a factor of B^n in W, but use U' = BU as base.  After
+     multiplying by this (pseudo two-limb) number, we need to multiply by 1/B
+     mod M.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#undef MPN_REDC_0
+#define MPN_REDC_0(r0, u1, u0, m0, invm)				\
+  do {									\
+    mp_limb_t _p1, _u1, _u0, _m0, _r0, _dummy;				\
+    _u0 = (u0);								\
+    _m0 = (m0);								\
+    umul_ppmm (_p1, _dummy, _m0, (_u0 * (invm)) & GMP_NUMB_MASK);	\
+    ASSERT (((_u0 - _dummy) & GMP_NUMB_MASK) == 0);			\
+    _u1 = (u1);								\
+    _r0 = _u1 - _p1;							\
+    _r0 = _u1 < _p1 ? _r0 + _m0 : _r0; /* _u1 < _r0 */			\
+    (r0) = _r0 & GMP_NUMB_MASK;						\
+  } while (0)
+
+#undef MPN_REDC_1
+#if HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#define MPN_REDC_1(rp, up, mp, n, invm)					\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_sbpi1_bdiv_r (up, 2 * n, mp, n, invm);			\
+    if (cy != 0)							\
+      mpn_sub_n (rp, up + n, mp, n);					\
+    else								\
+      MPN_COPY (rp, up + n, n);						\
+  } while (0)
+#else
+#define MPN_REDC_1(rp, up, mp, n, invm)					\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_1 (rp, up, mp, n, invm);				\
+    if (cy != 0)							\
+      mpn_sub_n (rp, rp, mp, n);					\
+  } while (0)
+#endif
+
+#undef MPN_REDC_2
+#define MPN_REDC_2(rp, up, mp, n, mip)					\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_2 (rp, up, mp, n, mip);				\
+    if (cy != 0)							\
+      mpn_sub_n (rp, rp, mp, n);					\
+  } while (0)
+
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+#define WANT_REDC_2 1
+#endif
+
+#define getbit(p,bi) \
+  ((p[(bi - 1) / GMP_LIMB_BITS] >> (bi - 1) % GMP_LIMB_BITS) & 1)
+
+static inline mp_limb_t
+getbits (const mp_limb_t *p, mp_bitcnt_t bi, int nbits)
+{
+  int nbits_in_r;
+  mp_limb_t r;
+  mp_size_t i;
+
+  if (bi <= nbits)
+    {
+      return p[0] & (((mp_limb_t) 1 << bi) - 1);
+    }
+  else
+    {
+      bi -= nbits;			/* bit index of low bit to extract */
+      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
+      bi %= GMP_NUMB_BITS;		/* bit index in low word */
+      r = p[i] >> bi;			/* extract (low) bits */
+      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
+      if (nbits_in_r < nbits)		/* did we get enough bits? */
+	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
+      return r & (((mp_limb_t) 1 << nbits) - 1);
+    }
+}
+
+static inline int
+win_size (mp_bitcnt_t eb)
+{
+  int k;
+  static mp_bitcnt_t x[] = {7,25,81,241,673,1793,4609,11521,28161,~(mp_bitcnt_t)0};
+  for (k = 0; eb > x[k++]; )
+    ;
+  return k;
+}
+
+/* Convert U to REDC form, U_r = B^n * U mod M */
+static void
+redcify (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr mp, mp_size_t n)
+{
+  mp_ptr tp, qp;
+  TMP_DECL;
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (tp, un + n, qp, un + 1);
+
+  MPN_ZERO (tp, n);
+  MPN_COPY (tp + n, up, un);
+  mpn_tdiv_qr (qp, rp, 0L, tp, un + n, mp, n);
+  TMP_FREE;
+}
+
+#if ! HAVE_NATIVE_mpn_rsblsh1_n_ip2
+#undef mpn_rsblsh1_n_ip2
+#if HAVE_NATIVE_mpn_rsblsh1_n
+#define mpn_rsblsh1_n_ip2(a,b,n)	mpn_rsblsh1_n(a,b,a,n)
+#else
+#define mpn_rsblsh1_n_ip2(a,b,n)				\
+  do								\
+    {								\
+      mpn_lshift (a, a, n, 1);					\
+      mpn_sub_n (a, a, b, n);					\
+    } while (0)
+#endif
+#endif
+
+#define INNERLOOP2						\
+  do								\
+    {								\
+      MPN_SQR (tp, rp, n);					\
+      MPN_REDUCE (rp, tp, mp, n, mip);				\
+      if (mpn_cmp (rp, mp, n) >= 0)				\
+	ASSERT_NOCARRY (mpn_sub_n (rp, rp, mp, n));		\
+      if (getbit (ep, ebi) != 0)				\
+	{							\
+	  if (rp[n - 1] >> (mbi - 1) % GMP_LIMB_BITS == 0)	\
+	    ASSERT_NOCARRY (mpn_lshift (rp, rp, n, 1));		\
+	  else							\
+	    mpn_rsblsh1_n_ip2 (rp, mp, n);			\
+	}							\
+    } while (--ebi != 0)
+
+/* rp[n-1..0] = 2 ^ ep[en-1..0] mod mp[n-1..0]
+   Requires that mp[n-1..0] is odd and > 1.
+   Requires that ep[en-1..0] is > 1.
+   Uses scratch space at tp of MAX(mpn_binvert_itch(n),2n) limbs.  */
+static void
+mpn_2powm (mp_ptr rp, mp_srcptr ep, mp_size_t en,
+	  mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ip[2], *mip;
+  mp_bitcnt_t ebi, mbi, tbi;
+  mp_size_t tn;
+  int count;
+  TMP_DECL;
+
+  ASSERT (en > 1 || (en == 1 && ep[0] > 1));
+  ASSERT (n > 0 && (mp[0] & 1) != 0);
+
+  MPN_SIZEINBASE_2EXP(ebi, ep, en, 1);
+  MPN_SIZEINBASE_2EXP(mbi, mp, n, 1);
+
+  if (LIKELY (mbi <= GMP_NUMB_MAX))
+    {
+      count_leading_zeros(count, (mp_limb_t) mbi);
+      count = GMP_NUMB_BITS - (count - GMP_NAIL_BITS);
+    }
+  else
+    {
+      mp_bitcnt_t tc = mbi;
+
+      count = 0;
+      do { ++count; } while ((tc >>= 1) != 0);
+    }
+
+  tbi = getbits (ep, ebi, count);
+  if (tbi >= mbi)
+    {
+      --count;
+      ASSERT ((tbi >> count) == 1);
+      tbi >>= 1;
+      ASSERT (tbi < mbi);
+      ASSERT (ebi > count);
+    }
+  else if (ebi <= count)
+    {
+      MPN_FILL (rp, n, 0);
+      rp[tbi / GMP_LIMB_BITS] = CNST_LIMB (1) << (tbi % GMP_LIMB_BITS);
+      return;
+    }
+  ebi -= count;
+
+  if (n == 1)
+    {
+      mp_limb_t r0, m0, invm;
+      m0 = *mp;
+
+      /* redcify (rp, tp, tn + 1, mp, n); */
+      /* TODO: test direct use of udiv_qrnnd */
+      ASSERT (tbi < GMP_LIMB_BITS);
+      tp[1] = CNST_LIMB (1) << tbi;
+      tp[0] = CNST_LIMB (0);
+      r0 = mpn_mod_1 (tp, 2, m0);
+
+      binvert_limb (invm, m0);
+      do
+	{
+	  mp_limb_t t0, t1, t2;
+	  /* MPN_SQR (tp, rp, n);			*/
+	  umul_ppmm (t1, t0, r0, r0);
+	  /* MPN_REDUCE (rp, tp, mp, n, mip);		*/
+	  MPN_REDC_0(r0, t1, t0, m0, invm);
+
+	  t2 = r0 << 1;
+	  t2 = r0 > (m0 >> 1) ? t2 - m0 : t2;
+	  r0 = getbit (ep, ebi) != 0 ? t2 : r0;
+	} while (--ebi != 0);
+
+      /* tp[1] = 0; tp[0] = r0;	*/
+      /* MPN_REDUCE (rp, tp, mp, n, mip);	*/
+      MPN_REDC_0(*rp, 0, r0, m0, invm);
+
+      return;
+    }
+
+  TMP_MARK;
+
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (ip[0], mp[0]);
+      ip[0] = -ip[0];
+    }
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    {
+      mip = ip;
+      mpn_binvert (ip, mp, 2, tp);
+      ip[0] = -ip[0]; ip[1] = ~ip[1];
+    }
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (ip[0], mp[0]);
+      ip[0] = -ip[0];
+    }
+#endif
+  else
+    {
+      mip = TMP_ALLOC_LIMBS (n);
+      mpn_binvert (mip, mp, n, tp);
+    }
+
+  tn = tbi / GMP_LIMB_BITS;
+  MPN_ZERO (tp, tn);
+  tp[tn] = CNST_LIMB (1) << (tbi % GMP_LIMB_BITS);
+
+  redcify (rp, tp, tn + 1, mp, n);
+
+#if WANT_REDC_2
+  if (REDC_1_TO_REDC_2_THRESHOLD < MUL_TOOM22_THRESHOLD)
+    {
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	{
+	  if (REDC_1_TO_REDC_2_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	  else
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	      INNERLOOP2;
+	    }
+	  else
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	      INNERLOOP2;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	  INNERLOOP2;
+	}
+      else
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP2;
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	  else
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	  INNERLOOP2;
+	}
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	  INNERLOOP2;
+	}
+      else
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP2;
+	}
+    }
+
+#else  /* WANT_REDC_2 */
+
+  if (REDC_1_TO_REDC_N_THRESHOLD < MUL_TOOM22_THRESHOLD)
+    {
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	{
+	  if (REDC_1_TO_REDC_N_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	  else
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	      INNERLOOP2;
+	    }
+	  else
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	      INNERLOOP2;
+	    }
+	}
+      else
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP2;
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	  else
+	    {
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP2;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	  INNERLOOP2;
+	}
+      else
+	{
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP2;
+	}
+    }
+#endif  /* WANT_REDC_2 */
+
+  MPN_COPY (tp, rp, n);
+  MPN_FILL (tp + n, n, 0);
+
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, ip[0]);
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    MPN_REDC_2 (rp, tp, mp, n, mip);
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, ip[0]);
+#endif
+  else
+    mpn_redc_n (rp, tp, mp, n, mip);
+
+  if (mpn_cmp (rp, mp, n) >= 0)
+    mpn_sub_n (rp, rp, mp, n);
+
+  TMP_FREE;
+}
+
+/* rp[n-1..0] = bp[bn-1..0] ^ ep[en-1..0] mod mp[n-1..0]
+   Requires that mp[n-1..0] is odd.
+   Requires that ep[en-1..0] is > 1.
+   Uses scratch space at tp of MAX(mpn_binvert_itch(n),2n) limbs.  */
+void
+mpn_powm (mp_ptr rp, mp_srcptr bp, mp_size_t bn,
+	  mp_srcptr ep, mp_size_t en,
+	  mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ip[2], *mip;
+  int cnt;
+  mp_bitcnt_t ebi;
+  int windowsize, this_windowsize;
+  mp_limb_t expbits;
+  mp_ptr pp, this_pp;
+  long i;
+  TMP_DECL;
+
+  ASSERT (en > 1 || (en == 1 && ep[0] > 1));
+  ASSERT (n >= 1 && ((mp[0] & 1) != 0));
+
+  if (bn == 1 && bp[0] == 2)
+    {
+      mpn_2powm (rp, ep, en, mp, n, tp);
+      return;
+    }
+
+  TMP_MARK;
+
+  MPN_SIZEINBASE_2EXP(ebi, ep, en, 1);
+
+#if 0
+  if (bn < n)
+    {
+      /* Do the first few exponent bits without mod reductions,
+	 until the result is greater than the mod argument.  */
+      for (;;)
+	{
+	  mpn_sqr (tp, this_pp, tn);
+	  tn = tn * 2 - 1,  tn += tp[tn] != 0;
+	  if (getbit (ep, ebi) != 0)
+	    mpn_mul (..., tp, tn, bp, bn);
+	  ebi--;
+	}
+    }
+#endif
+
+  windowsize = win_size (ebi);
+
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (mip[0], mp[0]);
+      mip[0] = -mip[0];
+    }
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    {
+      mip = ip;
+      mpn_binvert (mip, mp, 2, tp);
+      mip[0] = -mip[0]; mip[1] = ~mip[1];
+    }
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (mip[0], mp[0]);
+      mip[0] = -mip[0];
+    }
+#endif
+  else
+    {
+      mip = TMP_ALLOC_LIMBS (n);
+      mpn_binvert (mip, mp, n, tp);
+    }
+
+  pp = TMP_ALLOC_LIMBS (n << (windowsize - 1));
+
+  this_pp = pp;
+  redcify (this_pp, bp, bn, mp, n);
+
+  /* Store b^2 at rp.  */
+  mpn_sqr (tp, this_pp, n);
+#if 0
+  if (n == 1) {
+    MPN_REDC_0 (rp[0], tp[1], tp[0], mp[0], -mip[0]);
+  } else
+#endif
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    MPN_REDC_2 (rp, tp, mp, n, mip);
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+#endif
+  else
+    mpn_redc_n (rp, tp, mp, n, mip);
+
+  /* Precompute odd powers of b and put them in the temporary area at pp.  */
+  for (i = (1 << (windowsize - 1)) - 1; i > 0; i--)
+#if 1
+    if (n == 1) {
+      umul_ppmm((tp)[1], *(tp), *(this_pp), *(rp));
+      ++this_pp ;
+      MPN_REDC_0 (*this_pp, tp[1], tp[0], *mp, -mip[0]);
+    } else
+#endif
+    {
+      mpn_mul_n (tp, this_pp, rp, n);
+      this_pp += n;
+#if WANT_REDC_2
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	MPN_REDC_1 (this_pp, tp, mp, n, mip[0]);
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	MPN_REDC_2 (this_pp, tp, mp, n, mip);
+#else
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	MPN_REDC_1 (this_pp, tp, mp, n, mip[0]);
+#endif
+      else
+	mpn_redc_n (this_pp, tp, mp, n, mip);
+    }
+
+  expbits = getbits (ep, ebi, windowsize);
+  ebi -= windowsize;
+
+  /* THINK: Should we initialise the case expbits % 4 == 0 with a mul? */
+  count_trailing_zeros (cnt, expbits);
+  ebi += cnt;
+  expbits >>= cnt;
+
+  MPN_COPY (rp, pp + n * (expbits >> 1), n);
+
+#define INNERLOOP							\
+  while (ebi != 0)							\
+    {									\
+      while (getbit (ep, ebi) == 0)					\
+	{								\
+	  MPN_SQR (tp, rp, n);						\
+	  MPN_REDUCE (rp, tp, mp, n, mip);				\
+	  if (--ebi == 0)						\
+	    goto done;							\
+	}								\
+									\
+      /* The next bit of the exponent is 1.  Now extract the largest	\
+	 block of bits <= windowsize, and such that the least		\
+	 significant bit is 1.  */					\
+									\
+      expbits = getbits (ep, ebi, windowsize);				\
+      this_windowsize = MIN (ebi, windowsize);				\
+									\
+      count_trailing_zeros (cnt, expbits);				\
+      this_windowsize -= cnt;						\
+      ebi -= this_windowsize;						\
+      expbits >>= cnt;							\
+									\
+      do								\
+	{								\
+	  MPN_SQR (tp, rp, n);						\
+	  MPN_REDUCE (rp, tp, mp, n, mip);				\
+	}								\
+      while (--this_windowsize != 0);					\
+									\
+      MPN_MUL_N (tp, rp, pp + n * (expbits >> 1), n);			\
+      MPN_REDUCE (rp, tp, mp, n, mip);					\
+    }
+
+
+  if (n == 1)
+    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		umul_ppmm((r)[1], *(r), *(a), *(b))
+#define MPN_SQR(r,a,n)			umul_ppmm((r)[1], *(r), *(a), *(a))
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_0(*(rp), (tp)[1], (tp)[0], *(mp), - *(mip))
+      INNERLOOP;
+    }
+  else
+#if WANT_REDC_2
+  if (REDC_1_TO_REDC_2_THRESHOLD < MUL_TOOM22_THRESHOLD)
+    {
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	{
+	  if (REDC_1_TO_REDC_2_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	  INNERLOOP;
+	}
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+
+#else  /* WANT_REDC_2 */
+
+  if (REDC_1_TO_REDC_N_THRESHOLD < MUL_TOOM22_THRESHOLD)
+    {
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	{
+	  if (REDC_1_TO_REDC_N_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	  INNERLOOP;
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+#endif  /* WANT_REDC_2 */
+
+ done:
+
+  MPN_COPY (tp, rp, n);
+  MPN_ZERO (tp + n, n);
+
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    MPN_REDC_2 (rp, tp, mp, n, mip);
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+#endif
+  else
+    mpn_redc_n (rp, tp, mp, n, mip);
+
+  if (mpn_cmp (rp, mp, n) >= 0)
+    mpn_sub_n (rp, rp, mp, n);
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/pre_divrem_1.c b/mpn/generic/pre_divrem_1.c
new file mode 100644
index 0000000..3b29d77
--- /dev/null
+++ b/mpn/generic/pre_divrem_1.c
@@ -0,0 +1,145 @@
+/* mpn_preinv_divrem_1 -- mpn by limb division with pre-inverted divisor.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Don't bloat a shared library with unused code. */
+#if USE_PREINV_DIVREM_1
+
+/* Same test here for skipping one divide step as in mpn_divrem_1.
+
+   The main reason for a separate shift==0 case is that not all CPUs give
+   zero for "n0 >> GMP_LIMB_BITS" which would arise in the general case
+   code used on shift==0.  shift==0 is also reasonably common in mp_bases
+   big_base, for instance base==10 on a 64-bit limb.
+
+   Under shift!=0 it would be possible to call mpn_lshift to adjust the
+   dividend all in one go (into the quotient space say), rather than
+   limb-by-limb in the loop.  This might help if mpn_lshift is a lot faster
+   than what the compiler can generate for EXTRACT.  But this is left to CPU
+   specific implementations to consider, especially since EXTRACT isn't on
+   the dependent chain.
+
+   If size==0 then the result is simply xsize limbs of zeros, but nothing
+   special is done for that, since it wouldn't be a usual call, and
+   certainly never arises from mpn_get_str which is our main caller.  */
+
+mp_limb_t
+mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t xsize,
+		     mp_srcptr ap, mp_size_t size, mp_limb_t d_unnorm,
+		     mp_limb_t dinv, int shift)
+{
+  mp_limb_t  ahigh, qhigh, r;
+  mp_size_t  i;
+  mp_limb_t  n1, n0;
+  mp_limb_t  d;
+
+  ASSERT (xsize >= 0);
+  ASSERT (size >= 1);
+  ASSERT (d_unnorm != 0);
+#if WANT_ASSERT
+  {
+    int        want_shift;
+    mp_limb_t  want_dinv;
+    count_leading_zeros (want_shift, d_unnorm);
+    ASSERT (shift == want_shift);
+    invert_limb (want_dinv, d_unnorm << shift);
+    ASSERT (dinv == want_dinv);
+  }
+#endif
+  /* FIXME: What's the correct overlap rule when xsize!=0? */
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp+xsize, ap, size));
+
+  ahigh = ap[size-1];
+  d = d_unnorm << shift;
+  qp += (size + xsize - 1);   /* dest high limb */
+
+  if (shift == 0)
+    {
+      /* High quotient limb is 0 or 1, and skip a divide step. */
+      r = ahigh;
+      qhigh = (r >= d);
+      r = (qhigh ? r-d : r);
+      *qp-- = qhigh;
+      size--;
+
+      for (i = size-1; i >= 0; i--)
+	{
+	  n0 = ap[i];
+	  udiv_qrnnd_preinv (*qp, r, r, n0, d, dinv);
+	  qp--;
+	}
+    }
+  else
+    {
+      r = 0;
+      if (ahigh < d_unnorm)
+	{
+	  r = ahigh << shift;
+	  *qp-- = 0;
+	  size--;
+	  if (size == 0)
+	    goto done_integer;
+	}
+
+      n1 = ap[size-1];
+      r |= n1 >> (GMP_LIMB_BITS - shift);
+
+      for (i = size-2; i >= 0; i--)
+	{
+	  ASSERT (r < d);
+	  n0 = ap[i];
+	  udiv_qrnnd_preinv (*qp, r, r,
+			     ((n1 << shift) | (n0 >> (GMP_LIMB_BITS - shift))),
+			     d, dinv);
+	  qp--;
+	  n1 = n0;
+	}
+      udiv_qrnnd_preinv (*qp, r, r, n1 << shift, d, dinv);
+      qp--;
+    }
+
+ done_integer:
+  for (i = 0; i < xsize; i++)
+    {
+      udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv);
+      qp--;
+    }
+
+  return r >> shift;
+}
+
+#endif /* USE_PREINV_DIVREM_1 */
diff --git a/mpn/generic/pre_mod_1.c b/mpn/generic/pre_mod_1.c
new file mode 100644
index 0000000..78ae308
--- /dev/null
+++ b/mpn/generic/pre_mod_1.c
@@ -0,0 +1,61 @@
+/* mpn_preinv_mod_1 (up, un, d, dinv) -- Divide (UP,,UN) by the normalized D.
+   DINV should be 2^(2*GMP_LIMB_BITS) / D - 2^GMP_LIMB_BITS.
+   Return the single-limb remainder.
+
+Copyright 1991, 1993, 1994, 2000-2002, 2004, 2005 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This function used to be documented, but is now considered obsolete.  It
+   continues to exist for binary compatibility, even when not required
+   internally.  */
+
+mp_limb_t
+mpn_preinv_mod_1 (mp_srcptr up, mp_size_t un, mp_limb_t d, mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t n0, r;
+
+  ASSERT (un >= 1);
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+
+  r = up[un - 1];
+  if (r >= d)
+    r -= d;
+
+  for (i = un - 2; i >= 0; i--)
+    {
+      n0 = up[i];
+      udiv_rnnd_preinv (r, r, n0, d, dinv);
+    }
+  return r;
+}
diff --git a/mpn/generic/random.c b/mpn/generic/random.c
new file mode 100644
index 0000000..485f9eb
--- /dev/null
+++ b/mpn/generic/random.c
@@ -0,0 +1,50 @@
+/* mpn_random -- Generate random numbers.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_random (mp_ptr ptr, mp_size_t size)
+{
+  gmp_randstate_ptr  rands;
+
+  /* FIXME: Is size==0 supposed to be allowed? */
+  ASSERT (size >= 0);
+
+  if (size == 0)
+    return;
+
+  rands = RANDS;
+  _gmp_rand (ptr, rands, size * GMP_NUMB_BITS);
+
+  /* Make sure the most significant limb is non-zero.  */
+  while (ptr[size-1] == 0)
+    _gmp_rand (&ptr[size-1], rands, GMP_NUMB_BITS);
+}
diff --git a/mpn/generic/random2.c b/mpn/generic/random2.c
new file mode 100644
index 0000000..1eede67
--- /dev/null
+++ b/mpn/generic/random2.c
@@ -0,0 +1,105 @@
+/* mpn_random2 -- Generate random numbers with relatively long strings
+   of ones and zeroes.  Suitable for border testing.
+
+Copyright 1992-1994, 1996, 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+static void gmp_rrandomb (mp_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+/* Ask _gmp_rand for 32 bits per call unless that's more than a limb can hold.
+   Thus, we get the same random number sequence in the common cases.
+   FIXME: We should always generate the same random number sequence!  */
+#if GMP_NUMB_BITS < 32
+#define BITS_PER_RANDCALL GMP_NUMB_BITS
+#else
+#define BITS_PER_RANDCALL 32
+#endif
+
+void
+mpn_random2 (mp_ptr rp, mp_size_t n)
+{
+  gmp_randstate_ptr rstate = RANDS;
+  int bit_pos;			/* bit number of least significant bit where
+				   next bit field to be inserted */
+  mp_limb_t ran, ranm;		/* buffer for random bits */
+
+  /* FIXME: Is n==0 supposed to be allowed? */
+  ASSERT (n >= 0);
+
+  _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+  ran = ranm;
+
+  /* Start off at a random bit position in the most significant limb.  */
+  bit_pos = ran % GMP_NUMB_BITS;
+
+  gmp_rrandomb (rp, rstate, n * GMP_NUMB_BITS - bit_pos);
+}
+
+static void
+gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, mp_bitcnt_t nbits)
+{
+  mp_bitcnt_t bi;
+  mp_limb_t ranm;		/* buffer for random bits */
+  unsigned cap_chunksize, chunksize;
+  mp_size_t i;
+
+  /* Set entire result to 111..1  */
+  i = BITS_TO_LIMBS (nbits) - 1;
+  rp[i] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - (nbits % GMP_NUMB_BITS)) % GMP_NUMB_BITS;
+  for (i = i - 1; i >= 0; i--)
+    rp[i] = GMP_NUMB_MAX;
+
+  _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+  cap_chunksize = nbits / (ranm % 4 + 1);
+  cap_chunksize += cap_chunksize == 0; /* make it at least 1 */
+
+  bi = nbits;
+
+  for (;;)
+    {
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      if (bi == 0)
+	break;			/* low chunk is ...1 */
+
+      rp[bi / GMP_NUMB_BITS] ^= CNST_LIMB (1) << bi % GMP_NUMB_BITS;
+
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      mpn_incr_u (rp + bi / GMP_NUMB_BITS, CNST_LIMB (1) << bi % GMP_NUMB_BITS);
+
+      if (bi == 0)
+	break;			/* low chunk is ...0 */
+    }
+}
diff --git a/mpn/generic/redc_1.c b/mpn/generic/redc_1.c
new file mode 100644
index 0000000..eab128f
--- /dev/null
+++ b/mpn/generic/redc_1.c
@@ -0,0 +1,56 @@
+/* mpn_redc_1.  Set rp[] <- up[]/R^n mod mp[].  Clobber up[].
+   mp[] is n limbs; up[] is 2n limbs.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright (C) 2000-2002, 2004, 2008, 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_redc_1 (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_limb_t invm)
+{
+  mp_size_t j;
+  mp_limb_t cy;
+
+  ASSERT (n > 0);
+  ASSERT_MPN (up, 2*n);
+
+  for (j = n - 1; j >= 0; j--)
+    {
+      cy = mpn_addmul_1 (up, mp, n, (up[0] * invm) & GMP_NUMB_MASK);
+      ASSERT (up[0] == 0);
+      up[0] = cy;
+      up++;
+    }
+
+  cy = mpn_add_n (rp, up, up - n, n);
+  return cy;
+}
diff --git a/mpn/generic/redc_2.c b/mpn/generic/redc_2.c
new file mode 100644
index 0000000..8d15589
--- /dev/null
+++ b/mpn/generic/redc_2.c
@@ -0,0 +1,110 @@
+/* mpn_redc_2.  Set rp[] <- up[]/R^n mod mp[].  Clobber up[].
+   mp[] is n limbs; up[] is 2n limbs.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright (C) 2000-2002, 2004, 2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS != 0
+you lose
+#endif
+
+/* For testing purposes, define our own mpn_addmul_2 if there is none already
+   available.  */
+#ifndef HAVE_NATIVE_mpn_addmul_2
+#undef mpn_addmul_2
+static mp_limb_t
+mpn_addmul_2 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_srcptr vp)
+{
+  rp[n] = mpn_addmul_1 (rp, up, n, vp[0]);
+  return mpn_addmul_1 (rp + 1, up, n, vp[1]);
+}
+#endif
+
+#if defined (__GNUC__) && ! defined (NO_ASM) \
+  && defined (__ia64) && W_TYPE_SIZE == 64
+#define umul2low(ph, pl, uh, ul, vh, vl) \
+  do {									\
+    mp_limb_t _ph, _pl;							\
+    __asm__ ("xma.hu %0 = %3, %5, f0\n\t"				\
+	     "xma.l %1 = %3, %5, f0\n\t"				\
+	     ";;\n\t"							\
+	     "xma.l %0 = %3, %4, %0\n\t"				\
+	     ";;\n\t"							\
+	     "xma.l %0 = %2, %5, %0"					\
+	     : "=&f" (ph), "=&f" (pl)					\
+	     : "f" (uh), "f" (ul), "f" (vh), "f" (vl));			\
+  } while (0)
+#endif
+
+#ifndef umul2low
+#define umul2low(ph, pl, uh, ul, vh, vl) \
+  do {									\
+    mp_limb_t _ph, _pl;							\
+    umul_ppmm (_ph, _pl, ul, vl);					\
+    (ph) = _ph + (ul) * (vh) + (uh) * (vl);				\
+    (pl) = _pl;								\
+  } while (0)
+#endif
+
+mp_limb_t
+mpn_redc_2 (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_srcptr mip)
+{
+  mp_limb_t q[2];
+  mp_size_t j;
+  mp_limb_t upn;
+  mp_limb_t cy;
+
+  ASSERT (n > 0);
+  ASSERT_MPN (up, 2*n);
+
+  if ((n & 1) != 0)
+    {
+      up[0] = mpn_addmul_1 (up, mp, n, (up[0] * mip[0]) & GMP_NUMB_MASK);
+      up++;
+    }
+
+  for (j = n - 2; j >= 0; j -= 2)
+    {
+      umul2low (q[1], q[0], mip[1], mip[0], up[1], up[0]);
+      upn = up[n];		/* mpn_addmul_2 overwrites this */
+      up[1] = mpn_addmul_2 (up, mp, n, q);
+      up[0] = up[n];
+      up[n] = upn;
+      up += 2;
+    }
+
+  cy = mpn_add_n (rp, up, up - n, n);
+  return cy;
+}
diff --git a/mpn/generic/redc_n.c b/mpn/generic/redc_n.c
new file mode 100644
index 0000000..0c94b7c
--- /dev/null
+++ b/mpn/generic/redc_n.c
@@ -0,0 +1,80 @@
+/* mpn_redc_n.  Set rp[] <- up[]/R^n mod mp[].  Clobber up[].
+   mp[] is n limbs; up[] is 2n limbs, the inverse ip[] is n limbs.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  TODO
+
+  * We assume mpn_mulmod_bnm1 is always faster than plain mpn_mul_n (or a
+    future mpn_mulhi) for the range we will be called.  Follow up that
+    assumption.
+
+  * Decrease scratch usage.
+
+  * Consider removing the residue canonicalisation.
+*/
+
+void
+mpn_redc_n (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_srcptr ip)
+{
+  mp_ptr xp, yp, scratch;
+  mp_limb_t cy;
+  mp_size_t rn;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (n > 8);
+
+  rn = mpn_mulmod_bnm1_next_size (n);
+
+  scratch = TMP_ALLOC_LIMBS (n + rn + mpn_mulmod_bnm1_itch (rn, n, n));
+
+  xp = scratch;
+  mpn_mullo_n (xp, up, ip, n);
+
+  yp = scratch + n;
+  mpn_mulmod_bnm1 (yp, rn, xp, n, mp, n, scratch + n + rn);
+
+  ASSERT_ALWAYS (2 * n > rn);				/* could handle this */
+
+  cy = mpn_sub_n (yp + rn, yp, up, 2*n - rn);		/* undo wrap around */
+  MPN_DECR_U (yp + 2*n - rn, rn, cy);
+
+  cy = mpn_sub_n (rp, up + n, yp + n, n);
+  if (cy != 0)
+    mpn_add_n (rp, rp, mp, n);
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/remove.c b/mpn/generic/remove.c
new file mode 100644
index 0000000..cbb0742
--- /dev/null
+++ b/mpn/generic/remove.c
@@ -0,0 +1,182 @@
+/* mpn_remove -- divide out all multiples of odd mpn number from another mpn
+   number.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2009, 2012-2014, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if GMP_LIMB_BITS > 50
+#define LOG 50
+#else
+#define LOG GMP_LIMB_BITS
+#endif
+
+
+/* Input: U = {up,un}, V = {vp,vn} must be odd, cap
+   Ouput  W = {wp,*wn} allocation need is exactly *wn
+
+   Set W = U / V^k, where k is the largest integer <= cap such that the
+   division yields an integer.
+
+   FIXME: We currently allow any operand overlap.  This is quite non mpn-ish
+   and might be changed, since it cost significant temporary space.
+   * If we require W to have space for un + 1 limbs, we could save qp or qp2
+     (but we will still need to copy things into wp 50% of the time).
+   * If we allow ourselves to clobber U, we could save the other of qp and qp2,
+     and the initial COPY (but also here we would need un + 1 limbs).
+*/
+
+/* FIXME: We need to wrap mpn_bdiv_qr due to the itch interface.  This need
+   indicates a flaw in the current itch mechanism: Which operands not greater
+   than un,un will incur the worst itch?  We need a parallel foo_maxitch set
+   of functions.  */
+static void
+mpn_bdiv_qr_wrap (mp_ptr qp, mp_ptr rp,
+		  mp_srcptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn)
+{
+  mp_ptr scratch_out;
+  TMP_DECL;
+
+  TMP_MARK;
+  scratch_out = TMP_ALLOC_LIMBS (mpn_bdiv_qr_itch (nn, dn));
+  mpn_bdiv_qr (qp, rp, np, nn, dp, dn, scratch_out);
+
+  TMP_FREE;
+}
+
+mp_bitcnt_t
+mpn_remove (mp_ptr wp, mp_size_t *wn,
+	    mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn,
+	    mp_bitcnt_t cap)
+{
+  mp_srcptr pwpsp[LOG];
+  mp_size_t pwpsn[LOG];
+  mp_size_t npowers;
+  mp_ptr tp, qp, np, qp2;
+  mp_srcptr pp;
+  mp_size_t pn, nn, qn, i;
+  mp_bitcnt_t pwr;
+  TMP_DECL;
+
+  ASSERT (un > 0);
+  ASSERT (vn > 0);
+  ASSERT (vp[0] % 2 != 0);	/* 2-adic division wants odd numbers */
+  ASSERT (vn > 1 || vp[0] > 1);	/* else we would loop indefinitely */
+
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_3 (qp, un + 1,	/* quotient, alternating */
+		     qp2, un + 1,	/* quotient, alternating */
+		     tp, (un + 1 + vn) / 2); /* remainder */
+  pp = vp;
+  pn = vn;
+
+  MPN_COPY (qp, up, un);
+  qn = un;
+
+  npowers = 0;
+  while (qn >= pn)
+    {
+      qp[qn] = 0;
+      mpn_bdiv_qr_wrap (qp2, tp, qp, qn + 1, pp, pn);
+      if (!mpn_zero_p (tp, pn))
+	{
+	  if (mpn_cmp (tp, pp, pn) != 0)
+	    break;		/* could not divide by V^npowers */
+	}
+
+      MP_PTR_SWAP (qp, qp2);
+      qn = qn - pn;
+      mpn_neg (qp, qp, qn+1);
+
+      qn += qp[qn] != 0;
+
+      pwpsp[npowers] = pp;
+      pwpsn[npowers] = pn;
+      ++npowers;
+
+      if (((mp_bitcnt_t) 2 << npowers) - 1 > cap)
+	break;
+
+      nn = 2 * pn - 1;		/* next power will be at least this large */
+      if (nn > qn)
+	break;			/* next power would be overlarge */
+
+      if (npowers == 1)		/* Alloc once, but only if it's needed */
+	np = TMP_ALLOC_LIMBS (qn + LOG);	/* powers of V */
+      else
+	np += pn;
+
+      mpn_sqr (np, pp, pn);
+      pn = nn + (np[nn] != 0);
+      pp = np;
+    }
+
+  pwr = ((mp_bitcnt_t) 1 << npowers) - 1;
+
+  for (i = npowers; --i >= 0;)
+    {
+      pn = pwpsn[i];
+      if (qn < pn)
+	continue;
+
+      if (pwr + ((mp_bitcnt_t) 1 << i) > cap)
+	continue;		/* V^i would bring us past cap */
+
+      qp[qn] = 0;
+      mpn_bdiv_qr_wrap (qp2, tp, qp, qn + 1, pwpsp[i], pn);
+      if (!mpn_zero_p (tp, pn))
+	{
+	  if (mpn_cmp (tp, pwpsp[i], pn) != 0)
+	    continue;		/* could not divide by V^i */
+	}
+
+      MP_PTR_SWAP (qp, qp2);
+      qn = qn - pn;
+      mpn_neg (qp, qp, qn+1);
+
+      qn += qp[qn] != 0;
+
+      pwr += (mp_bitcnt_t) 1 << i;
+    }
+
+  MPN_COPY (wp, qp, qn);
+  *wn = qn;
+
+  TMP_FREE;
+
+  return pwr;
+}
diff --git a/mpn/generic/rootrem.c b/mpn/generic/rootrem.c
new file mode 100644
index 0000000..a79099e
--- /dev/null
+++ b/mpn/generic/rootrem.c
@@ -0,0 +1,515 @@
+/* mpn_rootrem(rootp,remp,ap,an,nth) -- Compute the nth root of {ap,an}, and
+   store the truncated integer part at rootp and the remainder at remp.
+
+   Contributed by Paul Zimmermann (algorithm) and
+   Paul Zimmermann and Torbjorn Granlund (implementation).
+   Marco Bodrato wrote logbased_root to seed the loop.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL, AND HAVE MUTABLE INTERFACES.  IT'S
+   ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT'S ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2002, 2005, 2009-2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* FIXME:
+     This implementation is not optimal when remp == NULL, since the complexity
+     is M(n), whereas it should be M(n/k) on average.
+*/
+
+#include <stdio.h>		/* for NULL */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static mp_size_t mpn_rootrem_internal (mp_ptr, mp_ptr, mp_srcptr, mp_size_t,
+				       mp_limb_t, int);
+
+#define MPN_RSHIFT(rp,up,un,cnt) \
+  do {									\
+    if ((cnt) != 0)							\
+      mpn_rshift (rp, up, un, cnt);					\
+    else								\
+      {									\
+	MPN_COPY_INCR (rp, up, un);					\
+      }									\
+  } while (0)
+
+#define MPN_LSHIFT(cy,rp,up,un,cnt) \
+  do {									\
+    if ((cnt) != 0)							\
+      cy = mpn_lshift (rp, up, un, cnt);				\
+    else								\
+      {									\
+	MPN_COPY_DECR (rp, up, un);					\
+	cy = 0;								\
+      }									\
+  } while (0)
+
+
+/* Put in {rootp, ceil(un/k)} the kth root of {up, un}, rounded toward zero.
+   If remp <> NULL, put in {remp, un} the remainder.
+   Return the size (in limbs) of the remainder if remp <> NULL,
+	  or a non-zero value iff the remainder is non-zero when remp = NULL.
+   Assumes:
+   (a) up[un-1] is not zero
+   (b) rootp has at least space for ceil(un/k) limbs
+   (c) remp has at least space for un limbs (in case remp <> NULL)
+   (d) the operands do not overlap.
+
+   The auxiliary memory usage is 3*un+2 if remp = NULL,
+   and 2*un+2 if remp <> NULL.  FIXME: This is an incorrect comment.
+*/
+mp_size_t
+mpn_rootrem (mp_ptr rootp, mp_ptr remp,
+	     mp_srcptr up, mp_size_t un, mp_limb_t k)
+{
+  ASSERT (un > 0);
+  ASSERT (up[un - 1] != 0);
+  ASSERT (k > 1);
+
+  if (UNLIKELY (k == 2))
+    return mpn_sqrtrem (rootp, remp, up, un);
+  /* (un-1)/k > 2 <=> un > 3k <=> (un + 2)/3 > k */
+  if (remp == NULL && (un + 2) / 3 > k)
+    /* Pad {up,un} with k zero limbs.  This will produce an approximate root
+       with one more limb, allowing us to compute the exact integral result. */
+    {
+      mp_ptr sp, wp;
+      mp_size_t rn, sn, wn;
+      TMP_DECL;
+      TMP_MARK;
+      wn = un + k;
+      sn = (un - 1) / k + 2; /* ceil(un/k) + 1 */
+      TMP_ALLOC_LIMBS_2 (wp, wn, /* will contain the padded input */
+			 sp, sn); /* approximate root of padded input */
+      MPN_COPY (wp + k, up, un);
+      MPN_FILL (wp, k, 0);
+      rn = mpn_rootrem_internal (sp, NULL, wp, wn, k, 1);
+      /* The approximate root S = {sp,sn} is either the correct root of
+	 {sp,sn}, or 1 too large.  Thus unless the least significant limb of
+	 S is 0 or 1, we can deduce the root of {up,un} is S truncated by one
+	 limb.  (In case sp[0]=1, we can deduce the root, but not decide
+	 whether it is exact or not.) */
+      MPN_COPY (rootp, sp + 1, sn - 1);
+      TMP_FREE;
+      return rn;
+    }
+  else
+    {
+      return mpn_rootrem_internal (rootp, remp, up, un, k, 0);
+    }
+}
+
+#define LOGROOT_USED_BITS 8
+#define LOGROOT_NEEDS_TWO_CORRECTIONS 1
+#define LOGROOT_RETURNED_BITS (LOGROOT_USED_BITS + LOGROOT_NEEDS_TWO_CORRECTIONS)
+/* Puts in *rootp some bits of the k^nt root of the number
+   2^bitn * 1.op ; where op represents the "fractional" bits.
+
+   The returned value is the number of bits of the root minus one;
+   i.e. an approximation of the root will be
+   (*rootp) * 2^(retval-LOGROOT_RETURNED_BITS+1).
+
+   Currently, only LOGROOT_USED_BITS bits of op are used (the implicit
+   one is not counted).
+ */
+static unsigned
+logbased_root (mp_ptr rootp, mp_limb_t op, mp_bitcnt_t bitn, mp_limb_t k)
+{
+  /* vlog=vector(256,i,floor((log(256+i)/log(2)-8)*256)-(i>255)) */
+  static const
+  unsigned char vlog[] = {1,   2,   4,   5,   7,   8,   9,  11,  12,  14,  15,  16,  18,  19,  21,  22,
+			 23,  25,  26,  27,  29,  30,  31,  33,  34,  35,  37,  38,  39,  40,  42,  43,
+			 44,  46,  47,  48,  49,  51,  52,  53,  54,  56,  57,  58,  59,  61,  62,  63,
+			 64,  65,  67,  68,  69,  70,  71,  73,  74,  75,  76,  77,  78,  80,  81,  82,
+			 83,  84,  85,  87,  88,  89,  90,  91,  92,  93,  94,  96,  97,  98,  99, 100,
+			101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+			118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 132, 133, 134,
+			135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+			150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 162, 163, 164,
+			165, 166, 167, 168, 169, 170, 171, 172, 173, 173, 174, 175, 176, 177, 178, 179,
+			180, 181, 181, 182, 183, 184, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193,
+			194, 194, 195, 196, 197, 198, 199, 200, 200, 201, 202, 203, 204, 205, 205, 206,
+			207, 208, 209, 209, 210, 211, 212, 213, 214, 214, 215, 216, 217, 218, 218, 219,
+			220, 221, 222, 222, 223, 224, 225, 225, 226, 227, 228, 229, 229, 230, 231, 232,
+			232, 233, 234, 235, 235, 236, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244,
+			245, 245, 246, 247, 247, 248, 249, 250, 250, 251, 252, 253, 253, 254, 255, 255};
+
+  /* vexp=vector(256,i,floor(2^(8+i/256)-256)-(i>255)) */
+  static const
+  unsigned char vexp[] = {0,   1,   2,   2,   3,   4,   4,   5,   6,   7,   7,   8,   9,   9,  10,  11,
+			 12,  12,  13,  14,  14,  15,  16,  17,  17,  18,  19,  20,  20,  21,  22,  23,
+			 23,  24,  25,  26,  26,  27,  28,  29,  30,  30,  31,  32,  33,  33,  34,  35,
+			 36,  37,  37,  38,  39,  40,  41,  41,  42,  43,  44,  45,  45,  46,  47,  48,
+			 49,  50,  50,  51,  52,  53,  54,  55,  55,  56,  57,  58,  59,  60,  61,  61,
+			 62,  63,  64,  65,  66,  67,  67,  68,  69,  70,  71,  72,  73,  74,  75,  75,
+			 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  86,  87,  88,  89,  90,
+			 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106,
+			107, 108, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122,
+			123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+			139, 140, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156,
+			157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 171, 172, 173, 174,
+			175, 176, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 191, 192, 193,
+			194, 196, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208, 209, 210, 212, 213,
+			214, 216, 217, 218, 219, 221, 222, 223, 225, 226, 227, 229, 230, 231, 232, 234,
+			235, 236, 238, 239, 240, 242, 243, 245, 246, 247, 249, 250, 251, 253, 254, 255};
+  mp_bitcnt_t retval;
+
+  if (UNLIKELY (bitn > (~ (mp_bitcnt_t) 0) >> LOGROOT_USED_BITS))
+    {
+      /* In the unlikely case, we use two divisions and a modulo. */
+      retval = bitn / k;
+      bitn %= k;
+      bitn = (bitn << LOGROOT_USED_BITS |
+	      vlog[op >> (GMP_NUMB_BITS - LOGROOT_USED_BITS)]) / k;
+    }
+  else
+    {
+      bitn = (bitn << LOGROOT_USED_BITS |
+	      vlog[op >> (GMP_NUMB_BITS - LOGROOT_USED_BITS)]) / k;
+      retval = bitn >> LOGROOT_USED_BITS;
+      bitn &= (CNST_LIMB (1) << LOGROOT_USED_BITS) - 1;
+    }
+  ASSERT(bitn < CNST_LIMB (1) << LOGROOT_USED_BITS);
+  *rootp = CNST_LIMB(1) << (LOGROOT_USED_BITS - ! LOGROOT_NEEDS_TWO_CORRECTIONS)
+    | vexp[bitn] >> ! LOGROOT_NEEDS_TWO_CORRECTIONS;
+  return retval;
+}
+
+/* if approx is non-zero, does not compute the final remainder */
+static mp_size_t
+mpn_rootrem_internal (mp_ptr rootp, mp_ptr remp, mp_srcptr up, mp_size_t un,
+		      mp_limb_t k, int approx)
+{
+  mp_ptr qp, rp, sp, wp, scratch;
+  mp_size_t qn, rn, sn, wn, nl, bn;
+  mp_limb_t save, save2, cy, uh;
+  mp_bitcnt_t unb; /* number of significant bits of {up,un} */
+  mp_bitcnt_t xnb; /* number of significant bits of the result */
+  mp_bitcnt_t b, kk;
+  mp_bitcnt_t sizes[GMP_NUMB_BITS + 1];
+  int ni;
+  int perf_pow;
+  unsigned ulz, snb, c, logk;
+  TMP_DECL;
+
+  /* MPN_SIZEINBASE_2EXP(unb, up, un, 1); --unb; */
+  uh = up[un - 1];
+  count_leading_zeros (ulz, uh);
+  ulz = ulz - GMP_NAIL_BITS + 1; /* Ignore the first 1. */
+  unb = (mp_bitcnt_t) un * GMP_NUMB_BITS - ulz;
+  /* unb is the (truncated) logarithm of the input U in base 2*/
+
+  if (unb < k) /* root is 1 */
+    {
+      rootp[0] = 1;
+      if (remp == NULL)
+	un -= (*up == CNST_LIMB (1)); /* Non-zero iif {up,un} > 1 */
+      else
+	{
+	  mpn_sub_1 (remp, up, un, CNST_LIMB (1));
+	  un -= (remp [un - 1] == 0);	/* There should be at most one zero limb,
+				   if we demand u to be normalized  */
+	}
+      return un;
+    }
+  /* if (unb - k < k/2 + k/16) // root is 2 */
+
+  if (ulz == GMP_NUMB_BITS)
+    uh = up[un - 2];
+  else
+    uh = (uh << ulz & GMP_NUMB_MASK) | up[un - 1 - (un != 1)] >> (GMP_NUMB_BITS - ulz);
+  ASSERT (un != 1 || up[un - 1 - (un != 1)] >> (GMP_NUMB_BITS - ulz) == 1);
+
+  xnb = logbased_root (rootp, uh, unb, k);
+  snb = LOGROOT_RETURNED_BITS - 1;
+  /* xnb+1 is the number of bits of the root R */
+  /* snb+1 is the number of bits of the current approximation S */
+
+  kk = k * xnb;		/* number of truncated bits in the input */
+
+  /* FIXME: Should we skip the next two loops when xnb <= snb ? */
+  for (uh = (k - 1) / 2, logk = 3; (uh >>= 1) != 0; ++logk )
+    ;
+  /* logk = ceil(log(k)/log(2)) + 1 */
+
+  /* xnb is the number of remaining bits to determine in the kth root */
+  for (ni = 0; (sizes[ni] = xnb) > snb; ++ni)
+    {
+      /* invariant: here we want xnb+1 total bits for the kth root */
+
+      /* if c is the new value of xnb, this means that we'll go from a
+	 root of c+1 bits (say s') to a root of xnb+1 bits.
+	 It is proved in the book "Modern Computer Arithmetic" by Brent
+	 and Zimmermann, Chapter 1, that
+	 if s' >= k*beta, then at most one correction is necessary.
+	 Here beta = 2^(xnb-c), and s' >= 2^c, thus it suffices that
+	 c >= ceil((xnb + log2(k))/2). */
+      if (xnb > logk)
+	xnb = (xnb + logk) / 2;
+      else
+	--xnb;	/* add just one bit at a time */
+    }
+
+  *rootp >>= snb - xnb;
+  kk -= xnb;
+
+  ASSERT_ALWAYS (ni < GMP_NUMB_BITS + 1);
+  /* We have sizes[0] = b > sizes[1] > ... > sizes[ni] = 0 with
+     sizes[i] <= 2 * sizes[i+1].
+     Newton iteration will first compute sizes[ni-1] extra bits,
+     then sizes[ni-2], ..., then sizes[0] = b. */
+
+  TMP_MARK;
+  /* qp and wp need enough space to store S'^k where S' is an approximate
+     root. Since S' can be as large as S+2, the worst case is when S=2 and
+     S'=4. But then since we know the number of bits of S in advance, S'
+     can only be 3 at most. Similarly for S=4, then S' can be 6 at most.
+     So the worst case is S'/S=3/2, thus S'^k <= (3/2)^k * S^k. Since S^k
+     fits in un limbs, the number of extra limbs needed is bounded by
+     ceil(k*log2(3/2)/GMP_NUMB_BITS). */
+  /* THINK: with the use of logbased_root, maybe the constant is
+     258/256 instead of 3/2 ? log2(258/256) < 1/89 < 1/64 */
+#define EXTRA 2 + (mp_size_t) (0.585 * (double) k / (double) GMP_NUMB_BITS)
+  TMP_ALLOC_LIMBS_3 (scratch, un + 1, /* used by mpn_div_q */
+		     qp, un + EXTRA,  /* will contain quotient and remainder
+					 of R/(k*S^(k-1)), and S^k */
+		     wp, un + EXTRA); /* will contain S^(k-1), k*S^(k-1),
+					 and temporary for mpn_pow_1 */
+
+  if (remp == NULL)
+    rp = scratch;	/* will contain the remainder */
+  else
+    rp = remp;
+  sp = rootp;
+
+  sn = 1;		/* Initial approximation has one limb */
+
+  for (b = xnb; ni != 0; --ni)
+    {
+      /* 1: loop invariant:
+	 {sp, sn} is the current approximation of the root, which has
+		  exactly 1 + sizes[ni] bits.
+	 {rp, rn} is the current remainder
+	 {wp, wn} = {sp, sn}^(k-1)
+	 kk = number of truncated bits of the input
+      */
+
+      /* Since each iteration treats b bits from the root and thus k*b bits
+	 from the input, and we already considered b bits from the input,
+	 we now have to take another (k-1)*b bits from the input. */
+      kk -= (k - 1) * b; /* remaining input bits */
+      /* {rp, rn} = floor({up, un} / 2^kk) */
+      rn = un - kk / GMP_NUMB_BITS;
+      MPN_RSHIFT (rp, up + kk / GMP_NUMB_BITS, rn, kk % GMP_NUMB_BITS);
+      rn -= rp[rn - 1] == 0;
+
+      /* 9: current buffers: {sp,sn}, {rp,rn} */
+
+      for (c = 0;; c++)
+	{
+	  /* Compute S^k in {qp,qn}. */
+	  /* W <- S^(k-1) for the next iteration,
+	     and S^k = W * S. */
+	  wn = mpn_pow_1 (wp, sp, sn, k - 1, qp);
+	  mpn_mul (qp, wp, wn, sp, sn);
+	  qn = wn + sn;
+	  qn -= qp[qn - 1] == 0;
+
+	  perf_pow = 1;
+	  /* if S^k > floor(U/2^kk), the root approximation was too large */
+	  if (qn > rn || (qn == rn && (perf_pow=mpn_cmp (qp, rp, rn)) > 0))
+	    MPN_DECR_U (sp, sn, 1);
+	  else
+	    break;
+	}
+
+      /* 10: current buffers: {sp,sn}, {rp,rn}, {qp,qn}, {wp,wn} */
+
+      /* sometimes two corrections are needed with logbased_root*/
+      ASSERT (c <= 1 + LOGROOT_NEEDS_TWO_CORRECTIONS);
+      ASSERT_ALWAYS (rn >= qn);
+
+      b = sizes[ni - 1] - sizes[ni]; /* number of bits to compute in the
+				      next iteration */
+      bn = b / GMP_NUMB_BITS; /* lowest limb from high part of rp[], after shift */
+
+      kk = kk - b;
+      /* nl is the number of limbs in U which contain bits [kk,kk+b-1] */
+      nl = 1 + (kk + b - 1) / GMP_NUMB_BITS - (kk / GMP_NUMB_BITS);
+      /* nl  = 1 + floor((kk + b - 1) / GMP_NUMB_BITS)
+		 - floor(kk / GMP_NUMB_BITS)
+	     <= 1 + (kk + b - 1) / GMP_NUMB_BITS
+		  - (kk - GMP_NUMB_BITS + 1) / GMP_NUMB_BITS
+	     = 2 + (b - 2) / GMP_NUMB_BITS
+	 thus since nl is an integer:
+	 nl <= 2 + floor(b/GMP_NUMB_BITS) <= 2 + bn. */
+
+      /* 11: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* R = R - Q = floor(U/2^kk) - S^k */
+      if (perf_pow != 0)
+	{
+	  mpn_sub (rp, rp, rn, qp, qn);
+	  MPN_NORMALIZE_NOT_ZERO (rp, rn);
+
+	  /* first multiply the remainder by 2^b */
+	  MPN_LSHIFT (cy, rp + bn, rp, rn, b % GMP_NUMB_BITS);
+	  rn = rn + bn;
+	  if (cy != 0)
+	    {
+	      rp[rn] = cy;
+	      rn++;
+	    }
+
+	  save = rp[bn];
+	  /* we have to save rp[bn] up to rp[nl-1], i.e. 1 or 2 limbs */
+	  if (nl - 1 > bn)
+	    save2 = rp[bn + 1];
+	}
+      else
+	{
+	  rn = bn;
+	  save2 = save = 0;
+	}
+      /* 2: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* Now insert bits [kk,kk+b-1] from the input U */
+      MPN_RSHIFT (rp, up + kk / GMP_NUMB_BITS, nl, kk % GMP_NUMB_BITS);
+      /* set to zero high bits of rp[bn] */
+      rp[bn] &= (CNST_LIMB (1) << (b % GMP_NUMB_BITS)) - 1;
+      /* restore corresponding bits */
+      rp[bn] |= save;
+      if (nl - 1 > bn)
+	rp[bn + 1] = save2; /* the low b bits go in rp[0..bn] only, since
+			       they start by bit 0 in rp[0], so they use
+			       at most ceil(b/GMP_NUMB_BITS) limbs */
+      /* FIXME: Should we normalise {rp,rn} here ?*/
+
+      /* 3: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* compute {wp, wn} = k * {sp, sn}^(k-1) */
+      cy = mpn_mul_1 (wp, wp, wn, k);
+      wp[wn] = cy;
+      wn += cy != 0;
+
+      /* 6: current buffers: {sp,sn}, {qp,qn} */
+
+      /* multiply the root approximation by 2^b */
+      MPN_LSHIFT (cy, sp + b / GMP_NUMB_BITS, sp, sn, b % GMP_NUMB_BITS);
+      sn = sn + b / GMP_NUMB_BITS;
+      if (cy != 0)
+	{
+	  sp[sn] = cy;
+	  sn++;
+	}
+
+      save = sp[b / GMP_NUMB_BITS];
+
+      /* Number of limbs used by b bits, when least significant bit is
+	 aligned to least limb */
+      bn = (b - 1) / GMP_NUMB_BITS + 1;
+
+      /* 4: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* now divide {rp, rn} by {wp, wn} to get the low part of the root */
+      if (UNLIKELY (rn < wn))
+	{
+	  MPN_FILL (sp, bn, 0);
+	}
+      else
+	{
+	  qn = rn - wn; /* expected quotient size */
+	  if (qn <= bn) { /* Divide only if result is not too big. */
+	    mpn_div_q (qp, rp, rn, wp, wn, scratch);
+	    qn += qp[qn] != 0;
+	  }
+
+      /* 5: current buffers: {sp,sn}, {qp,qn}.
+	 Note: {rp,rn} is not needed any more since we'll compute it from
+	 scratch at the end of the loop.
+       */
+
+      /* the quotient should be smaller than 2^b, since the previous
+	 approximation was correctly rounded toward zero */
+	  if (qn > bn || (qn == bn && (b % GMP_NUMB_BITS != 0) &&
+			  qp[qn - 1] >= (CNST_LIMB (1) << (b % GMP_NUMB_BITS))))
+	    {
+	      for (qn = 1; qn < bn; ++qn)
+		sp[qn - 1] = GMP_NUMB_MAX;
+	      sp[qn - 1] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - 1 - ((b - 1) % GMP_NUMB_BITS));
+	    }
+	  else
+	    {
+      /* 7: current buffers: {sp,sn}, {qp,qn} */
+
+      /* Combine sB and q to form sB + q.  */
+	      MPN_COPY (sp, qp, qn);
+	      MPN_ZERO (sp + qn, bn - qn);
+	    }
+	}
+      sp[b / GMP_NUMB_BITS] |= save;
+
+      /* 8: current buffer: {sp,sn} */
+
+    }
+
+  /* otherwise we have rn > 0, thus the return value is ok */
+  if (!approx || sp[0] <= CNST_LIMB (1))
+    {
+      for (c = 0;; c++)
+	{
+	  /* Compute S^k in {qp,qn}. */
+	  /* Last iteration: we don't need W anymore. */
+	  /* mpn_pow_1 requires that both qp and wp have enough
+	     space to store the result {sp,sn}^k + 1 limb */
+	  qn = mpn_pow_1 (qp, sp, sn, k, wp);
+
+	  perf_pow = 1;
+	  if (qn > un || (qn == un && (perf_pow=mpn_cmp (qp, up, un)) > 0))
+	    MPN_DECR_U (sp, sn, 1);
+	  else
+	    break;
+	};
+
+      /* sometimes two corrections are needed with logbased_root*/
+      ASSERT (c <= 1 + LOGROOT_NEEDS_TWO_CORRECTIONS);
+
+      rn = perf_pow != 0;
+      if (rn != 0 && remp != NULL)
+	{
+	  mpn_sub (remp, up, un, qp, qn);
+	  rn = un;
+	  MPN_NORMALIZE_NOT_ZERO (remp, rn);
+	}
+    }
+
+  TMP_FREE;
+  return rn;
+}
diff --git a/mpn/generic/rshift.c b/mpn/generic/rshift.c
new file mode 100644
index 0000000..15d427d
--- /dev/null
+++ b/mpn/generic/rshift.c
@@ -0,0 +1,69 @@
+/* mpn_rshift -- Shift right low level.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Shift U (pointed to by up and N limbs long) cnt bits to the right
+   and store the n least significant limbs of the result at rp.
+   The bits shifted out to the right are returned.
+
+   Argument constraints:
+   1. 0 < cnt < GMP_NUMB_BITS.
+   2. If the result is to be written over the input, rp must be <= up.
+*/
+
+mp_limb_t
+mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  ASSERT (n >= 1);
+  ASSERT (cnt >= 1);
+  ASSERT (cnt < GMP_NUMB_BITS);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+
+  tnc = GMP_NUMB_BITS - cnt;
+  high_limb = *up++;
+  retval = (high_limb << tnc) & GMP_NUMB_MASK;
+  low_limb = high_limb >> cnt;
+
+  for (i = n - 1; i != 0; i--)
+    {
+      high_limb = *up++;
+      *rp++ = low_limb | ((high_limb << tnc) & GMP_NUMB_MASK);
+      low_limb = high_limb >> cnt;
+    }
+  *rp = low_limb;
+
+  return retval;
+}
diff --git a/mpn/generic/sbpi1_bdiv_q.c b/mpn/generic/sbpi1_bdiv_q.c
new file mode 100644
index 0000000..850e593
--- /dev/null
+++ b/mpn/generic/sbpi1_bdiv_q.c
@@ -0,0 +1,96 @@
+/* mpn_sbpi1_bdiv_q -- schoolbook Hensel division with precomputed inverse,
+   returning quotient only.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.
+   IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005, 2006, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes Q = - U / D mod B^un, destroys U.
+
+   D must be odd. dinv is (-D)^-1 mod B.
+
+*/
+
+void
+mpn_sbpi1_bdiv_q (mp_ptr qp,
+		  mp_ptr up, mp_size_t un,
+		  mp_srcptr dp, mp_size_t dn,
+		  mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t q;
+
+  ASSERT (dn > 0);
+  ASSERT (un >= dn);
+  ASSERT ((dp[0] & 1) != 0);
+  ASSERT (-(dp[0] * dinv) == 1);
+  ASSERT (up == qp || !MPN_OVERLAP_P (up, un, qp, un - dn));
+
+  if (un > dn)
+    {
+      mp_limb_t cy, hi;
+      for (i = un - dn - 1, cy = 0; i > 0; i--)
+	{
+	  q = dinv * up[0];
+	  hi = mpn_addmul_1 (up, dp, dn, q);
+
+	  ASSERT (up[0] == 0);
+	  *qp++ = q;
+	  hi += cy;
+	  cy = hi < cy;
+	  hi += up[dn];
+	  cy += hi < up[dn];
+	  up[dn] = hi;
+	  up++;
+	}
+      q = dinv * up[0];
+      hi = cy + mpn_addmul_1 (up, dp, dn, q);
+      ASSERT (up[0] == 0);
+      *qp++ = q;
+      up[dn] += hi;
+      up++;
+    }
+  for (i = dn; i > 1; i--)
+    {
+      mp_limb_t q = dinv * up[0];
+      mpn_addmul_1 (up, dp, i, q);
+      ASSERT (up[0] == 0);
+      *qp++ = q;
+      up++;
+    }
+
+  /* Final limb */
+  *qp = dinv * up[0];
+}
diff --git a/mpn/generic/sbpi1_bdiv_qr.c b/mpn/generic/sbpi1_bdiv_qr.c
new file mode 100644
index 0000000..6146c45
--- /dev/null
+++ b/mpn/generic/sbpi1_bdiv_qr.c
@@ -0,0 +1,82 @@
+/* mpn_sbpi1_bdiv_qr -- schoolbook Hensel division with precomputed inverse,
+   returning quotient and remainder.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.
+   IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes a binary quotient of size qn = un - dn.
+   Output:
+
+      Q = -U * D^{-1} mod B^qn,
+
+      R = (U + Q * D) * B^(-qn)
+
+   Stores the dn least significant limbs of R at {up + un - dn, dn},
+   and returns the carry from the addition N + Q*D.
+
+   D must be odd. dinv is (-D)^-1 mod B. */
+
+mp_limb_t
+mpn_sbpi1_bdiv_qr (mp_ptr qp,
+		   mp_ptr up, mp_size_t un,
+		   mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  ASSERT (dn > 0);
+  ASSERT (un > dn);
+  ASSERT ((dp[0] & 1) != 0);
+  ASSERT (-(dp[0] * dinv) == 1);
+  ASSERT (up == qp || !MPN_OVERLAP_P (up, un, qp, un - dn));
+
+  for (i = un - dn, cy = 0; i != 0; i--)
+    {
+      mp_limb_t q = dinv * up[0];
+      mp_limb_t hi = mpn_addmul_1 (up, dp, dn, q);
+      *qp++ = q;
+
+      hi += cy;
+      cy = hi < cy;
+      hi += up[dn];
+      cy += hi < up[dn];
+      up[dn] = hi;
+      up++;
+    }
+
+  return cy;
+}
diff --git a/mpn/generic/sbpi1_bdiv_r.c b/mpn/generic/sbpi1_bdiv_r.c
new file mode 100644
index 0000000..a609951
--- /dev/null
+++ b/mpn/generic/sbpi1_bdiv_r.c
@@ -0,0 +1,79 @@
+/* mpn_sbpi1_bdiv_r -- schoolbook Hensel division with precomputed inverse,
+   returning remainder.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.
+   IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes a binary quotient of size qn = un - dn.
+   Output:
+
+      Q = -U * D^{-1} mod B^qn,
+
+      R = (U + Q * D) * B^(-qn)
+
+   Stores the dn least significant limbs of R at {up + un - dn, dn},
+   and returns the carry from the addition N + Q*D.
+
+   D must be odd. dinv is (-D)^-1 mod B. */
+
+mp_limb_t
+mpn_sbpi1_bdiv_r (mp_ptr up, mp_size_t un,
+		  mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  ASSERT (dn > 0);
+  ASSERT (un > dn);
+  ASSERT ((dp[0] & 1) != 0);
+  ASSERT (-(dp[0] * dinv) == 1);
+
+  for (i = un - dn, cy = 0; i != 0; i--)
+    {
+      mp_limb_t q = dinv * up[0];
+      mp_limb_t hi = mpn_addmul_1 (up, dp, dn, q);
+
+      hi += cy;
+      cy = hi < cy;
+      hi += up[dn];
+      cy += hi < up[dn];
+      up[dn] = hi;
+      up++;
+    }
+
+  return cy;
+}
diff --git a/mpn/generic/sbpi1_div_q.c b/mpn/generic/sbpi1_div_q.c
new file mode 100644
index 0000000..a9975eb
--- /dev/null
+++ b/mpn/generic/sbpi1_div_q.c
@@ -0,0 +1,302 @@
+/* mpn_sbpi1_div_q -- Schoolbook division using the Möller-Granlund 3/2
+   division algorithm.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_sbpi1_div_q (mp_ptr qp,
+		 mp_ptr np, mp_size_t nn,
+		 mp_srcptr dp, mp_size_t dn,
+		 mp_limb_t dinv)
+{
+  mp_limb_t qh;
+  mp_size_t qn, i;
+  mp_limb_t n1, n0;
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+  mp_limb_t flag;
+
+  mp_size_t dn_orig = dn;
+  mp_srcptr dp_orig = dp;
+  mp_ptr np_orig = np;
+
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  np += nn;
+
+  qn = nn - dn;
+  if (qn + 1 < dn)
+    {
+      dp += dn - (qn + 1);
+      dn = qn + 1;
+    }
+
+  qh = mpn_cmp (np - dn, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (np - dn, np - dn, dp, dn);
+
+  qp += qn;
+
+  dn -= 2;			/* offset dn by 2 for main division loops,
+				   saving two iterations in mpn_submul_1.  */
+  d1 = dp[dn + 1];
+  d0 = dp[dn + 0];
+
+  np -= 2;
+
+  n1 = np[1];
+
+  for (i = qn - (dn + 2); i >= 0; i--)
+    {
+      np--;
+      if (UNLIKELY (n1 == d1) && np[1] == d0)
+	{
+	  q = GMP_NUMB_MASK;
+	  mpn_submul_1 (np - dn, dp, dn + 2, q);
+	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	  cy1 = n0 < cy;
+	  n0 = (n0 - cy) & GMP_NUMB_MASK;
+	  cy = n1 < cy1;
+	  n1 -= cy1;
+	  np[0] = n0;
+
+	  if (UNLIKELY (cy != 0))
+	    {
+	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+	      q--;
+	    }
+	}
+
+      *--qp = q;
+    }
+
+  flag = ~CNST_LIMB(0);
+
+  if (dn >= 0)
+    {
+      for (i = dn; i > 0; i--)
+	{
+	  np--;
+	  if (UNLIKELY (n1 >= (d1 & flag)))
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp, dn + 2, q);
+
+	      if (UNLIKELY (n1 != cy))
+		{
+		  if (n1 < (cy & flag))
+		    {
+		      q--;
+		      mpn_add_n (np - dn, np - dn, dp, dn + 2);
+		    }
+		  else
+		    flag = 0;
+		}
+	      n1 = np[1];
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	      cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	      cy1 = n0 < cy;
+	      n0 = (n0 - cy) & GMP_NUMB_MASK;
+	      cy = n1 < cy1;
+	      n1 -= cy1;
+	      np[0] = n0;
+
+	      if (UNLIKELY (cy != 0))
+		{
+		  n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+		  q--;
+		}
+	    }
+
+	  *--qp = q;
+
+	  /* Truncate operands.  */
+	  dn--;
+	  dp++;
+	}
+
+      np--;
+      if (UNLIKELY (n1 >= (d1 & flag)))
+	{
+	  q = GMP_NUMB_MASK;
+	  cy = mpn_submul_1 (np, dp, 2, q);
+
+	  if (UNLIKELY (n1 != cy))
+	    {
+	      if (n1 < (cy & flag))
+		{
+		  q--;
+		  add_ssaaaa (np[1], np[0], np[1], np[0], dp[1], dp[0]);
+		}
+	      else
+		flag = 0;
+	    }
+	  n1 = np[1];
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  np[0] = n0;
+	  np[1] = n1;
+	}
+
+      *--qp = q;
+    }
+  ASSERT_ALWAYS (np[1] == n1);
+  np += 2;
+
+
+  dn = dn_orig;
+  if (UNLIKELY (n1 < (dn & flag)))
+    {
+      mp_limb_t q, x;
+
+      /* The quotient may be too large if the remainder is small.  Recompute
+	 for above ignored operand parts, until the remainder spills.
+
+	 FIXME: The quality of this code isn't the same as the code above.
+	 1. We don't compute things in an optimal order, high-to-low, in order
+	    to terminate as quickly as possible.
+	 2. We mess with pointers and sizes, adding and subtracting and
+	    adjusting to get things right.  It surely could be streamlined.
+	 3. The only termination criteria are that we determine that the
+	    quotient needs to be adjusted, or that we have recomputed
+	    everything.  We should stop when the remainder is so large
+	    that no additional subtracting could make it spill.
+	 4. If nothing else, we should not do two loops of submul_1 over the
+	    data, instead handle both the triangularization and chopping at
+	    once.  */
+
+      x = n1;
+
+      if (dn > 2)
+	{
+	  /* Compensate for triangularization.  */
+	  mp_limb_t y;
+
+	  dp = dp_orig;
+	  if (qn + 1 < dn)
+	    {
+	      dp += dn - (qn + 1);
+	      dn = qn + 1;
+	    }
+
+	  y = np[-2];
+
+	  for (i = dn - 3; i >= 0; i--)
+	    {
+	      q = qp[i];
+	      cy = mpn_submul_1 (np - (dn - i), dp, dn - i - 2, q);
+
+	      if (y < cy)
+		{
+		  if (x == 0)
+		    {
+		      cy = mpn_sub_1 (qp, qp, qn, 1);
+		      ASSERT_ALWAYS (cy == 0);
+		      return qh - cy;
+		    }
+		  x--;
+		}
+	      y -= cy;
+	    }
+	  np[-2] = y;
+	}
+
+      dn = dn_orig;
+      if (qn + 1 < dn)
+	{
+	  /* Compensate for ignored dividend and divisor tails.  */
+
+	  dp = dp_orig;
+	  np = np_orig;
+
+	  if (qh != 0)
+	    {
+	      cy = mpn_sub_n (np + qn, np + qn, dp, dn - (qn + 1));
+	      if (cy != 0)
+		{
+		  if (x == 0)
+		    {
+		      if (qn != 0)
+			cy = mpn_sub_1 (qp, qp, qn, 1);
+		      return qh - cy;
+		    }
+		  x--;
+		}
+	    }
+
+	  if (qn == 0)
+	    return qh;
+
+	  for (i = dn - qn - 2; i >= 0; i--)
+	    {
+	      cy = mpn_submul_1 (np + i, qp, qn, dp[i]);
+	      cy = mpn_sub_1 (np + qn + i, np + qn + i, dn - qn - i - 1, cy);
+	      if (cy != 0)
+		{
+		  if (x == 0)
+		    {
+		      cy = mpn_sub_1 (qp, qp, qn, 1);
+		      return qh;
+		    }
+		  x--;
+		}
+	    }
+	}
+    }
+
+  return qh;
+}
diff --git a/mpn/generic/sbpi1_div_qr.c b/mpn/generic/sbpi1_div_qr.c
new file mode 100644
index 0000000..7330a77
--- /dev/null
+++ b/mpn/generic/sbpi1_div_qr.c
@@ -0,0 +1,109 @@
+/* mpn_sbpi1_div_qr -- Schoolbook division using the Möller-Granlund 3/2
+   division algorithm.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_sbpi1_div_qr (mp_ptr qp,
+		  mp_ptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn,
+		  mp_limb_t dinv)
+{
+  mp_limb_t qh;
+  mp_size_t i;
+  mp_limb_t n1, n0;
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  np += nn;
+
+  qh = mpn_cmp (np - dn, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (np - dn, np - dn, dp, dn);
+
+  qp += nn - dn;
+
+  dn -= 2;			/* offset dn by 2 for main division loops,
+				   saving two iterations in mpn_submul_1.  */
+  d1 = dp[dn + 1];
+  d0 = dp[dn + 0];
+
+  np -= 2;
+
+  n1 = np[1];
+
+  for (i = nn - (dn + 2); i > 0; i--)
+    {
+      np--;
+      if (UNLIKELY (n1 == d1) && np[1] == d0)
+	{
+	  q = GMP_NUMB_MASK;
+	  mpn_submul_1 (np - dn, dp, dn + 2, q);
+	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	  cy1 = n0 < cy;
+	  n0 = (n0 - cy) & GMP_NUMB_MASK;
+	  cy = n1 < cy1;
+	  n1 = (n1 - cy1) & GMP_NUMB_MASK;
+	  np[0] = n0;
+
+	  if (UNLIKELY (cy != 0))
+	    {
+	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+	      q--;
+	    }
+	}
+
+      *--qp = q;
+    }
+  np[1] = n1;
+
+  return qh;
+}
diff --git a/mpn/generic/sbpi1_divappr_q.c b/mpn/generic/sbpi1_divappr_q.c
new file mode 100644
index 0000000..ef7ca26
--- /dev/null
+++ b/mpn/generic/sbpi1_divappr_q.c
@@ -0,0 +1,198 @@
+/* mpn_sbpi1_divappr_q -- Schoolbook division using the Möller-Granlund 3/2
+   division algorithm, returning approximate quotient.  The quotient returned
+   is either correct, or one too large.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_sbpi1_divappr_q (mp_ptr qp,
+		     mp_ptr np, mp_size_t nn,
+		     mp_srcptr dp, mp_size_t dn,
+		     mp_limb_t dinv)
+{
+  mp_limb_t qh;
+  mp_size_t qn, i;
+  mp_limb_t n1, n0;
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+  mp_limb_t flag;
+
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  np += nn;
+
+  qn = nn - dn;
+  if (qn + 1 < dn)
+    {
+      dp += dn - (qn + 1);
+      dn = qn + 1;
+    }
+
+  qh = mpn_cmp (np - dn, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (np - dn, np - dn, dp, dn);
+
+  qp += qn;
+
+  dn -= 2;			/* offset dn by 2 for main division loops,
+				   saving two iterations in mpn_submul_1.  */
+  d1 = dp[dn + 1];
+  d0 = dp[dn + 0];
+
+  np -= 2;
+
+  n1 = np[1];
+
+  for (i = qn - (dn + 2); i >= 0; i--)
+    {
+      np--;
+      if (UNLIKELY (n1 == d1) && np[1] == d0)
+	{
+	  q = GMP_NUMB_MASK;
+	  mpn_submul_1 (np - dn, dp, dn + 2, q);
+	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	  cy1 = n0 < cy;
+	  n0 = (n0 - cy) & GMP_NUMB_MASK;
+	  cy = n1 < cy1;
+	  n1 -= cy1;
+	  np[0] = n0;
+
+	  if (UNLIKELY (cy != 0))
+	    {
+	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+	      q--;
+	    }
+	}
+
+      *--qp = q;
+    }
+
+  flag = ~CNST_LIMB(0);
+
+  if (dn >= 0)
+    {
+      for (i = dn; i > 0; i--)
+	{
+	  np--;
+	  if (UNLIKELY (n1 >= (d1 & flag)))
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp, dn + 2, q);
+
+	      if (UNLIKELY (n1 != cy))
+		{
+		  if (n1 < (cy & flag))
+		    {
+		      q--;
+		      mpn_add_n (np - dn, np - dn, dp, dn + 2);
+		    }
+		  else
+		    flag = 0;
+		}
+	      n1 = np[1];
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	      cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	      cy1 = n0 < cy;
+	      n0 = (n0 - cy) & GMP_NUMB_MASK;
+	      cy = n1 < cy1;
+	      n1 -= cy1;
+	      np[0] = n0;
+
+	      if (UNLIKELY (cy != 0))
+		{
+		  n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+		  q--;
+		}
+	    }
+
+	  *--qp = q;
+
+	  /* Truncate operands.  */
+	  dn--;
+	  dp++;
+	}
+
+      np--;
+      if (UNLIKELY (n1 >= (d1 & flag)))
+	{
+	  q = GMP_NUMB_MASK;
+	  cy = mpn_submul_1 (np, dp, 2, q);
+
+	  if (UNLIKELY (n1 != cy))
+	    {
+	      if (n1 < (cy & flag))
+		{
+		  q--;
+		  add_ssaaaa (np[1], np[0], np[1], np[0], dp[1], dp[0]);
+		}
+	      else
+		flag = 0;
+	    }
+	  n1 = np[1];
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  np[1] = n1;
+	  np[0] = n0;
+	}
+
+      *--qp = q;
+    }
+
+  ASSERT_ALWAYS (np[1] == n1);
+
+  return qh;
+}
diff --git a/mpn/generic/scan0.c b/mpn/generic/scan0.c
new file mode 100644
index 0000000..d71832e
--- /dev/null
+++ b/mpn/generic/scan0.c
@@ -0,0 +1,59 @@
+/* mpn_scan0 -- Scan from a given bit position for the next clear bit.
+
+Copyright 1994, 1996, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Argument constraints:
+   1. U must sooner or later have a limb with a clear bit.
+ */
+
+mp_bitcnt_t
+mpn_scan0 (mp_srcptr up, mp_bitcnt_t starting_bit)
+{
+  mp_size_t starting_word;
+  mp_limb_t alimb;
+  int cnt;
+  mp_srcptr p;
+
+  /* Start at the word implied by STARTING_BIT.  */
+  starting_word = starting_bit / GMP_NUMB_BITS;
+  p = up + starting_word;
+  alimb = *p++ ^ GMP_NUMB_MASK;
+
+  /* Mask off any bits before STARTING_BIT in the first limb.  */
+  alimb &= - (mp_limb_t) 1 << (starting_bit % GMP_NUMB_BITS);
+
+  while (alimb == 0)
+    alimb = *p++ ^ GMP_NUMB_MASK;
+
+  count_trailing_zeros (cnt, alimb);
+  return (p - up - 1) * GMP_NUMB_BITS + cnt;
+}
diff --git a/mpn/generic/scan1.c b/mpn/generic/scan1.c
new file mode 100644
index 0000000..09e8060
--- /dev/null
+++ b/mpn/generic/scan1.c
@@ -0,0 +1,59 @@
+/* mpn_scan1 -- Scan from a given bit position for the next set bit.
+
+Copyright 1994, 1996, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Argument constraints:
+   1. U must sooner or later have a limb != 0.
+ */
+
+mp_bitcnt_t
+mpn_scan1 (mp_srcptr up, mp_bitcnt_t starting_bit)
+{
+  mp_size_t starting_word;
+  mp_limb_t alimb;
+  int cnt;
+  mp_srcptr p;
+
+  /* Start at the word implied by STARTING_BIT.  */
+  starting_word = starting_bit / GMP_NUMB_BITS;
+  p = up + starting_word;
+  alimb = *p++;
+
+  /* Mask off any bits before STARTING_BIT in the first limb.  */
+  alimb &= - (mp_limb_t) 1 << (starting_bit % GMP_NUMB_BITS);
+
+  while (alimb == 0)
+    alimb = *p++;
+
+  count_trailing_zeros (cnt, alimb);
+  return (p - up - 1) * GMP_NUMB_BITS + cnt;
+}
diff --git a/mpn/generic/sec_aors_1.c b/mpn/generic/sec_aors_1.c
new file mode 100644
index 0000000..6480fa1
--- /dev/null
+++ b/mpn/generic/sec_aors_1.c
@@ -0,0 +1,59 @@
+/* mpn_sec_add_1, mpn_sec_sub_1
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if OPERATION_sec_add_1
+#define FNAME mpn_sec_add_1
+#define FNAME_itch mpn_sec_add_1_itch
+#define OP_N mpn_add_n
+#endif
+#if OPERATION_sec_sub_1
+#define FNAME mpn_sec_sub_1
+#define FNAME_itch mpn_sec_sub_1_itch
+#define OP_N mpn_sub_n
+#endif
+
+/* It's annoying to that we need scratch space */
+mp_size_t
+FNAME_itch (mp_size_t n)
+{
+  return n;
+}
+
+mp_limb_t
+FNAME (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b, mp_ptr scratch)
+{
+  scratch[0] = b;
+  MPN_ZERO (scratch + 1, n-1);
+  return OP_N (rp, ap, scratch, n);
+}
diff --git a/mpn/generic/sec_div.c b/mpn/generic/sec_div.c
new file mode 100644
index 0000000..1f08649
--- /dev/null
+++ b/mpn/generic/sec_div.c
@@ -0,0 +1,131 @@
+/* mpn_sec_div_qr, mpn_sec_div_r -- Compute Q = floor(U / V), U = U mod V.
+   Side-channel silent under the assumption that the used instructions are
+   side-channel silent.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2011-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if OPERATION_sec_div_qr
+#define FNAME mpn_sec_div_qr
+#define FNAME_itch mpn_sec_div_qr_itch
+#define Q(q) q,
+#define RETTYPE mp_limb_t
+#endif
+#if OPERATION_sec_div_r
+#define FNAME mpn_sec_div_r
+#define FNAME_itch mpn_sec_div_r_itch
+#define Q(q)
+#define RETTYPE void
+#endif
+
+mp_size_t
+FNAME_itch (mp_size_t nn, mp_size_t dn)
+{
+#if OPERATION_sec_div_qr
+/* Needs (nn + dn + 1) + mpn_sec_pi1_div_qr's needs of (2nn' - dn + 1) for a
+   total of 3nn + 4 limbs at tp.  Note that mpn_sec_pi1_div_qr's nn is one
+   greater than ours, therefore +4 and not just +2.  */
+  return 3 * nn + 4;
+#endif
+#if OPERATION_sec_div_r
+/* Needs (nn + dn + 1) + mpn_sec_pi1_div_r's needs of (dn + 1) for a total of
+   nn + 2dn + 2 limbs at tp.  */
+  return nn + 2 * dn + 2;
+#endif
+}
+
+RETTYPE
+FNAME (Q(mp_ptr qp)
+       mp_ptr np, mp_size_t nn,
+       mp_srcptr dp, mp_size_t dn,
+       mp_ptr tp)
+{
+  mp_limb_t d1, d0;
+  unsigned int cnt;
+  mp_limb_t inv32;
+
+  ASSERT (dn >= 1);
+  ASSERT (nn >= dn);
+  ASSERT (dp[dn - 1] != 0);
+
+  d1 = dp[dn - 1];
+  count_leading_zeros (cnt, d1);
+
+  if (cnt != 0)
+    {
+      mp_limb_t qh, cy;
+      mp_ptr np2, dp2;
+      dp2 = tp;					/* dn limbs */
+      mpn_lshift (dp2, dp, dn, cnt);
+
+      np2 = tp + dn;				/* (nn + 1) limbs */
+      cy = mpn_lshift (np2, np, nn, cnt);
+      np2[nn++] = cy;
+
+      d0 = dp2[dn - 1];
+      d0 += (~d0 != 0);
+      invert_limb (inv32, d0);
+
+      /* We add nn + dn to tp here, not nn + 1 + dn, as expected.  This is
+	 since nn here will have been incremented.  */
+#if OPERATION_sec_div_qr
+      qh = mpn_sec_pi1_div_qr (np2 + dn, np2, nn, dp2, dn, inv32, tp + nn + dn);
+      ASSERT (qh == 0);		/* FIXME: this indicates inefficiency! */
+      MPN_COPY (qp, np2 + dn, nn - dn - 1);
+      qh = np2[nn - 1];
+#else
+      mpn_sec_pi1_div_r (np2, nn, dp2, dn, inv32, tp + nn + dn);
+#endif
+
+      mpn_rshift (np, np2, dn, cnt);
+
+#if OPERATION_sec_div_qr
+      return qh;
+#endif
+    }
+  else
+    {
+      /* FIXME: Consider copying np => np2 here, adding a 0-limb at the top.
+	 That would simplify the underlying pi1 function, since then it could
+	 assume nn > dn.  */
+      d0 = dp[dn - 1];
+      d0 += (~d0 != 0);
+      invert_limb (inv32, d0);
+
+#if OPERATION_sec_div_qr
+      return mpn_sec_pi1_div_qr (qp, np, nn, dp, dn, inv32, tp);
+#else
+      mpn_sec_pi1_div_r (np, nn, dp, dn, inv32, tp);
+#endif
+    }
+}
diff --git a/mpn/generic/sec_invert.c b/mpn/generic/sec_invert.c
new file mode 100644
index 0000000..07665d1
--- /dev/null
+++ b/mpn/generic/sec_invert.c
@@ -0,0 +1,177 @@
+/* mpn_sec_invert
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if 0
+/* Currently unused. Should be resurrected once mpn_cnd_neg is
+   advertised. */
+static mp_size_t
+mpn_cnd_neg_itch (mp_size_t n)
+{
+  return n;
+}
+#endif
+
+/* FIXME: Ought to return carry */
+static void
+mpn_cnd_neg (int cnd, mp_limb_t *rp, const mp_limb_t *ap, mp_size_t n,
+	     mp_ptr scratch)
+{
+  mpn_lshift (scratch, ap, n, 1);
+  mpn_cnd_sub_n (cnd, rp, ap, scratch, n);
+}
+
+static int
+mpn_sec_eq_ui (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_limb_t d;
+  ASSERT (n > 0);
+
+  d = ap[0] ^ b;
+
+  while (--n > 0)
+    d |= ap[n];
+
+  return d == 0;
+}
+
+mp_size_t
+mpn_sec_invert_itch (mp_size_t n)
+{
+  return 4*n;
+}
+
+/* Compute V <-- A^{-1} (mod M), in data-independent time. M must be
+   odd. Returns 1 on success, and 0 on failure (i.e., if gcd (A, m) !=
+   1). Inputs and outputs of size n, and no overlap allowed. The {ap,
+   n} area is destroyed. For arbitrary inputs, bit_size should be
+   2*n*GMP_NUMB_BITS, but if A or M are known to be smaller, e.g., if
+   M = 2^521 - 1 and A < M, bit_size can be any bound on the sum of
+   the bit sizes of A and M. */
+int
+mpn_sec_invert (mp_ptr vp, mp_ptr ap, mp_srcptr mp,
+		mp_size_t n, mp_bitcnt_t bit_size,
+		mp_ptr scratch)
+{
+  ASSERT (n > 0);
+  ASSERT (bit_size > 0);
+  ASSERT (mp[0] & 1);
+  ASSERT (! MPN_OVERLAP_P (ap, n, vp, n));
+#define bp (scratch + n)
+#define up (scratch + 2*n)
+#define m1hp (scratch + 3*n)
+
+  /* Maintain
+
+       a = u * orig_a (mod m)
+       b = v * orig_a (mod m)
+
+     and b odd at all times. Initially,
+
+       a = a_orig, u = 1
+       b = m,      v = 0
+     */
+
+
+  up[0] = 1;
+  mpn_zero (up+1, n - 1);
+  mpn_copyi (bp, mp, n);
+  mpn_zero (vp, n);
+
+  ASSERT_CARRY (mpn_rshift (m1hp, mp, n, 1));
+  ASSERT_NOCARRY (mpn_sec_add_1 (m1hp, m1hp, n, 1, scratch));
+
+  while (bit_size-- > 0)
+    {
+      mp_limb_t odd, swap, cy;
+
+      /* Always maintain b odd. The logic of the iteration is as
+	 follows. For a, b:
+
+	   odd = a & 1
+	   a -= odd * b
+	   if (underflow from a-b)
+	     {
+	       b += a, assigns old a
+	       a = B^n-a
+	     }
+
+	   a /= 2
+
+	 For u, v:
+
+	   if (underflow from a - b)
+	     swap u, v
+	   u -= odd * v
+	   if (underflow from u - v)
+	     u += m
+
+	   u /= 2
+	   if (a one bit was shifted out)
+	     u += (m+1)/2
+
+	 As long as a > 0, the quantity
+
+	   (bitsize of a) + (bitsize of b)
+
+	 is reduced by at least one bit per iteration, hence after (bit_size of
+	 orig_a) + (bit_size of m) - 1 iterations we surely have a = 0. Then b
+	 = gcd(orig_a, m) and if b = 1 then also v = orig_a^{-1} (mod m).
+      */
+
+      ASSERT (bp[0] & 1);
+      odd = ap[0] & 1;
+
+      swap = mpn_cnd_sub_n (odd, ap, ap, bp, n);
+      mpn_cnd_add_n (swap, bp, bp, ap, n);
+      mpn_cnd_neg (swap, ap, ap, n, scratch);
+
+      mpn_cnd_swap (swap, up, vp, n);
+      cy = mpn_cnd_sub_n (odd, up, up, vp, n);
+      cy -= mpn_cnd_add_n (cy, up, up, mp, n);
+      ASSERT (cy == 0);
+
+      cy = mpn_rshift (ap, ap, n, 1);
+      ASSERT (cy == 0);
+      cy = mpn_rshift (up, up, n, 1);
+      cy = mpn_cnd_add_n (cy, up, up, m1hp, n);
+      ASSERT (cy == 0);
+    }
+  /* Should be all zeros, but check only extreme limbs */
+  ASSERT ( (ap[0] | ap[n-1]) == 0);
+  /* Check if indeed gcd == 1. */
+  return mpn_sec_eq_ui (bp, n, 1);
+#undef bp
+#undef up
+#undef m1hp
+}
diff --git a/mpn/generic/sec_mul.c b/mpn/generic/sec_mul.c
new file mode 100644
index 0000000..4bbfa61
--- /dev/null
+++ b/mpn/generic/sec_mul.c
@@ -0,0 +1,48 @@
+/* mpn_sec_mul.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_sec_mul (mp_ptr rp,
+	     mp_srcptr ap, mp_size_t an,
+	     mp_srcptr bp, mp_size_t bn,
+	     mp_ptr tp)
+{
+  mpn_mul_basecase (rp, ap, an, bp, bn);
+}
+
+mp_size_t
+mpn_sec_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  return 0;
+}
diff --git a/mpn/generic/sec_pi1_div.c b/mpn/generic/sec_pi1_div.c
new file mode 100644
index 0000000..29d01e7
--- /dev/null
+++ b/mpn/generic/sec_pi1_div.c
@@ -0,0 +1,172 @@
+/* mpn_sec_pi1_div_qr, mpn_sec_pi1_div_r -- Compute Q = floor(U / V), U = U
+   mod V.  Side-channel silent under the assumption that the used instructions
+   are side-channel silent.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011-2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* This side-channel silent division algorithm reduces the partial remainder by
+   GMP_NUMB_BITS/2 bits at a time, compared to GMP_NUMB_BITS for the main
+   division algorithm.  We actually do not insist on reducing by exactly
+   GMP_NUMB_BITS/2, but may leave a partial remainder that is D*B^i to 3D*B^i
+   too large (B is the limb base, D is the divisor, and i is the induction
+   variable); the subsequent step will handle the extra partial remainder bits.
+
+   With that partial remainder reduction, each step generates a quotient "half
+   limb".  The outer loop generates two quotient half limbs, an upper (q1h) and
+   a lower (q0h) which are stored sparsely in separate limb arrays.  These
+   arrays are added at the end; using separate arrays avoids data-dependent
+   carry propagation which could else pose a side-channel leakage problem.
+
+   The quotient half limbs may be between -3 to 0 from the accurate value
+   ("accurate" being the one which corresponds to a reduction to a principal
+   partial remainder).  Too small quotient half limbs correspond to too large
+   remainders, which we reduce later, as described above.
+
+   In order to keep quotients from getting too big, corresponding to a negative
+   partial remainder, we use an inverse which is slightly smaller than usually.
+*/
+
+#if OPERATION_sec_pi1_div_qr
+/* Needs (dn + 1) + (nn - dn) + (nn - dn) = 2nn - dn + 1 limbs at tp. */
+#define FNAME mpn_sec_pi1_div_qr
+#define Q(q) q,
+#define RETTYPE mp_limb_t
+#endif
+#if OPERATION_sec_pi1_div_r
+/* Needs (dn + 1) limbs at tp.  */
+#define FNAME mpn_sec_pi1_div_r
+#define Q(q)
+#define RETTYPE void
+#endif
+
+RETTYPE
+FNAME (Q(mp_ptr qp)
+       mp_ptr np, mp_size_t nn,
+       mp_srcptr dp, mp_size_t dn,
+       mp_limb_t dinv,
+       mp_ptr tp)
+{
+  mp_limb_t nh, cy, q1h, q0h, dummy, cnd;
+  mp_size_t i;
+  mp_ptr hp;
+#if OPERATION_sec_pi1_div_qr
+  mp_limb_t qh;
+  mp_ptr qlp, qhp;
+#endif
+
+  ASSERT (dn >= 1);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn - 1] & GMP_NUMB_HIGHBIT) != 0);
+
+  if (nn == dn)
+    {
+      cy = mpn_sub_n (np, np, dp, dn);
+      mpn_cnd_add_n (cy, np, np, dp, dn);
+#if OPERATION_sec_pi1_div_qr
+      return 1 - cy;
+#else
+      return;
+#endif
+    }
+
+  /* Create a divisor copy shifted half a limb.  */
+  hp = tp;					/* (dn + 1) limbs */
+  hp[dn] = mpn_lshift (hp, dp, dn, GMP_NUMB_BITS / 2);
+
+#if OPERATION_sec_pi1_div_qr
+  qlp = tp + (dn + 1);				/* (nn - dn) limbs */
+  qhp = tp + (nn + 1);				/* (nn - dn) limbs */
+#endif
+
+  np += nn - dn;
+  nh = 0;
+
+  for (i = nn - dn - 1; i >= 0; i--)
+    {
+      np--;
+
+      nh = (nh << GMP_NUMB_BITS/2) + (np[dn] >> GMP_NUMB_BITS/2);
+      umul_ppmm (q1h, dummy, nh, dinv);
+      q1h += nh;
+#if OPERATION_sec_pi1_div_qr
+      qhp[i] = q1h;
+#endif
+      mpn_submul_1 (np, hp, dn + 1, q1h);
+
+      nh = np[dn];
+      umul_ppmm (q0h, dummy, nh, dinv);
+      q0h += nh;
+#if OPERATION_sec_pi1_div_qr
+      qlp[i] = q0h;
+#endif
+      nh -= mpn_submul_1 (np, dp, dn, q0h);
+    }
+
+  /* 1st adjustment depends on extra high remainder limb.  */
+  cnd = nh != 0;				/* FIXME: cmp-to-int */
+#if OPERATION_sec_pi1_div_qr
+  qlp[0] += cnd;
+#endif
+  nh -= mpn_cnd_sub_n (cnd, np, np, dp, dn);
+
+  /* 2nd adjustment depends on remainder/divisor comparison as well as whether
+     extra remainder limb was nullified by previous subtract.  */
+  cy = mpn_sub_n (np, np, dp, dn);
+  cy = cy - nh;
+#if OPERATION_sec_pi1_div_qr
+  qlp[0] += 1 - cy;
+#endif
+  mpn_cnd_add_n (cy, np, np, dp, dn);
+
+  /* 3rd adjustment depends on remainder/divisor comparison.  */
+  cy = mpn_sub_n (np, np, dp, dn);
+#if OPERATION_sec_pi1_div_qr
+  qlp[0] += 1 - cy;
+#endif
+  mpn_cnd_add_n (cy, np, np, dp, dn);
+
+#if OPERATION_sec_pi1_div_qr
+  /* Combine quotient halves into final quotient.  */
+  qh = mpn_lshift (qhp, qhp, nn - dn, GMP_NUMB_BITS/2);
+  qh += mpn_add_n (qp, qhp, qlp, nn - dn);
+
+  return qh;
+#else
+  return;
+#endif
+}
diff --git a/mpn/generic/sec_powm.c b/mpn/generic/sec_powm.c
new file mode 100644
index 0000000..bba11cf
--- /dev/null
+++ b/mpn/generic/sec_powm.c
@@ -0,0 +1,430 @@
+/* mpn_sec_powm -- Compute R = U^E mod M.  Secure variant, side-channel silent
+   under the assumption that the multiply instruction is side channel silent.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2007-2009, 2011-2014, 2018-2019, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+  BASIC ALGORITHM, Compute U^E mod M, where M < B^n is odd.
+
+  1. T <- (B^n * U) mod M; convert to REDC form
+
+  2. Compute table U^0, U^1, U^2... of floor(log(E))-dependent size
+
+  3. While there are more bits in E
+       W <- power left-to-right base-k
+
+  The article "Defeating modexp side-channel attacks with data-independent
+  execution traces", https://gmplib.org/~tege/modexp-silent.pdf, has details.
+
+
+  TODO:
+
+   * Make getbits a macro, thereby allowing it to update the index operand.
+     That will simplify the code using getbits.  (Perhaps make getbits' sibling
+     getbit then have similar form, for symmetry.)
+
+   * Choose window size without looping.  (Superoptimize or think(tm).)
+
+   * REDC_1_TO_REDC_2_THRESHOLD might actually represent the cutoff between
+     redc_1 and redc_n.  On such systems, we will switch to redc_2 causing
+     slowdown.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#undef MPN_REDC_1_SEC
+#if HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#define MPN_REDC_1_SEC(rp, up, mp, n, invm)				\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_sbpi1_bdiv_r (up, 2 * n, mp, n, invm);			\
+    mpn_cnd_sub_n (cy, rp, up + n, mp, n);				\
+  } while (0)
+#else
+#define MPN_REDC_1_SEC(rp, up, mp, n, invm)				\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_1 (rp, up, mp, n, invm);				\
+    mpn_cnd_sub_n (cy, rp, rp, mp, n);					\
+  } while (0)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+#undef MPN_REDC_2_SEC
+#define MPN_REDC_2_SEC(rp, up, mp, n, mip)				\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_2 (rp, up, mp, n, mip);				\
+    mpn_cnd_sub_n (cy, rp, rp, mp, n);					\
+  } while (0)
+#else
+#define MPN_REDC_2_SEC(rp, up, mp, n, mip) /* empty */
+#undef REDC_1_TO_REDC_2_THRESHOLD
+#define REDC_1_TO_REDC_2_THRESHOLD MP_SIZE_T_MAX
+#endif
+
+/* Define our own mpn squaring function.  We do this since we cannot use a
+   native mpn_sqr_basecase over TUNE_SQR_TOOM2_MAX, or a non-native one over
+   SQR_TOOM2_THRESHOLD.  This is so because of fixed size stack allocations
+   made inside mpn_sqr_basecase.  */
+
+#if ! HAVE_NATIVE_mpn_sqr_basecase
+/* The limit of the generic code is SQR_TOOM2_THRESHOLD.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_basecase
+#ifdef TUNE_SQR_TOOM2_MAX
+/* We slightly abuse TUNE_SQR_TOOM2_MAX here.  If it is set for an assembly
+   mpn_sqr_basecase, it comes from SQR_TOOM2_THRESHOLD_MAX in the assembly
+   file.  An assembly mpn_sqr_basecase that does not define it should allow
+   any size.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+#endif
+
+#ifdef WANT_FAT_BINARY
+/* For fat builds, we use SQR_TOOM2_THRESHOLD which will expand to a read from
+   __gmpn_cpuvec.  Perhaps any possible sqr_basecase.asm allow any size, and we
+   limit the use unnecessarily.  We cannot tell, so play it safe.  FIXME.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+#ifndef SQR_BASECASE_LIM
+/* If SQR_BASECASE_LIM is now not defined, use mpn_sqr_basecase for any operand
+   size.  */
+#define SQR_BASECASE_LIM  MP_SIZE_T_MAX
+#endif
+
+#define mpn_local_sqr(rp,up,n)						\
+  do {									\
+    if (ABOVE_THRESHOLD (n, SQR_BASECASE_THRESHOLD)			\
+	&& BELOW_THRESHOLD (n, SQR_BASECASE_LIM))			\
+      mpn_sqr_basecase (rp, up, n);					\
+    else								\
+      mpn_mul_basecase(rp, up, n, up, n);				\
+  } while (0)
+
+#define getbit(p,bi) \
+  ((p[(bi - 1) / GMP_NUMB_BITS] >> (bi - 1) % GMP_NUMB_BITS) & 1)
+
+/* FIXME: Maybe some things would get simpler if all callers ensure
+   that bi >= nbits. As far as I understand, with the current code bi
+   < nbits can happen only for the final iteration. */
+static inline mp_limb_t
+getbits (const mp_limb_t *p, mp_bitcnt_t bi, int nbits)
+{
+  int nbits_in_r;
+  mp_limb_t r;
+  mp_size_t i;
+
+  if (bi < nbits)
+    {
+      return p[0] & (((mp_limb_t) 1 << bi) - 1);
+    }
+  else
+    {
+      bi -= nbits;			/* bit index of low bit to extract */
+      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
+      bi %= GMP_NUMB_BITS;		/* bit index in low word */
+      r = p[i] >> bi;			/* extract (low) bits */
+      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
+      if (nbits_in_r < nbits)		/* did we get enough bits? */
+	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
+      return r & (((mp_limb_t ) 1 << nbits) - 1);
+    }
+}
+
+#ifndef POWM_SEC_TABLE
+#if GMP_NUMB_BITS < 50
+#define POWM_SEC_TABLE  2,33,96,780,2741
+#else
+#define POWM_SEC_TABLE  2,130,524,2578
+#endif
+#endif
+
+#if TUNE_PROGRAM_BUILD
+extern int win_size (mp_bitcnt_t);
+#else
+static inline int
+win_size (mp_bitcnt_t enb)
+{
+  int k;
+  /* Find k, such that x[k-1] < enb <= x[k].
+
+     We require that x[k] >= k, then it follows that enb > x[k-1] >=
+     k-1, which implies k <= enb.
+  */
+  static const mp_bitcnt_t x[] = {POWM_SEC_TABLE,~(mp_bitcnt_t)0};
+  for (k = 0; enb > x[k++]; )
+    ;
+  ASSERT (k <= enb);
+  return k;
+}
+#endif
+
+/* Convert U to REDC form, U_r = B^n * U mod M.
+   Uses scratch space at tp of size 2un + n + 1.  */
+static void
+redcify (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  MPN_ZERO (tp, n);
+  MPN_COPY (tp + n, up, un);
+
+  mpn_sec_div_r (tp, un + n, mp, n, tp + un + n);
+  MPN_COPY (rp, tp, n);
+}
+
+static mp_limb_t
+sec_binvert_limb (mp_limb_t n)
+{
+  mp_limb_t inv, t;
+  ASSERT ((n & 1) == 1);
+  /* 3 + 2 -> 5 */
+  inv = n + (((n + 1) << 1) & 0x18);
+
+  t = n * inv;
+#if GMP_NUMB_BITS <= 10
+  /* 5 x 2 -> 10 */
+  inv = 2 * inv - inv * t;
+#else /* GMP_NUMB_BITS > 10 */
+  /* 5 x 2 + 2 -> 12 */
+  inv = 2 * inv - inv * t + ((inv<<10)&-(t&(1<<5)));
+#endif /* GMP_NUMB_BITS <= 10 */
+
+  if (GMP_NUMB_BITS > 12)
+    {
+      t = n * inv - 1;
+      if (GMP_NUMB_BITS <= 36)
+	{
+	  /* 12 x 3 -> 36 */
+	  inv += inv * t * (t - 1);
+	}
+      else /* GMP_NUMB_BITS > 36 */
+	{
+	  mp_limb_t t2 = t * t;
+#if GMP_NUMB_BITS <= 60
+	  /* 12 x 5 -> 60 */
+	  inv += inv * (t2 + 1) * (t2 - t);
+#else /* GMP_NUMB_BITS > 60 */
+	  /* 12 x 5 + 4 -> 64 */
+	  inv *= (t2 + 1) * (t2 - t) + 1 - ((t<<48)&-(t&(1<<12)));
+
+	  /* 64 -> 128 -> 256 -> ... */
+	  for (int todo = (GMP_NUMB_BITS - 1) >> 6; todo != 0; todo >>= 1)
+	    inv = 2 * inv - inv * inv * n;
+#endif /* GMP_NUMB_BITS <= 60 */
+	}
+    }
+
+  ASSERT ((inv * n & GMP_NUMB_MASK) == 1);
+  return inv & GMP_NUMB_MASK;
+}
+
+/* {rp, n} <-- {bp, bn} ^ {ep, en} mod {mp, n},
+   where en = ceil (enb / GMP_NUMB_BITS)
+   Requires that {mp, n} is odd (and hence also mp[0] odd).
+   Uses scratch space at tp as defined by mpn_sec_powm_itch.  */
+void
+mpn_sec_powm (mp_ptr rp, mp_srcptr bp, mp_size_t bn,
+	      mp_srcptr ep, mp_bitcnt_t enb,
+	      mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ip[2], *mip;
+  int windowsize, this_windowsize;
+  mp_limb_t expbits;
+  mp_ptr pp, this_pp, ps;
+  long i;
+  int cnd;
+
+  ASSERT (enb > 0);
+  ASSERT (n > 0);
+  /* The code works for bn = 0, but the defined scratch space is 2 limbs
+     greater than we supply, when converting 1 to redc form .  */
+  ASSERT (bn > 0);
+  ASSERT ((mp[0] & 1) != 0);
+
+  windowsize = win_size (enb);
+
+  mip = ip;
+  mip[0] = sec_binvert_limb (mp[0]);
+  if (ABOVE_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      mp_limb_t t, dummy, mip0 = mip[0];
+
+      umul_ppmm (t, dummy, mip0, mp[0]);
+      ASSERT (dummy == 1);
+      t += mip0 * mp[1]; /* t = (mp * mip0)[1] */
+
+      mip[1] = t * mip0 - 1; /* ~( - t * mip0) */
+    }
+  mip[0] = -mip[0];
+
+  pp = tp;
+  tp += (n << windowsize);	/* put tp after power table */
+
+  /* Compute pp[0] table entry */
+  /* scratch: |   n   | 1 |   n+2    |  */
+  /*          | pp[0] | 1 | redcify  |  */
+  this_pp = pp;
+  this_pp[n] = 1;
+  redcify (this_pp, this_pp + n, 1, mp, n, this_pp + n + 1);
+  this_pp += n;
+
+  /* Compute pp[1] table entry.  To avoid excessive scratch usage in the
+     degenerate situation where B >> M, we let redcify use scratch space which
+     will later be used by the pp table (element 2 and up).  */
+  /* scratch: |   n   |   n   |  bn + n + 1  |  */
+  /*          | pp[0] | pp[1] |   redcify    |  */
+  redcify (this_pp, bp, bn, mp, n, this_pp + n);
+
+  /* Precompute powers of b and put them in the temporary area at pp.  */
+  /* scratch: |   n   |   n   | ...  |                    |   2n      |  */
+  /*          | pp[0] | pp[1] | ...  | pp[2^windowsize-1] |  product  |  */
+  ps = pp + n;		/* initially B^1 */
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      for (i = (1 << windowsize) - 2; i > 0; i -= 2)
+	{
+	  mpn_local_sqr (tp, ps, n);
+	  ps += n;
+	  this_pp += n;
+	  MPN_REDC_1_SEC (this_pp, tp, mp, n, mip[0]);
+
+	  mpn_mul_basecase (tp, this_pp, n, pp + n, n);
+	  this_pp += n;
+	  MPN_REDC_1_SEC (this_pp, tp, mp, n, mip[0]);
+	}
+    }
+  else
+    {
+      for (i = (1 << windowsize) - 2; i > 0; i -= 2)
+	{
+	  mpn_local_sqr (tp, ps, n);
+	  ps += n;
+	  this_pp += n;
+	  MPN_REDC_2_SEC (this_pp, tp, mp, n, mip);
+
+	  mpn_mul_basecase (tp, this_pp, n, pp + n, n);
+	  this_pp += n;
+	  MPN_REDC_2_SEC (this_pp, tp, mp, n, mip);
+	}
+    }
+
+  expbits = getbits (ep, enb, windowsize);
+  ASSERT_ALWAYS (enb >= windowsize);
+  enb -= windowsize;
+
+  mpn_sec_tabselect (rp, pp, n, 1 << windowsize, expbits);
+
+  /* Main exponentiation loop.  */
+  /* scratch: |   n   |   n   | ...  |                    |     3n-4n     |  */
+  /*          | pp[0] | pp[1] | ...  | pp[2^windowsize-1] |  loop scratch |  */
+
+#define INNERLOOP							\
+  while (enb != 0)							\
+    {									\
+      expbits = getbits (ep, enb, windowsize);				\
+      this_windowsize = windowsize;					\
+      if (enb < windowsize)						\
+	{								\
+	  this_windowsize -= windowsize - enb;				\
+	  enb = 0;							\
+	}								\
+      else								\
+	enb -= windowsize;						\
+									\
+      do								\
+	{								\
+	  mpn_local_sqr (tp, rp, n);					\
+	  MPN_REDUCE (rp, tp, mp, n, mip);				\
+	  this_windowsize--;						\
+	}								\
+      while (this_windowsize != 0);					\
+									\
+      mpn_sec_tabselect (tp + 2*n, pp, n, 1 << windowsize, expbits);	\
+      mpn_mul_basecase (tp, rp, n, tp + 2*n, n);			\
+									\
+      MPN_REDUCE (rp, tp, mp, n, mip);					\
+    }
+
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+#undef MPN_REDUCE
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1_SEC (rp, tp, mp, n, mip[0])
+      INNERLOOP;
+    }
+  else
+    {
+#undef MPN_REDUCE
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2_SEC (rp, tp, mp, n, mip)
+      INNERLOOP;
+    }
+
+  MPN_COPY (tp, rp, n);
+  MPN_ZERO (tp + n, n);
+
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1_SEC (rp, tp, mp, n, mip[0]);
+  else
+    MPN_REDC_2_SEC (rp, tp, mp, n, mip);
+
+  cnd = mpn_sub_n (tp, rp, mp, n);	/* we need just retval */
+  mpn_cnd_sub_n (!cnd, rp, rp, mp, n);
+}
+
+mp_size_t
+mpn_sec_powm_itch (mp_size_t bn, mp_bitcnt_t enb, mp_size_t n)
+{
+  int windowsize;
+  mp_size_t redcify_itch, itch;
+
+  /* FIXME: no more _local/_basecase difference. */
+  /* The top scratch usage will either be when reducing B in the 2nd redcify
+     call, or more typically n*2^windowsize + 3n or 4n, in the main loop.  (It
+     is 3n or 4n depending on if we use mpn_local_sqr or a native
+     mpn_sqr_basecase.  We assume 4n always for now.) */
+
+  windowsize = win_size (enb);
+
+  /* The 2n term is due to pp[0] and pp[1] at the time of the 2nd redcify call,
+     the (bn + n) term is due to redcify's own usage, and the rest is due to
+     mpn_sec_div_r's usage when called from redcify.  */
+  redcify_itch = (2 * n) + (bn + n) + ((bn + n) + 2 * n + 2);
+
+  /* The n * 2^windowsize term is due to the power table, the 4n term is due to
+     scratch needs of squaring/multiplication in the exponentiation loop.  */
+  itch = (n << windowsize) + (4 * n);
+
+  return MAX (itch, redcify_itch);
+}
diff --git a/mpn/generic/sec_sqr.c b/mpn/generic/sec_sqr.c
new file mode 100644
index 0000000..83fc7d9
--- /dev/null
+++ b/mpn/generic/sec_sqr.c
@@ -0,0 +1,76 @@
+/* mpn_sec_sqr.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if ! HAVE_NATIVE_mpn_sqr_basecase
+/* The limit of the generic code is SQR_TOOM2_THRESHOLD.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_basecase
+#ifdef TUNE_SQR_TOOM2_MAX
+/* We slightly abuse TUNE_SQR_TOOM2_MAX here.  If it is set for an assembly
+   mpn_sqr_basecase, it comes from SQR_TOOM2_THRESHOLD_MAX in the assembly
+   file.  An assembly mpn_sqr_basecase that does not define it should allow
+   any size.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+#endif
+
+#ifdef WANT_FAT_BINARY
+/* For fat builds, we use SQR_TOOM2_THRESHOLD which will expand to a read from
+   __gmpn_cpuvec.  Perhaps any possible sqr_basecase.asm allow any size, and we
+   limit the use unnecessarily.  We cannot tell, so play it safe.  FIXME.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+void
+mpn_sec_sqr (mp_ptr rp,
+	     mp_srcptr ap, mp_size_t an,
+	     mp_ptr tp)
+{
+#ifndef SQR_BASECASE_LIM
+/* If SQR_BASECASE_LIM is now not defined, use mpn_sqr_basecase for any operand
+   size.  */
+  mpn_sqr_basecase (rp, ap, an);
+#else
+/* Else use mpn_mul_basecase.  */
+  mpn_mul_basecase (rp, ap, an, ap, an);
+#endif
+}
+
+mp_size_t
+mpn_sec_sqr_itch (mp_size_t an)
+{
+  return 0;
+}
diff --git a/mpn/generic/sec_tabselect.c b/mpn/generic/sec_tabselect.c
new file mode 100644
index 0000000..f50bdac
--- /dev/null
+++ b/mpn/generic/sec_tabselect.c
@@ -0,0 +1,134 @@
+/* mpn_sec_tabselect.
+
+Copyright 2007-2009, 2011, 2013, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+#ifndef SEC_TABSELECT_METHOD
+#define SEC_TABSELECT_METHOD 1
+#endif
+
+/* Select entry `which' from table `tab', which has nents entries, each `n'
+   limbs.  Store the selected entry at rp.  Reads entire table to avoid
+   side-channel information leaks.  O(n*nents).  */
+
+#if SEC_TABSELECT_METHOD == 1
+void
+mpn_sec_tabselect (volatile mp_limb_t *rp, volatile const mp_limb_t *tab,
+		   mp_size_t n, mp_size_t nents, mp_size_t which)
+{
+  mp_size_t k, i;
+  mp_limb_t mask;
+  volatile const mp_limb_t *tp;
+
+  tp = tab;
+
+  /* Place first entry into result area. */
+  for (i = 0; i < n; i++)
+    rp[i] = tp[i];
+
+  /* Conditionally replace entry in result area by entry 1...(nents-1) using
+     masking trickery. */
+  for (k = 1; k < nents; k++)
+    {
+      /* Generate a mask using an expression which all compilers should compile
+	 into branch-free code.  The convoluted expression is designed to both
+	 allow mp_limb_t greater and mp_limb_t smaller than mp_size_t. */
+      mask = -(mp_limb_t) ((-(unsigned long) (which ^ k)) >> (BITS_PER_ULONG - 1));
+      tp += n;
+      for (i = 0; i < n; i++)
+	rp[i] = (rp[i] & mask) | (tp[i] & ~mask);
+    }
+}
+#endif
+
+#if SEC_TABSELECT_METHOD == 2
+void
+mpn_sec_tabselect (volatile mp_limb_t * restrict rp,
+		   volatile const mp_limb_t * restrict tab,
+		   mp_size_t n, mp_size_t nents, mp_size_t which)
+{
+  mp_size_t k, i;
+  mp_limb_t mask, r0, r1, r2, r3;
+  volatile const mp_limb_t * restrict tp;
+
+  if (n & 1)
+    {
+      tp = tab;
+      r0 = 0;
+      for (k = 0; k < nents; k++)
+	{
+	  mask = (mp_limb_t) ((-(unsigned long) (which ^ k)) >> (BITS_PER_ULONG - 1)) - 1;
+	  r0 += tp[0] & mask;
+	  tp += n;
+	}
+      rp[0] = r0;
+      rp += 1;
+      tab += 1;
+    }
+
+  if (n & 2)
+    {
+      tp = tab;
+      r0 = r1 = 0;
+      for (k = 0; k < nents; k++)
+	{
+	  mask = (mp_limb_t) ((-(unsigned long) (which ^ k)) >> (BITS_PER_ULONG - 1)) - 1;
+	  r0 += tp[0] & mask;
+	  r1 += tp[1] & mask;
+	  tp += n;
+	}
+      rp[0] = r0;
+      rp[1] = r1;
+      rp += 2;
+      tab += 2;
+    }
+
+  for (i = 0; i <= n - 4; i += 4)
+    {
+      tp = tab + i;
+      r0 = r1 = r2 = r3 = 0;
+      for (k = 0; k < nents; k++)
+	{
+	  mask = (mp_limb_t) ((-(unsigned long) (which ^ k)) >> (BITS_PER_ULONG - 1)) - 1;
+	  r0 += tp[0] & mask;
+	  r1 += tp[1] & mask;
+	  r2 += tp[2] & mask;
+	  r3 += tp[3] & mask;
+	  tp += n;
+	}
+      rp[0] = r0;
+      rp[1] = r1;
+      rp[2] = r2;
+      rp[3] = r3;
+      rp += 4;
+    }
+}
+#endif
diff --git a/mpn/generic/set_str.c b/mpn/generic/set_str.c
new file mode 100644
index 0000000..2bd584c
--- /dev/null
+++ b/mpn/generic/set_str.c
@@ -0,0 +1,290 @@
+/* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base) --
+   Convert a STR_LEN long base BASE byte string pointed to by STR to a limb
+   vector pointed to by RES_PTR.  Return the number of limbs in RES_PTR.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE, EXCEPT mpn_set_str, ARE INTERNAL WITH MUTABLE
+   INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
+   IN FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A
+   FUTURE GNU MP RELEASE.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* TODO:
+
+      Perhaps do not compute the highest power?
+      Instead, multiply twice by the 2nd highest power:
+
+	       _______
+	      |_______|  hp
+	      |_______|  pow
+       _______________
+      |_______________|  final result
+
+
+	       _______
+	      |_______|  hp
+		  |___|  pow[-1]
+	   ___________
+	  |___________|  intermediate result
+		  |___|  pow[-1]
+       _______________
+      |_______________|  final result
+
+      Generalizing that idea, perhaps we should make powtab contain successive
+      cubes, not squares.
+*/
+
+#include "gmp-impl.h"
+
+mp_size_t
+mpn_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
+{
+  if (POW2_P (base))
+    {
+      /* The base is a power of 2.  Read the input string from least to most
+	 significant character/digit.  */
+
+      const unsigned char *s;
+      int next_bitpos;
+      mp_limb_t res_digit;
+      mp_size_t size;
+      int bits_per_indigit = mp_bases[base].big_base;
+
+      size = 0;
+      res_digit = 0;
+      next_bitpos = 0;
+
+      for (s = str + str_len - 1; s >= str; s--)
+	{
+	  int inp_digit = *s;
+
+	  res_digit |= ((mp_limb_t) inp_digit << next_bitpos) & GMP_NUMB_MASK;
+	  next_bitpos += bits_per_indigit;
+	  if (next_bitpos >= GMP_NUMB_BITS)
+	    {
+	      rp[size++] = res_digit;
+	      next_bitpos -= GMP_NUMB_BITS;
+	      res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
+	    }
+	}
+
+      if (res_digit != 0)
+	rp[size++] = res_digit;
+      return size;
+    }
+
+  if (BELOW_THRESHOLD (str_len, SET_STR_PRECOMPUTE_THRESHOLD))
+    return mpn_bc_set_str (rp, str, str_len, base);
+  else
+    {
+      mp_ptr powtab_mem, tp;
+      powers_t powtab[GMP_LIMB_BITS];
+      int chars_per_limb;
+      mp_size_t size;
+      mp_size_t un;
+      TMP_DECL;
+
+      TMP_MARK;
+
+      chars_per_limb = mp_bases[base].chars_per_limb;
+
+      un = str_len / chars_per_limb + 1; /* FIXME: scalar integer division */
+
+      /* Allocate one large block for the powers of big_base.  */
+      powtab_mem = TMP_BALLOC_LIMBS (mpn_str_powtab_alloc (un));
+
+      size_t n_pows = mpn_compute_powtab (powtab, powtab_mem, un, base);
+      powers_t *pt = powtab + n_pows;
+
+      tp = TMP_BALLOC_LIMBS (mpn_dc_set_str_itch (un));
+      size = mpn_dc_set_str (rp, str, str_len, pt, tp);
+
+      TMP_FREE;
+      return size;
+    }
+}
+
+mp_size_t
+mpn_dc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len,
+		const powers_t *powtab, mp_ptr tp)
+{
+  size_t len_lo, len_hi;
+  mp_limb_t cy;
+  mp_size_t ln, hn, n, sn;
+
+  len_lo = powtab->digits_in_base;
+
+  if (str_len <= len_lo)
+    {
+      if (BELOW_THRESHOLD (str_len, SET_STR_DC_THRESHOLD))
+	return mpn_bc_set_str (rp, str, str_len, powtab->base);
+      else
+	return mpn_dc_set_str (rp, str, str_len, powtab - 1, tp);
+    }
+
+  len_hi = str_len - len_lo;
+  ASSERT (len_lo >= len_hi);
+
+  if (BELOW_THRESHOLD (len_hi, SET_STR_DC_THRESHOLD))
+    hn = mpn_bc_set_str (tp, str, len_hi, powtab->base);
+  else
+    hn = mpn_dc_set_str (tp, str, len_hi, powtab - 1, rp);
+
+  sn = powtab->shift;
+
+  if (hn == 0)
+    {
+      /* Zero +1 limb here, to avoid reading an allocated but uninitialised
+	 limb in mpn_incr_u below.  */
+      MPN_ZERO (rp, powtab->n + sn + 1);
+    }
+  else
+    {
+      if (powtab->n > hn)
+	mpn_mul (rp + sn, powtab->p, powtab->n, tp, hn);
+      else
+	mpn_mul (rp + sn, tp, hn, powtab->p, powtab->n);
+      MPN_ZERO (rp, sn);
+    }
+
+  str = str + str_len - len_lo;
+  if (BELOW_THRESHOLD (len_lo, SET_STR_DC_THRESHOLD))
+    ln = mpn_bc_set_str (tp, str, len_lo, powtab->base);
+  else
+    ln = mpn_dc_set_str (tp, str, len_lo, powtab - 1, tp + powtab->n + sn + 1);
+
+  if (ln != 0)
+    {
+      cy = mpn_add_n (rp, rp, tp, ln);
+      mpn_incr_u (rp + ln, cy);
+    }
+  n = hn + powtab->n + sn;
+  return n - (rp[n - 1] == 0);
+}
+
+mp_size_t
+mpn_bc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
+{
+  mp_size_t size;
+  size_t i;
+  long j;
+  mp_limb_t cy_limb;
+
+  mp_limb_t big_base;
+  int chars_per_limb;
+  mp_limb_t res_digit;
+
+  ASSERT (base >= 2);
+  ASSERT (base < numberof (mp_bases));
+  ASSERT (str_len >= 1);
+
+  big_base = mp_bases[base].big_base;
+  chars_per_limb = mp_bases[base].chars_per_limb;
+
+  size = 0;
+  for (i = chars_per_limb; i < str_len; i += chars_per_limb)
+    {
+      res_digit = *str++;
+      if (base == 10)
+	{ /* This is a common case.
+	     Help the compiler to avoid multiplication.  */
+	  for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
+	    res_digit = res_digit * 10 + *str++;
+	}
+      else
+	{
+	  for (j = chars_per_limb - 1; j != 0; j--)
+	    res_digit = res_digit * base + *str++;
+	}
+
+      if (size == 0)
+	{
+	  if (res_digit != 0)
+	    {
+	      rp[0] = res_digit;
+	      size = 1;
+	    }
+	}
+      else
+	{
+#if HAVE_NATIVE_mpn_mul_1c
+	  cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
+#else
+	  cy_limb = mpn_mul_1 (rp, rp, size, big_base);
+	  cy_limb += mpn_add_1 (rp, rp, size, res_digit);
+#endif
+	  if (cy_limb != 0)
+	    rp[size++] = cy_limb;
+	}
+    }
+
+  big_base = base;
+  res_digit = *str++;
+  if (base == 10)
+    { /* This is a common case.
+	 Help the compiler to avoid multiplication.  */
+      for (j = str_len - (i - MP_BASES_CHARS_PER_LIMB_10) - 1; j > 0; j--)
+	{
+	  res_digit = res_digit * 10 + *str++;
+	  big_base *= 10;
+	}
+    }
+  else
+    {
+      for (j = str_len - (i - chars_per_limb) - 1; j > 0; j--)
+	{
+	  res_digit = res_digit * base + *str++;
+	  big_base *= base;
+	}
+    }
+
+  if (size == 0)
+    {
+      if (res_digit != 0)
+	{
+	  rp[0] = res_digit;
+	  size = 1;
+	}
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_mul_1c
+      cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
+#else
+      cy_limb = mpn_mul_1 (rp, rp, size, big_base);
+      cy_limb += mpn_add_1 (rp, rp, size, res_digit);
+#endif
+      if (cy_limb != 0)
+	rp[size++] = cy_limb;
+    }
+  return size;
+}
diff --git a/mpn/generic/sizeinbase.c b/mpn/generic/sizeinbase.c
new file mode 100644
index 0000000..faee947
--- /dev/null
+++ b/mpn/generic/sizeinbase.c
@@ -0,0 +1,49 @@
+/* mpn_sizeinbase -- approximation to chars required for an mpn.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2011, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Same as mpz_sizeinbase, meaning exact for power-of-2 bases, and either
+   exact or 1 too big for other bases.  */
+
+size_t
+mpn_sizeinbase (mp_srcptr xp, mp_size_t xsize, int base)
+{
+  size_t  result;
+  MPN_SIZEINBASE (result, xp, xsize, base);
+  return result;
+}
diff --git a/mpn/generic/sqr.c b/mpn/generic/sqr.c
new file mode 100644
index 0000000..74fbff0
--- /dev/null
+++ b/mpn/generic/sqr.c
@@ -0,0 +1,98 @@
+/* mpn_sqr -- square natural numbers.
+
+Copyright 1991, 1993, 1994, 1996-2003, 2005, 2008, 2009 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_sqr (mp_ptr p, mp_srcptr a, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (p, 2 * n, a, n));
+
+  if (BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+    { /* mul_basecase is faster than sqr_basecase on small sizes sometimes */
+      mpn_mul_basecase (p, a, n, a, n);
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))
+    {
+      mpn_sqr_basecase (p, a, n);
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))
+    {
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t ws[mpn_toom2_sqr_itch (SQR_TOOM3_THRESHOLD_LIMIT-1)];
+      ASSERT (SQR_TOOM3_THRESHOLD <= SQR_TOOM3_THRESHOLD_LIMIT);
+      mpn_toom2_sqr (p, a, n, ws);
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom3_sqr_itch (n));
+      mpn_toom3_sqr (p, a, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM6_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom4_sqr_itch (n));
+      mpn_toom4_sqr (p, a, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM8_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom6_sqr_itch (n));
+      mpn_toom6_sqr (p, a, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, SQR_FFT_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_DECL;
+      TMP_MARK;
+      ws = TMP_ALLOC_LIMBS (mpn_toom8_sqr_itch (n));
+      mpn_toom8_sqr (p, a, n, ws);
+      TMP_FREE;
+    }
+  else
+    {
+      /* The current FFT code allocates its own space.  That should probably
+	 change.  */
+      mpn_fft_mul (p, a, n, a, n);
+    }
+}
diff --git a/mpn/generic/sqr_basecase.c b/mpn/generic/sqr_basecase.c
new file mode 100644
index 0000000..2645bad
--- /dev/null
+++ b/mpn/generic/sqr_basecase.c
@@ -0,0 +1,361 @@
+/* mpn_sqr_basecase -- Internal routine to square a natural number
+   of length n.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+
+Copyright 1991-1994, 1996, 1997, 2000-2005, 2008, 2010, 2011, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if HAVE_NATIVE_mpn_sqr_diagonal
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  mpn_sqr_diagonal (rp, up, n)
+#else
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  do {									\
+    mp_size_t _i;							\
+    for (_i = 0; _i < (n); _i++)					\
+      {									\
+	mp_limb_t ul, lpl;						\
+	ul = (up)[_i];							\
+	umul_ppmm ((rp)[2 * _i + 1], lpl, ul, ul << GMP_NAIL_BITS);	\
+	(rp)[2 * _i] = lpl >> GMP_NAIL_BITS;				\
+      }									\
+  } while (0)
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_diag_addlsh1
+#define MPN_SQR_DIAG_ADDLSH1(rp, tp, up, n)				\
+  mpn_sqr_diag_addlsh1 (rp, tp, up, n)
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+#define MPN_SQR_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    mp_limb_t cy;							\
+    MPN_SQR_DIAGONAL (rp, up, n);					\
+    cy = mpn_addlsh1_n (rp + 1, rp + 1, tp, 2 * n - 2);			\
+    rp[2 * n - 1] += cy;						\
+  } while (0)
+#else
+#define MPN_SQR_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    mp_limb_t cy;							\
+    MPN_SQR_DIAGONAL (rp, up, n);					\
+    cy = mpn_lshift (tp, tp, 2 * n - 2, 1);				\
+    cy += mpn_add_n (rp + 1, rp + 1, tp, 2 * n - 2);			\
+    rp[2 * n - 1] += cy;						\
+  } while (0)
+#endif
+#endif
+
+
+#undef READY_WITH_mpn_sqr_basecase
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase) && HAVE_NATIVE_mpn_addmul_2s
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t tarr[2 * SQR_TOOM2_THRESHOLD];
+  mp_ptr tp = tarr;
+  mp_limb_t cy;
+
+  /* must fit 2*n limbs in tarr */
+  ASSERT (n <= SQR_TOOM2_THRESHOLD);
+
+  if ((n & 1) != 0)
+    {
+      if (n == 1)
+	{
+	  mp_limb_t ul, lpl;
+	  ul = up[0];
+	  umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+	  rp[0] = lpl >> GMP_NAIL_BITS;
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 2; i += 2)
+	{
+	  cy = mpn_addmul_2s (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+    }
+  else
+    {
+      if (n == 2)
+	{
+#if HAVE_NATIVE_mpn_mul_2
+	  rp[3] = mpn_mul_2 (rp, up, 2, up);
+#else
+	  rp[0] = 0;
+	  rp[1] = 0;
+	  rp[3] = mpn_addmul_2 (rp, up, 2, up);
+#endif
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 4; i += 2)
+	{
+	  cy = mpn_addmul_2s (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+      cy = mpn_addmul_1 (tp + 2 * n - 4, up + n - 1, 1, up[n - 2]);
+      tp[2 * n - 3] = cy;
+    }
+
+  MPN_SQR_DIAG_ADDLSH1 (rp, tp, up, n);
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase) && HAVE_NATIVE_mpn_addmul_2
+
+/* mpn_sqr_basecase using plain mpn_addmul_2.
+
+   This is tricky, since we have to let mpn_addmul_2 make some undesirable
+   multiplies, u[k]*u[k], that we would like to let mpn_sqr_diagonal handle.
+   This forces us to conditionally add or subtract the mpn_sqr_diagonal
+   results.  Examples of the product we form:
+
+   n = 4              n = 5		n = 6
+   u1u0 * u3u2u1      u1u0 * u4u3u2u1	u1u0 * u5u4u3u2u1
+   u2 * u3	      u3u2 * u4u3	u3u2 * u5u4u3
+					u4 * u5
+   add: u0 u2 u3      add: u0 u2 u4	add: u0 u2 u4 u5
+   sub: u1	      sub: u1 u3	sub: u1 u3
+*/
+
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t tarr[2 * SQR_TOOM2_THRESHOLD];
+  mp_ptr tp = tarr;
+  mp_limb_t cy;
+
+  /* must fit 2*n limbs in tarr */
+  ASSERT (n <= SQR_TOOM2_THRESHOLD);
+
+  if ((n & 1) != 0)
+    {
+      mp_limb_t x0, x1;
+
+      if (n == 1)
+	{
+	  mp_limb_t ul, lpl;
+	  ul = up[0];
+	  umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+	  rp[0] = lpl >> GMP_NAIL_BITS;
+	  return;
+	}
+
+      /* The code below doesn't like unnormalized operands.  Since such
+	 operands are unusual, handle them with a dumb recursion.  */
+      if (up[n - 1] == 0)
+	{
+	  rp[2 * n - 2] = 0;
+	  rp[2 * n - 1] = 0;
+	  mpn_sqr_basecase (rp, up, n - 1);
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 2; i += 2)
+	{
+	  cy = mpn_addmul_2 (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+
+      MPN_SQR_DIAGONAL (rp, up, n);
+
+      for (i = 2;; i += 4)
+	{
+	  x0 = rp[i + 0];
+	  rp[i + 0] = (-x0) & GMP_NUMB_MASK;
+	  x1 = rp[i + 1];
+	  rp[i + 1] = (-x1 - (x0 != 0)) & GMP_NUMB_MASK;
+	  __GMPN_SUB_1 (cy, rp + i + 2, rp + i + 2, 2, (x1 | x0) != 0);
+	  if (i + 4 >= 2 * n)
+	    break;
+	  mpn_incr_u (rp + i + 4, cy);
+	}
+    }
+  else
+    {
+      mp_limb_t x0, x1;
+
+      if (n == 2)
+	{
+#if HAVE_NATIVE_mpn_mul_2
+	  rp[3] = mpn_mul_2 (rp, up, 2, up);
+#else
+	  rp[0] = 0;
+	  rp[1] = 0;
+	  rp[3] = mpn_addmul_2 (rp, up, 2, up);
+#endif
+	  return;
+	}
+
+      /* The code below doesn't like unnormalized operands.  Since such
+	 operands are unusual, handle them with a dumb recursion.  */
+      if (up[n - 1] == 0)
+	{
+	  rp[2 * n - 2] = 0;
+	  rp[2 * n - 1] = 0;
+	  mpn_sqr_basecase (rp, up, n - 1);
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 4; i += 2)
+	{
+	  cy = mpn_addmul_2 (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+      cy = mpn_addmul_1 (tp + 2 * n - 4, up + n - 1, 1, up[n - 2]);
+      tp[2 * n - 3] = cy;
+
+      MPN_SQR_DIAGONAL (rp, up, n);
+
+      for (i = 2;; i += 4)
+	{
+	  x0 = rp[i + 0];
+	  rp[i + 0] = (-x0) & GMP_NUMB_MASK;
+	  x1 = rp[i + 1];
+	  rp[i + 1] = (-x1 - (x0 != 0)) & GMP_NUMB_MASK;
+	  if (i + 6 >= 2 * n)
+	    break;
+	  __GMPN_SUB_1 (cy, rp + i + 2, rp + i + 2, 2, (x1 | x0) != 0);
+	  mpn_incr_u (rp + i + 4, cy);
+	}
+      mpn_decr_u (rp + i + 2, (x1 | x0) != 0);
+    }
+
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (rp + 1, rp + 1, tp, 2 * n - 2);
+#else
+  cy = mpn_lshift (tp, tp, 2 * n - 2, 1);
+  cy += mpn_add_n (rp + 1, rp + 1, tp, 2 * n - 2);
+#endif
+  rp[2 * n - 1] += cy;
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase) && HAVE_NATIVE_mpn_sqr_diag_addlsh1
+
+/* mpn_sqr_basecase using mpn_addmul_1 and mpn_sqr_diag_addlsh1, avoiding stack
+   allocation.  */
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  if (n == 1)
+    {
+      mp_limb_t ul, lpl;
+      ul = up[0];
+      umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+      rp[0] = lpl >> GMP_NAIL_BITS;
+    }
+  else
+    {
+      mp_size_t i;
+      mp_ptr xp;
+
+      rp += 1;
+      rp[n - 1] = mpn_mul_1 (rp, up + 1, n - 1, up[0]);
+      for (i = n - 2; i != 0; i--)
+	{
+	  up += 1;
+	  rp += 2;
+	  rp[i] = mpn_addmul_1 (rp, up + 1, i, up[0]);
+	}
+
+      xp = rp - 2 * n + 3;
+      mpn_sqr_diag_addlsh1 (xp, xp + 1, up - n + 2, n);
+    }
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase)
+
+/* Default mpn_sqr_basecase using mpn_addmul_1.  */
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, 2*n, up, n));
+
+  if (n == 1)
+    {
+      mp_limb_t ul, lpl;
+      ul = up[0];
+      umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+      rp[0] = lpl >> GMP_NAIL_BITS;
+    }
+  else
+    {
+      mp_limb_t tarr[2 * SQR_TOOM2_THRESHOLD];
+      mp_ptr tp = tarr;
+      mp_limb_t cy;
+
+      /* must fit 2*n limbs in tarr */
+      ASSERT (n <= SQR_TOOM2_THRESHOLD);
+
+      cy = mpn_mul_1 (tp, up + 1, n - 1, up[0]);
+      tp[n - 1] = cy;
+      for (i = 2; i < n; i++)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_addmul_1 (tp + 2 * i - 2, up + i, n - i, up[i - 1]);
+	  tp[n + i - 2] = cy;
+	}
+
+      MPN_SQR_DIAG_ADDLSH1 (rp, tp, up, n);
+    }
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
diff --git a/mpn/generic/sqrlo.c b/mpn/generic/sqrlo.c
new file mode 100644
index 0000000..71530b6
--- /dev/null
+++ b/mpn/generic/sqrlo.c
@@ -0,0 +1,239 @@
+/* mpn_sqrlo -- squares an n-limb number and returns the low n limbs
+   of the result.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THIS IS (FOR NOW) AN INTERNAL FUNCTION.  IT IS ONLY SAFE TO REACH THIS
+   FUNCTION THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST GUARANTEED
+   THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2004, 2005, 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_range_basecase 1
+#define MAYBE_range_toom22   1
+#else
+#define MAYBE_range_basecase                                           \
+  ((SQRLO_DC_THRESHOLD == 0 ? SQRLO_BASECASE_THRESHOLD : SQRLO_DC_THRESHOLD) < SQR_TOOM2_THRESHOLD*36/(36-11))
+#define MAYBE_range_toom22                                             \
+  ((SQRLO_DC_THRESHOLD == 0 ? SQRLO_BASECASE_THRESHOLD : SQRLO_DC_THRESHOLD) < SQR_TOOM3_THRESHOLD*36/(36-11) )
+#endif
+
+/*  THINK: The DC strategy uses different constants in different Toom's
+	 ranges. Something smoother?
+*/
+
+/*
+  Compute the least significant half of the product {xy,n}*{yp,n}, or
+  formally {rp,n} = {xy,n}*{yp,n} Mod (B^n).
+
+  Above the given threshold, the Divide and Conquer strategy is used.
+  The operand is split in two, and a full square plus a mullo
+  is used to obtain the final result. The more natural strategy is to
+  split in two halves, but this is far from optimal when a
+  sub-quadratic multiplication is used.
+
+  Mulders suggests an unbalanced split in favour of the full product,
+  split n = n1 + n2, where an = n1 <= n2 = (1-a)n; i.e. 0 < a <= 1/2.
+
+  To compute the value of a, we assume that the cost of mullo for a
+  given size ML(n) is a fraction of the cost of a full product with
+  same size M(n), and the cost M(n)=n^e for some exponent 1 < e <= 2;
+  then we can write:
+
+  ML(n) = 2*ML(an) + M((1-a)n) => k*M(n) = 2*k*M(n)*a^e + M(n)*(1-a)^e
+
+  Given a value for e, want to minimise the value of k, i.e. the
+  function k=(1-a)^e/(1-2*a^e).
+
+  With e=2, the exponent for schoolbook multiplication, the minimum is
+  given by the values a=1-a=1/2.
+
+  With e=log(3)/log(2), the exponent for Karatsuba (aka toom22),
+  Mulders compute (1-a) = 0.694... and we approximate a with 11/36.
+
+  Other possible approximations follow:
+  e=log(5)/log(3) [Toom-3] -> a ~= 9/40
+  e=log(7)/log(4) [Toom-4] -> a ~= 7/39
+  e=log(11)/log(6) [Toom-6] -> a ~= 1/8
+  e=log(15)/log(8) [Toom-8] -> a ~= 1/10
+
+  The values above where obtained with the following trivial commands
+  in the gp-pari shell:
+
+fun(e,a)=(1-a)^e/(1-2*a^e)
+mul(a,b,c)={local(m,x,p);if(b-c<1/10000,(b+c)/2,m=1;x=b;forstep(p=c,b,(b-c)/8,if(fun(a,p)<m,m=fun(a,p);x=p));mul(a,(b+x)/2,(c+x)/2))}
+contfracpnqn(contfrac(mul(log(2*2-1)/log(2),1/2,0),5))
+contfracpnqn(contfrac(mul(log(3*2-1)/log(3),1/2,0),5))
+contfracpnqn(contfrac(mul(log(4*2-1)/log(4),1/2,0),5))
+contfracpnqn(contfrac(mul(log(6*2-1)/log(6),1/2,0),3))
+contfracpnqn(contfrac(mul(log(8*2-1)/log(8),1/2,0),3))
+
+  ,
+  |\
+  | \
+  +----,
+  |    |
+  |    |
+  |    |\
+  |    | \
+  +----+--`
+  ^ n2 ^n1^
+
+  For an actual implementation, the assumption that M(n)=n^e is
+  incorrect, as a consequence also the assumption that ML(n)=k*M(n)
+  with a constant k is wrong.
+
+  But theory suggest us two things:
+  - the best the multiplication product is (lower e), the more k
+    approaches 1, and a approaches 0.
+
+  - A value for a smaller than optimal is probably less bad than a
+    bigger one: e.g. let e=log(3)/log(2), a=0.3058_ the optimal
+    value, and k(a)=0.808_ the mul/mullo speed ratio. We get
+    k(a+1/6)=0.929_ but k(a-1/6)=0.865_.
+*/
+
+static mp_size_t
+mpn_sqrlo_itch (mp_size_t n)
+{
+  return 2*n;
+}
+
+/*
+    mpn_dc_sqrlo requires a scratch space of 2*n limbs at tp.
+    It accepts tp == rp.
+*/
+static void
+mpn_dc_sqrlo (mp_ptr rp, mp_srcptr xp, mp_size_t n, mp_ptr tp)
+{
+  mp_size_t n2, n1;
+  ASSERT (n >= 2);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+  ASSERT (MPN_SAME_OR_SEPARATE2_P(rp, n, tp, 2*n));
+
+  /* Divide-and-conquer */
+
+  /* We need fractional approximation of the value 0 < a <= 1/2
+     giving the minimum in the function k=(1-a)^e/(1-2*a^e).
+  */
+  if (MAYBE_range_basecase && BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD*36/(36-11)))
+    n1 = n >> 1;
+  else if (MAYBE_range_toom22 && BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD*36/(36-11)))
+    n1 = n * 11 / (size_t) 36;	/* n1 ~= n*(1-.694...) */
+  else if (BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD*40/(40-9)))
+    n1 = n * 9 / (size_t) 40;	/* n1 ~= n*(1-.775...) */
+  else if (BELOW_THRESHOLD (n, SQR_TOOM8_THRESHOLD*10/9))
+    n1 = n * 7 / (size_t) 39;	/* n1 ~= n*(1-.821...) */
+  /* n1 = n * 4 / (size_t) 31;	// n1 ~= n*(1-.871...) [TOOM66] */
+  else
+    n1 = n / (size_t) 10;		/* n1 ~= n*(1-.899...) [TOOM88] */
+
+  n2 = n - n1;
+
+  /* Split as x = x1 2^(n2 GMP_NUMB_BITS) + x0 */
+
+  /* x0 ^ 2 */
+  mpn_sqr (tp, xp, n2);
+  MPN_COPY (rp, tp, n2);
+
+  /* x1 * x0 * 2^(n2 GMP_NUMB_BITS) */
+  if (BELOW_THRESHOLD (n1, MULLO_BASECASE_THRESHOLD))
+    mpn_mul_basecase (tp + n, xp + n2, n1, xp, n1);
+  else if (BELOW_THRESHOLD (n1, MULLO_DC_THRESHOLD))
+    mpn_mullo_basecase (tp + n, xp + n2, xp, n1);
+  else
+    mpn_mullo_n (tp + n, xp + n2, xp, n1);
+  /* mpn_dc_mullo_n (tp + n, xp + n2, xp, n1, tp + n); */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  mpn_addlsh1_n (rp + n2, tp + n2, tp + n, n1);
+#else
+  mpn_lshift (rp + n2, tp + n, n1, 1);
+  mpn_add_n (rp + n2, rp + n2, tp + n2, n1);
+#endif
+}
+
+/* Avoid zero allocations when MULLO_BASECASE_THRESHOLD is 0.  */
+#define SQR_BASECASE_ALLOC \
+ (SQRLO_BASECASE_THRESHOLD_LIMIT == 0 ? 1 : 2*SQRLO_BASECASE_THRESHOLD_LIMIT)
+
+/* FIXME: This function should accept a temporary area; dc_sqrlo
+   accepts a pointer tp, and handle the case tp == rp, do the same here.
+*/
+
+void
+mpn_sqrlo (mp_ptr rp, mp_srcptr xp, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+
+  if (BELOW_THRESHOLD (n, SQRLO_BASECASE_THRESHOLD))
+    {
+      /* FIXME: smarter criteria? */
+#if HAVE_NATIVE_mpn_mullo_basecase || ! HAVE_NATIVE_mpn_sqr_basecase
+      /* mullo computes as many products as sqr, but directly writes
+	 on the result area. */
+      mpn_mullo_basecase (rp, xp, xp, n);
+#else
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t tp[SQR_BASECASE_ALLOC];
+      mpn_sqr_basecase (tp, xp, n);
+      MPN_COPY (rp, tp, n);
+#endif
+    }
+  else if (BELOW_THRESHOLD (n, SQRLO_DC_THRESHOLD))
+    {
+      mpn_sqrlo_basecase (rp, xp, n);
+    }
+  else
+    {
+      mp_ptr tp;
+      TMP_DECL;
+      TMP_MARK;
+      tp = TMP_ALLOC_LIMBS (mpn_sqrlo_itch (n));
+      if (BELOW_THRESHOLD (n, SQRLO_SQR_THRESHOLD))
+	{
+	  mpn_dc_sqrlo (rp, xp, n, tp);
+	}
+      else
+	{
+	  /* For really large operands, use plain mpn_mul_n but throw away upper n
+	     limbs of result.  */
+#if !TUNE_PROGRAM_BUILD && (SQRLO_SQR_THRESHOLD > SQR_FFT_THRESHOLD)
+	  mpn_fft_mul (tp, xp, n, xp, n);
+#else
+	  mpn_sqr (tp, xp, n);
+#endif
+	  MPN_COPY (rp, tp, n);
+	}
+      TMP_FREE;
+    }
+}
diff --git a/mpn/generic/sqrlo_basecase.c b/mpn/generic/sqrlo_basecase.c
new file mode 100644
index 0000000..3148609
--- /dev/null
+++ b/mpn/generic/sqrlo_basecase.c
@@ -0,0 +1,194 @@
+/* mpn_sqrlo_basecase -- Internal routine to square a natural number
+   of length n.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+
+Copyright 1991-1994, 1996, 1997, 2000-2005, 2008, 2010, 2011, 2015,
+2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef SQRLO_SHORTCUT_MULTIPLICATIONS
+#if HAVE_NATIVE_mpn_addmul_1
+#define SQRLO_SHORTCUT_MULTIPLICATIONS 0
+#else
+#define SQRLO_SHORTCUT_MULTIPLICATIONS 1
+#endif
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_diagonal
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  mpn_sqr_diagonal (rp, up, n)
+#else
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  do {									\
+    mp_size_t _i;							\
+    for (_i = 0; _i < (n); _i++)					\
+      {									\
+	mp_limb_t ul, lpl;						\
+	ul = (up)[_i];							\
+	umul_ppmm ((rp)[2 * _i + 1], lpl, ul, ul << GMP_NAIL_BITS);	\
+	(rp)[2 * _i] = lpl >> GMP_NAIL_BITS;				\
+      }									\
+  } while (0)
+#endif
+
+#define MPN_SQRLO_DIAGONAL(rp, up, n)					\
+  do {									\
+    mp_size_t nhalf;							\
+    nhalf = (n) >> 1;							\
+    MPN_SQR_DIAGONAL ((rp), (up), nhalf);				\
+    if (((n) & 1) != 0)							\
+      {									\
+	mp_limb_t op;							\
+	op = (up)[nhalf];						\
+	(rp)[(n) - 1] = (op * op) & GMP_NUMB_MASK;			\
+      }									\
+  } while (0)
+
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+#define MPN_SQRLO_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    MPN_SQRLO_DIAGONAL((rp), (up), (n));				\
+    mpn_addlsh1_n_ip1 ((rp) + 1, (tp), (n) - 1);			\
+  } while (0)
+#else
+#define MPN_SQRLO_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    MPN_SQRLO_DIAGONAL((rp), (up), (n));				\
+    mpn_lshift ((tp), (tp), (n) - 1, 1);				\
+    mpn_add_n ((rp) + 1, (rp) + 1, (tp), (n) - 1);			\
+  } while (0)
+#endif
+
+/* Avoid zero allocations when SQRLO_LO_THRESHOLD is 0 (this code not used). */
+#define SQRLO_BASECASE_ALLOC						\
+  (SQRLO_DC_THRESHOLD_LIMIT < 2 ? 1 : SQRLO_DC_THRESHOLD_LIMIT - 1)
+
+/* Default mpn_sqrlo_basecase using mpn_addmul_1.  */
+#ifndef SQRLO_SPECIAL_CASES
+#define SQRLO_SPECIAL_CASES 2
+#endif
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_special_cases 1
+#else
+#define MAYBE_special_cases \
+  ((SQRLO_BASECASE_THRESHOLD <= SQRLO_SPECIAL_CASES) && (SQRLO_DC_THRESHOLD != 0))
+#endif
+
+void
+mpn_sqrlo_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_limb_t ul;
+
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n, up, n));
+
+  ul = up[0];
+
+  if (MAYBE_special_cases && n <= SQRLO_SPECIAL_CASES)
+    {
+#if SQRLO_SPECIAL_CASES == 1
+      rp[0] = (ul * ul) & GMP_NUMB_MASK;
+#else
+      if (n == 1)
+	rp[0] = (ul * ul) & GMP_NUMB_MASK;
+      else
+	{
+	  mp_limb_t hi, lo, ul1;
+	  umul_ppmm (hi, lo, ul, ul << GMP_NAIL_BITS);
+	  rp[0] = lo >> GMP_NAIL_BITS;
+	  ul1 = up[1];
+#if SQRLO_SPECIAL_CASES == 2
+	  rp[1] = (hi + ul * ul1 * 2) & GMP_NUMB_MASK;
+#else
+	  if (n == 2)
+	    rp[1] = (hi + ul * ul1 * 2) & GMP_NUMB_MASK;
+	  else
+	    {
+	      mp_limb_t hi1;
+#if GMP_NAIL_BITS != 0
+	      ul <<= 1;
+#endif
+	      umul_ppmm (hi1, lo, ul1 << GMP_NAIL_BITS, ul);
+	      hi1 += ul * up[2];
+#if GMP_NAIL_BITS == 0
+	      hi1 = (hi1 << 1) | (lo >> (GMP_LIMB_BITS - 1));
+	      add_ssaaaa(rp[2], rp[1], hi1, lo << 1, ul1 * ul1, hi);
+#else
+	      hi += lo >> GMP_NAIL_BITS;
+	      rp[1] = hi & GMP_NUMB_MASK;
+	      rp[2] = (hi1 + ul1 * ul1 + (hi >> GMP_NUMB_BITS)) & GMP_NUMB_MASK;
+#endif
+	    }
+#endif
+	}
+#endif
+    }
+  else
+    {
+      mp_limb_t tp[SQRLO_BASECASE_ALLOC];
+      mp_size_t i;
+
+      /* must fit n-1 limbs in tp */
+      ASSERT (n <= SQRLO_DC_THRESHOLD_LIMIT);
+
+      --n;
+#if SQRLO_SHORTCUT_MULTIPLICATIONS
+      {
+	mp_limb_t cy;
+
+	cy = ul * up[n] + mpn_mul_1 (tp, up + 1, n - 1, ul);
+	for (i = 1; 2 * i + 1 < n; ++i)
+	  {
+	    ul = up[i];
+	    cy += ul * up[n - i] + mpn_addmul_1 (tp + 2 * i, up + i + 1, n - 2 * i - 1, ul);
+	  }
+	tp [n-1] = (cy + ((n & 1)?up[i] * up[i + 1]:0)) & GMP_NUMB_MASK;
+      }
+#else
+      mpn_mul_1 (tp, up + 1, n, ul);
+      for (i = 1; 2 * i < n; ++i)
+	mpn_addmul_1 (tp + 2 * i, up + i + 1, n - 2 * i, up[i]);
+#endif
+
+      MPN_SQRLO_DIAG_ADDLSH1 (rp, tp, up, n + 1);
+    }
+}
+#undef SQRLO_SPECIAL_CASES
+#undef MAYBE_special_cases
+#undef SQRLO_BASECASE_ALLOC
+#undef SQRLO_SHORTCUT_MULTIPLICATIONS
+#undef MPN_SQR_DIAGONAL
+#undef MPN_SQRLO_DIAGONAL
+#undef MPN_SQRLO_DIAG_ADDLSH1
diff --git a/mpn/generic/sqrmod_bnm1.c b/mpn/generic/sqrmod_bnm1.c
new file mode 100644
index 0000000..0acbe12
--- /dev/null
+++ b/mpn/generic/sqrmod_bnm1.c
@@ -0,0 +1,328 @@
+/* sqrmod_bnm1.c -- squaring mod B^n-1.
+
+   Contributed to the GNU project by Niels Möller, Torbjorn Granlund and
+   Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2020, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Input is {ap,rn}; output is {rp,rn}, computation is
+   mod B^rn - 1, and values are semi-normalised; zero is represented
+   as either 0 or B^n - 1.  Needs a scratch of 2rn limbs at tp.
+   tp==rp is allowed. */
+static void
+mpn_bc_sqrmod_bnm1 (mp_ptr rp, mp_srcptr ap, mp_size_t rn, mp_ptr tp)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < rn);
+
+  mpn_sqr (tp, ap, rn);
+  cy = mpn_add_n (rp, tp, tp + rn, rn);
+  /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+   * be no overflow when adding in the carry. */
+  MPN_INCR_U (rp, rn, cy);
+}
+
+
+/* Input is {ap,rn+1}; output is {rp,rn+1}, in
+   normalised representation, computation is mod B^rn + 1. Needs
+   a scratch area of 2rn limbs at tp; tp == rp is allowed.
+   Output is normalised. */
+static void
+mpn_bc_sqrmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_size_t rn, mp_ptr tp)
+{
+  mp_limb_t cy;
+  unsigned k;
+
+  ASSERT (0 < rn);
+
+  if (UNLIKELY (ap[rn]))
+    {
+      *rp = 1;
+      MPN_FILL (rp + 1, rn, 0);
+      return;
+    }
+  else if (MPN_SQRMOD_BKNP1_USABLE (rn, k, MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_size_t n_k = rn / k;
+      TMP_DECL;
+
+      TMP_MARK;
+      mpn_sqrmod_bknp1 (rp, ap, n_k, k,
+			TMP_ALLOC_LIMBS (mpn_sqrmod_bknp1_itch (rn)));
+      TMP_FREE;
+      return;
+    }
+  mpn_sqr (tp, ap, rn);
+  cy = mpn_sub_n (rp, tp, tp + rn, rn);
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, cy);
+}
+
+
+/* Computes {rp,MIN(rn,2an)} <- {ap,an}^2 Mod(B^rn-1)
+ *
+ * The result is expected to be ZERO if and only if the operand
+ * already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+ * B^rn-1.
+ * It should not be a problem if sqrmod_bnm1 is used to
+ * compute the full square with an <= 2*rn, because this condition
+ * implies (B^an-1)^2 < (B^rn-1) .
+ *
+ * Requires rn/4 < an <= rn
+ * Scratch need: rn/2 + (need for recursive call OR rn + 3). This gives
+ *
+ * S(n) <= rn/2 + MAX (rn + 4, S(n/2)) <= 3/2 rn + 4
+ */
+void
+mpn_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_ptr tp)
+{
+  ASSERT (0 < an);
+  ASSERT (an <= rn);
+
+  if ((rn & 1) != 0 || BELOW_THRESHOLD (rn, SQRMOD_BNM1_THRESHOLD))
+    {
+      if (UNLIKELY (an < rn))
+	{
+	  if (UNLIKELY (2*an <= rn))
+	    {
+	      mpn_sqr (rp, ap, an);
+	    }
+	  else
+	    {
+	      mp_limb_t cy;
+	      mpn_sqr (tp, ap, an);
+	      cy = mpn_add (rp, tp, rn, tp + rn, 2*an - rn);
+	      MPN_INCR_U (rp, rn, cy);
+	    }
+	}
+      else
+	mpn_bc_sqrmod_bnm1 (rp, ap, rn, tp);
+    }
+  else
+    {
+      mp_size_t n;
+      mp_limb_t cy;
+      mp_limb_t hi;
+
+      n = rn >> 1;
+
+      ASSERT (2*an > n);
+
+      /* Compute xm = a^2 mod (B^n - 1), xp = a^2 mod (B^n + 1)
+	 and crt together as
+
+	 x = -xp * B^n + (B^n + 1) * [ (xp + xm)/2 mod (B^n-1)]
+      */
+
+#define a0 ap
+#define a1 (ap + n)
+
+#define xp  tp	/* 2n + 2 */
+      /* am1  maybe in {xp, n} */
+#define sp1 (tp + 2*n + 2)
+      /* ap1  maybe in {sp1, n + 1} */
+
+      {
+	mp_srcptr am1;
+	mp_size_t anm;
+	mp_ptr so;
+
+	if (LIKELY (an > n))
+	  {
+	    so = xp + n;
+	    am1 = xp;
+	    cy = mpn_add (xp, a0, n, a1, an - n);
+	    MPN_INCR_U (xp, n, cy);
+	    anm = n;
+	  }
+	else
+	  {
+	    so = xp;
+	    am1 = a0;
+	    anm = an;
+	  }
+
+	mpn_sqrmod_bnm1 (rp, n, am1, anm, so);
+      }
+
+      {
+	int       k;
+	mp_srcptr ap1;
+	mp_size_t anp;
+
+	if (LIKELY (an > n)) {
+	  ap1 = sp1;
+	  cy = mpn_sub (sp1, a0, n, a1, an - n);
+	  sp1[n] = 0;
+	  MPN_INCR_U (sp1, n + 1, cy);
+	  anp = n + ap1[n];
+	} else {
+	  ap1 = a0;
+	  anp = an;
+	}
+
+	if (BELOW_THRESHOLD (n, MUL_FFT_MODF_THRESHOLD))
+	  k=0;
+	else
+	  {
+	    int mask;
+	    k = mpn_fft_best_k (n, 1);
+	    mask = (1<<k) -1;
+	    while (n & mask) {k--; mask >>=1;};
+	  }
+	if (k >= FFT_FIRST_K)
+	  xp[n] = mpn_mul_fft (xp, n, ap1, anp, ap1, anp, k);
+	else if (UNLIKELY (ap1 == a0))
+	  {
+	    ASSERT (anp <= n);
+	    ASSERT (2*anp > n);
+	    mpn_sqr (xp, a0, an);
+	    anp = 2*an - n;
+	    cy = mpn_sub (xp, xp, n, xp + n, anp);
+	    xp[n] = 0;
+	    MPN_INCR_U (xp, n+1, cy);
+	  }
+	else
+	  mpn_bc_sqrmod_bnp1 (xp, ap1, n, xp);
+      }
+
+      /* Here the CRT recomposition begins.
+
+	 xm <- (xp + xm)/2 = (xp + xm)B^n/2 mod (B^n-1)
+	 Division by 2 is a bitwise rotation.
+
+	 Assumes xp normalised mod (B^n+1).
+
+	 The residue class [0] is represented by [B^n-1]; except when
+	 both input are ZERO.
+      */
+
+#if HAVE_NATIVE_mpn_rsh1add_n || HAVE_NATIVE_mpn_rsh1add_nc
+#if HAVE_NATIVE_mpn_rsh1add_nc
+      cy = mpn_rsh1add_nc(rp, rp, xp, n, xp[n]); /* B^n = 1 */
+      hi = cy << (GMP_NUMB_BITS - 1);
+      cy = 0;
+      /* next update of rp[n-1] will set cy = 1 only if rp[n-1]+=hi
+	 overflows, i.e. a further increment will not overflow again. */
+#else /* ! _nc */
+      cy = xp[n] + mpn_rsh1add_n(rp, rp, xp, n); /* B^n = 1 */
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* cy = 1 only if xp[n] = 1 i.e. {xp,n} = ZERO, this implies that
+	 the rsh1add was a simple rshift: the top bit is 0. cy=1 => hi=0. */
+#endif
+#if GMP_NAIL_BITS == 0
+      add_ssaaaa(cy, rp[n-1], cy, rp[n-1], CNST_LIMB(0), hi);
+#else
+      cy += (hi & rp[n-1]) >> (GMP_NUMB_BITS-1);
+      rp[n-1] ^= hi;
+#endif
+#else /* ! HAVE_NATIVE_mpn_rsh1add_n */
+#if HAVE_NATIVE_mpn_add_nc
+      cy = mpn_add_nc(rp, rp, xp, n, xp[n]);
+#else /* ! _nc */
+      cy = xp[n] + mpn_add_n(rp, rp, xp, n); /* xp[n] == 1 implies {xp,n} == ZERO */
+#endif
+      cy += (rp[0]&1);
+      mpn_rshift(rp, rp, n, 1);
+      ASSERT (cy <= 2);
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* We can have cy != 0 only if hi = 0... */
+      ASSERT ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0);
+      rp[n-1] |= hi;
+      /* ... rp[n-1] + cy can not overflow, the following INCR is correct. */
+#endif
+      ASSERT (cy <= 1);
+      /* Next increment can not overflow, read the previous comments about cy. */
+      ASSERT ((cy == 0) || ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0));
+      MPN_INCR_U(rp, n, cy);
+
+      /* Compute the highest half:
+	 ([(xp + xm)/2 mod (B^n-1)] - xp ) * B^n
+       */
+      if (UNLIKELY (2*an < rn))
+	{
+	  /* Note that in this case, the only way the result can equal
+	     zero mod B^{rn} - 1 is if the input is zero, and
+	     then the output of both the recursive calls and this CRT
+	     reconstruction is zero, not B^{rn} - 1. */
+	  cy = mpn_sub_n (rp + n, rp, xp, 2*an - n);
+
+	  /* FIXME: This subtraction of the high parts is not really
+	     necessary, we do it to get the carry out, and for sanity
+	     checking. */
+	  cy = xp[n] + mpn_sub_nc (xp + 2*an - n, rp + 2*an - n,
+				   xp + 2*an - n, rn - 2*an, cy);
+	  ASSERT (mpn_zero_p (xp + 2*an - n+1, rn - 1 - 2*an));
+	  cy = mpn_sub_1 (rp, rp, 2*an, cy);
+	  ASSERT (cy == (xp + 2*an - n)[0]);
+	}
+      else
+	{
+	  cy = xp[n] + mpn_sub_n (rp + n, rp, xp, n);
+	  /* cy = 1 only if {xp,n+1} is not ZERO, i.e. {rp,n} is not ZERO.
+	     DECR will affect _at most_ the lowest n limbs. */
+	  MPN_DECR_U (rp, 2*n, cy);
+	}
+#undef a0
+#undef a1
+#undef xp
+#undef sp1
+    }
+}
+
+mp_size_t
+mpn_sqrmod_bnm1_next_size (mp_size_t n)
+{
+  mp_size_t nh;
+
+  if (BELOW_THRESHOLD (n,     SQRMOD_BNM1_THRESHOLD))
+    return n;
+  if (BELOW_THRESHOLD (n, 4 * (SQRMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (2-1)) & (-2);
+  if (BELOW_THRESHOLD (n, 8 * (SQRMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (4-1)) & (-4);
+
+  nh = (n + 1) >> 1;
+
+  if (BELOW_THRESHOLD (nh, SQR_FFT_MODF_THRESHOLD))
+    return (n + (8-1)) & (-8);
+
+  return 2 * mpn_fft_next_size (nh, mpn_fft_best_k (nh, 1));
+}
diff --git a/mpn/generic/sqrtrem.c b/mpn/generic/sqrtrem.c
new file mode 100644
index 0000000..cc6dd9c
--- /dev/null
+++ b/mpn/generic/sqrtrem.c
@@ -0,0 +1,555 @@
+/* mpn_sqrtrem -- square root and remainder
+
+   Contributed to the GNU project by Paul Zimmermann (most code),
+   Torbjorn Granlund (mpn_sqrtrem1) and Marco Bodrato (mpn_dc_sqrt).
+
+   THE FUNCTIONS IN THIS FILE EXCEPT mpn_sqrtrem ARE INTERNAL WITH MUTABLE
+   INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
+   IN FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A
+   FUTURE GMP RELEASE.
+
+Copyright 1999-2002, 2004, 2005, 2008, 2010, 2012, 2015, 2017 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* See "Karatsuba Square Root", reference in gmp.texi.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#define USE_DIVAPPR_Q 1
+#define TRACE(x)
+
+static const unsigned char invsqrttab[384] = /* The common 0x100 was removed */
+{
+  0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf2, /* sqrt(1/80)..sqrt(1/87) */
+  0xf0,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe4, /* sqrt(1/88)..sqrt(1/8f) */
+  0xe2,0xe0,0xdf,0xdd,0xdb,0xda,0xd8,0xd7, /* sqrt(1/90)..sqrt(1/97) */
+  0xd5,0xd4,0xd2,0xd1,0xcf,0xce,0xcc,0xcb, /* sqrt(1/98)..sqrt(1/9f) */
+  0xc9,0xc8,0xc6,0xc5,0xc4,0xc2,0xc1,0xc0, /* sqrt(1/a0)..sqrt(1/a7) */
+  0xbe,0xbd,0xbc,0xba,0xb9,0xb8,0xb7,0xb5, /* sqrt(1/a8)..sqrt(1/af) */
+  0xb4,0xb3,0xb2,0xb0,0xaf,0xae,0xad,0xac, /* sqrt(1/b0)..sqrt(1/b7) */
+  0xaa,0xa9,0xa8,0xa7,0xa6,0xa5,0xa4,0xa3, /* sqrt(1/b8)..sqrt(1/bf) */
+  0xa2,0xa0,0x9f,0x9e,0x9d,0x9c,0x9b,0x9a, /* sqrt(1/c0)..sqrt(1/c7) */
+  0x99,0x98,0x97,0x96,0x95,0x94,0x93,0x92, /* sqrt(1/c8)..sqrt(1/cf) */
+  0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8c,0x8b, /* sqrt(1/d0)..sqrt(1/d7) */
+  0x8a,0x89,0x88,0x87,0x86,0x85,0x84,0x83, /* sqrt(1/d8)..sqrt(1/df) */
+  0x83,0x82,0x81,0x80,0x7f,0x7e,0x7e,0x7d, /* sqrt(1/e0)..sqrt(1/e7) */
+  0x7c,0x7b,0x7a,0x79,0x79,0x78,0x77,0x76, /* sqrt(1/e8)..sqrt(1/ef) */
+  0x76,0x75,0x74,0x73,0x72,0x72,0x71,0x70, /* sqrt(1/f0)..sqrt(1/f7) */
+  0x6f,0x6f,0x6e,0x6d,0x6d,0x6c,0x6b,0x6a, /* sqrt(1/f8)..sqrt(1/ff) */
+  0x6a,0x69,0x68,0x68,0x67,0x66,0x66,0x65, /* sqrt(1/100)..sqrt(1/107) */
+  0x64,0x64,0x63,0x62,0x62,0x61,0x60,0x60, /* sqrt(1/108)..sqrt(1/10f) */
+  0x5f,0x5e,0x5e,0x5d,0x5c,0x5c,0x5b,0x5a, /* sqrt(1/110)..sqrt(1/117) */
+  0x5a,0x59,0x59,0x58,0x57,0x57,0x56,0x56, /* sqrt(1/118)..sqrt(1/11f) */
+  0x55,0x54,0x54,0x53,0x53,0x52,0x52,0x51, /* sqrt(1/120)..sqrt(1/127) */
+  0x50,0x50,0x4f,0x4f,0x4e,0x4e,0x4d,0x4d, /* sqrt(1/128)..sqrt(1/12f) */
+  0x4c,0x4b,0x4b,0x4a,0x4a,0x49,0x49,0x48, /* sqrt(1/130)..sqrt(1/137) */
+  0x48,0x47,0x47,0x46,0x46,0x45,0x45,0x44, /* sqrt(1/138)..sqrt(1/13f) */
+  0x44,0x43,0x43,0x42,0x42,0x41,0x41,0x40, /* sqrt(1/140)..sqrt(1/147) */
+  0x40,0x3f,0x3f,0x3e,0x3e,0x3d,0x3d,0x3c, /* sqrt(1/148)..sqrt(1/14f) */
+  0x3c,0x3b,0x3b,0x3a,0x3a,0x39,0x39,0x39, /* sqrt(1/150)..sqrt(1/157) */
+  0x38,0x38,0x37,0x37,0x36,0x36,0x35,0x35, /* sqrt(1/158)..sqrt(1/15f) */
+  0x35,0x34,0x34,0x33,0x33,0x32,0x32,0x32, /* sqrt(1/160)..sqrt(1/167) */
+  0x31,0x31,0x30,0x30,0x2f,0x2f,0x2f,0x2e, /* sqrt(1/168)..sqrt(1/16f) */
+  0x2e,0x2d,0x2d,0x2d,0x2c,0x2c,0x2b,0x2b, /* sqrt(1/170)..sqrt(1/177) */
+  0x2b,0x2a,0x2a,0x29,0x29,0x29,0x28,0x28, /* sqrt(1/178)..sqrt(1/17f) */
+  0x27,0x27,0x27,0x26,0x26,0x26,0x25,0x25, /* sqrt(1/180)..sqrt(1/187) */
+  0x24,0x24,0x24,0x23,0x23,0x23,0x22,0x22, /* sqrt(1/188)..sqrt(1/18f) */
+  0x21,0x21,0x21,0x20,0x20,0x20,0x1f,0x1f, /* sqrt(1/190)..sqrt(1/197) */
+  0x1f,0x1e,0x1e,0x1e,0x1d,0x1d,0x1d,0x1c, /* sqrt(1/198)..sqrt(1/19f) */
+  0x1c,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x19, /* sqrt(1/1a0)..sqrt(1/1a7) */
+  0x19,0x19,0x18,0x18,0x18,0x18,0x17,0x17, /* sqrt(1/1a8)..sqrt(1/1af) */
+  0x17,0x16,0x16,0x16,0x15,0x15,0x15,0x14, /* sqrt(1/1b0)..sqrt(1/1b7) */
+  0x14,0x14,0x13,0x13,0x13,0x12,0x12,0x12, /* sqrt(1/1b8)..sqrt(1/1bf) */
+  0x12,0x11,0x11,0x11,0x10,0x10,0x10,0x0f, /* sqrt(1/1c0)..sqrt(1/1c7) */
+  0x0f,0x0f,0x0f,0x0e,0x0e,0x0e,0x0d,0x0d, /* sqrt(1/1c8)..sqrt(1/1cf) */
+  0x0d,0x0c,0x0c,0x0c,0x0c,0x0b,0x0b,0x0b, /* sqrt(1/1d0)..sqrt(1/1d7) */
+  0x0a,0x0a,0x0a,0x0a,0x09,0x09,0x09,0x09, /* sqrt(1/1d8)..sqrt(1/1df) */
+  0x08,0x08,0x08,0x07,0x07,0x07,0x07,0x06, /* sqrt(1/1e0)..sqrt(1/1e7) */
+  0x06,0x06,0x06,0x05,0x05,0x05,0x04,0x04, /* sqrt(1/1e8)..sqrt(1/1ef) */
+  0x04,0x04,0x03,0x03,0x03,0x03,0x02,0x02, /* sqrt(1/1f0)..sqrt(1/1f7) */
+  0x02,0x02,0x01,0x01,0x01,0x01,0x00,0x00  /* sqrt(1/1f8)..sqrt(1/1ff) */
+};
+
+/* Compute s = floor(sqrt(a0)), and *rp = a0 - s^2.  */
+
+#if GMP_NUMB_BITS > 32
+#define MAGIC CNST_LIMB(0x10000000000)	/* 0xffe7debbfc < MAGIC < 0x232b1850f410 */
+#else
+#define MAGIC CNST_LIMB(0x100000)		/* 0xfee6f < MAGIC < 0x29cbc8 */
+#endif
+
+static mp_limb_t
+mpn_sqrtrem1 (mp_ptr rp, mp_limb_t a0)
+{
+#if GMP_NUMB_BITS > 32
+  mp_limb_t a1;
+#endif
+  mp_limb_t x0, t2, t, x2;
+  unsigned abits;
+
+  ASSERT_ALWAYS (GMP_NAIL_BITS == 0);
+  ASSERT_ALWAYS (GMP_LIMB_BITS == 32 || GMP_LIMB_BITS == 64);
+  ASSERT (a0 >= GMP_NUMB_HIGHBIT / 2);
+
+  /* Use Newton iterations for approximating 1/sqrt(a) instead of sqrt(a),
+     since we can do the former without division.  As part of the last
+     iteration convert from 1/sqrt(a) to sqrt(a).  */
+
+  abits = a0 >> (GMP_LIMB_BITS - 1 - 8);	/* extract bits for table lookup */
+  x0 = 0x100 | invsqrttab[abits - 0x80];	/* initial 1/sqrt(a) */
+
+  /* x0 is now an 8 bits approximation of 1/sqrt(a0) */
+
+#if GMP_NUMB_BITS > 32
+  a1 = a0 >> (GMP_LIMB_BITS - 1 - 32);
+  t = (mp_limb_signed_t) (CNST_LIMB(0x2000000000000) - 0x30000 - a1 * x0 * x0) >> 16;
+  x0 = (x0 << 16) + ((mp_limb_signed_t) (x0 * t) >> (16+2));
+
+  /* x0 is now a 16 bits approximation of 1/sqrt(a0) */
+
+  t2 = x0 * (a0 >> (32-8));
+  t = t2 >> 25;
+  t = ((mp_limb_signed_t) ((a0 << 14) - t * t - MAGIC) >> (32-8));
+  x0 = t2 + ((mp_limb_signed_t) (x0 * t) >> 15);
+  x0 >>= 32;
+#else
+  t2 = x0 * (a0 >> (16-8));
+  t = t2 >> 13;
+  t = ((mp_limb_signed_t) ((a0 << 6) - t * t - MAGIC) >> (16-8));
+  x0 = t2 + ((mp_limb_signed_t) (x0 * t) >> 7);
+  x0 >>= 16;
+#endif
+
+  /* x0 is now a full limb approximation of sqrt(a0) */
+
+  x2 = x0 * x0;
+  if (x2 + 2*x0 <= a0 - 1)
+    {
+      x2 += 2*x0 + 1;
+      x0++;
+    }
+
+  *rp = a0 - x2;
+  return x0;
+}
+
+
+#define Prec (GMP_NUMB_BITS >> 1)
+#if ! defined(SQRTREM2_INPLACE)
+#define SQRTREM2_INPLACE 0
+#endif
+
+/* same as mpn_sqrtrem, but for size=2 and {np, 2} normalized
+   return cc such that {np, 2} = sp[0]^2 + cc*2^GMP_NUMB_BITS + rp[0] */
+#if SQRTREM2_INPLACE
+#define CALL_SQRTREM2_INPLACE(sp,rp) mpn_sqrtrem2 (sp, rp)
+static mp_limb_t
+mpn_sqrtrem2 (mp_ptr sp, mp_ptr rp)
+{
+  mp_srcptr np = rp;
+#else
+#define CALL_SQRTREM2_INPLACE(sp,rp) mpn_sqrtrem2 (sp, rp, rp)
+static mp_limb_t
+mpn_sqrtrem2 (mp_ptr sp, mp_ptr rp, mp_srcptr np)
+{
+#endif
+  mp_limb_t q, u, np0, sp0, rp0, q2;
+  int cc;
+
+  ASSERT (np[1] >= GMP_NUMB_HIGHBIT / 2);
+
+  np0 = np[0];
+  sp0 = mpn_sqrtrem1 (rp, np[1]);
+  rp0 = rp[0];
+  /* rp0 <= 2*sp0 < 2^(Prec + 1) */
+  rp0 = (rp0 << (Prec - 1)) + (np0 >> (Prec + 1));
+  q = rp0 / sp0;
+  /* q <= 2^Prec, if q = 2^Prec, reduce the overestimate. */
+  q -= q >> Prec;
+  /* now we have q < 2^Prec */
+  u = rp0 - q * sp0;
+  /* now we have (rp[0]<<Prec + np0>>Prec)/2 = q * sp0 + u */
+  sp0 = (sp0 << Prec) | q;
+  cc = u >> (Prec - 1);
+  rp0 = ((u << (Prec + 1)) & GMP_NUMB_MASK) + (np0 & ((CNST_LIMB (1) << (Prec + 1)) - 1));
+  /* subtract q * q from rp */
+  q2 = q * q;
+  cc -= rp0 < q2;
+  rp0 -= q2;
+  if (cc < 0)
+    {
+      rp0 += sp0;
+      cc += rp0 < sp0;
+      --sp0;
+      rp0 += sp0;
+      cc += rp0 < sp0;
+    }
+
+  rp[0] = rp0;
+  sp[0] = sp0;
+  return cc;
+}
+
+/* writes in {sp, n} the square root (rounded towards zero) of {np, 2n},
+   and in {np, n} the low n limbs of the remainder, returns the high
+   limb of the remainder (which is 0 or 1).
+   Assumes {np, 2n} is normalized, i.e. np[2n-1] >= B/4
+   where B=2^GMP_NUMB_BITS.
+   Needs a scratch of n/2+1 limbs. */
+static mp_limb_t
+mpn_dc_sqrtrem (mp_ptr sp, mp_ptr np, mp_size_t n, mp_limb_t approx, mp_ptr scratch)
+{
+  mp_limb_t q;			/* carry out of {sp, n} */
+  int c, b;			/* carry out of remainder */
+  mp_size_t l, h;
+
+  ASSERT (n > 1);
+  ASSERT (np[2 * n - 1] >= GMP_NUMB_HIGHBIT / 2);
+
+  l = n / 2;
+  h = n - l;
+  if (h == 1)
+    q = CALL_SQRTREM2_INPLACE (sp + l, np + 2 * l);
+  else
+    q = mpn_dc_sqrtrem (sp + l, np + 2 * l, h, 0, scratch);
+  if (q != 0)
+    ASSERT_CARRY (mpn_sub_n (np + 2 * l, np + 2 * l, sp + l, h));
+  TRACE(printf("tdiv_qr(,,,,%u,,%u) -> %u\n", (unsigned) n, (unsigned) h, (unsigned) (n - h + 1)));
+  mpn_tdiv_qr (scratch, np + l, 0, np + l, n, sp + l, h);
+  q += scratch[l];
+  c = scratch[0] & 1;
+  mpn_rshift (sp, scratch, l, 1);
+  sp[l - 1] |= (q << (GMP_NUMB_BITS - 1)) & GMP_NUMB_MASK;
+  if (UNLIKELY ((sp[0] & approx) != 0)) /* (sp[0] & mask) > 1 */
+    return 1; /* Remainder is non-zero */
+  q >>= 1;
+  if (c != 0)
+    c = mpn_add_n (np + l, np + l, sp + l, h);
+  TRACE(printf("sqr(,,%u)\n", (unsigned) l));
+  mpn_sqr (np + n, sp, l);
+  b = q + mpn_sub_n (np, np, np + n, 2 * l);
+  c -= (l == h) ? b : mpn_sub_1 (np + 2 * l, np + 2 * l, 1, (mp_limb_t) b);
+
+  if (c < 0)
+    {
+      q = mpn_add_1 (sp + l, sp + l, h, q);
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1 || HAVE_NATIVE_mpn_addlsh1_n
+      c += mpn_addlsh1_n_ip1 (np, sp, n) + 2 * q;
+#else
+      c += mpn_addmul_1 (np, sp, n, CNST_LIMB(2)) + 2 * q;
+#endif
+      c -= mpn_sub_1 (np, np, n, CNST_LIMB(1));
+      q -= mpn_sub_1 (sp, sp, n, CNST_LIMB(1));
+    }
+
+  return c;
+}
+
+#if USE_DIVAPPR_Q
+static void
+mpn_divappr_q (mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, mp_ptr scratch)
+{
+  gmp_pi1_t inv;
+  mp_limb_t qh;
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  MPN_COPY (scratch, np, nn);
+  invert_pi1 (inv, dp[dn-1], dp[dn-2]);
+  if (BELOW_THRESHOLD (dn, DC_DIVAPPR_Q_THRESHOLD))
+    qh = mpn_sbpi1_divappr_q (qp, scratch, nn, dp, dn, inv.inv32);
+  else if (BELOW_THRESHOLD (dn, MU_DIVAPPR_Q_THRESHOLD))
+    qh = mpn_dcpi1_divappr_q (qp, scratch, nn, dp, dn, &inv);
+  else
+    {
+      mp_size_t itch = mpn_mu_divappr_q_itch (nn, dn, 0);
+      TMP_DECL;
+      TMP_MARK;
+      /* Sadly, scratch is too small. */
+      qh = mpn_mu_divappr_q (qp, np, nn, dp, dn, TMP_ALLOC_LIMBS (itch));
+      TMP_FREE;
+    }
+  qp [nn - dn] = qh;
+}
+#endif
+
+/* writes in {sp, n} the square root (rounded towards zero) of {np, 2n-odd},
+   returns zero if the operand was a perfect square, one otherwise.
+   Assumes {np, 2n-odd}*4^nsh is normalized, i.e. B > np[2n-1-odd]*4^nsh >= B/4
+   where B=2^GMP_NUMB_BITS.
+   THINK: In the odd case, three more (dummy) limbs are taken into account,
+   when nsh is maximal, two limbs are discarded from the result of the
+   division. Too much? Is a single dummy limb enough? */
+static int
+mpn_dc_sqrt (mp_ptr sp, mp_srcptr np, mp_size_t n, unsigned nsh, unsigned odd)
+{
+  mp_limb_t q;			/* carry out of {sp, n} */
+  int c;			/* carry out of remainder */
+  mp_size_t l, h;
+  mp_ptr qp, tp, scratch;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (np[2 * n - 1 - odd] != 0);
+  ASSERT (n > 4);
+  ASSERT (nsh < GMP_NUMB_BITS / 2);
+
+  l = (n - 1) / 2;
+  h = n - l;
+  ASSERT (n >= l + 2 && l + 2 >= h && h > l && l >= 1 + odd);
+  scratch = TMP_ALLOC_LIMBS (l + 2 * n + 5 - USE_DIVAPPR_Q); /* n + 2-USE_DIVAPPR_Q */
+  tp = scratch + n + 2 - USE_DIVAPPR_Q; /* n + h + 1, but tp [-1] is writable */
+  if (nsh != 0)
+    {
+      /* o is used to exactly set the lowest bits of the dividend, is it needed? */
+      int o = l > (1 + odd);
+      ASSERT_NOCARRY (mpn_lshift (tp - o, np + l - 1 - o - odd, n + h + 1 + o, 2 * nsh));
+    }
+  else
+    MPN_COPY (tp, np + l - 1 - odd, n + h + 1);
+  q = mpn_dc_sqrtrem (sp + l, tp + l + 1, h, 0, scratch);
+  if (q != 0)
+    ASSERT_CARRY (mpn_sub_n (tp + l + 1, tp + l + 1, sp + l, h));
+  qp = tp + n + 1; /* l + 2 */
+  TRACE(printf("div(appr)_q(,,%u,,%u) -> %u \n", (unsigned) n+1, (unsigned) h, (unsigned) (n + 1 - h + 1)));
+#if USE_DIVAPPR_Q
+  mpn_divappr_q (qp, tp, n + 1, sp + l, h, scratch);
+#else
+  mpn_div_q (qp, tp, n + 1, sp + l, h, scratch);
+#endif
+  q += qp [l + 1];
+  c = 1;
+  if (q > 1)
+    {
+      /* FIXME: if s!=0 we will shift later, a noop on this area. */
+      MPN_FILL (sp, l, GMP_NUMB_MAX);
+    }
+  else
+    {
+      /* FIXME: if s!=0 we will shift again later, shift just once. */
+      mpn_rshift (sp, qp + 1, l, 1);
+      sp[l - 1] |= q << (GMP_NUMB_BITS - 1);
+      if (((qp[0] >> (2 + USE_DIVAPPR_Q)) | /* < 3 + 4*USE_DIVAPPR_Q */
+	   (qp[1] & (GMP_NUMB_MASK >> ((GMP_NUMB_BITS >> odd)- nsh - 1)))) == 0)
+	{
+	  mp_limb_t cy;
+	  /* Approximation is not good enough, the extra limb(+ nsh bits)
+	     is smaller than needed to absorb the possible error. */
+	  /* {qp + 1, l + 1} equals 2*{sp, l} */
+	  /* FIXME: use mullo or wrap-around, or directly evaluate
+	     remainder with a single sqrmod_bnm1. */
+	  TRACE(printf("mul(,,%u,,%u)\n", (unsigned) h, (unsigned) (l+1)));
+	  ASSERT_NOCARRY (mpn_mul (scratch, sp + l, h, qp + 1, l + 1));
+	  /* Compute the remainder of the previous mpn_div(appr)_q. */
+	  cy = mpn_sub_n (tp + 1, tp + 1, scratch, h);
+#if USE_DIVAPPR_Q || WANT_ASSERT
+	  MPN_DECR_U (tp + 1 + h, l, cy);
+#if USE_DIVAPPR_Q
+	  ASSERT (mpn_cmp (tp + 1 + h, scratch + h, l) <= 0);
+	  if (mpn_cmp (tp + 1 + h, scratch + h, l) < 0)
+	    {
+	      /* May happen only if div result was not exact. */
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1 || HAVE_NATIVE_mpn_addlsh1_n
+	      cy = mpn_addlsh1_n_ip1 (tp + 1, sp + l, h);
+#else
+	      cy = mpn_addmul_1 (tp + 1, sp + l, h, CNST_LIMB(2));
+#endif
+	      ASSERT_NOCARRY (mpn_add_1 (tp + 1 + h, tp + 1 + h, l, cy));
+	      MPN_DECR_U (sp, l, 1);
+	    }
+	  /* Can the root be exact when a correction was needed? We
+	     did not find an example, but it depends on divappr
+	     internals, and we can not assume it true in general...*/
+	  /* else */
+#else /* WANT_ASSERT */
+	  ASSERT (mpn_cmp (tp + 1 + h, scratch + h, l) == 0);
+#endif
+#endif
+	  if (mpn_zero_p (tp + l + 1, h - l))
+	    {
+	      TRACE(printf("sqr(,,%u)\n", (unsigned) l));
+	      mpn_sqr (scratch, sp, l);
+	      c = mpn_cmp (tp + 1, scratch + l, l);
+	      if (c == 0)
+		{
+		  if (nsh != 0)
+		    {
+		      mpn_lshift (tp, np, l, 2 * nsh);
+		      np = tp;
+		    }
+		  c = mpn_cmp (np, scratch + odd, l - odd);
+		}
+	      if (c < 0)
+		{
+		  MPN_DECR_U (sp, l, 1);
+		  c = 1;
+		}
+	    }
+	}
+    }
+  TMP_FREE;
+
+  if ((odd | nsh) != 0)
+    mpn_rshift (sp, sp, n, nsh + (odd ? GMP_NUMB_BITS / 2 : 0));
+  return c;
+}
+
+
+mp_size_t
+mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr np, mp_size_t nn)
+{
+  mp_limb_t cc, high, rl;
+  int c;
+  mp_size_t rn, tn;
+  TMP_DECL;
+
+  ASSERT (nn > 0);
+  ASSERT_MPN (np, nn);
+
+  ASSERT (np[nn - 1] != 0);
+  ASSERT (rp == NULL || MPN_SAME_OR_SEPARATE_P (np, rp, nn));
+  ASSERT (rp == NULL || ! MPN_OVERLAP_P (sp, (nn + 1) / 2, rp, nn));
+  ASSERT (! MPN_OVERLAP_P (sp, (nn + 1) / 2, np, nn));
+
+  high = np[nn - 1];
+  if (high & (GMP_NUMB_HIGHBIT | (GMP_NUMB_HIGHBIT / 2)))
+    c = 0;
+  else
+    {
+      count_leading_zeros (c, high);
+      c -= GMP_NAIL_BITS;
+
+      c = c / 2; /* we have to shift left by 2c bits to normalize {np, nn} */
+    }
+  if (nn == 1) {
+    if (c == 0)
+      {
+	sp[0] = mpn_sqrtrem1 (&rl, high);
+	if (rp != NULL)
+	  rp[0] = rl;
+      }
+    else
+      {
+	cc = mpn_sqrtrem1 (&rl, high << (2*c)) >> c;
+	sp[0] = cc;
+	if (rp != NULL)
+	  rp[0] = rl = high - cc*cc;
+      }
+    return rl != 0;
+  }
+  if (nn == 2) {
+    mp_limb_t tp [2];
+    if (rp == NULL) rp = tp;
+    if (c == 0)
+      {
+#if SQRTREM2_INPLACE
+	rp[1] = high;
+	rp[0] = np[0];
+	cc = CALL_SQRTREM2_INPLACE (sp, rp);
+#else
+	cc = mpn_sqrtrem2 (sp, rp, np);
+#endif
+	rp[1] = cc;
+	return ((rp[0] | cc) != 0) + cc;
+      }
+    else
+      {
+	rl = np[0];
+	rp[1] = (high << (2*c)) | (rl >> (GMP_NUMB_BITS - 2*c));
+	rp[0] = rl << (2*c);
+	CALL_SQRTREM2_INPLACE (sp, rp);
+	cc = sp[0] >>= c;	/* c != 0, the highest bit of the root cc is 0. */
+	rp[0] = rl -= cc*cc;	/* Computed modulo 2^GMP_LIMB_BITS, because it's smaller. */
+	return rl != 0;
+      }
+  }
+  tn = (nn + 1) / 2; /* 2*tn is the smallest even integer >= nn */
+
+  if ((rp == NULL) && (nn > 8))
+    return mpn_dc_sqrt (sp, np, tn, c, nn & 1);
+  TMP_MARK;
+  if (((nn & 1) | c) != 0)
+    {
+      mp_limb_t s0[1], mask;
+      mp_ptr tp, scratch;
+      TMP_ALLOC_LIMBS_2 (tp, 2 * tn, scratch, tn / 2 + 1);
+      tp[0] = 0;	     /* needed only when 2*tn > nn, but saves a test */
+      if (c != 0)
+	mpn_lshift (tp + (nn & 1), np, nn, 2 * c);
+      else
+	MPN_COPY (tp + (nn & 1), np, nn);
+      c += (nn & 1) ? GMP_NUMB_BITS / 2 : 0;		/* c now represents k */
+      mask = (CNST_LIMB (1) << c) - 1;
+      rl = mpn_dc_sqrtrem (sp, tp, tn, (rp == NULL) ? mask - 1 : 0, scratch);
+      /* We have 2^(2k)*N = S^2 + R where k = c + (2tn-nn)*GMP_NUMB_BITS/2,
+	 thus 2^(2k)*N = (S-s0)^2 + 2*S*s0 - s0^2 + R where s0=S mod 2^k */
+      s0[0] = sp[0] & mask;	/* S mod 2^k */
+      rl += mpn_addmul_1 (tp, sp, tn, 2 * s0[0]);	/* R = R + 2*s0*S */
+      cc = mpn_submul_1 (tp, s0, 1, s0[0]);
+      rl -= (tn > 1) ? mpn_sub_1 (tp + 1, tp + 1, tn - 1, cc) : cc;
+      mpn_rshift (sp, sp, tn, c);
+      tp[tn] = rl;
+      if (rp == NULL)
+	rp = tp;
+      c = c << 1;
+      if (c < GMP_NUMB_BITS)
+	tn++;
+      else
+	{
+	  tp++;
+	  c -= GMP_NUMB_BITS;
+	}
+      if (c != 0)
+	mpn_rshift (rp, tp, tn, c);
+      else
+	MPN_COPY_INCR (rp, tp, tn);
+      rn = tn;
+    }
+  else
+    {
+      if (rp != np)
+	{
+	  if (rp == NULL) /* nn <= 8 */
+	    rp = TMP_SALLOC_LIMBS (nn);
+	  MPN_COPY (rp, np, nn);
+	}
+      rn = tn + (rp[tn] = mpn_dc_sqrtrem (sp, rp, tn, 0, TMP_ALLOC_LIMBS(tn / 2 + 1)));
+    }
+
+  MPN_NORMALIZE (rp, rn);
+
+  TMP_FREE;
+  return rn;
+}
diff --git a/mpn/generic/strongfibo.c b/mpn/generic/strongfibo.c
new file mode 100644
index 0000000..7e8d612
--- /dev/null
+++ b/mpn/generic/strongfibo.c
@@ -0,0 +1,219 @@
+/* mpn_fib2m -- calculate Fibonacci numbers, modulo m.
+
+Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2018, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+#if ! HAVE_NATIVE_mpn_rsblsh1_n && ! HAVE_NATIVE_mpn_sublsh1_n
+/* Stores |{ap,n}-{bp,n}| in {rp,n},
+   returns the sign of {ap,n}-{bp,n}. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_limb_t  x, y;
+  while (--n >= 0)
+    {
+      x = ap[n];
+      y = bp[n];
+      if (x != y)
+        {
+          ++n;
+          if (x > y)
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, ap, bp, n));
+              return 1;
+            }
+          else
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, bp, ap, n));
+              return -1;
+            }
+        }
+      rp[n] = 0;
+    }
+  return 0;
+}
+#endif
+
+/* Computes at most count terms of the sequence needed by the
+   Lucas-Lehmer-Riesel test, indexing backward:
+   L_i = L_{i+1}^2 - 2
+
+   The sequence is computed modulo M = {mp, mn}.
+   The starting point is given in L_{count+1} = {lp, mn}.
+   The scratch pointed by sp, needs a space of at least 3 * mn + 1 limbs.
+
+   Returns the index i>0 if L_i = 0 (mod M) is found within the
+   computed count terms of the sequence.  Otherwise it returns zero.
+
+   Note: (+/-2)^2-2=2, (+/-1)^2-2=-1, 0^2-2=-2
+ */
+
+static mp_bitcnt_t
+mpn_llriter (mp_ptr lp, mp_srcptr mp, mp_size_t mn, mp_bitcnt_t count, mp_ptr sp)
+{
+  do
+    {
+      mpn_sqr (sp, lp, mn);
+      mpn_tdiv_qr (sp + 2 * mn, lp, 0, sp, 2 * mn, mp, mn);
+      if (lp[0] < 5)
+	{
+	  /* If L^2 % M < 5, |L^2 % M - 2| <= 2 */
+	  if (mn == 1 || mpn_zero_p (lp + 1, mn - 1))
+	    return (lp[0] == 2) ? count : 0;
+	  else
+	    MPN_DECR_U (lp, mn, 2);
+	}
+      else
+	lp[0] -= 2;
+    } while (--count != 0);
+  return 0;
+}
+
+/* Store the Lucas' number L[n] at lp (maybe), computed modulo m.  lp
+   and scratch should have room for mn*2+1 limbs.
+
+   Returns the size of L[n] normally.
+
+   If F[n] is zero modulo m, or L[n] is, returns 0 and lp is
+   undefined.
+*/
+
+static mp_size_t
+mpn_lucm (mp_ptr lp, mp_srcptr np, mp_size_t nn, mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
+{
+  int		neg;
+  mp_limb_t	cy;
+
+  ASSERT (! MPN_OVERLAP_P (lp, MAX(2*mn+1,5), scratch, MAX(2*mn+1,5)));
+  ASSERT (nn > 0);
+
+  neg = mpn_fib2m (lp, scratch, np, nn, mp, mn);
+
+  /* F[n] = +/-{lp, mn}, F[n-1] = +/-{scratch, mn} */
+  if (mpn_zero_p (lp, mn))
+    return 0;
+
+  if (neg) /* One sign is opposite, use sub instead of add. */
+    {
+#if HAVE_NATIVE_mpn_rsblsh1_n || HAVE_NATIVE_mpn_sublsh1_n
+#if HAVE_NATIVE_mpn_rsblsh1_n
+      cy = mpn_rsblsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
+#else
+      cy = mpn_sublsh1_n (lp, lp, scratch, mn); /* L[n] = -/+(F[n]-(-2F[n-1])) */
+      if (cy != 0)
+	cy = mpn_add_n (lp, lp, mp, mn) - cy;
+#endif
+      if (cy > 1)
+	cy += mpn_add_n (lp, lp, mp, mn);
+#else
+      cy = mpn_lshift (scratch, scratch, mn, 1); /* 2F[n-1] */
+      if (UNLIKELY (cy))
+	cy -= mpn_sub_n (lp, scratch, lp, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
+      else
+	abs_sub_n (lp, lp, scratch, mn);
+#endif
+      ASSERT (cy <= 1);
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = mpn_addlsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]+F[n])) */
+#else
+      cy = mpn_lshift (scratch, scratch, mn, 1);
+      cy+= mpn_add_n (lp, lp, scratch, mn);
+#endif
+      ASSERT (cy <= 2);
+    }
+  while (cy || mpn_cmp (lp, mp, mn) >= 0)
+    cy -= mpn_sub_n (lp, lp, mp, mn);
+  MPN_NORMALIZE (lp, mn);
+  return mn;
+}
+
+int
+mpn_strongfibo (mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
+{
+  mp_ptr	lp, sp;
+  mp_size_t	en;
+  mp_bitcnt_t	b0;
+  TMP_DECL;
+
+#if GMP_NUMB_BITS % 4 == 0
+  b0 = mpn_scan0 (mp, 0);
+#else
+  {
+    mpz_t m = MPZ_ROINIT_N(mp, mn);
+    b0 = mpz_scan0 (m, 0);
+  }
+  if (UNLIKELY (b0 == mn * GMP_NUMB_BITS))
+    {
+      en = 1;
+      scratch [0] = 1;
+    }
+  else
+#endif
+    {
+      int cnt = b0 % GMP_NUMB_BITS;
+      en = b0 / GMP_NUMB_BITS;
+      if (LIKELY (cnt != 0))
+	mpn_rshift (scratch, mp + en, mn - en, cnt);
+      else
+	MPN_COPY (scratch, mp + en, mn - en);
+      en = mn - en;
+      scratch [0] |= 1;
+      en -= scratch [en - 1] == 0;
+    }
+  TMP_MARK;
+
+  lp = TMP_ALLOC_LIMBS (4 * mn + 6);
+  sp = lp + 2 * mn + 3;
+  en = mpn_lucm (sp, scratch, en, mp, mn, lp);
+  if (en != 0 && LIKELY (--b0 != 0))
+    {
+      mpn_sqr (lp, sp, en);
+      lp [0] |= 2; /* V^2 + 2 */
+      if (LIKELY (2 * en >= mn))
+	mpn_tdiv_qr (sp, lp, 0, lp, 2 * en, mp, mn);
+      else
+	MPN_ZERO (lp + 2 * en, mn - 2 * en);
+      if (! mpn_zero_p (lp, mn) && LIKELY (--b0 != 0))
+	b0 = mpn_llriter (lp, mp, mn, b0, lp + mn + 1);
+    }
+  TMP_FREE;
+  return (b0 != 0);
+}
diff --git a/mpn/generic/sub.c b/mpn/generic/sub.c
new file mode 100644
index 0000000..df0afd6
--- /dev/null
+++ b/mpn/generic/sub.c
@@ -0,0 +1,33 @@
+/* mpn_sub - subtract mpn from mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_sub 1
+
+#include "gmp-impl.h"
diff --git a/mpn/generic/sub_1.c b/mpn/generic/sub_1.c
new file mode 100644
index 0000000..a20f191
--- /dev/null
+++ b/mpn/generic/sub_1.c
@@ -0,0 +1,33 @@
+/* mpn_sub_1 - subtract limb from mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_sub_1 1
+
+#include "gmp-impl.h"
diff --git a/mpn/generic/sub_err1_n.c b/mpn/generic/sub_err1_n.c
new file mode 100644
index 0000000..beca57e
--- /dev/null
+++ b/mpn/generic/sub_err1_n.c
@@ -0,0 +1,100 @@
+/* mpn_sub_err1_n -- sub_n with one error term
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} - {vp,n} (just like mpn_sub_n) with incoming borrow cy,
+  return value is borrow out.
+
+  (2) Let c[i+1] = borrow from i-th limb subtraction (c[0] = cy).
+  Computes c[1]*yp[n-1] + ... + c[n]*yp[0], stores two-limb result at ep.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_sub_err1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		mp_ptr ep, mp_srcptr yp,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el, eh, ul, vl, yl, zl, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, rp, n));
+
+  yp += n - 1;
+  el = eh = 0;
+
+  do
+    {
+      yl = *yp--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary sub_n */
+      SUBC_LIMB (cy1, sl, ul, vl);
+      SUBC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh:el) */
+      zl = (-cy) & yl;
+      el += zl;
+      eh += el < zl;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh = (eh << GMP_NAIL_BITS) + (el >> GMP_NUMB_BITS);
+  el &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el;
+  ep[1] = eh;
+
+  return cy;
+}
diff --git a/mpn/generic/sub_err2_n.c b/mpn/generic/sub_err2_n.c
new file mode 100644
index 0000000..1edf8d6
--- /dev/null
+++ b/mpn/generic/sub_err2_n.c
@@ -0,0 +1,116 @@
+/* mpn_sub_err2_n -- sub_n with two error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} - {vp,n} (just like mpn_sub_n) with incoming borrow cy,
+  return value is borrow out.
+
+  (2) Let c[i+1] = borrow from i-th limb subtraction (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+  stores two-limb results at {ep,2} and {ep+2,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_sub_err2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, ul, vl, yl1, yl2, zl1, zl2, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary sub_n */
+      SUBC_LIMB (cy1, sl, ul, vl);
+      SUBC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+
+  return cy;
+}
diff --git a/mpn/generic/sub_err3_n.c b/mpn/generic/sub_err3_n.c
new file mode 100644
index 0000000..2db3c63
--- /dev/null
+++ b/mpn/generic/sub_err3_n.c
@@ -0,0 +1,131 @@
+/* mpn_sub_err3_n -- sub_n with three error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} - {vp,n} (just like mpn_sub_n) with incoming borrow cy,
+  return value is borrow out.
+
+  (2) Let c[i+1] = borrow from i-th limb subtraction (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+           c[1]*yp3[n-1] + ... + c[n]*yp3[0],
+  stores two-limb results at {ep,2}, {ep+2,2} and {ep+4,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_sub_err3_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2, mp_srcptr yp3,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, el3, eh3, ul, vl, yl1, yl2, yl3, zl1, zl2, zl3, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  yp3 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+  el3 = eh3 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      yl3 = *yp3--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary sub_n */
+      SUBC_LIMB (cy1, sl, ul, vl);
+      SUBC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+
+      /* update (eh3:el3) */
+      zl3 = (-cy) & yl3;
+      el3 += zl3;
+      eh3 += el3 < zl3;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+  eh3 = (eh3 << GMP_NAIL_BITS) + (el3 >> GMP_NUMB_BITS);
+  el3 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+  ep[4] = el3;
+  ep[5] = eh3;
+
+  return cy;
+}
diff --git a/mpn/generic/sub_n.c b/mpn/generic/sub_n.c
new file mode 100644
index 0000000..b192c96
--- /dev/null
+++ b/mpn/generic/sub_n.c
@@ -0,0 +1,89 @@
+/* mpn_sub_n -- Subtract equal length limb vectors.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      sl = ul - vl;
+      cy1 = sl > ul;
+      rl = sl - cy;
+      cy2 = rl > sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 1
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, rl, cy;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      rl = ul - vl - cy;
+      cy = rl >> (GMP_LIMB_BITS - 1);
+      *rp++ = rl & GMP_NUMB_MASK;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
diff --git a/mpn/generic/submul_1.c b/mpn/generic/submul_1.c
new file mode 100644
index 0000000..4744274
--- /dev/null
+++ b/mpn/generic/submul_1.c
@@ -0,0 +1,144 @@
+/* mpn_submul_1 -- multiply the N long limb vector pointed to by UP by VL,
+   subtract the N least significant limbs of the product from the limb
+   vector pointed to by RP.  Return the most significant limb of the
+   product, adjusted for carry-out from the subtraction.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t u0, crec, c, p1, p0, r0;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+
+  crec = 0;
+  do
+    {
+      u0 = *up++;
+      umul_ppmm (p1, p0, u0, v0);
+
+      r0 = *rp;
+
+      p0 = r0 - p0;
+      c = r0 < p0;
+
+      p1 = p1 + c;
+
+      r0 = p0 - crec;		/* cycle 0, 3, ... */
+      c = p0 < r0;		/* cycle 1, 4, ... */
+
+      crec = p1 + c;		/* cycle 2, 5, ... */
+
+      *rp++ = r0;
+    }
+  while (--n != 0);
+
+  return crec;
+}
+
+#endif
+
+#if GMP_NAIL_BITS == 1
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, cl, xl, c1, c2, c3;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  cl = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      SUBC_LIMB (c1, xl, r0, prev_p1);
+      SUBC_LIMB (c2, xl, xl, p0);
+      SUBC_LIMB (c3, xl, xl, cl);
+      cl = c1 + c2 + c3;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 + cl;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 2
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, xw, cl, xl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  cl = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      xw = r0 - (prev_p1 + p0) + cl;
+      cl = (mp_limb_signed_t) xw >> GMP_NUMB_BITS; /* FIXME: non-portable */
+      xl = xw & GMP_NUMB_MASK;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 - cl;
+}
+
+#endif
diff --git a/mpn/generic/tdiv_qr.c b/mpn/generic/tdiv_qr.c
new file mode 100644
index 0000000..92ff33c
--- /dev/null
+++ b/mpn/generic/tdiv_qr.c
@@ -0,0 +1,386 @@
+/* mpn_tdiv_qr -- Divide the numerator (np,nn) by the denominator (dp,dn) and
+   write the nn-dn+1 quotient limbs at qp and the dn remainder limbs at rp.  If
+   qxn is non-zero, generate that many fraction limbs and append them after the
+   other quotient limbs, and update the remainder accordingly.  The input
+   operands are unaffected.
+
+   Preconditions:
+   1. The most significant limb of the divisor must be non-zero.
+   2. nn >= dn, even if qxn is non-zero.  (??? relax this ???)
+
+   The time complexity of this is O(qn*qn+M(dn,qn)), where M(m,n) is the time
+   complexity of multiplication.
+
+Copyright 1997, 2000-2002, 2005, 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpn_tdiv_qr (mp_ptr qp, mp_ptr rp, mp_size_t qxn,
+	     mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
+{
+  ASSERT_ALWAYS (qxn == 0);
+
+  ASSERT (nn >= 0);
+  ASSERT (dn >= 0);
+  ASSERT (dn == 0 || dp[dn - 1] != 0);
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1 + qxn, np, nn));
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1 + qxn, dp, dn));
+
+  switch (dn)
+    {
+    case 0:
+      DIVIDE_BY_ZERO;
+
+    case 1:
+      {
+	rp[0] = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, dp[0]);
+	return;
+      }
+
+    case 2:
+      {
+	mp_ptr n2p;
+	mp_limb_t qhl, cy;
+	TMP_DECL;
+	TMP_MARK;
+	if ((dp[1] & GMP_NUMB_HIGHBIT) == 0)
+	  {
+	    int cnt;
+	    mp_limb_t d2p[2];
+	    count_leading_zeros (cnt, dp[1]);
+	    cnt -= GMP_NAIL_BITS;
+	    d2p[1] = (dp[1] << cnt) | (dp[0] >> (GMP_NUMB_BITS - cnt));
+	    d2p[0] = (dp[0] << cnt) & GMP_NUMB_MASK;
+	    n2p = TMP_ALLOC_LIMBS (nn + 1);
+	    cy = mpn_lshift (n2p, np, nn, cnt);
+	    n2p[nn] = cy;
+	    qhl = mpn_divrem_2 (qp, 0L, n2p, nn + (cy != 0), d2p);
+	    if (cy == 0)
+	      qp[nn - 2] = qhl;	/* always store nn-2+1 quotient limbs */
+	    rp[0] = (n2p[0] >> cnt)
+	      | ((n2p[1] << (GMP_NUMB_BITS - cnt)) & GMP_NUMB_MASK);
+	    rp[1] = (n2p[1] >> cnt);
+	  }
+	else
+	  {
+	    n2p = TMP_ALLOC_LIMBS (nn);
+	    MPN_COPY (n2p, np, nn);
+	    qhl = mpn_divrem_2 (qp, 0L, n2p, nn, dp);
+	    qp[nn - 2] = qhl;	/* always store nn-2+1 quotient limbs */
+	    rp[0] = n2p[0];
+	    rp[1] = n2p[1];
+	  }
+	TMP_FREE;
+	return;
+      }
+
+    default:
+      {
+	int adjust;
+	gmp_pi1_t dinv;
+	TMP_DECL;
+	TMP_MARK;
+	adjust = np[nn - 1] >= dp[dn - 1];	/* conservative tests for quotient size */
+	if (nn + adjust >= 2 * dn)
+	  {
+	    mp_ptr n2p, d2p;
+	    mp_limb_t cy;
+	    int cnt;
+
+	    qp[nn - dn] = 0;			  /* zero high quotient limb */
+	    if ((dp[dn - 1] & GMP_NUMB_HIGHBIT) == 0) /* normalize divisor */
+	      {
+		count_leading_zeros (cnt, dp[dn - 1]);
+		cnt -= GMP_NAIL_BITS;
+		d2p = TMP_ALLOC_LIMBS (dn);
+		mpn_lshift (d2p, dp, dn, cnt);
+		n2p = TMP_ALLOC_LIMBS (nn + 1);
+		cy = mpn_lshift (n2p, np, nn, cnt);
+		n2p[nn] = cy;
+		nn += adjust;
+	      }
+	    else
+	      {
+		cnt = 0;
+		d2p = (mp_ptr) dp;
+		n2p = TMP_ALLOC_LIMBS (nn + 1);
+		MPN_COPY (n2p, np, nn);
+		n2p[nn] = 0;
+		nn += adjust;
+	      }
+
+	    invert_pi1 (dinv, d2p[dn - 1], d2p[dn - 2]);
+	    if (BELOW_THRESHOLD (dn, DC_DIV_QR_THRESHOLD))
+	      mpn_sbpi1_div_qr (qp, n2p, nn, d2p, dn, dinv.inv32);
+	    else if (BELOW_THRESHOLD (dn, MUPI_DIV_QR_THRESHOLD) ||   /* fast condition */
+		     BELOW_THRESHOLD (nn, 2 * MU_DIV_QR_THRESHOLD) || /* fast condition */
+		     (double) (2 * (MU_DIV_QR_THRESHOLD - MUPI_DIV_QR_THRESHOLD)) * dn /* slow... */
+		     + (double) MUPI_DIV_QR_THRESHOLD * nn > (double) dn * nn)    /* ...condition */
+	      mpn_dcpi1_div_qr (qp, n2p, nn, d2p, dn, &dinv);
+	    else
+	      {
+		mp_size_t itch = mpn_mu_div_qr_itch (nn, dn, 0);
+		mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+		mpn_mu_div_qr (qp, rp, n2p, nn, d2p, dn, scratch);
+		n2p = rp;
+	      }
+
+	    if (cnt != 0)
+	      mpn_rshift (rp, n2p, dn, cnt);
+	    else
+	      MPN_COPY (rp, n2p, dn);
+	    TMP_FREE;
+	    return;
+	  }
+
+	/* When we come here, the numerator/partial remainder is less
+	   than twice the size of the denominator.  */
+
+	  {
+	    /* Problem:
+
+	       Divide a numerator N with nn limbs by a denominator D with dn
+	       limbs forming a quotient of qn=nn-dn+1 limbs.  When qn is small
+	       compared to dn, conventional division algorithms perform poorly.
+	       We want an algorithm that has an expected running time that is
+	       dependent only on qn.
+
+	       Algorithm (very informally stated):
+
+	       1) Divide the 2 x qn most significant limbs from the numerator
+		  by the qn most significant limbs from the denominator.  Call
+		  the result qest.  This is either the correct quotient, but
+		  might be 1 or 2 too large.  Compute the remainder from the
+		  division.  (This step is implemented by an mpn_divrem call.)
+
+	       2) Is the most significant limb from the remainder < p, where p
+		  is the product of the most significant limb from the quotient
+		  and the next(d)?  (Next(d) denotes the next ignored limb from
+		  the denominator.)  If it is, decrement qest, and adjust the
+		  remainder accordingly.
+
+	       3) Is the remainder >= qest?  If it is, qest is the desired
+		  quotient.  The algorithm terminates.
+
+	       4) Subtract qest x next(d) from the remainder.  If there is
+		  borrow out, decrement qest, and adjust the remainder
+		  accordingly.
+
+	       5) Skip one word from the denominator (i.e., let next(d) denote
+		  the next less significant limb.  */
+
+	    mp_size_t qn;
+	    mp_ptr n2p, d2p;
+	    mp_ptr tp;
+	    mp_limb_t cy;
+	    mp_size_t in, rn;
+	    mp_limb_t quotient_too_large;
+	    unsigned int cnt;
+
+	    qn = nn - dn;
+	    qp[qn] = 0;				/* zero high quotient limb */
+	    qn += adjust;			/* qn cannot become bigger */
+
+	    if (qn == 0)
+	      {
+		MPN_COPY (rp, np, dn);
+		TMP_FREE;
+		return;
+	      }
+
+	    in = dn - qn;		/* (at least partially) ignored # of limbs in ops */
+	    /* Normalize denominator by shifting it to the left such that its
+	       most significant bit is set.  Then shift the numerator the same
+	       amount, to mathematically preserve quotient.  */
+	    if ((dp[dn - 1] & GMP_NUMB_HIGHBIT) == 0)
+	      {
+		count_leading_zeros (cnt, dp[dn - 1]);
+		cnt -= GMP_NAIL_BITS;
+
+		d2p = TMP_ALLOC_LIMBS (qn);
+		mpn_lshift (d2p, dp + in, qn, cnt);
+		d2p[0] |= dp[in - 1] >> (GMP_NUMB_BITS - cnt);
+
+		n2p = TMP_ALLOC_LIMBS (2 * qn + 1);
+		cy = mpn_lshift (n2p, np + nn - 2 * qn, 2 * qn, cnt);
+		if (adjust)
+		  {
+		    n2p[2 * qn] = cy;
+		    n2p++;
+		  }
+		else
+		  {
+		    n2p[0] |= np[nn - 2 * qn - 1] >> (GMP_NUMB_BITS - cnt);
+		  }
+	      }
+	    else
+	      {
+		cnt = 0;
+		d2p = (mp_ptr) dp + in;
+
+		n2p = TMP_ALLOC_LIMBS (2 * qn + 1);
+		MPN_COPY (n2p, np + nn - 2 * qn, 2 * qn);
+		if (adjust)
+		  {
+		    n2p[2 * qn] = 0;
+		    n2p++;
+		  }
+	      }
+
+	    /* Get an approximate quotient using the extracted operands.  */
+	    if (qn == 1)
+	      {
+		mp_limb_t q0, r0;
+		udiv_qrnnd (q0, r0, n2p[1], n2p[0] << GMP_NAIL_BITS, d2p[0] << GMP_NAIL_BITS);
+		n2p[0] = r0 >> GMP_NAIL_BITS;
+		qp[0] = q0;
+	      }
+	    else if (qn == 2)
+	      mpn_divrem_2 (qp, 0L, n2p, 4L, d2p); /* FIXME: obsolete function */
+	    else
+	      {
+		invert_pi1 (dinv, d2p[qn - 1], d2p[qn - 2]);
+		if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+		  mpn_sbpi1_div_qr (qp, n2p, 2 * qn, d2p, qn, dinv.inv32);
+		else if (BELOW_THRESHOLD (qn, MU_DIV_QR_THRESHOLD))
+		  mpn_dcpi1_div_qr (qp, n2p, 2 * qn, d2p, qn, &dinv);
+		else
+		  {
+		    mp_size_t itch = mpn_mu_div_qr_itch (2 * qn, qn, 0);
+		    mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+		    mp_ptr r2p = rp;
+		    if (np == r2p)	/* If N and R share space, put ... */
+		      r2p += nn - qn;	/* intermediate remainder at N's upper end. */
+		    mpn_mu_div_qr (qp, r2p, n2p, 2 * qn, d2p, qn, scratch);
+		    MPN_COPY (n2p, r2p, qn);
+		  }
+	      }
+
+	    rn = qn;
+	    /* Multiply the first ignored divisor limb by the most significant
+	       quotient limb.  If that product is > the partial remainder's
+	       most significant limb, we know the quotient is too large.  This
+	       test quickly catches most cases where the quotient is too large;
+	       it catches all cases where the quotient is 2 too large.  */
+	    {
+	      mp_limb_t dl, x;
+	      mp_limb_t h, dummy;
+
+	      if (in - 2 < 0)
+		dl = 0;
+	      else
+		dl = dp[in - 2];
+
+#if GMP_NAIL_BITS == 0
+	      x = (dp[in - 1] << cnt) | ((dl >> 1) >> ((~cnt) % GMP_LIMB_BITS));
+#else
+	      x = (dp[in - 1] << cnt) & GMP_NUMB_MASK;
+	      if (cnt != 0)
+		x |= dl >> (GMP_NUMB_BITS - cnt);
+#endif
+	      umul_ppmm (h, dummy, x, qp[qn - 1] << GMP_NAIL_BITS);
+
+	      if (n2p[qn - 1] < h)
+		{
+		  mp_limb_t cy;
+
+		  mpn_decr_u (qp, (mp_limb_t) 1);
+		  cy = mpn_add_n (n2p, n2p, d2p, qn);
+		  if (cy)
+		    {
+		      /* The partial remainder is safely large.  */
+		      n2p[qn] = cy;
+		      ++rn;
+		    }
+		}
+	    }
+
+	    quotient_too_large = 0;
+	    if (cnt != 0)
+	      {
+		mp_limb_t cy1, cy2;
+
+		/* Append partially used numerator limb to partial remainder.  */
+		cy1 = mpn_lshift (n2p, n2p, rn, GMP_NUMB_BITS - cnt);
+		n2p[0] |= np[in - 1] & (GMP_NUMB_MASK >> cnt);
+
+		/* Update partial remainder with partially used divisor limb.  */
+		cy2 = mpn_submul_1 (n2p, qp, qn, dp[in - 1] & (GMP_NUMB_MASK >> cnt));
+		if (qn != rn)
+		  {
+		    ASSERT_ALWAYS (n2p[qn] >= cy2);
+		    n2p[qn] -= cy2;
+		  }
+		else
+		  {
+		    n2p[qn] = cy1 - cy2; /* & GMP_NUMB_MASK; */
+
+		    quotient_too_large = (cy1 < cy2);
+		    ++rn;
+		  }
+		--in;
+	      }
+	    /* True: partial remainder now is neutral, i.e., it is not shifted up.  */
+
+	    tp = TMP_ALLOC_LIMBS (dn);
+
+	    if (in < qn)
+	      {
+		if (in == 0)
+		  {
+		    MPN_COPY (rp, n2p, rn);
+		    ASSERT_ALWAYS (rn == dn);
+		    goto foo;
+		  }
+		mpn_mul (tp, qp, qn, dp, in);
+	      }
+	    else
+	      mpn_mul (tp, dp, in, qp, qn);
+
+	    cy = mpn_sub (n2p, n2p, rn, tp + in, qn);
+	    MPN_COPY (rp + in, n2p, dn - in);
+	    quotient_too_large |= cy;
+	    cy = mpn_sub_n (rp, np, tp, in);
+	    cy = mpn_sub_1 (rp + in, rp + in, rn, cy);
+	    quotient_too_large |= cy;
+	  foo:
+	    if (quotient_too_large)
+	      {
+		mpn_decr_u (qp, (mp_limb_t) 1);
+		mpn_add_n (rp, rp, dp, dn);
+	      }
+	  }
+	TMP_FREE;
+	return;
+      }
+    }
+}
diff --git a/mpn/generic/toom22_mul.c b/mpn/generic/toom22_mul.c
new file mode 100644
index 0000000..da56014
--- /dev/null
+++ b/mpn/generic/toom22_mul.c
@@ -0,0 +1,222 @@
+/* mpn_toom22_mul -- Multiply {ap,an} and {bp,bn} where an >= bn.  Or more
+   accurately, bn <= an < 2bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2012, 2014, 2018, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +inf
+
+  <-s--><--n-->
+   ____ ______
+  |_a1_|___a0_|
+   |b1_|___b0_|
+   <-t-><--n-->
+
+  v0  =  a0     * b0       #   A(0)*B(0)
+  vm1 = (a0- a1)*(b0- b1)  #  A(-1)*B(-1)
+  vinf=      a1 *     b1   # A(inf)*B(inf)
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_mul_toom22   1
+#else
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM33_THRESHOLD >= 2 * MUL_TOOM22_THRESHOLD)
+#endif
+
+#define TOOM22_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    if (! MAYBE_mul_toom22						\
+	|| BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+    else								\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+  } while (0)
+
+/* Normally, this calls mul_basecase or toom22_mul.  But when when the fraction
+   MUL_TOOM33_THRESHOLD / MUL_TOOM22_THRESHOLD is large, an initially small
+   relative unbalance will become a larger and larger relative unbalance with
+   each recursion (the difference s-t will be invariant over recursive calls).
+   Therefore, we need to call toom32_mul.  FIXME: Suppress depending on
+   MUL_TOOM33_THRESHOLD / MUL_TOOM22_THRESHOLD and on MUL_TOOM22_THRESHOLD.  */
+#define TOOM22_MUL_REC(p, a, an, b, bn, ws)				\
+  do {									\
+    if (! MAYBE_mul_toom22						\
+	|| BELOW_THRESHOLD (bn, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, an, b, bn);				\
+    else if (4 * an < 5 * bn)						\
+      mpn_toom22_mul (p, a, an, b, bn, ws);				\
+    else								\
+      mpn_toom32_mul (p, a, an, b, bn, ws);				\
+  } while (0)
+
+void
+mpn_toom22_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy, cy2;
+  mp_ptr asm1;
+  mp_ptr bsm1;
+
+#define a0  ap
+#define a1  (ap + n)
+#define b0  bp
+#define b1  (bp + n)
+
+  s = an >> 1;
+  n = an - s;
+  t = bn - n;
+
+  ASSERT (an >= bn);
+
+  ASSERT (0 < s && s <= n && (n - s) == (an & 1));
+  ASSERT (0 < t && t <= s);
+
+  asm1 = pp;
+  bsm1 = pp + n;
+
+  vm1_neg = 0;
+
+  /* Compute asm1.  */
+  if ((an & 1) == 0) /* s == n */
+    {
+      if (mpn_cmp (a0, a1, n) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, n);
+	  vm1_neg = 1;
+	}
+      else
+	{
+	  mpn_sub_n (asm1, a0, a1, n);
+	}
+    }
+  else /* n - s == 1 */
+    {
+      if (a0[s] == 0 && mpn_cmp (a0, a1, s) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, s);
+	  asm1[s] = 0;
+	  vm1_neg = 1;
+	}
+      else
+	{
+	  asm1[s] = a0[s] - mpn_sub_n (asm1, a0, a1, s);
+	}
+    }
+
+  /* Compute bsm1.  */
+  if (t == n)
+    {
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	}
+    }
+  else
+    {
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	}
+    }
+
+#define v0	pp				/* 2n */
+#define vinf	(pp + 2 * n)			/* s+t */
+#define vm1	scratch				/* 2n */
+#define scratch_out	scratch + 2 * n
+
+  /* vm1, 2n limbs */
+  TOOM22_MUL_N_REC (vm1, asm1, bsm1, n, scratch_out);
+
+  if (s > t)  TOOM22_MUL_REC (vinf, a1, s, b1, t, scratch_out);
+  else        TOOM22_MUL_N_REC (vinf, a1, b1, s, scratch_out);
+
+  /* v0, 2n limbs */
+  TOOM22_MUL_N_REC (v0, ap, bp, n, scratch_out);
+
+  /* H(v0) + L(vinf) */
+  cy = mpn_add_n (pp + 2 * n, v0 + n, vinf, n);
+
+  /* L(v0) + (H(v0) + L(vinf)) */
+  cy2 = cy + mpn_add_n (pp + n, pp + 2 * n, v0, n);
+
+  /* (H(v0) + L(vinf)) + H(vinf) */
+  cy += mpn_add (pp + 2 * n, pp + 2 * n, n, vinf + n, s + t - n);
+
+  if (vm1_neg)
+    cy += mpn_add_n (pp + n, pp + n, vm1, 2 * n);
+  else {
+    cy -= mpn_sub_n (pp + n, pp + n, vm1, 2 * n);
+    if (UNLIKELY (cy + 1 == 0)) { /* cy is negative */
+      /* The total contribution of v0+vinf-vm1 can not be negative. */
+#if WANT_ASSERT
+      /* The borrow in cy stops the propagation of the carry cy2, */
+      ASSERT (cy2 == 1);
+      cy += mpn_add_1 (pp + 2 * n, pp + 2 * n, n, cy2);
+      ASSERT (cy == 0);
+#else
+      /* we simply fill the area with zeros. */
+      MPN_FILL (pp + 2 * n, n, 0);
+      /* ASSERT (s + t == n || mpn_zero_p (pp + 3 * n, s + t - n)); */
+#endif
+      return;
+    }
+  }
+
+  ASSERT (cy  <= 2);
+  ASSERT (cy2 <= 2);
+
+  MPN_INCR_U (pp + 2 * n, s + t, cy2);
+  /* if s+t==n, cy is zero, but we should not access pp[3*n] at all. */
+  MPN_INCR_U (pp + 3 * n, s + t - n, cy);
+}
diff --git a/mpn/generic/toom2_sqr.c b/mpn/generic/toom2_sqr.c
new file mode 100644
index 0000000..db7a846
--- /dev/null
+++ b/mpn/generic/toom2_sqr.c
@@ -0,0 +1,155 @@
+/* mpn_toom2_sqr -- Square {ap,an}.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2012, 2014, 2018, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +inf
+
+  <-s--><--n-->
+   ____ ______
+  |_a1_|___a0_|
+
+  v0  =  a0     ^2  #   A(0)^2
+  vm1 = (a0- a1)^2  #  A(-1)^2
+  vinf=      a1 ^2  # A(inf)^2
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_sqr_toom2   1
+#else
+#define MAYBE_sqr_toom2							\
+  (SQR_TOOM3_THRESHOLD >= 2 * SQR_TOOM2_THRESHOLD)
+#endif
+
+#define TOOM2_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (! MAYBE_sqr_toom2						\
+	|| BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else								\
+      mpn_toom2_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom2_sqr (mp_ptr pp,
+	       mp_srcptr ap, mp_size_t an,
+	       mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s;
+  mp_limb_t cy, cy2;
+  mp_ptr asm1;
+
+#define a0  ap
+#define a1  (ap + n)
+
+  s = an >> 1;
+  n = an - s;
+
+  ASSERT (0 < s && s <= n && (n - s) == (an & 1));
+
+  asm1 = pp;
+
+  /* Compute asm1.  */
+  if ((an & 1) == 0) /* s == n */
+    {
+      if (mpn_cmp (a0, a1, n) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, n);
+	}
+      else
+	{
+	  mpn_sub_n (asm1, a0, a1, n);
+	}
+    }
+  else /* n - s == 1 */
+    {
+      if (a0[s] == 0 && mpn_cmp (a0, a1, s) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, s);
+	  asm1[s] = 0;
+	}
+      else
+	{
+	  asm1[s] = a0[s] - mpn_sub_n (asm1, a0, a1, s);
+	}
+    }
+
+#define v0	pp				/* 2n */
+#define vinf	(pp + 2 * n)			/* s+s */
+#define vm1	scratch				/* 2n */
+#define scratch_out	scratch + 2 * n
+
+  /* vm1, 2n limbs */
+  TOOM2_SQR_REC (vm1, asm1, n, scratch_out);
+
+  /* vinf, s+s limbs */
+  TOOM2_SQR_REC (vinf, a1, s, scratch_out);
+
+  /* v0, 2n limbs */
+  TOOM2_SQR_REC (v0, ap, n, scratch_out);
+
+  /* H(v0) + L(vinf) */
+  cy = mpn_add_n (pp + 2 * n, v0 + n, vinf, n);
+
+  /* L(v0) + H(v0) */
+  cy2 = cy + mpn_add_n (pp + n, pp + 2 * n, v0, n);
+
+  /* L(vinf) + H(vinf) */
+  cy += mpn_add (pp + 2 * n, pp + 2 * n, n, vinf + n, s + s - n);
+
+  cy -= mpn_sub_n (pp + n, pp + n, vm1, 2 * n);
+
+  ASSERT (cy + 1 <= 3);
+  ASSERT (cy2 <= 2);
+
+  if (LIKELY (cy <= 2)) {
+    MPN_INCR_U (pp + 2 * n, s + s, cy2);
+    MPN_INCR_U (pp + 3 * n, s + s - n, cy);
+  } else { /* cy is negative */
+    /* The total contribution of v0+vinf-vm1 can not be negative. */
+#if WANT_ASSERT
+    /* The borrow in cy stops the propagation of the carry cy2, */
+    ASSERT (cy2 == 1);
+    cy += mpn_add_1 (pp + 2 * n, pp + 2 * n, n, cy2);
+    ASSERT (cy == 0);
+#else
+    /* we simply fill the area with zeros. */
+    MPN_FILL (pp + 2 * n, n, 0);
+#endif
+  }
+}
diff --git a/mpn/generic/toom32_mul.c b/mpn/generic/toom32_mul.c
new file mode 100644
index 0000000..1139d17
--- /dev/null
+++ b/mpn/generic/toom32_mul.c
@@ -0,0 +1,320 @@
+/* mpn_toom32_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 1.5
+   times as large as bn.  Or more accurately, bn < an < 3bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Improvements by Marco Bodrato and Niels Möller.
+
+   The idea of applying Toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2020, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +inf
+
+  <-s-><--n--><--n-->
+   ___ ______ ______
+  |a2_|___a1_|___a0_|
+	|_b1_|___b0_|
+	<-t--><--n-->
+
+  v0  =  a0         * b0      #   A(0)*B(0)
+  v1  = (a0+ a1+ a2)*(b0+ b1) #   A(1)*B(1)      ah  <= 2  bh <= 1
+  vm1 = (a0- a1+ a2)*(b0- b1) #  A(-1)*B(-1)    |ah| <= 1  bh = 0
+  vinf=          a2 *     b1  # A(inf)*B(inf)
+*/
+
+#define TOOM32_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    mpn_mul_n (p, a, b, n);						\
+  } while (0)
+
+void
+mpn_toom32_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy;
+  mp_limb_signed_t hi;
+  mp_limb_t ap1_hi, bp1_hi;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2 * n)
+#define b0  bp
+#define b1  (bp + n)
+
+  /* Required, to ensure that s + t >= n. */
+  ASSERT (bn + 2 <= an && an + 6 <= 3*bn);
+
+  n = 2 * an >= 3 * bn ? (an + 2) / (size_t) 3 : (bn + 1) >> 1;
+
+  s = an - 2 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (s + t >= n);
+
+  /* Product area of size an + bn = 3*n + s + t >= 4*n + 2. */
+#define ap1 (pp)		/* n, most significant limb in ap1_hi */
+#define bp1 (pp + n)		/* n, most significant bit in bp1_hi */
+#define am1 (pp + 2*n)		/* n, most significant bit in hi */
+#define bm1 (pp + 3*n)		/* n */
+#define v1 (scratch)		/* 2n + 1 */
+#define vm1 (pp)		/* 2n + 1 */
+#define scratch_out (scratch + 2*n + 1) /* Currently unused. */
+
+  /* Scratch need: 2*n + 1 + scratch for the recursive multiplications. */
+
+  /* FIXME: Keep v1[2*n] and vm1[2*n] in scalar variables? */
+
+  /* Compute ap1 = a0 + a1 + a2, am1 = a0 - a1 + a2 */
+  ap1_hi = mpn_add (ap1, a0, n, a2, s);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (ap1_hi == 0 && mpn_cmp (ap1, a1, n) < 0)
+    {
+      ap1_hi = mpn_add_n_sub_n (ap1, am1, a1, ap1, n) >> 1;
+      hi = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      cy = mpn_add_n_sub_n (ap1, am1, ap1, a1, n);
+      hi = ap1_hi - (cy & 1);
+      ap1_hi += (cy >> 1);
+      vm1_neg = 0;
+    }
+#else
+  if (ap1_hi == 0 && mpn_cmp (ap1, a1, n) < 0)
+    {
+      ASSERT_NOCARRY (mpn_sub_n (am1, a1, ap1, n));
+      hi = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      hi = ap1_hi - mpn_sub_n (am1, ap1, a1, n);
+      vm1_neg = 0;
+    }
+  ap1_hi += mpn_add_n (ap1, ap1, a1, n);
+#endif
+
+  /* Compute bp1 = b0 + b1 and bm1 = b0 - b1. */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bp1, bm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bp1, bm1, b0, b1, n);
+	}
+      bp1_hi = cy >> 1;
+#else
+      bp1_hi = mpn_add_n (bp1, b0, b1, n);
+
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  ASSERT_NOCARRY (mpn_sub_n (bm1, b1, b0, n));
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  ASSERT_NOCARRY (mpn_sub_n (bm1, b0, b1, n));
+	}
+#endif
+    }
+  else
+    {
+      /* FIXME: Should still use mpn_add_n_sub_n for the main part. */
+      bp1_hi = mpn_add (bp1, b0, n, b1, t);
+
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  ASSERT_NOCARRY (mpn_sub_n (bm1, b1, b0, t));
+	  MPN_ZERO (bm1 + t, n - t);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  ASSERT_NOCARRY (mpn_sub (bm1, b0, n, b1, t));
+	}
+    }
+
+  TOOM32_MUL_N_REC (v1, ap1, bp1, n, scratch_out);
+  if (ap1_hi == 1)
+    {
+      cy = mpn_add_n (v1 + n, v1 + n, bp1, n);
+    }
+  else if (ap1_hi > 1) /* ap1_hi == 2 */
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = mpn_addlsh1_n_ip1 (v1 + n, bp1, n);
+#else
+      cy = mpn_addmul_1 (v1 + n, bp1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (bp1_hi != 0)
+    cy += ap1_hi + mpn_add_n (v1 + n, v1 + n, ap1, n);
+  v1[2 * n] = cy;
+
+  TOOM32_MUL_N_REC (vm1, am1, bm1, n, scratch_out);
+  if (hi)
+    hi = mpn_add_n (vm1+n, vm1+n, bm1, n);
+
+  vm1[2*n] = hi;
+
+  /* v1 <-- (v1 + vm1) / 2 = x0 + x2 */
+  if (vm1_neg)
+    {
+#if HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (v1, v1, vm1, 2*n+1);
+#else
+      mpn_sub_n (v1, v1, vm1, 2*n+1);
+      ASSERT_NOCARRY (mpn_rshift (v1, v1, 2*n+1, 1));
+#endif
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (v1, v1, vm1, 2*n+1);
+#else
+      mpn_add_n (v1, v1, vm1, 2*n+1);
+      ASSERT_NOCARRY (mpn_rshift (v1, v1, 2*n+1, 1));
+#endif
+    }
+
+  /* We get x1 + x3 = (x0 + x2) - (x0 - x1 + x2 - x3), and hence
+
+     y = x1 + x3 + (x0 + x2) * B
+       = (x0 + x2) * B + (x0 + x2) - vm1.
+
+     y is 3*n + 1 limbs, y = y0 + y1 B + y2 B^2. We store them as
+     follows: y0 at scratch, y1 at pp + 2*n, and y2 at scratch + n
+     (already in place, except for carry propagation).
+
+     We thus add
+
+   B^3  B^2   B    1
+    |    |    |    |
+   +-----+----+
+ + |  x0 + x2 |
+   +----+-----+----+
+ +      |  x0 + x2 |
+	+----------+
+ -      |  vm1     |
+ --+----++----+----+-
+   | y2  | y1 | y0 |
+   +-----+----+----+
+
+  Since we store y0 at the same location as the low half of x0 + x2, we
+  need to do the middle sum first. */
+
+  hi = vm1[2*n];
+  cy = mpn_add_n (pp + 2*n, v1, v1 + n, n);
+  MPN_INCR_U (v1 + n, n + 1, cy + v1[2*n]);
+
+  /* FIXME: Can we get rid of this second vm1_neg conditional by
+     swapping the location of +1 and -1 values? */
+  if (vm1_neg)
+    {
+      cy = mpn_add_n (v1, v1, vm1, n);
+      hi += mpn_add_nc (pp + 2*n, pp + 2*n, vm1 + n, n, cy);
+      MPN_INCR_U (v1 + n, n+1, hi);
+    }
+  else
+    {
+      cy = mpn_sub_n (v1, v1, vm1, n);
+      hi += mpn_sub_nc (pp + 2*n, pp + 2*n, vm1 + n, n, cy);
+      MPN_DECR_U (v1 + n, n+1, hi);
+    }
+
+  TOOM32_MUL_N_REC (pp, a0, b0, n, scratch_out);
+  /* vinf, s+t limbs.  Use mpn_mul for now, to handle unbalanced operands */
+  if (s > t)  mpn_mul (pp+3*n, a2, s, b1, t);
+  else        mpn_mul (pp+3*n, b1, t, a2, s);
+
+  /* Remaining interpolation.
+
+     y * B + x0 + x3 B^3 - x0 B^2 - x3 B
+     = (x1 + x3) B + (x0 + x2) B^2 + x0 + x3 B^3 - x0 B^2 - x3 B
+     = y0 B + y1 B^2 + y3 B^3 + Lx0 + H x0 B
+       + L x3 B^3 + H x3 B^4 - Lx0 B^2 - H x0 B^3 - L x3 B - H x3 B^2
+     = L x0 + (y0 + H x0 - L x3) B + (y1 - L x0 - H x3) B^2
+       + (y2 - (H x0 - L x3)) B^3 + H x3 B^4
+
+	  B^4       B^3       B^2        B         1
+ |         |         |         |         |         |
+   +-------+                   +---------+---------+
+   |  Hx3  |                   | Hx0-Lx3 |    Lx0  |
+   +------+----------+---------+---------+---------+
+	  |    y2    |  y1     |   y0    |
+	  ++---------+---------+---------+
+	  -| Hx0-Lx3 | - Lx0   |
+	   +---------+---------+
+		      | - Hx3  |
+		      +--------+
+
+    We must take into account the carry from Hx0 - Lx3.
+  */
+
+  cy = mpn_sub_n (pp + n, pp + n, pp+3*n, n);
+  hi = scratch[2*n] + cy;
+
+  cy = mpn_sub_nc (pp + 2*n, pp + 2*n, pp, n, cy);
+  hi -= mpn_sub_nc (pp + 3*n, scratch + n, pp + n, n, cy);
+
+  hi += mpn_add (pp + n, pp + n, 3*n, scratch, n);
+
+  /* FIXME: Is support for s + t == n needed? */
+  if (LIKELY (s + t > n))
+    {
+      hi -= mpn_sub (pp + 2*n, pp + 2*n, 2*n, pp + 4*n, s+t-n);
+
+      ASSERT (hi >= 0); /* contribution of the middle terms >= 0 */
+      MPN_INCR_U (pp + 4*n, s+t-n, hi);
+    }
+  else
+    ASSERT (hi == 0);
+}
diff --git a/mpn/generic/toom33_mul.c b/mpn/generic/toom33_mul.c
new file mode 100644
index 0000000..54f055f
--- /dev/null
+++ b/mpn/generic/toom33_mul.c
@@ -0,0 +1,316 @@
+/* mpn_toom33_mul -- Multiply {ap,an} and {p,bn} where an and bn are close in
+   size.  Or more accurately, bn <= an < (3/2)bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Additional improvements by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2010, 2012, 2015, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +2, +inf
+
+  <-s--><--n--><--n-->
+   ____ ______ ______
+  |_a2_|___a1_|___a0_|
+   |b2_|___b1_|___b0_|
+   <-t-><--n--><--n-->
+
+  v0  =  a0         * b0          #   A(0)*B(0)
+  v1  = (a0+ a1+ a2)*(b0+ b1+ b2) #   A(1)*B(1)      ah  <= 2  bh <= 2
+  vm1 = (a0- a1+ a2)*(b0- b1+ b2) #  A(-1)*B(-1)    |ah| <= 1  bh <= 1
+  v2  = (a0+2a1+4a2)*(b0+2b1+4b2) #   A(2)*B(2)      ah  <= 6  bh <= 6
+  vinf=          a2 *         b2  # A(inf)*B(inf)
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom33   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM33_THRESHOLD < 3 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom33						\
+  (MUL_TOOM44_THRESHOLD >= 3 * MUL_TOOM33_THRESHOLD)
+#endif
+
+/* FIXME: TOOM33_MUL_N_REC is not quite right for a balanced
+   multiplication at the infinity point. We may have
+   MAYBE_mul_basecase == 0, and still get s just below
+   MUL_TOOM22_THRESHOLD. If MUL_TOOM33_THRESHOLD == 7, we can even get
+   s == 1 and mpn_toom22_mul will crash.
+*/
+
+#define TOOM33_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+    else if (! MAYBE_mul_toom33						\
+	     || BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+    else								\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+  } while (0)
+
+void
+mpn_toom33_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy, vinf0;
+  mp_ptr gp;
+  mp_ptr as1, asm1, as2;
+  mp_ptr bs1, bsm1, bs2;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2*n)
+
+  n = (an + 2) / (size_t) 3;
+
+  s = an - 2 * n;
+  t = bn - 2 * n;
+
+  ASSERT (an >= bn);
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  as1  = scratch + 4 * n + 4;
+  asm1 = scratch + 2 * n + 2;
+  as2 = pp + n + 1;
+
+  bs1 = pp;
+  bsm1 = scratch + 3 * n + 3; /* we need 4n+4 <= 4n+s+t */
+  bs2 = pp + 2 * n + 2;
+
+  gp = scratch;
+
+  vm1_neg = 0;
+
+  /* Compute as1 and asm1.  */
+  cy = mpn_add (gp, a0, n, a2, s);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (as1, asm1, a1, gp, n);
+      as1[n] = cy >> 1;
+      asm1[n] = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (as1, asm1, gp, a1, n);
+      as1[n] = cy + (cy2 >> 1);
+      asm1[n] = cy - (cy2 & 1);
+    }
+#else
+  as1[n] = cy + mpn_add_n (as1, gp, a1, n);
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      mpn_sub_n (asm1, a1, gp, n);
+      asm1[n] = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      cy -= mpn_sub_n (asm1, gp, a1, n);
+      asm1[n] = cy;
+    }
+#endif
+
+  /* Compute as2.  */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_rsblsh1_n (as2, a0, as2, n);
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (as2, a1, a2, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a1 + s, n - s, cy);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a0, as2, n);
+#else
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy -= mpn_sub_n (as2, as2, a0, n);
+#endif
+#endif
+  as2[n] = cy;
+
+  /* Compute bs1 and bsm1.  */
+  cy = mpn_add (gp, b0, n, b2, t);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (gp, b1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, b1, gp, n);
+      bs1[n] = cy >> 1;
+      bsm1[n] = 0;
+      vm1_neg ^= 1;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (bs1, bsm1, gp, b1, n);
+      bs1[n] = cy + (cy2 >> 1);
+      bsm1[n] = cy - (cy2 & 1);
+    }
+#else
+  bs1[n] = cy + mpn_add_n (bs1, gp, b1, n);
+  if (cy == 0 && mpn_cmp (gp, b1, n) < 0)
+    {
+      mpn_sub_n (bsm1, b1, gp, n);
+      bsm1[n] = 0;
+      vm1_neg ^= 1;
+    }
+  else
+    {
+      cy -= mpn_sub_n (bsm1, gp, b1, n);
+      bsm1[n] = cy;
+    }
+#endif
+
+  /* Compute bs2.  */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  cy = mpn_add_n (bs2, b2, bs1, t);
+  if (t != n)
+    cy = mpn_add_1 (bs2 + t, bs1 + t, n - t, cy);
+  cy += bs1[n];
+  cy = 2 * cy + mpn_rsblsh1_n (bs2, b0, bs2, n);
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (bs2, b1, b2, t);
+  if (t != n)
+    cy = mpn_add_1 (bs2 + t, b1 + t, n - t, cy);
+  cy = 2 * cy + mpn_addlsh1_n (bs2, b0, bs2, n);
+#else
+  cy  = mpn_add_n (bs2, bs1, b2, t);
+  if (t != n)
+    cy = mpn_add_1 (bs2 + t, bs1 + t, n - t, cy);
+  cy += bs1[n];
+  cy = 2 * cy + mpn_lshift (bs2, bs2, n, 1);
+  cy -= mpn_sub_n (bs2, bs2, b0, n);
+#endif
+#endif
+  bs2[n] = cy;
+
+  ASSERT (as1[n] <= 2);
+  ASSERT (bs1[n] <= 2);
+  ASSERT (asm1[n] <= 1);
+  ASSERT (bsm1[n] <= 1);
+  ASSERT (as2[n] <= 6);
+  ASSERT (bs2[n] <= 6);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 4 * n)			/* s+t */
+#define vm1   scratch				/* 2n+1 */
+#define v2    (scratch + 2 * n + 1)		/* 2n+2 */
+#define scratch_out  (scratch + 5 * n + 5)
+
+  /* vm1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  TOOM33_MUL_N_REC (vm1, asm1, bsm1, n, scratch_out);
+  cy = 0;
+  if (asm1[n] != 0)
+    cy = bsm1[n] + mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+  if (bsm1[n] != 0)
+    cy += mpn_add_n (vm1 + n, vm1 + n, asm1, n);
+  vm1[2 * n] = cy;
+#else
+  vm1[2 * n] = 0;
+  TOOM33_MUL_N_REC (vm1, asm1, bsm1, n + (bsm1[n] | asm1[n]), scratch_out);
+#endif
+
+  TOOM33_MUL_N_REC (v2, as2, bs2, n + 1, scratch_out);	/* v2, 2n+1 limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a2, s, b2, t);
+  else        TOOM33_MUL_N_REC (vinf, a2, b2, s, scratch_out);
+
+  vinf0 = vinf[0];				/* v1 overlaps with this */
+
+#ifdef SMALLER_RECURSION
+  /* v1, 2n+1 limbs */
+  TOOM33_MUL_N_REC (v1, as1, bs1, n, scratch_out);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * bs1[n] + mpn_addlsh1_n_ip1 (v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (bs1[n] == 1)
+    {
+      cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+    }
+  else if (bs1[n] != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy += mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  v1[2 * n] = cy;
+#else
+  cy = vinf[1];
+  TOOM33_MUL_N_REC (v1, as1, bs1, n + 1, scratch_out);
+  vinf[1] = cy;
+#endif
+
+  TOOM33_MUL_N_REC (v0, ap, bp, n, scratch_out);	/* v0, 2n limbs */
+
+  mpn_toom_interpolate_5pts (pp, v2, vm1, n, s + t, vm1_neg, vinf0);
+}
diff --git a/mpn/generic/toom3_sqr.c b/mpn/generic/toom3_sqr.c
new file mode 100644
index 0000000..297a27f
--- /dev/null
+++ b/mpn/generic/toom3_sqr.c
@@ -0,0 +1,221 @@
+/* mpn_toom3_sqr -- Square {ap,an}.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Additional improvements by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2012, 2015, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +2, +inf
+
+  <-s--><--n--><--n-->
+   ____ ______ ______
+  |_a2_|___a1_|___a0_|
+
+  v0  =  a0         ^2 #   A(0)^2
+  v1  = (a0+ a1+ a2)^2 #   A(1)^2    ah  <= 2
+  vm1 = (a0- a1+ a2)^2 #  A(-1)^2   |ah| <= 1
+  v2  = (a0+2a1+4a2)^2 #   A(2)^2    ah  <= 6
+  vinf=          a2 ^2 # A(inf)^2
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_toom3   1
+#else
+#define MAYBE_sqr_basecase						\
+  (SQR_TOOM3_THRESHOLD < 3 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom3							\
+  (SQR_TOOM4_THRESHOLD >= 3 * SQR_TOOM3_THRESHOLD)
+#endif
+
+#define TOOM3_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (MAYBE_sqr_basecase						\
+	&& BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else if (! MAYBE_sqr_toom3						\
+	     || BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+    else								\
+      mpn_toom3_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom3_sqr (mp_ptr pp,
+	       mp_srcptr ap, mp_size_t an,
+	       mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s;
+  mp_limb_t cy, vinf0;
+  mp_ptr gp;
+  mp_ptr as1, asm1, as2;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+
+  n = (an + 2) / (size_t) 3;
+
+  s = an - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+
+  as1 = scratch + 4 * n + 4;
+  asm1 = scratch + 2 * n + 2;
+  as2 = pp + n + 1;
+
+  gp = scratch;
+
+  /* Compute as1 and asm1.  */
+  cy = mpn_add (gp, a0, n, a2, s);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (as1, asm1, a1, gp, n);
+      as1[n] = cy >> 1;
+      asm1[n] = 0;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (as1, asm1, gp, a1, n);
+      as1[n] = cy + (cy2 >> 1);
+      asm1[n] = cy - (cy2 & 1);
+    }
+#else
+  as1[n] = cy + mpn_add_n (as1, gp, a1, n);
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      mpn_sub_n (asm1, a1, gp, n);
+      asm1[n] = 0;
+    }
+  else
+    {
+      cy -= mpn_sub_n (asm1, gp, a1, n);
+      asm1[n] = cy;
+    }
+#endif
+
+  /* Compute as2.  */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_rsblsh1_n (as2, a0, as2, n);
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (as2, a1, a2, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a1 + s, n - s, cy);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a0, as2, n);
+#else
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy -= mpn_sub_n (as2, as2, a0, n);
+#endif
+#endif
+  as2[n] = cy;
+
+  ASSERT (as1[n] <= 2);
+  ASSERT (asm1[n] <= 1);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 4 * n)			/* s+s */
+#define vm1   scratch				/* 2n+1 */
+#define v2    (scratch + 2 * n + 1)		/* 2n+2 */
+#define scratch_out  (scratch + 5 * n + 5)
+
+  /* vm1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  TOOM3_SQR_REC (vm1, asm1, n, scratch_out);
+  cy = asm1[n];
+  if (cy != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (vm1 + n, asm1, n);
+#else
+      cy += mpn_addmul_1 (vm1 + n, asm1, n, CNST_LIMB(2));
+#endif
+    }
+  vm1[2 * n] = cy;
+#else
+  vm1[2 * n] = 0;
+  TOOM3_SQR_REC (vm1, asm1, n + asm1[n], scratch_out);
+#endif
+
+  TOOM3_SQR_REC (v2, as2, n + 1, scratch_out);	/* v2, 2n+1 limbs */
+
+  TOOM3_SQR_REC (vinf, a2, s, scratch_out);	/* vinf, s+s limbs */
+
+  vinf0 = vinf[0];				/* v1 overlaps with this */
+
+#ifdef SMALLER_RECURSION
+  /* v1, 2n+1 limbs */
+  TOOM3_SQR_REC (v1, as1, n, scratch_out);
+  cy = as1[n];
+  if (cy == 1)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy += mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (cy != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+      cy = 4 + mpn_addlsh2_n_ip1 (v1 + n, as1, n);
+#else
+      cy = 4 + mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(4));
+#endif
+    }
+  v1[2 * n] = cy;
+#else
+  cy = vinf[1];
+  TOOM3_SQR_REC (v1, as1, n + 1, scratch_out);
+  vinf[1] = cy;
+#endif
+
+  TOOM3_SQR_REC (v0, ap, n, scratch_out);	/* v0, 2n limbs */
+
+  mpn_toom_interpolate_5pts (pp, v2, vm1, n, s + s, 0, vinf0);
+}
diff --git a/mpn/generic/toom42_mul.c b/mpn/generic/toom42_mul.c
new file mode 100644
index 0000000..e84ce65
--- /dev/null
+++ b/mpn/generic/toom42_mul.c
@@ -0,0 +1,234 @@
+/* mpn_toom42_mul -- Multiply {ap,an} and {bp,bn} where an is nominally twice
+   as large as bn.  Or more accurately, (3/2)bn < an < 4bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Additional improvements by Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +2, +inf
+
+  <-s-><--n--><--n--><--n-->
+   ___ ______ ______ ______
+  |a3_|___a2_|___a1_|___a0_|
+	       |_b1_|___b0_|
+	       <-t--><--n-->
+
+  v0  =  a0             * b0      #   A(0)*B(0)
+  v1  = (a0+ a1+ a2+ a3)*(b0+ b1) #   A(1)*B(1)      ah  <= 3  bh <= 1
+  vm1 = (a0- a1+ a2- a3)*(b0- b1) #  A(-1)*B(-1)    |ah| <= 1  bh  = 0
+  v2  = (a0+2a1+4a2+8a3)*(b0+2b1) #   A(2)*B(2)      ah  <= 14 bh <= 2
+  vinf=              a3 *     b1  # A(inf)*B(inf)
+*/
+
+#define TOOM42_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    mpn_mul_n (p, a, b, n);						\
+  } while (0)
+
+void
+mpn_toom42_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy, vinf0;
+  mp_ptr a0_a2;
+  mp_ptr as1, asm1, as2;
+  mp_ptr bs1, bsm1, bs2;
+  mp_ptr tmp;
+  TMP_DECL;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define b0  bp
+#define b1  (bp + n)
+
+  n = an >= 2 * bn ? (an + 3) >> 2 : (bn + 1) >> 1;
+
+  s = an - 3 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  TMP_MARK;
+
+  tmp = TMP_ALLOC_LIMBS (6 * n + 5);
+  as1  = tmp; tmp += n + 1;
+  asm1 = tmp; tmp += n + 1;
+  as2  = tmp; tmp += n + 1;
+  bs1  = tmp; tmp += n + 1;
+  bsm1 = tmp; tmp += n;
+  bs2  = tmp; tmp += n + 1;
+
+  a0_a2 = pp;
+
+  /* Compute as1 and asm1.  */
+  vm1_neg = mpn_toom_eval_dgr3_pm1 (as1, asm1, ap, n, s, a0_a2) & 1;
+
+  /* Compute as2.  */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (as2, a2, a3, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a2 + s, n - s, cy);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a1, as2, n);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a0, as2, n);
+#else
+  cy  = mpn_lshift (as2, a3, s, 1);
+  cy += mpn_add_n (as2, a2, as2, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a2 + s, n - s, cy);
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy += mpn_add_n (as2, a1, as2, n);
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy += mpn_add_n (as2, a0, as2, n);
+#endif
+  as2[n] = cy;
+
+  /* Compute bs1 and bsm1.  */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b0, b1, n);
+	}
+      bs1[n] = cy >> 1;
+#else
+      bs1[n] = mpn_add_n (bs1, b0, b1, n);
+
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	}
+#endif
+    }
+  else
+    {
+      bs1[n] = mpn_add (bs1, b0, n, b1, t);
+
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	}
+    }
+
+  /* Compute bs2, recycling bs1. bs2=bs1+b1  */
+  mpn_add (bs2, bs1, n + 1, b1, t);
+
+  ASSERT (as1[n] <= 3);
+  ASSERT (bs1[n] <= 1);
+  ASSERT (asm1[n] <= 1);
+/*ASSERT (bsm1[n] == 0);*/
+  ASSERT (as2[n] <= 14);
+  ASSERT (bs2[n] <= 2);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 4 * n)			/* s+t */
+#define vm1   scratch				/* 2n+1 */
+#define v2    (scratch + 2 * n + 1)		/* 2n+2 */
+#define scratch_out	scratch + 4 * n + 4	/* Currently unused. */
+
+  /* vm1, 2n+1 limbs */
+  TOOM42_MUL_N_REC (vm1, asm1, bsm1, n, scratch_out);
+  cy = 0;
+  if (asm1[n] != 0)
+    cy = mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+  vm1[2 * n] = cy;
+
+  TOOM42_MUL_N_REC (v2, as2, bs2, n + 1, scratch_out);	/* v2, 2n+1 limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a3, s, b1, t);
+  else        mpn_mul (vinf, b1, t, a3, s);
+
+  vinf0 = vinf[0];				/* v1 overlaps with this */
+
+  /* v1, 2n+1 limbs */
+  TOOM42_MUL_N_REC (v1, as1, bs1, n, scratch_out);
+  if (as1[n] == 1)
+    {
+      cy = mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = mpn_addlsh1_n_ip1 (v1 + n, bs1, n);
+#else
+      cy = mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (as1[n] == 3)
+    {
+      cy = mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(3));
+    }
+  else
+    cy = 0;
+  if (bs1[n] != 0)
+    cy += as1[n] + mpn_add_n (v1 + n, v1 + n, as1, n);
+  v1[2 * n] = cy;
+
+  TOOM42_MUL_N_REC (v0, ap, bp, n, scratch_out);	/* v0, 2n limbs */
+
+  mpn_toom_interpolate_5pts (pp, v2, vm1, n, s + t, vm1_neg, vinf0);
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/toom42_mulmid.c b/mpn/generic/toom42_mulmid.c
new file mode 100644
index 0000000..f581b10
--- /dev/null
+++ b/mpn/generic/toom42_mulmid.c
@@ -0,0 +1,237 @@
+/* mpn_toom42_mulmid -- toom42 middle product
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+
+/*
+  Middle product of {ap,2n-1} and {bp,n}, output written to {rp,n+2}.
+
+  Neither ap nor bp may overlap rp.
+
+  Must have n >= 4.
+
+  Amount of scratch space required is given by mpn_toom42_mulmid_itch().
+
+  FIXME: this code assumes that n is small compared to GMP_NUMB_MAX. The exact
+  requirements should be clarified.
+*/
+void
+mpn_toom42_mulmid (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n,
+                   mp_ptr scratch)
+{
+  mp_limb_t cy, e[12], zh, zl;
+  mp_size_t m;
+  int neg;
+
+  ASSERT (n >= 4);
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, ap, 2*n - 1));
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, bp, n));
+
+  ap += n & 1;   /* handle odd row and diagonal later */
+  m = n / 2;
+
+  /* (e0h:e0l) etc are correction terms, in 2's complement */
+#define e0l (e[0])
+#define e0h (e[1])
+#define e1l (e[2])
+#define e1h (e[3])
+#define e2l (e[4])
+#define e2h (e[5])
+#define e3l (e[6])
+#define e3h (e[7])
+#define e4l (e[8])
+#define e4h (e[9])
+#define e5l (e[10])
+#define e5h (e[11])
+
+#define s (scratch + 2)
+#define t (rp + m + 2)
+#define p0 rp
+#define p1 scratch
+#define p2 (rp + m)
+#define next_scratch (scratch + 3*m + 1)
+
+  /*
+            rp                            scratch
+  |---------|-----------|    |---------|---------|----------|
+  0         m         2m+2   0         m         2m        3m+1
+            <----p2---->       <-------------s------------->
+  <----p0----><---t---->     <----p1---->
+  */
+
+  /* compute {s,3m-1} = {a,3m-1} + {a+m,3m-1} and error terms e0, e1, e2, e3 */
+  cy = mpn_add_err1_n (s, ap, ap + m, &e0l, bp + m, m - 1, 0);
+  cy = mpn_add_err2_n (s + m - 1, ap + m - 1, ap + 2*m - 1, &e1l,
+		       bp + m, bp, m, cy);
+  mpn_add_err1_n (s + 2*m - 1, ap + 2*m - 1, ap + 3*m - 1, &e3l, bp, m, cy);
+
+  /* compute t = (-1)^neg * ({b,m} - {b+m,m}) and error terms e4, e5 */
+  if (mpn_cmp (bp + m, bp, m) < 0)
+    {
+      ASSERT_NOCARRY (mpn_sub_err2_n (t, bp, bp + m, &e4l,
+				      ap + m - 1, ap + 2*m - 1, m, 0));
+      neg = 1;
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_err2_n (t, bp + m, bp, &e4l,
+				      ap + m - 1, ap + 2*m - 1, m, 0));
+      neg = 0;
+    }
+
+  /* recursive middle products. The picture is:
+
+      b[2m-1]   A   A   A   B   B   B   -   -   -   -   -
+      ...       -   A   A   A   B   B   B   -   -   -   -
+      b[m]      -   -   A   A   A   B   B   B   -   -   -
+      b[m-1]    -   -   -   C   C   C   D   D   D   -   -
+      ...       -   -   -   -   C   C   C   D   D   D   -
+      b[0]      -   -   -   -   -   C   C   C   D   D   D
+               a[0]   ...  a[m]  ...  a[2m]    ...    a[4m-2]
+  */
+
+  if (m < MULMID_TOOM42_THRESHOLD)
+    {
+      /* A + B */
+      mpn_mulmid_basecase (p0, s, 2*m - 1, bp + m, m);
+      /* accumulate high limbs of p0 into e1 */
+      ADDC_LIMB (cy, e1l, e1l, p0[m]);
+      e1h += p0[m + 1] + cy;
+      /* (-1)^neg * (B - C)   (overwrites first m limbs of s) */
+      mpn_mulmid_basecase (p1, ap + m, 2*m - 1, t, m);
+      /* C + D   (overwrites t) */
+      mpn_mulmid_basecase (p2, s + m, 2*m - 1, bp, m);
+    }
+  else
+    {
+      /* as above, but use toom42 instead */
+      mpn_toom42_mulmid (p0, s, bp + m, m, next_scratch);
+      ADDC_LIMB (cy, e1l, e1l, p0[m]);
+      e1h += p0[m + 1] + cy;
+      mpn_toom42_mulmid (p1, ap + m, t, m, next_scratch);
+      mpn_toom42_mulmid (p2, s + m, bp, m, next_scratch);
+    }
+
+  /* apply error terms */
+
+  /* -e0 at rp[0] */
+  SUBC_LIMB (cy, rp[0], rp[0], e0l);
+  SUBC_LIMB (cy, rp[1], rp[1], e0h + cy);
+  if (UNLIKELY (cy))
+    {
+      cy = (m > 2) ? mpn_sub_1 (rp + 2, rp + 2, m - 2, 1) : 1;
+      SUBC_LIMB (cy, e1l, e1l, cy);
+      e1h -= cy;
+    }
+
+  /* z = e1 - e2 + high(p0) */
+  SUBC_LIMB (cy, zl, e1l, e2l);
+  zh = e1h - e2h - cy;
+
+  /* z at rp[m] */
+  ADDC_LIMB (cy, rp[m], rp[m], zl);
+  zh = (zh + cy) & GMP_NUMB_MASK;
+  ADDC_LIMB (cy, rp[m + 1], rp[m + 1], zh);
+  cy -= (zh >> (GMP_NUMB_BITS - 1));
+  if (UNLIKELY (cy))
+    {
+      if (cy == 1)
+	mpn_add_1 (rp + m + 2, rp + m + 2, m, 1);
+      else /* cy == -1 */
+	mpn_sub_1 (rp + m + 2, rp + m + 2, m, 1);
+    }
+
+  /* e3 at rp[2*m] */
+  ADDC_LIMB (cy, rp[2*m], rp[2*m], e3l);
+  rp[2*m + 1] = (rp[2*m + 1] + e3h + cy) & GMP_NUMB_MASK;
+
+  /* e4 at p1[0] */
+  ADDC_LIMB (cy, p1[0], p1[0], e4l);
+  ADDC_LIMB (cy, p1[1], p1[1], e4h + cy);
+  if (UNLIKELY (cy))
+    mpn_add_1 (p1 + 2, p1 + 2, m, 1);
+
+  /* -e5 at p1[m] */
+  SUBC_LIMB (cy, p1[m], p1[m], e5l);
+  p1[m + 1] = (p1[m + 1] - e5h - cy) & GMP_NUMB_MASK;
+
+  /* adjustment if p1 ends up negative */
+  cy = (p1[m + 1] >> (GMP_NUMB_BITS - 1));
+
+  /* add (-1)^neg * (p1 - B^m * p1) to output */
+  if (neg)
+    {
+      mpn_sub_1 (rp + m + 2, rp + m + 2, m, cy);
+      mpn_add (rp, rp, 2*m + 2, p1, m + 2);             /* A + C */
+      mpn_sub_n (rp + m, rp + m, p1, m + 2);            /* B + D */
+    }
+  else
+    {
+      mpn_add_1 (rp + m + 2, rp + m + 2, m, cy);
+      mpn_sub (rp, rp, 2*m + 2, p1, m + 2);             /* A + C */
+      mpn_add_n (rp + m, rp + m, p1, m + 2);            /* B + D */
+    }
+
+  /* odd row and diagonal */
+  if (n & 1)
+    {
+      /*
+        Products marked E are already done. We need to do products marked O.
+
+        OOOOO----
+        -EEEEO---
+        --EEEEO--
+        ---EEEEO-
+        ----EEEEO
+       */
+
+      /* first row of O's */
+      cy = mpn_addmul_1 (rp, ap - 1, n, bp[n - 1]);
+      ADDC_LIMB (rp[n + 1], rp[n], rp[n], cy);
+
+      /* O's on diagonal */
+      /* FIXME: should probably define an interface "mpn_mulmid_diag_1"
+         that can handle the sum below. Currently we're relying on
+         mulmid_basecase being pretty fast for a diagonal sum like this,
+	 which is true at least for the K8 asm version, but surely false
+	 for the generic version. */
+      mpn_mulmid_basecase (e, ap + n - 1, n - 1, bp, n - 1);
+      mpn_add_n (rp + n - 1, rp + n - 1, e, 3);
+    }
+}
diff --git a/mpn/generic/toom43_mul.c b/mpn/generic/toom43_mul.c
new file mode 100644
index 0000000..34acd25
--- /dev/null
+++ b/mpn/generic/toom43_mul.c
@@ -0,0 +1,238 @@
+/* mpn_toom43_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 4/3
+   times as large as bn.  Or more accurately, bn < an < 2 bn.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -2, -1, 0, +1, +2, +inf
+
+  <-s-><--n--><--n--><--n-->
+   ___ ______ ______ ______
+  |a3_|___a2_|___a1_|___a0_|
+	|_b2_|___b1_|___b0_|
+	<-t--><--n--><--n-->
+
+  v0  =  a0             * b0          #   A(0)*B(0)
+  v1  = (a0+ a1+ a2+ a3)*(b0+ b1+ b2) #   A(1)*B(1)      ah  <= 3  bh <= 2
+  vm1 = (a0- a1+ a2- a3)*(b0- b1+ b2) #  A(-1)*B(-1)    |ah| <= 1 |bh|<= 1
+  v2  = (a0+2a1+4a2+8a3)*(b0+2b1+4b2) #   A(2)*B(2)      ah  <= 14 bh <= 6
+  vm2 = (a0-2a1+4a2-8a3)*(b0-2b1+4b2) #  A(-2)*B(-2)    |ah| <= 9 |bh|<= 4
+  vinf=              a3 *         b2  # A(inf)*B(inf)
+*/
+
+void
+mpn_toom43_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  enum toom6_flags flags;
+  mp_limb_t cy;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2 * n)
+#define a3  (ap + 3 * n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2 * n)
+
+  n = 1 + (3 * an >= 4 * bn ? (an - 1) >> 2 : (bn - 1) / (size_t) 3);
+
+  s = an - 3 * n;
+  t = bn - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  /* This is true whenever an >= 25 or bn >= 19, I think. It
+     guarantees that we can fit 5 values of size n+1 in the product
+     area. */
+  ASSERT (s+t >= 5);
+
+#define v0    pp				/* 2n */
+#define vm1   (scratch)				/* 2n+1 */
+#define v1    (pp + 2*n)			/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define v2    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vinf  (pp + 5 * n)			/* s+t */
+#define bs1    pp				/* n+1 */
+#define bsm1  (scratch + 2 * n + 2)		/* n+1 */
+#define asm1  (scratch + 3 * n + 3)		/* n+1 */
+#define asm2  (scratch + 4 * n + 4)		/* n+1 */
+#define bsm2  (pp + n + 1)			/* n+1 */
+#define bs2   (pp + 2 * n + 2)			/* n+1 */
+#define as2   (pp + 3 * n + 3)			/* n+1 */
+#define as1   (pp + 4 * n + 4)			/* n+1 */
+
+  /* Total sccratch need is 6 * n + 3 + 1; we allocate one extra
+     limb, because products will overwrite 2n+2 limbs. */
+
+#define a0a2  scratch
+#define b0b2  scratch
+#define a1a3  asm1
+#define b1d   bsm1
+
+  /* Compute as2 and asm2.  */
+  flags = (enum toom6_flags) (toom6_vm2_neg & mpn_toom_eval_dgr3_pm2 (as2, asm2, ap, n, s, a1a3));
+
+  /* Compute bs2 and bsm2.  */
+  b1d[n] = mpn_lshift (b1d, b1, n, 1);			/*       2b1      */
+#if HAVE_NATIVE_mpn_addlsh2_n
+  cy = mpn_addlsh2_n (b0b2, b0, b2, t);			/*  4b2      + b0 */
+#else
+  cy  = mpn_lshift (b0b2, b2, t, 2);			/*  4b2           */
+  cy += mpn_add_n (b0b2, b0b2, b0, t);			/*  4b2      + b0 */
+#endif
+  if (t != n)
+    cy = mpn_add_1 (b0b2 + t, b0 + t, n - t, cy);
+  b0b2[n] = cy;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (mpn_cmp (b0b2, b1d, n+1) < 0)
+    {
+      mpn_add_n_sub_n (bs2, bsm2, b1d, b0b2, n+1);
+      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+    }
+  else
+    {
+      mpn_add_n_sub_n (bs2, bsm2, b0b2, b1d, n+1);
+    }
+#else
+  mpn_add_n (bs2, b0b2, b1d, n+1);
+  if (mpn_cmp (b0b2, b1d, n+1) < 0)
+    {
+      mpn_sub_n (bsm2, b1d, b0b2, n+1);
+      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+    }
+  else
+    {
+      mpn_sub_n (bsm2, b0b2, b1d, n+1);
+    }
+#endif
+
+  /* Compute as1 and asm1.  */
+  flags = (enum toom6_flags) (flags ^ (toom6_vm1_neg & mpn_toom_eval_dgr3_pm1 (as1, asm1, ap, n, s, a0a2)));
+
+  /* Compute bs1 and bsm1.  */
+  bsm1[n] = mpn_add (bsm1, b0, n, b2, t);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (bsm1[n] == 0 && mpn_cmp (bsm1, b1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, b1, bsm1, n);
+      bs1[n] = cy >> 1;
+      flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+    }
+  else
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, bsm1, b1, n);
+      bs1[n] = bsm1[n] + (cy >> 1);
+      bsm1[n]-= cy & 1;
+    }
+#else
+  bs1[n] = bsm1[n] + mpn_add_n (bs1, bsm1, b1, n);
+  if (bsm1[n] == 0 && mpn_cmp (bsm1, b1, n) < 0)
+    {
+      mpn_sub_n (bsm1, b1, bsm1, n);
+      flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+    }
+  else
+    {
+      bsm1[n] -= mpn_sub_n (bsm1, bsm1, b1, n);
+    }
+#endif
+
+  ASSERT (as1[n] <= 3);
+  ASSERT (bs1[n] <= 2);
+  ASSERT (asm1[n] <= 1);
+  ASSERT (bsm1[n] <= 1);
+  ASSERT (as2[n] <=14);
+  ASSERT (bs2[n] <= 6);
+  ASSERT (asm2[n] <= 9);
+  ASSERT (bsm2[n] <= 4);
+
+  /* vm1, 2n+1 limbs */
+  vm1[2*n] = 0;
+  mpn_mul_n (vm1, asm1, bsm1, n + (asm1[n] | bsm1[n]));  /* W4 */
+
+  /* vm2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n+1);  /* W2 */
+
+  /* v2, 2n+1 limbs */
+  mpn_mul_n (v2, as2, bs2, n+1);  /* W1 */
+
+  /* v1, 2n+1 limbs */
+  mpn_mul_n (v1, as1, bs1, n+1);  /* W3 */
+
+  /* vinf, s+t limbs */   /* W0 */
+  if (s > t)  mpn_mul (vinf, a3, s, b2, t);
+  else        mpn_mul (vinf, b2, t, a3, s);
+
+  /* v0, 2n limbs */
+  mpn_mul_n (v0, ap, bp, n);  /* W5 */
+
+  mpn_toom_interpolate_6pts (pp, n, flags, vm1, vm2, v2, t + s);
+
+#undef v0
+#undef vm1
+#undef v1
+#undef vm2
+#undef v2
+#undef vinf
+#undef bs1
+#undef bs2
+#undef bsm1
+#undef bsm2
+#undef asm1
+#undef asm2
+/* #undef as1 */
+/* #undef as2 */
+#undef a0a2
+#undef b0b2
+#undef a1a3
+#undef b1d
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef b0
+#undef b1
+#undef b2
+}
diff --git a/mpn/generic/toom44_mul.c b/mpn/generic/toom44_mul.c
new file mode 100644
index 0000000..a361899
--- /dev/null
+++ b/mpn/generic/toom44_mul.c
@@ -0,0 +1,239 @@
+/* mpn_toom44_mul -- Multiply {ap,an} and {bp,bn} where an and bn are close in
+   size.  Or more accurately, bn <= an < (4/3)bn.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: 0, +1, -1, +2, -2, 1/2, +inf
+
+  <-s--><--n--><--n--><--n-->
+   ____ ______ ______ ______
+  |_a3_|___a2_|___a1_|___a0_|
+   |b3_|___b2_|___b1_|___b0_|
+   <-t-><--n--><--n--><--n-->
+
+  v0  =   a0             *  b0              #    A(0)*B(0)
+  v1  = ( a0+ a1+ a2+ a3)*( b0+ b1+ b2+ b3) #    A(1)*B(1)      ah  <= 3   bh  <= 3
+  vm1 = ( a0- a1+ a2- a3)*( b0- b1+ b2- b3) #   A(-1)*B(-1)    |ah| <= 1  |bh| <= 1
+  v2  = ( a0+2a1+4a2+8a3)*( b0+2b1+4b2+8b3) #    A(2)*B(2)      ah  <= 14  bh  <= 14
+  vm2 = ( a0-2a1+4a2-8a3)*( b0-2b1+4b2-8b3) #   A(-2)*B(-2)    |ah| <= 9  |bh| <= 9
+  vh  = (8a0+4a1+2a2+ a3)*(8b0+4b1+2b2+ b3) #  A(1/2)*B(1/2)    ah  <= 14  bh  <= 14
+  vinf=               a3 *          b2      #  A(inf)*B(inf)
+*/
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom22   1
+#define MAYBE_mul_toom44   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM44_THRESHOLD < 4 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM44_THRESHOLD < 4 * MUL_TOOM33_THRESHOLD)
+#define MAYBE_mul_toom44						\
+  (MUL_TOOM6H_THRESHOLD >= 4 * MUL_TOOM44_THRESHOLD)
+#endif
+
+#define TOOM44_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+    else if (MAYBE_mul_toom22						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+    else if (! MAYBE_mul_toom44						\
+	     || BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD))		\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+    else								\
+      mpn_toom44_mul (p, a, n, b, n, ws);				\
+  } while (0)
+
+/* Use of scratch space. In the product area, we store
+
+      ___________________
+     |vinf|____|_v1_|_v0_|
+      s+t  2n-1 2n+1  2n
+
+   The other recursive products, vm1, v2, vm2, vh are stored in the
+   scratch area. When computing them, we use the product area for
+   intermediate values.
+
+   Next, we compute v1. We can store the intermediate factors at v0
+   and at vh + 2n + 2.
+
+   Finally, for v0 and vinf, factors are parts of the input operands,
+   and we need scratch space only for the recursive multiplication.
+
+   In all, if S(an) is the scratch need, the needed space is bounded by
+
+     S(an) <= 4 (2*ceil(an/4) + 1) + 1 + S(ceil(an/4) + 1)
+
+   which should give S(n) = 8 n/3 + c log(n) for some constant c.
+*/
+
+void
+mpn_toom44_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  enum toom7_flags flags;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2*n)
+#define b3  (bp + 3*n)
+
+  ASSERT (an >= bn);
+
+  n = (an + 3) >> 2;
+
+  s = an - 3 * n;
+  t = bn - 3 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (s >= t);
+
+  /* NOTE: The multiplications to v2, vm2, vh and vm1 overwrites the
+   * following limb, so these must be computed in order, and we need a
+   * one limb gap to tp. */
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define tp (scratch + 8*n + 5)
+
+  /* apx and bpx must not overlap with v1 */
+#define apx   pp				/* n+1 */
+#define amx   (pp + n + 1)			/* n+1 */
+#define bmx   (pp + 2*n + 2)			/* n+1 */
+#define bpx   (pp + 4*n + 2)			/* n+1 */
+
+  /* Total scratch need: 8*n + 5 + scratch for recursive calls. This
+     gives roughly 32 n/3 + log term. */
+
+  /* Compute apx = a0 + 2 a1 + 4 a2 + 8 a3 and amx = a0 - 2 a1 + 4 a2 - 8 a3.  */
+  flags = (enum toom7_flags) (toom7_w1_neg & mpn_toom_eval_dgr3_pm2 (apx, amx, ap, n, s, tp));
+
+  /* Compute bpx = b0 + 2 b1 + 4 b2 + 8 b3 and bmx = b0 - 2 b1 + 4 b2 - 8 b3.  */
+  flags = (enum toom7_flags) (flags ^ (toom7_w1_neg & mpn_toom_eval_dgr3_pm2 (bpx, bmx, bp, n, t, tp)));
+
+  TOOM44_MUL_N_REC (v2, apx, bpx, n + 1, tp);	/* v2,  2n+1 limbs */
+  TOOM44_MUL_N_REC (vm2, amx, bmx, n + 1, tp);	/* vm2,  2n+1 limbs */
+
+  /* Compute apx = 8 a0 + 4 a1 + 2 a2 + a3 = (((2*a0 + a1) * 2 + a2) * 2 + a3 */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (apx, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (apx, a2, apx, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (apx, a3, apx, s);
+      apx[n] = 2*cy + mpn_lshift (apx + s, apx + s, n - s, 1);
+      MPN_INCR_U (apx + s, n+1-s, cy2);
+    }
+  else
+    apx[n] = 2*cy + mpn_addlsh1_n (apx, a3, apx, n);
+#else
+  cy = mpn_lshift (apx, a0, n, 1);
+  cy += mpn_add_n (apx, apx, a1, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  cy += mpn_add_n (apx, apx, a2, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  apx[n] = cy + mpn_add (apx, apx, n, a3, s);
+#endif
+
+  /* Compute bpx = 8 b0 + 4 b1 + 2 b2 + b3 = (((2*b0 + b1) * 2 + b2) * 2 + b3 */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (bpx, b1, b0, n);
+  cy = 2*cy + mpn_addlsh1_n (bpx, b2, bpx, n);
+  if (t < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (bpx, b3, bpx, t);
+      bpx[n] = 2*cy + mpn_lshift (bpx + t, bpx + t, n - t, 1);
+      MPN_INCR_U (bpx + t, n+1-t, cy2);
+    }
+  else
+    bpx[n] = 2*cy + mpn_addlsh1_n (bpx, b3, bpx, n);
+#else
+  cy = mpn_lshift (bpx, b0, n, 1);
+  cy += mpn_add_n (bpx, bpx, b1, n);
+  cy = 2*cy + mpn_lshift (bpx, bpx, n, 1);
+  cy += mpn_add_n (bpx, bpx, b2, n);
+  cy = 2*cy + mpn_lshift (bpx, bpx, n, 1);
+  bpx[n] = cy + mpn_add (bpx, bpx, n, b3, t);
+#endif
+
+  ASSERT (apx[n] < 15);
+  ASSERT (bpx[n] < 15);
+
+  TOOM44_MUL_N_REC (vh, apx, bpx, n + 1, tp);	/* vh,  2n+1 limbs */
+
+  /* Compute apx = a0 + a1 + a2 + a3 and amx = a0 - a1 + a2 - a3.  */
+  flags = (enum toom7_flags) (flags | (toom7_w3_neg & mpn_toom_eval_dgr3_pm1 (apx, amx, ap, n, s, tp)));
+
+  /* Compute bpx = b0 + b1 + b2 + b3 and bmx = b0 - b1 + b2 - b3.  */
+  flags = (enum toom7_flags) (flags ^ (toom7_w3_neg & mpn_toom_eval_dgr3_pm1 (bpx, bmx, bp, n, t, tp)));
+
+  ASSERT (amx[n] <= 1);
+  ASSERT (bmx[n] <= 1);
+
+  vm1 [2 * n] = 0;
+  TOOM44_MUL_N_REC (vm1, amx, bmx, n + (bmx[n] | amx[n]), tp);	/* vm1,  2n+1 limbs */
+  /* Clobbers amx, bmx. */
+  TOOM44_MUL_N_REC (v1, apx, bpx, n + 1, tp);	/* v1,  2n+1 limbs */
+
+  TOOM44_MUL_N_REC (v0, a0, b0, n, tp);
+  if (s > t)
+    mpn_mul (vinf, a3, s, b3, t);
+  else
+    TOOM44_MUL_N_REC (vinf, a3, b3, s, tp);	/* vinf, s+t limbs */
+
+  mpn_toom_interpolate_7pts (pp, n, flags, vm2, vm1, v2, vh, s + t, tp);
+}
diff --git a/mpn/generic/toom4_sqr.c b/mpn/generic/toom4_sqr.c
new file mode 100644
index 0000000..fd59d1c
--- /dev/null
+++ b/mpn/generic/toom4_sqr.c
@@ -0,0 +1,164 @@
+/* mpn_toom4_sqr -- Square {ap,an}.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2013, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -2, -1, 0, +1/2, +1, +2, +inf
+
+  <-s--><--n--><--n--><--n-->
+   ____ ______ ______ ______
+  |_a3_|___a2_|___a1_|___a0_|
+
+  v0  =   a0             ^2 #    A(0)^2
+  v1  = ( a0+ a1+ a2+ a3)^2 #    A(1)^2   ah  <= 3
+  vm1 = ( a0- a1+ a2- a3)^2 #   A(-1)^2  |ah| <= 1
+  v2  = ( a0+2a1+4a2+8a3)^2 #    A(2)^2   ah  <= 14
+  vm2 = ( a0-2a1+4a2-8a3)^2 #   A(-2)^2  -9<=ah<=4
+  vh  = (8a0+4a1+2a2+ a3)^2 #  A(1/2)^2   ah  <= 14
+  vinf=               a3 ^2 #  A(inf)^2
+*/
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_toom2   1
+#define MAYBE_sqr_toom4   1
+#else
+#define MAYBE_sqr_basecase						\
+  (SQR_TOOM4_THRESHOLD < 4 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom2							\
+  (SQR_TOOM4_THRESHOLD < 4 * SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_toom4							\
+  (SQR_TOOM6_THRESHOLD >= 4 * SQR_TOOM4_THRESHOLD)
+#endif
+
+#define TOOM4_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (MAYBE_sqr_basecase						\
+	&& BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else if (MAYBE_sqr_toom2						\
+	     && BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+    else if (! MAYBE_sqr_toom4						\
+	     || BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD))		\
+      mpn_toom3_sqr (p, a, n, ws);					\
+    else								\
+      mpn_toom4_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom4_sqr (mp_ptr pp,
+	       mp_srcptr ap, mp_size_t an,
+	       mp_ptr scratch)
+{
+  mp_size_t n, s;
+  mp_limb_t cy;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+
+  n = (an + 3) >> 2;
+
+  s = an - 3 * n;
+
+  ASSERT (0 < s && s <= n);
+
+  /* NOTE: The multiplications to v2, vm2, vh and vm1 overwrites the
+   * following limb, so these must be computed in order, and we need a
+   * one limb gap to tp. */
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define tp (scratch + 8*n + 5)
+
+  /* No overlap with v1 */
+#define apx   pp				/* n+1 */
+#define amx   (pp + 4*n + 2)			/* n+1 */
+
+  /* Total scratch need: 8*n + 5 + scratch for recursive calls. This
+     gives roughly 32 n/3 + log term. */
+
+  /* Compute apx = a0 + 2 a1 + 4 a2 + 8 a3 and amx = a0 - 2 a1 + 4 a2 - 8 a3.  */
+  mpn_toom_eval_dgr3_pm2 (apx, amx, ap, n, s, tp);
+
+  TOOM4_SQR_REC (v2, apx, n + 1, tp);	/* v2,  2n+1 limbs */
+  TOOM4_SQR_REC (vm2, amx, n + 1, tp);	/* vm2,  2n+1 limbs */
+
+  /* Compute apx = 8 a0 + 4 a1 + 2 a2 + a3 = (((2*a0 + a1) * 2 + a2) * 2 + a3 */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (apx, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (apx, a2, apx, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (apx, a3, apx, s);
+      apx[n] = 2*cy + mpn_lshift (apx + s, apx + s, n - s, 1);
+      MPN_INCR_U (apx + s, n+1-s, cy2);
+    }
+  else
+    apx[n] = 2*cy + mpn_addlsh1_n (apx, a3, apx, n);
+#else
+  cy = mpn_lshift (apx, a0, n, 1);
+  cy += mpn_add_n (apx, apx, a1, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  cy += mpn_add_n (apx, apx, a2, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  apx[n] = cy + mpn_add (apx, apx, n, a3, s);
+#endif
+
+  ASSERT (apx[n] < 15);
+
+  TOOM4_SQR_REC (vh, apx, n + 1, tp);	/* vh,  2n+1 limbs */
+
+  /* Compute apx = a0 + a1 + a2 + a3 and amx = a0 - a1 + a2 - a3.  */
+  mpn_toom_eval_dgr3_pm1 (apx, amx, ap, n, s, tp);
+
+  TOOM4_SQR_REC (v1, apx, n + 1, tp);	/* v1,  2n+1 limbs */
+  vm1 [2 * n] = 0;
+  TOOM4_SQR_REC (vm1, amx, n + amx[n], tp);	/* vm1,  2n+1 limbs */
+
+  TOOM4_SQR_REC (v0, a0, n, tp);
+  TOOM4_SQR_REC (vinf, a3, s, tp);	/* vinf, 2s limbs */
+
+  mpn_toom_interpolate_7pts (pp, n, (enum toom7_flags) 0, vm2, vm1, v2, vh, 2*s, tp);
+}
diff --git a/mpn/generic/toom52_mul.c b/mpn/generic/toom52_mul.c
new file mode 100644
index 0000000..974059b
--- /dev/null
+++ b/mpn/generic/toom52_mul.c
@@ -0,0 +1,256 @@
+/* mpn_toom52_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 4/3
+   times as large as bn.  Or more accurately, bn < an < 2 bn.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -2, -1, 0, +1, +2, +inf
+
+  <-s-><--n--><--n--><--n--><--n-->
+   ___ ______ ______ ______ ______
+  |a4_|___a3_|___a2_|___a1_|___a0_|
+			|b1|___b0_|
+			<t-><--n-->
+
+  v0  =  a0                  * b0      #   A(0)*B(0)
+  v1  = (a0+ a1+ a2+ a3+  a4)*(b0+ b1) #   A(1)*B(1)      ah  <= 4   bh <= 1
+  vm1 = (a0- a1+ a2- a3+  a4)*(b0- b1) #  A(-1)*B(-1)    |ah| <= 2   bh  = 0
+  v2  = (a0+2a1+4a2+8a3+16a4)*(b0+2b1) #   A(2)*B(2)      ah  <= 30  bh <= 2
+  vm2 = (a0-2a1+4a2-8a3+16a4)*(b0-2b1) #  A(-2)*B(-2)    |ah| <= 20 |bh|<= 1
+  vinf=                   a4 *     b1  # A(inf)*B(inf)
+
+  Some slight optimization in evaluation are taken from the paper:
+  "Towards Optimal Toom-Cook Multiplication for Univariate and
+  Multivariate Polynomials in Characteristic 2 and 0."
+*/
+
+void
+mpn_toom52_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  enum toom6_flags flags;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2 * n)
+#define a3  (ap + 3 * n)
+#define a4  (ap + 4 * n)
+#define b0  bp
+#define b1  (bp + n)
+
+  n = 1 + (2 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) >> 1);
+
+  s = an - 4 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  /* Ensures that 5 values of n+1 limbs each fits in the product area.
+     Borderline cases are an = 32, bn = 8, n = 7, and an = 36, bn = 9,
+     n = 8. */
+  ASSERT (s+t >= 5);
+
+#define v0    pp				/* 2n */
+#define vm1   (scratch)				/* 2n+1 */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define v2    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vinf  (pp + 5 * n)			/* s+t */
+#define bs1    pp				/* n+1 */
+#define bsm1  (scratch + 2 * n + 2)		/* n   */
+#define asm1  (scratch + 3 * n + 3)		/* n+1 */
+#define asm2  (scratch + 4 * n + 4)		/* n+1 */
+#define bsm2  (pp + n + 1)			/* n+1 */
+#define bs2   (pp + 2 * n + 2)			/* n+1 */
+#define as2   (pp + 3 * n + 3)			/* n+1 */
+#define as1   (pp + 4 * n + 4)			/* n+1 */
+
+  /* Scratch need is 6 * n + 3 + 1. We need one extra limb, because
+     products will overwrite 2n+2 limbs. */
+
+#define a0a2  scratch
+#define a1a3  asm1
+
+  /* Compute as2 and asm2.  */
+  flags = (enum toom6_flags) (toom6_vm2_neg & mpn_toom_eval_pm2 (as2, asm2, 4, ap, n, s, a1a3));
+
+  /* Compute bs1 and bsm1.  */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      mp_limb_t cy;
+
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b1, b0, n);
+	  flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b0, b1, n);
+	}
+      bs1[n] = cy >> 1;
+#else
+      bs1[n] = mpn_add_n (bs1, b0, b1, n);
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	}
+#endif
+    }
+  else
+    {
+      bs1[n] = mpn_add (bs1, b0, n, b1, t);
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	}
+    }
+
+  /* Compute bs2 and bsm2, recycling bs1 and bsm1. bs2=bs1+b1; bsm2=bsm1-b1  */
+  mpn_add (bs2, bs1, n+1, b1, t);
+  if (flags & toom6_vm1_neg)
+    {
+      bsm2[n] = mpn_add (bsm2, bsm1, n, b1, t);
+      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+    }
+  else
+    {
+      bsm2[n] = 0;
+      if (t == n)
+	{
+	  if (mpn_cmp (bsm1, b1, n) < 0)
+	    {
+	      mpn_sub_n (bsm2, b1, bsm1, n);
+	      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+	    }
+	  else
+	    {
+	      mpn_sub_n (bsm2, bsm1, b1, n);
+	    }
+	}
+      else
+	{
+	  if (mpn_zero_p (bsm1 + t, n - t) && mpn_cmp (bsm1, b1, t) < 0)
+	    {
+	      mpn_sub_n (bsm2, b1, bsm1, t);
+	      MPN_ZERO (bsm2 + t, n - t);
+	      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+	    }
+	  else
+	    {
+	      mpn_sub (bsm2, bsm1, n, b1, t);
+	    }
+	}
+    }
+
+  /* Compute as1 and asm1.  */
+  flags = (enum toom6_flags) (flags ^ (toom6_vm1_neg & mpn_toom_eval_pm1 (as1, asm1, 4, ap, n, s, a0a2)));
+
+  ASSERT (as1[n] <= 4);
+  ASSERT (bs1[n] <= 1);
+  ASSERT (asm1[n] <= 2);
+/*   ASSERT (bsm1[n] <= 1); */
+  ASSERT (as2[n] <=30);
+  ASSERT (bs2[n] <= 2);
+  ASSERT (asm2[n] <= 20);
+  ASSERT (bsm2[n] <= 1);
+
+  /* vm1, 2n+1 limbs */
+  mpn_mul (vm1, asm1, n+1, bsm1, n);  /* W4 */
+
+  /* vm2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n+1);  /* W2 */
+
+  /* v2, 2n+1 limbs */
+  mpn_mul_n (v2, as2, bs2, n+1);  /* W1 */
+
+  /* v1, 2n+1 limbs */
+  mpn_mul_n (v1, as1, bs1, n+1);  /* W3 */
+
+  /* vinf, s+t limbs */   /* W0 */
+  if (s > t)  mpn_mul (vinf, a4, s, b1, t);
+  else        mpn_mul (vinf, b1, t, a4, s);
+
+  /* v0, 2n limbs */
+  mpn_mul_n (v0, ap, bp, n);  /* W5 */
+
+  mpn_toom_interpolate_6pts (pp, n, flags, vm1, vm2, v2, t + s);
+
+#undef v0
+#undef vm1
+#undef v1
+#undef vm2
+#undef v2
+#undef vinf
+#undef bs1
+#undef bs2
+#undef bsm1
+#undef bsm2
+#undef asm1
+#undef asm2
+#undef as1
+#undef as2
+#undef a0a2
+#undef b0b2
+#undef a1a3
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef b0
+#undef b1
+#undef b2
+
+}
diff --git a/mpn/generic/toom53_mul.c b/mpn/generic/toom53_mul.c
new file mode 100644
index 0000000..c934297
--- /dev/null
+++ b/mpn/generic/toom53_mul.c
@@ -0,0 +1,331 @@
+/* mpn_toom53_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 5/3
+   times as large as bn.  Or more accurately, (4/3)bn < an < (5/2)bn.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: 0, +1, -1, +2, -2, 1/2, +inf
+
+  <-s-><--n--><--n--><--n--><--n-->
+   ___ ______ ______ ______ ______
+  |a4_|___a3_|___a2_|___a1_|___a0_|
+	       |__b2|___b1_|___b0_|
+	       <-t--><--n--><--n-->
+
+  v0  =    a0                  *  b0          #    A(0)*B(0)
+  v1  = (  a0+ a1+ a2+ a3+  a4)*( b0+ b1+ b2) #    A(1)*B(1)      ah  <= 4   bh <= 2
+  vm1 = (  a0- a1+ a2- a3+  a4)*( b0- b1+ b2) #   A(-1)*B(-1)    |ah| <= 2   bh <= 1
+  v2  = (  a0+2a1+4a2+8a3+16a4)*( b0+2b1+4b2) #    A(2)*B(2)      ah  <= 30  bh <= 6
+  vm2 = (  a0-2a1+4a2-8a3+16a4)*( b0-2b1+4b2) #    A(2)*B(2)     -9<=ah<=20 -1<=bh<=4
+  vh  = (16a0+8a1+4a2+2a3+  a4)*(4b0+2b1+ b2) #  A(1/2)*B(1/2)    ah  <= 30  bh <= 6
+  vinf=                     a4 *          b2  #  A(inf)*B(inf)
+*/
+
+void
+mpn_toom53_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  mp_ptr gp;
+  mp_ptr as1, asm1, as2, asm2, ash;
+  mp_ptr bs1, bsm1, bs2, bsm2, bsh;
+  mp_ptr tmp;
+  enum toom7_flags flags;
+  TMP_DECL;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define a4  (ap + 4*n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2*n)
+
+  n = 1 + (3 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 3);
+
+  s = an - 4 * n;
+  t = bn - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  TMP_MARK;
+
+  tmp = TMP_ALLOC_LIMBS (10 * (n + 1));
+  as1  = tmp; tmp += n + 1;
+  asm1 = tmp; tmp += n + 1;
+  as2  = tmp; tmp += n + 1;
+  asm2 = tmp; tmp += n + 1;
+  ash  = tmp; tmp += n + 1;
+  bs1  = tmp; tmp += n + 1;
+  bsm1 = tmp; tmp += n + 1;
+  bs2  = tmp; tmp += n + 1;
+  bsm2 = tmp; tmp += n + 1;
+  bsh  = tmp; tmp += n + 1;
+
+  gp = pp;
+
+  /* Compute as1 and asm1.  */
+  flags = (enum toom7_flags) (toom7_w3_neg & mpn_toom_eval_pm1 (as1, asm1, 4, ap, n, s, gp));
+
+  /* Compute as2 and asm2. */
+  flags = (enum toom7_flags) (flags | (toom7_w1_neg & mpn_toom_eval_pm2 (as2, asm2, 4, ap, n, s, gp)));
+
+  /* Compute ash = 16 a0 + 8 a1 + 4 a2 + 2 a3 + a4
+     = 2*(2*(2*(2*a0 + a1) + a2) + a3) + a4  */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (ash, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a2, ash, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a3, ash, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (ash, a4, ash, s);
+      ash[n] = 2*cy + mpn_lshift (ash + s, ash + s, n - s, 1);
+      MPN_INCR_U (ash + s, n+1-s, cy2);
+    }
+  else
+    ash[n] = 2*cy + mpn_addlsh1_n (ash, a4, ash, n);
+#else
+  cy = mpn_lshift (ash, a0, n, 1);
+  cy += mpn_add_n (ash, ash, a1, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a2, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a3, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  ash[n] = cy + mpn_add (ash, ash, n, a4, s);
+#endif
+
+  /* Compute bs1 and bsm1.  */
+  bs1[n] = mpn_add (bs1, b0, n, b2, t);		/* b0 + b2 */
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (bs1[n] == 0 && mpn_cmp (bs1, b1, n) < 0)
+    {
+      bs1[n] = mpn_add_n_sub_n (bs1, bsm1, b1, bs1, n) >> 1;
+      bsm1[n] = 0;
+      flags = (enum toom7_flags) (flags ^ toom7_w3_neg);
+    }
+  else
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, bs1, b1, n);
+      bsm1[n] = bs1[n] - (cy & 1);
+      bs1[n] += (cy >> 1);
+    }
+#else
+  if (bs1[n] == 0 && mpn_cmp (bs1, b1, n) < 0)
+    {
+      mpn_sub_n (bsm1, b1, bs1, n);
+      bsm1[n] = 0;
+      flags = (enum toom7_flags) (flags ^ toom7_w3_neg);
+    }
+  else
+    {
+      bsm1[n] = bs1[n] - mpn_sub_n (bsm1, bs1, b1, n);
+    }
+  bs1[n] += mpn_add_n (bs1, bs1, b1, n);  /* b0+b1+b2 */
+#endif
+
+  /* Compute bs2 and bsm2. */
+#if HAVE_NATIVE_mpn_addlsh_n || HAVE_NATIVE_mpn_addlsh2_n
+#if HAVE_NATIVE_mpn_addlsh2_n
+  cy = mpn_addlsh2_n (bs2, b0, b2, t);
+#else /* HAVE_NATIVE_mpn_addlsh_n */
+  cy = mpn_addlsh_n (bs2, b0, b2, t, 2);
+#endif
+  if (t < n)
+    cy = mpn_add_1 (bs2 + t, b0 + t, n - t, cy);
+  bs2[n] = cy;
+#else
+  cy = mpn_lshift (gp, b2, t, 2);
+  bs2[n] = mpn_add (bs2, b0, n, gp, t);
+  MPN_INCR_U (bs2 + t, n+1-t, cy);
+#endif
+
+  gp[n] = mpn_lshift (gp, b1, n, 1);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (mpn_cmp (bs2, gp, n+1) < 0)
+    {
+      ASSERT_NOCARRY (mpn_add_n_sub_n (bs2, bsm2, gp, bs2, n+1));
+      flags = (enum toom7_flags) (flags ^ toom7_w1_neg);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n_sub_n (bs2, bsm2, bs2, gp, n+1));
+    }
+#else
+  if (mpn_cmp (bs2, gp, n+1) < 0)
+    {
+      ASSERT_NOCARRY (mpn_sub_n (bsm2, gp, bs2, n+1));
+      flags = (enum toom7_flags) (flags ^ toom7_w1_neg);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_n (bsm2, bs2, gp, n+1));
+    }
+  mpn_add_n (bs2, bs2, gp, n+1);
+#endif
+
+  /* Compute bsh = 4 b0 + 2 b1 + b2 = 2*(2*b0 + b1)+b2.  */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (bsh, b1, b0, n);
+  if (t < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (bsh, b2, bsh, t);
+      bsh[n] = 2*cy + mpn_lshift (bsh + t, bsh + t, n - t, 1);
+      MPN_INCR_U (bsh + t, n+1-t, cy2);
+    }
+  else
+    bsh[n] = 2*cy + mpn_addlsh1_n (bsh, b2, bsh, n);
+#else
+  cy = mpn_lshift (bsh, b0, n, 1);
+  cy += mpn_add_n (bsh, bsh, b1, n);
+  cy = 2*cy + mpn_lshift (bsh, bsh, n, 1);
+  bsh[n] = cy + mpn_add (bsh, bsh, n, b2, t);
+#endif
+
+  ASSERT (as1[n] <= 4);
+  ASSERT (bs1[n] <= 2);
+  ASSERT (asm1[n] <= 2);
+  ASSERT (bsm1[n] <= 1);
+  ASSERT (as2[n] <= 30);
+  ASSERT (bs2[n] <= 6);
+  ASSERT (asm2[n] <= 20);
+  ASSERT (bsm2[n] <= 4);
+  ASSERT (ash[n] <= 30);
+  ASSERT (bsh[n] <= 6);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define scratch_out (scratch + 8 * n + 4)		/* 2n+1 */
+  /* Total scratch need: 10*n+5 */
+
+  /* Must be in allocation order, as they overwrite one limb beyond
+   * 2n+1. */
+  mpn_mul_n (v2, as2, bs2, n + 1);		/* v2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n + 1);		/* vm2, 2n+1 limbs */
+  mpn_mul_n (vh, ash, bsh, n + 1);		/* vh, 2n+1 limbs */
+
+  /* vm1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  mpn_mul_n (vm1, asm1, bsm1, n);
+  if (asm1[n] == 1)
+    {
+      cy = bsm1[n] + mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+    }
+  else if (asm1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * bsm1[n] + mpn_addlsh1_n_ip1 (vm1 + n, bsm1, n);
+#else
+      cy = 2 * bsm1[n] + mpn_addmul_1 (vm1 + n, bsm1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (bsm1[n] != 0)
+    cy += mpn_add_n (vm1 + n, vm1 + n, asm1, n);
+  vm1[2 * n] = cy;
+#else /* SMALLER_RECURSION */
+  vm1[2 * n] = 0;
+  mpn_mul_n (vm1, asm1, bsm1, n + ((asm1[n] | bsm1[n]) != 0));
+#endif /* SMALLER_RECURSION */
+
+  /* v1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  mpn_mul_n (v1, as1, bs1, n);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * bs1[n] + mpn_addlsh1_n_ip1 (v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (as1[n] != 0)
+    {
+      cy = as1[n] * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, as1[n]);
+    }
+  else
+    cy = 0;
+  if (bs1[n] == 1)
+    {
+      cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+    }
+  else if (bs1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy += mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  v1[2 * n] = cy;
+#else /* SMALLER_RECURSION */
+  v1[2 * n] = 0;
+  mpn_mul_n (v1, as1, bs1, n + ((as1[n] | bs1[n]) != 0));
+#endif /* SMALLER_RECURSION */
+
+  mpn_mul_n (v0, a0, b0, n);			/* v0, 2n limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a4, s, b2, t);
+  else        mpn_mul (vinf, b2, t, a4, s);
+
+  mpn_toom_interpolate_7pts (pp, n, flags, vm2, vm1, v2, vh, s + t,
+			     scratch_out);
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/toom54_mul.c b/mpn/generic/toom54_mul.c
new file mode 100644
index 0000000..343b02e
--- /dev/null
+++ b/mpn/generic/toom54_mul.c
@@ -0,0 +1,142 @@
+/* Implementation of the algorithm for Toom-Cook 4.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Toom-4.5, the splitting 5x4 unbalanced version.
+   Evaluate in: infinity, +4, -4, +2, -2, +1, -1, 0.
+
+  <--s-><--n--><--n--><--n--><--n-->
+   ____ ______ ______ ______ ______
+  |_a4_|__a3__|__a2__|__a1__|__a0__|
+	  |b3_|__b2__|__b1__|__b0__|
+	  <-t-><--n--><--n--><--n-->
+
+*/
+#define TOOM_54_MUL_N_REC(p, a, b, n, ws)		\
+  do {	mpn_mul_n (p, a, b, n);				\
+  } while (0)
+
+#define TOOM_54_MUL_REC(p, a, na, b, nb, ws)		\
+  do {	mpn_mul (p, a, na, b, nb);			\
+  } while (0)
+
+void
+mpn_toom54_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int sign;
+
+  /***************************** decomposition *******************************/
+#define a4  (ap + 4 * n)
+#define b3  (bp + 3 * n)
+
+  ASSERT (an >= bn);
+  n = 1 + (4 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 4);
+
+  s = an - 4 * n;
+  t = bn - 3 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  /* Required by mpn_toom_interpolate_8pts. */
+  ASSERT ( s + t >= n );
+  ASSERT ( s + t > 4);
+  ASSERT ( n > 2);
+
+#define   r8    pp				/* 2n   */
+#define   r7    scratch				/* 3n+1 */
+#define   r5    (pp + 3*n)			/* 3n+1 */
+#define   v0    (pp + 3*n)			/* n+1 */
+#define   v1    (pp + 4*n+1)			/* n+1 */
+#define   v2    (pp + 5*n+2)			/* n+1 */
+#define   v3    (pp + 6*n+3)			/* n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (pp + 7*n)			/* s+t <= 2*n */
+#define   ws    (scratch + 6 * n + 2)		/* ??? */
+
+  /* Alloc also 3n+1 limbs for ws... mpn_toom_interpolate_8pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, 4, ap, n, s, 2, pp)
+       ^ mpn_toom_eval_pm2exp (v3, v1, 3, bp, n, t, 2, pp);
+  TOOM_54_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-4)*B(-4) */
+  TOOM_54_MUL_N_REC(r3, v2, v3, n + 1, ws); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r3, 2*n+1, pp, sign, n, 2, 4);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, 4, ap, n, s,    pp)
+       ^ mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t,    pp);
+  TOOM_54_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-1)*B(-1) */
+  TOOM_54_MUL_N_REC(r7, v2, v3, n + 1, ws); /* A(1)*B(1) */
+  mpn_toom_couple_handling (r7, 2*n+1, pp, sign, n, 0, 0);
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, 4, ap, n, s, pp)
+       ^ mpn_toom_eval_dgr3_pm2 (v3, v1, bp, n, t, pp);
+  TOOM_54_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-2)*B(-2) */
+  TOOM_54_MUL_N_REC(r5, v2, v3, n + 1, ws); /* A(+2)*B(+2) */
+  mpn_toom_couple_handling (r5, 2*n+1, pp, sign, n, 1, 2);
+
+  /* A(0)*B(0) */
+  TOOM_54_MUL_N_REC(pp, ap, bp, n, ws);
+
+  /* Infinity */
+  if (s > t) {
+    TOOM_54_MUL_REC(r1, a4, s, b3, t, ws);
+  } else {
+    TOOM_54_MUL_REC(r1, b3, t, a4, s, ws);
+  };
+
+  mpn_toom_interpolate_8pts (pp, n, r3, r7, s + t, ws);
+
+#undef a4
+#undef b3
+#undef r1
+#undef r3
+#undef r5
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef r7
+#undef r8
+#undef ws
+}
diff --git a/mpn/generic/toom62_mul.c b/mpn/generic/toom62_mul.c
new file mode 100644
index 0000000..d971cc0
--- /dev/null
+++ b/mpn/generic/toom62_mul.c
@@ -0,0 +1,310 @@
+/* mpn_toom62_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 3 times
+   as large as bn.  Or more accurately, (5/2)bn < an < 6bn.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in:
+   0, +1, -1, +2, -2, 1/2, +inf
+
+  <-s-><--n--><--n--><--n--><--n--><--n-->
+   ___ ______ ______ ______ ______ ______
+  |a5_|___a4_|___a3_|___a2_|___a1_|___a0_|
+			     |_b1_|___b0_|
+			     <-t--><--n-->
+
+  v0  =    a0                       *   b0      #    A(0)*B(0)
+  v1  = (  a0+  a1+ a2+ a3+  a4+  a5)*( b0+ b1) #    A(1)*B(1)      ah  <= 5   bh <= 1
+  vm1 = (  a0-  a1+ a2- a3+  a4-  a5)*( b0- b1) #   A(-1)*B(-1)    |ah| <= 2   bh  = 0
+  v2  = (  a0+ 2a1+4a2+8a3+16a4+32a5)*( b0+2b1) #    A(2)*B(2)      ah  <= 62  bh <= 2
+  vm2 = (  a0- 2a1+4a2-8a3+16a4-32a5)*( b0-2b1) #   A(-2)*B(-2)    -41<=ah<=20 -1<=bh<=0
+  vh  = (32a0+16a1+8a2+4a3+ 2a4+  a5)*(2b0+ b1) #  A(1/2)*B(1/2)    ah  <= 62  bh <= 2
+  vinf=                           a5 *      b1  #  A(inf)*B(inf)
+*/
+
+void
+mpn_toom62_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  mp_ptr as1, asm1, as2, asm2, ash;
+  mp_ptr bs1, bsm1, bs2, bsm2, bsh;
+  mp_ptr gp;
+  enum toom7_flags aflags, bflags;
+  TMP_DECL;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define a4  (ap + 4*n)
+#define a5  (ap + 5*n)
+#define b0  bp
+#define b1  (bp + n)
+
+  n = 1 + (an >= 3 * bn ? (an - 1) / (size_t) 6 : (bn - 1) >> 1);
+
+  s = an - 5 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  TMP_MARK;
+
+  as1 = TMP_SALLOC_LIMBS (n + 1);
+  asm1 = TMP_SALLOC_LIMBS (n + 1);
+  as2 = TMP_SALLOC_LIMBS (n + 1);
+  asm2 = TMP_SALLOC_LIMBS (n + 1);
+  ash = TMP_SALLOC_LIMBS (n + 1);
+
+  bs1 = TMP_SALLOC_LIMBS (n + 1);
+  bsm1 = TMP_SALLOC_LIMBS (n);
+  bs2 = TMP_SALLOC_LIMBS (n + 1);
+  bsm2 = TMP_SALLOC_LIMBS (n + 1);
+  bsh = TMP_SALLOC_LIMBS (n + 1);
+
+  gp = pp;
+
+  /* Compute as1 and asm1.  */
+  aflags = (enum toom7_flags) (toom7_w3_neg & mpn_toom_eval_pm1 (as1, asm1, 5, ap, n, s, gp));
+
+  /* Compute as2 and asm2. */
+  aflags = (enum toom7_flags) (aflags | (toom7_w1_neg & mpn_toom_eval_pm2 (as2, asm2, 5, ap, n, s, gp)));
+
+  /* Compute ash = 32 a0 + 16 a1 + 8 a2 + 4 a3 + 2 a4 + a5
+     = 2*(2*(2*(2*(2*a0 + a1) + a2) + a3) + a4) + a5  */
+
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (ash, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a2, ash, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a3, ash, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a4, ash, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (ash, a5, ash, s);
+      ash[n] = 2*cy + mpn_lshift (ash + s, ash + s, n - s, 1);
+      MPN_INCR_U (ash + s, n+1-s, cy2);
+    }
+  else
+    ash[n] = 2*cy + mpn_addlsh1_n (ash, a5, ash, n);
+#else
+  cy = mpn_lshift (ash, a0, n, 1);
+  cy += mpn_add_n (ash, ash, a1, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a2, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a3, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a4, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  ash[n] = cy + mpn_add (ash, ash, n, a5, s);
+#endif
+
+  /* Compute bs1 and bsm1.  */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b1, b0, n);
+	  bflags = toom7_w3_neg;
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b0, b1, n);
+	  bflags = (enum toom7_flags) 0;
+	}
+      bs1[n] = cy >> 1;
+#else
+      bs1[n] = mpn_add_n (bs1, b0, b1, n);
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  bflags = toom7_w3_neg;
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	  bflags = (enum toom7_flags) 0;
+	}
+#endif
+    }
+  else
+    {
+      bs1[n] = mpn_add (bs1, b0, n, b1, t);
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  bflags = toom7_w3_neg;
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	  bflags = (enum toom7_flags) 0;
+	}
+    }
+
+  /* Compute bs2 and bsm2. Recycling bs1 and bsm1; bs2=bs1+b1, bsm2 =
+     bsm1 - b1 */
+  mpn_add (bs2, bs1, n + 1, b1, t);
+  if (bflags & toom7_w3_neg)
+    {
+      bsm2[n] = mpn_add (bsm2, bsm1, n, b1, t);
+      bflags = (enum toom7_flags) (bflags | toom7_w1_neg);
+    }
+  else
+    {
+      /* FIXME: Simplify this logic? */
+      if (t < n)
+	{
+	  if (mpn_zero_p (bsm1 + t, n - t) && mpn_cmp (bsm1, b1, t) < 0)
+	    {
+	      ASSERT_NOCARRY (mpn_sub_n (bsm2, b1, bsm1, t));
+	      MPN_ZERO (bsm2 + t, n + 1 - t);
+	      bflags = (enum toom7_flags) (bflags | toom7_w1_neg);
+	    }
+	  else
+	    {
+	      ASSERT_NOCARRY (mpn_sub (bsm2, bsm1, n, b1, t));
+	      bsm2[n] = 0;
+	    }
+	}
+      else
+	{
+	  if (mpn_cmp (bsm1, b1, n) < 0)
+	    {
+	      ASSERT_NOCARRY (mpn_sub_n (bsm2, b1, bsm1, n));
+	      bflags = (enum toom7_flags) (bflags | toom7_w1_neg);
+	    }
+	  else
+	    {
+	      ASSERT_NOCARRY (mpn_sub_n (bsm2, bsm1, b1, n));
+	    }
+	  bsm2[n] = 0;
+	}
+    }
+
+  /* Compute bsh, recycling bs1. bsh=bs1+b0;  */
+  bsh[n] = bs1[n] + mpn_add_n (bsh, bs1, b0, n);
+
+  ASSERT (as1[n] <= 5);
+  ASSERT (bs1[n] <= 1);
+  ASSERT (asm1[n] <= 2);
+  ASSERT (as2[n] <= 62);
+  ASSERT (bs2[n] <= 2);
+  ASSERT (asm2[n] <= 41);
+  ASSERT (bsm2[n] <= 1);
+  ASSERT (ash[n] <= 62);
+  ASSERT (bsh[n] <= 2);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define scratch_out (scratch + 8 * n + 4)		/* 2n+1 */
+  /* Total scratch need: 10*n+5 */
+
+  /* Must be in allocation order, as they overwrite one limb beyond
+   * 2n+1. */
+  mpn_mul_n (v2, as2, bs2, n + 1);		/* v2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n + 1);		/* vm2, 2n+1 limbs */
+  mpn_mul_n (vh, ash, bsh, n + 1);		/* vh, 2n+1 limbs */
+
+  /* vm1, 2n+1 limbs */
+  mpn_mul_n (vm1, asm1, bsm1, n);
+  cy = 0;
+  if (asm1[n] == 1)
+    {
+      cy = mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+    }
+  else if (asm1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = mpn_addlsh1_n (vm1 + n, vm1 + n, bsm1, n);
+#else
+      cy = mpn_addmul_1 (vm1 + n, bsm1, n, CNST_LIMB(2));
+#endif
+    }
+  vm1[2 * n] = cy;
+
+  /* v1, 2n+1 limbs */
+  mpn_mul_n (v1, as1, bs1, n);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = 2 * bs1[n] + mpn_addlsh1_n (v1 + n, v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (as1[n] != 0)
+    {
+      cy = as1[n] * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, as1[n]);
+    }
+  else
+    cy = 0;
+  if (bs1[n] != 0)
+    cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+  v1[2 * n] = cy;
+
+  mpn_mul_n (v0, a0, b0, n);			/* v0, 2n limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a5, s, b1, t);
+  else        mpn_mul (vinf, b1, t, a5, s);
+
+  mpn_toom_interpolate_7pts (pp, n, (enum toom7_flags) (aflags ^ bflags),
+			     vm2, vm1, v2, vh, s + t, scratch_out);
+
+  TMP_FREE;
+}
diff --git a/mpn/generic/toom63_mul.c b/mpn/generic/toom63_mul.c
new file mode 100644
index 0000000..181996d
--- /dev/null
+++ b/mpn/generic/toom63_mul.c
@@ -0,0 +1,231 @@
+/* Implementation of the algorithm for Toom-Cook 4.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Stores |{ap,n}-{bp,n}| in {rp,n}, returns the sign. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_limb_t  x, y;
+  while (--n >= 0)
+    {
+      x = ap[n];
+      y = bp[n];
+      if (x != y)
+	{
+	  n++;
+	  if (x > y)
+	    {
+	      mpn_sub_n (rp, ap, bp, n);
+	      return 0;
+	    }
+	  else
+	    {
+	      mpn_sub_n (rp, bp, ap, n);
+	      return ~0;
+	    }
+	}
+      rp[n] = 0;
+    }
+  return 0;
+}
+
+static int
+abs_sub_add_n (mp_ptr rm, mp_ptr rp, mp_srcptr rs, mp_size_t n) {
+  int result;
+  result = abs_sub_n (rm, rp, rs, n);
+  ASSERT_NOCARRY(mpn_add_n (rp, rp, rs, n));
+  return result;
+}
+
+
+/* Toom-4.5, the splitting 6x3 unbalanced version.
+   Evaluate in: infinity, +4, -4, +2, -2, +1, -1, 0.
+
+  <--s-><--n--><--n--><--n--><--n--><--n-->
+   ____ ______ ______ ______ ______ ______
+  |_a5_|__a4__|__a3__|__a2__|__a1__|__a0__|
+			|b2_|__b1__|__b0__|
+			<-t-><--n--><--n-->
+
+*/
+#define TOOM_63_MUL_N_REC(p, a, b, n, ws)		\
+  do {	mpn_mul_n (p, a, b, n);				\
+  } while (0)
+
+#define TOOM_63_MUL_REC(p, a, na, b, nb, ws)		\
+  do {	mpn_mul (p, a, na, b, nb);			\
+  } while (0)
+
+void
+mpn_toom63_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  int sign;
+
+  /***************************** decomposition *******************************/
+#define a5  (ap + 5 * n)
+#define b0  (bp + 0 * n)
+#define b1  (bp + 1 * n)
+#define b2  (bp + 2 * n)
+
+  ASSERT (an >= bn);
+  n = 1 + (an >= 2 * bn ? (an - 1) / (size_t) 6 : (bn - 1) / (size_t) 3);
+
+  s = an - 5 * n;
+  t = bn - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  /* WARNING! it assumes s+t>=n */
+  ASSERT ( s + t >= n );
+  ASSERT ( s + t > 4);
+  /* WARNING! it assumes n>1 */
+  ASSERT ( n > 2);
+
+#define   r8    pp				/* 2n   */
+#define   r7    scratch				/* 3n+1 */
+#define   r5    (pp + 3*n)			/* 3n+1 */
+#define   v0    (pp + 3*n)			/* n+1 */
+#define   v1    (pp + 4*n+1)			/* n+1 */
+#define   v2    (pp + 5*n+2)			/* n+1 */
+#define   v3    (pp + 6*n+3)			/* n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (pp + 7*n)			/* s+t <= 2*n */
+#define   ws    (scratch + 6 * n + 2)		/* ??? */
+
+  /* Alloc also 3n+1 limbs for ws... mpn_toom_interpolate_8pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+/*   if (scratch == NULL) scratch = TMP_SALLOC_LIMBS (9 * n + 3); */
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, 5, ap, n, s, 2, pp);
+  pp[n] = mpn_lshift (pp, b1, n, 2); /* 4b1 */
+  /* FIXME: use addlsh */
+  v3[t] = mpn_lshift (v3, b2, t, 4);/* 16b2 */
+  if ( n == t )
+    v3[n]+= mpn_add_n (v3, v3, b0, n); /* 16b2+b0 */
+  else
+    v3[n] = mpn_add (v3, b0, n, v3, t+1); /* 16b2+b0 */
+  sign ^= abs_sub_add_n (v1, v3, pp, n + 1);
+  TOOM_63_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-4)*B(-4) */
+  TOOM_63_MUL_N_REC(r3, v2, v3, n + 1, ws); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r3, 2*n+1, pp, sign, n, 2, 4);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, 5, ap, n, s,    pp);
+  /* Compute bs1 and bsm1. Code taken from toom33 */
+  cy = mpn_add (ws, b0, n, b2, t);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (ws, b1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (v3, v1, b1, ws, n);
+      v3[n] = cy >> 1;
+      v1[n] = 0;
+      sign = ~sign;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (v3, v1, ws, b1, n);
+      v3[n] = cy + (cy2 >> 1);
+      v1[n] = cy - (cy2 & 1);
+    }
+#else
+  v3[n] = cy + mpn_add_n (v3, ws, b1, n);
+  if (cy == 0 && mpn_cmp (ws, b1, n) < 0)
+    {
+      mpn_sub_n (v1, b1, ws, n);
+      v1[n] = 0;
+      sign = ~sign;
+    }
+  else
+    {
+      cy -= mpn_sub_n (v1, ws, b1, n);
+      v1[n] = cy;
+    }
+#endif
+  TOOM_63_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-1)*B(-1) */
+  TOOM_63_MUL_N_REC(r7, v2, v3, n + 1, ws); /* A(1)*B(1) */
+  mpn_toom_couple_handling (r7, 2*n+1, pp, sign, n, 0, 0);
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, 5, ap, n, s, pp);
+  pp[n] = mpn_lshift (pp, b1, n, 1); /* 2b1 */
+  /* FIXME: use addlsh or addlsh2 */
+  v3[t] = mpn_lshift (v3, b2, t, 2);/* 4b2 */
+  if ( n == t )
+    v3[n]+= mpn_add_n (v3, v3, b0, n); /* 4b2+b0 */
+  else
+    v3[n] = mpn_add (v3, b0, n, v3, t+1); /* 4b2+b0 */
+  sign ^= abs_sub_add_n (v1, v3, pp, n + 1);
+  TOOM_63_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-2)*B(-2) */
+  TOOM_63_MUL_N_REC(r5, v2, v3, n + 1, ws); /* A(+2)*B(+2) */
+  mpn_toom_couple_handling (r5, 2*n+1, pp, sign, n, 1, 2);
+
+  /* A(0)*B(0) */
+  TOOM_63_MUL_N_REC(pp, ap, bp, n, ws);
+
+  /* Infinity */
+  if (s > t) {
+    TOOM_63_MUL_REC(r1, a5, s, b2, t, ws);
+  } else {
+    TOOM_63_MUL_REC(r1, b2, t, a5, s, ws);
+  };
+
+  mpn_toom_interpolate_8pts (pp, n, r3, r7, s + t, ws);
+
+#undef a5
+#undef b0
+#undef b1
+#undef b2
+#undef r1
+#undef r3
+#undef r5
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef r7
+#undef r8
+#undef ws
+}
diff --git a/mpn/generic/toom6_sqr.c b/mpn/generic/toom6_sqr.c
new file mode 100644
index 0000000..336eef9
--- /dev/null
+++ b/mpn/generic/toom6_sqr.c
@@ -0,0 +1,181 @@
+/* Implementation of the squaring algorithm with Toom-Cook 6.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 21
+#error Not implemented.
+#endif
+
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_above_basecase   1
+#define MAYBE_sqr_toom2   1
+#define MAYBE_sqr_above_toom2   1
+#define MAYBE_sqr_toom3   1
+#define MAYBE_sqr_above_toom3   1
+#define MAYBE_sqr_above_toom4   1
+#else
+#ifdef  SQR_TOOM8_THRESHOLD
+#define SQR_TOOM6_MAX ((SQR_TOOM8_THRESHOLD+6*2-1+5)/6)
+#else
+#define SQR_TOOM6_MAX					\
+  ((SQR_FFT_THRESHOLD <= MP_SIZE_T_MAX - (6*2-1+5)) ?	\
+   ((SQR_FFT_THRESHOLD+6*2-1+5)/6)			\
+   : MP_SIZE_T_MAX )
+#endif
+#define MAYBE_sqr_basecase					\
+  (SQR_TOOM6_THRESHOLD < 6 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_above_basecase				\
+  (SQR_TOOM6_MAX >=  SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom2						\
+  (SQR_TOOM6_THRESHOLD < 6 * SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_above_toom2					\
+  (SQR_TOOM6_MAX >= SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_toom3						\
+  (SQR_TOOM6_THRESHOLD < 6 * SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_above_toom3					\
+  (SQR_TOOM6_MAX >= SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_above_toom4					\
+  (SQR_TOOM6_MAX >= SQR_TOOM6_THRESHOLD)
+#endif
+
+#define TOOM6_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (MAYBE_sqr_basecase && ( !MAYBE_sqr_above_basecase		\
+	|| BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD)))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else if (MAYBE_sqr_toom2 && ( !MAYBE_sqr_above_toom2		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD)))		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+    else if (MAYBE_sqr_toom3 && ( !MAYBE_sqr_above_toom3		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD)))		\
+      mpn_toom3_sqr (p, a, n, ws);					\
+    else if (! MAYBE_sqr_above_toom4					\
+	     || BELOW_THRESHOLD (n, SQR_TOOM6_THRESHOLD))		\
+      mpn_toom4_sqr (p, a, n, ws);					\
+    else								\
+      mpn_toom6_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom6_sqr  (mp_ptr pp, mp_srcptr ap, mp_size_t an, mp_ptr scratch)
+{
+  mp_size_t n, s;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT( an >= 18 );
+
+  n = 1 + (an - 1) / (size_t) 6;
+
+  s = an - 5 * n;
+
+  ASSERT (0 < s && s <= n);
+
+#define   r4    (pp + 3 * n)			/* 3n+1 */
+#define   r2    (pp + 7 * n)			/* 3n+1 */
+#define   r0    (pp +11 * n)			/* s+t <= 2*n */
+#define   r5    (scratch)			/* 3n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   v0    (pp + 7 * n)			/* n+1 */
+#define   v2    (pp + 9 * n+2)			/* n+1 */
+#define   wse   (scratch + 9 * n + 3)		/* 3n+1 */
+
+  /* Alloc also 3n+1 limbs for ws... toom_interpolate_12pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+/*   if (scratch== NULL) */
+/*     scratch = TMP_SALLOC_LIMBS (12 * n + 6); */
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm1/2$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 5, ap, n, s, 1, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-1/2)*B(-1/2)*2^. */
+  TOOM6_SQR_REC(r5, v2, n + 1, wse); /* A(+1/2)*B(+1/2)*2^. */
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, 0, n, 1, 0);
+
+  /* $\pm1$ */
+  mpn_toom_eval_pm1 (v2, v0, 5, ap, n, s,    pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-1)*B(-1) */
+  TOOM6_SQR_REC(r3, v2, n + 1, wse); /* A(1)*B(1) */
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, 0, n, 0, 0);
+
+  /* $\pm4$ */
+  mpn_toom_eval_pm2exp (v2, v0, 5, ap, n, s, 2, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-4)*B(-4) */
+  TOOM6_SQR_REC(r1, v2, n + 1, wse); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r1, 2 * n + 1, pp, 0, n, 2, 4);
+
+  /* $\pm1/4$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 5, ap, n, s, 2, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-1/4)*B(-1/4)*4^. */
+  TOOM6_SQR_REC(r4, v2, n + 1, wse); /* A(+1/4)*B(+1/4)*4^. */
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, 0, n, 2, 0);
+
+  /* $\pm2$ */
+  mpn_toom_eval_pm2 (v2, v0, 5, ap, n, s, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-2)*B(-2) */
+  TOOM6_SQR_REC(r2, v2, n + 1, wse); /* A(+2)*B(+2) */
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, 0, n, 1, 2);
+
+#undef v0
+#undef v2
+
+  /* A(0)*B(0) */
+  TOOM6_SQR_REC(pp, ap, n, wse);
+
+  mpn_toom_interpolate_12pts (pp, r1, r3, r5, n, 2 * s, 0, wse);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+
+}
+#undef TOOM6_SQR_REC
+#undef MAYBE_sqr_basecase
+#undef MAYBE_sqr_above_basecase
+#undef MAYBE_sqr_toom2
+#undef MAYBE_sqr_above_toom2
+#undef MAYBE_sqr_toom3
+#undef MAYBE_sqr_above_toom3
+#undef MAYBE_sqr_above_toom4
diff --git a/mpn/generic/toom6h_mul.c b/mpn/generic/toom6h_mul.c
new file mode 100644
index 0000000..637f2a5
--- /dev/null
+++ b/mpn/generic/toom6h_mul.c
@@ -0,0 +1,262 @@
+/* Implementation of the multiplication algorithm for Toom-Cook 6.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 21
+#error Not implemented.
+#endif
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom22   1
+#define MAYBE_mul_toom33   1
+#define MAYBE_mul_toom6h   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM33_THRESHOLD)
+#define MAYBE_mul_toom33						\
+  (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM44_THRESHOLD)
+#define MAYBE_mul_toom6h						\
+  (MUL_FFT_THRESHOLD >= 6 * MUL_TOOM6H_THRESHOLD)
+#endif
+
+#define TOOM6H_MUL_N_REC(p, a, b, f, p2, a2, b2, n, ws)			\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD)) {			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+      if (f)								\
+	mpn_mul_basecase (p2, a2, n, b2, n);				\
+    } else if (MAYBE_mul_toom22						\
+	       && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD)) {		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom22_mul (p2, a2, n, b2, n, ws);				\
+    } else if (MAYBE_mul_toom33						\
+	       && BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD)) {		\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom33_mul (p2, a2, n, b2, n, ws);				\
+    } else if (! MAYBE_mul_toom6h					\
+	       || BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD)) {		\
+      mpn_toom44_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom44_mul (p2, a2, n, b2, n, ws);				\
+    } else {								\
+      mpn_toom6h_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom6h_mul (p2, a2, n, b2, n, ws);				\
+    }									\
+  } while (0)
+
+#define TOOM6H_MUL_REC(p, a, na, b, nb, ws)		\
+  do { mpn_mul (p, a, na, b, nb);			\
+  } while (0)
+
+/* Toom-6.5 , compute the product {pp,an+bn} <- {ap,an} * {bp,bn}
+   With: an >= bn >= 46, an*6 <  bn * 17.
+   It _may_ work with bn<=46 and bn*17 < an*6 < bn*18
+
+   Evaluate in: infinity, +4, -4, +2, -2, +1, -1, +1/2, -1/2, +1/4, -1/4, 0.
+*/
+/* Estimate on needed scratch:
+   S(n) <= (n+5)\6*10+4+MAX(S((n+5)\6),1+2*(n+5)\6),
+   since n>42; S(n) <= ceil(log(n)/log(6))*(10+4)+n*12\6 < n*2 + lg2(n)*6
+ */
+
+void
+mpn_toom6h_mul   (mp_ptr pp,
+		  mp_srcptr ap, mp_size_t an,
+		  mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int p, q, half;
+  int sign;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT (an >= bn);
+  /* Can not handle too much unbalancement */
+  ASSERT (bn >= 42);
+  /* Can not handle too much unbalancement */
+  ASSERT ((an*3 <  bn * 8) || (bn >= 46 && an * 6 <  bn * 17));
+
+  /* Limit num/den is a rational number between
+     (12/11)^(log(4)/log(2*4-1)) and (12/11)^(log(6)/log(2*6-1))             */
+#define LIMIT_numerator (18)
+#define LIMIT_denominat (17)
+
+  if (LIKELY (an * LIMIT_denominat < LIMIT_numerator * bn)) /* is 6*... < 6*... */
+    {
+      n = 1 + (an - 1) / (size_t) 6;
+      p = q = 5;
+      half = 0;
+
+      s = an - 5 * n;
+      t = bn - 5 * n;
+    }
+  else {
+    if (an * 5 * LIMIT_numerator < LIMIT_denominat * 7 * bn)
+      { p = 7; q = 6; }
+    else if (an * 5 * LIMIT_denominat < LIMIT_numerator * 7 * bn)
+      { p = 7; q = 5; }
+    else if (an * LIMIT_numerator < LIMIT_denominat * 2 * bn)  /* is 4*... < 8*... */
+      { p = 8; q = 5; }
+    else if (an * LIMIT_denominat < LIMIT_numerator * 2 * bn)  /* is 4*... < 8*... */
+      { p = 8; q = 4; }
+    else
+      { p = 9; q = 4; }
+
+    half = (p ^ q) & 1;
+    n = 1 + (q * an >= p * bn ? (an - 1) / (size_t) p : (bn - 1) / (size_t) q);
+    p--; q--;
+
+    s = an - p * n;
+    t = bn - q * n;
+
+    /* With LIMIT = 16/15, the following recover is needed only if bn<=73*/
+    if (half) { /* Recover from badly chosen splitting */
+      if (UNLIKELY (s<1)) {p--; s+=n; half=0;}
+      else if (UNLIKELY (t<1)) {q--; t+=n; half=0;}
+    }
+  }
+#undef LIMIT_numerator
+#undef LIMIT_denominat
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (half || s + t > 3);
+  ASSERT (n > 2);
+
+#define   r4    (pp + 3 * n)			/* 3n+1 */
+#define   r2    (pp + 7 * n)			/* 3n+1 */
+#define   r0    (pp +11 * n)			/* s+t <= 2*n */
+#define   r5    (scratch)			/* 3n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   v0    (pp + 7 * n)			/* n+1 */
+#define   v1    (pp + 8 * n+1)			/* n+1 */
+#define   v2    (pp + 9 * n+2)			/* n+1 */
+#define   v3    (scratch + 9 * n + 3)		/* n+1 */
+#define   wsi   (scratch + 9 * n + 3)		/* 3n+1 */
+#define   wse   (scratch +10 * n + 4)		/* 2n+1 */
+
+  /* Alloc also 3n+1 limbs for wsi... toom_interpolate_12pts may
+     need all of them  */
+/*   if (scratch == NULL) */
+/*     scratch = TMP_SALLOC_LIMBS(mpn_toom6_sqr_itch(n * 6)); */
+  ASSERT (12 * n + 6 <= mpn_toom6h_mul_itch(an,bn));
+  ASSERT (12 * n + 6 <= mpn_toom6_sqr_itch(n * 6));
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm1/2$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 1, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 1, pp);
+  /* A(-1/2)*B(-1/2)*2^. */ /* A(+1/2)*B(+1/2)*2^. */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r5, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, sign, n, 1+half , half);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, p, ap, n, s,    pp);
+  if (UNLIKELY (q == 3))
+    sign ^= mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t,    pp);
+  else
+    sign ^= mpn_toom_eval_pm1 (v3, v1, q, bp, n, t,    pp);
+  /* A(-1)*B(-1) */ /* A(1)*B(1) */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r3, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, sign, n, 0, 0);
+
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-4)*B(-4) */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r1, v2, v3, n + 1, wse); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r1, 2 * n + 1, pp, sign, n, 2, 4);
+
+  /* $\pm1/4$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-1/4)*B(-1/4)*4^. */ /* A(+1/4)*B(+1/4)*4^. */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r4, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, sign, n, 2*(1+half), 2*(half));
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, p, ap, n, s, pp) ^
+	 mpn_toom_eval_pm2 (v3, v1, q, bp, n, t, pp);
+  /* A(-2)*B(-2) */ /* A(+2)*B(+2) */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r2, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, sign, n, 1, 2);
+
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef wse
+
+  /* A(0)*B(0) */
+  TOOM6H_MUL_N_REC(pp, ap, bp, 0, pp, ap, bp, n, wsi);
+
+  /* Infinity */
+  if (UNLIKELY (half != 0)) {
+    if (s > t) {
+      TOOM6H_MUL_REC(r0, ap + p * n, s, bp + q * n, t, wsi);
+    } else {
+      TOOM6H_MUL_REC(r0, bp + q * n, t, ap + p * n, s, wsi);
+    };
+  };
+
+  mpn_toom_interpolate_12pts (pp, r1, r3, r5, n, s+t, half, wsi);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+#undef wsi
+}
+
+#undef TOOM6H_MUL_N_REC
+#undef TOOM6H_MUL_REC
+#undef MAYBE_mul_basecase
+#undef MAYBE_mul_toom22
+#undef MAYBE_mul_toom33
+#undef MAYBE_mul_toom6h
diff --git a/mpn/generic/toom8_sqr.c b/mpn/generic/toom8_sqr.c
new file mode 100644
index 0000000..03e5c64
--- /dev/null
+++ b/mpn/generic/toom8_sqr.c
@@ -0,0 +1,225 @@
+/* Implementation of the squaring algorithm with Toom-Cook 8.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+#if GMP_NUMB_BITS < 29
+#error Not implemented.
+#endif
+
+#if GMP_NUMB_BITS < 43
+#define BIT_CORRECTION 1
+#define CORRECTION_BITS GMP_NUMB_BITS
+#else
+#define BIT_CORRECTION 0
+#define CORRECTION_BITS 0
+#endif
+
+#ifndef SQR_TOOM8_THRESHOLD
+#define SQR_TOOM8_THRESHOLD MUL_TOOM8H_THRESHOLD
+#endif
+
+#ifndef SQR_TOOM6_THRESHOLD
+#define SQR_TOOM6_THRESHOLD MUL_TOOM6H_THRESHOLD
+#endif
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_above_basecase   1
+#define MAYBE_sqr_toom2   1
+#define MAYBE_sqr_above_toom2   1
+#define MAYBE_sqr_toom3   1
+#define MAYBE_sqr_above_toom3   1
+#define MAYBE_sqr_toom4   1
+#define MAYBE_sqr_above_toom4   1
+#define MAYBE_sqr_above_toom6   1
+#else
+#define SQR_TOOM8_MAX					\
+  ((SQR_FFT_THRESHOLD <= MP_SIZE_T_MAX - (8*2-1+7)) ?	\
+   ((SQR_FFT_THRESHOLD+8*2-1+7)/8)			\
+   : MP_SIZE_T_MAX )
+#define MAYBE_sqr_basecase					\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_above_basecase				\
+  (SQR_TOOM8_MAX >= SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom2						\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_above_toom2					\
+  (SQR_TOOM8_MAX >= SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_toom3						\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_above_toom3					\
+  (SQR_TOOM8_MAX >= SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_toom4						\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM6_THRESHOLD)
+#define MAYBE_sqr_above_toom4					\
+  (SQR_TOOM8_MAX >= SQR_TOOM6_THRESHOLD)
+#define MAYBE_sqr_above_toom6					\
+  (SQR_TOOM8_MAX >= SQR_TOOM8_THRESHOLD)
+#endif
+
+#define TOOM8_SQR_REC(p, a, f, p2, a2, n, ws)				\
+  do {									\
+    if (MAYBE_sqr_basecase && ( !MAYBE_sqr_above_basecase		\
+	|| BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))) {			\
+      mpn_sqr_basecase (p, a, n);					\
+      if (f) mpn_sqr_basecase (p2, a2, n);				\
+    } else if (MAYBE_sqr_toom2 && ( !MAYBE_sqr_above_toom2		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))) {		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+      if (f) mpn_toom2_sqr (p2, a2, n, ws);				\
+    } else if (MAYBE_sqr_toom3 && ( !MAYBE_sqr_above_toom3		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD))) {		\
+      mpn_toom3_sqr (p, a, n, ws);					\
+      if (f) mpn_toom3_sqr (p2, a2, n, ws);				\
+    } else if (MAYBE_sqr_toom4 && ( !MAYBE_sqr_above_toom4		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM6_THRESHOLD))) {		\
+      mpn_toom4_sqr (p, a, n, ws);					\
+      if (f) mpn_toom4_sqr (p2, a2, n, ws);				\
+    } else if (! MAYBE_sqr_above_toom6					\
+	     || BELOW_THRESHOLD (n, SQR_TOOM8_THRESHOLD)) {		\
+      mpn_toom6_sqr (p, a, n, ws);					\
+      if (f) mpn_toom6_sqr (p2, a2, n, ws);				\
+    } else {								\
+      mpn_toom8_sqr (p, a, n, ws);					\
+      if (f) mpn_toom8_sqr (p2, a2, n, ws);				\
+    }									\
+  } while (0)
+
+void
+mpn_toom8_sqr  (mp_ptr pp, mp_srcptr ap, mp_size_t an, mp_ptr scratch)
+{
+  mp_size_t n, s;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT ( an >= 40 );
+
+  n = 1 + ((an - 1)>>3);
+
+  s = an - 7 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT ( s + s > 3 );
+
+#define   r6    (pp + 3 * n)			/* 3n+1 */
+#define   r4    (pp + 7 * n)			/* 3n+1 */
+#define   r2    (pp +11 * n)			/* 3n+1 */
+#define   r0    (pp +15 * n)			/* s+t <= 2*n */
+#define   r7    (scratch)			/* 3n+1 */
+#define   r5    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r3    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   r1    (scratch + 9 * n + 3)		/* 3n+1 */
+#define   v0    (pp +11 * n)			/* n+1 */
+#define   v2    (pp +13 * n+2)			/* n+1 */
+#define   wse   (scratch +12 * n + 4)		/* 3n+1 */
+
+  /* Alloc also 3n+1 limbs for ws... toom_interpolate_16pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+/*   if (scratch == NULL) */
+/*     scratch = TMP_SALLOC_LIMBS (30 * n + 6); */
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm1/8$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 7, ap, n, s, 3, pp);
+  /* A(-1/8)*B(-1/8)*8^. */ /* A(+1/8)*B(+1/8)*8^. */
+  TOOM8_SQR_REC(pp, v0, 2, r7, v2, n + 1, wse);
+  mpn_toom_couple_handling (r7, 2 * n + 1 + BIT_CORRECTION, pp, 0, n, 3, 0);
+
+  /* $\pm1/4$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 7, ap, n, s, 2, pp);
+  /* A(-1/4)*B(-1/4)*4^. */ /* A(+1/4)*B(+1/4)*4^. */
+  TOOM8_SQR_REC(pp, v0, 2, r5, v2, n + 1, wse);
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, 0, n, 2, 0);
+
+  /* $\pm2$ */
+  mpn_toom_eval_pm2 (v2, v0, 7, ap, n, s, pp);
+  /* A(-2)*B(-2) */ /* A(+2)*B(+2) */
+  TOOM8_SQR_REC(pp, v0, 2, r3, v2, n + 1, wse);
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, 0, n, 1, 2);
+
+  /* $\pm8$ */
+  mpn_toom_eval_pm2exp (v2, v0, 7, ap, n, s, 3, pp);
+  /* A(-8)*B(-8) */ /* A(+8)*B(+8) */
+  TOOM8_SQR_REC(pp, v0, 2, r1, v2, n + 1, wse);
+  mpn_toom_couple_handling (r1, 2 * n + 1 + BIT_CORRECTION, pp, 0, n, 3, 6);
+
+  /* $\pm1/2$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 7, ap, n, s, 1, pp);
+  /* A(-1/2)*B(-1/2)*2^. */ /* A(+1/2)*B(+1/2)*2^. */
+  TOOM8_SQR_REC(pp, v0, 2, r6, v2, n + 1, wse);
+  mpn_toom_couple_handling (r6, 2 * n + 1, pp, 0, n, 1, 0);
+
+  /* $\pm1$ */
+  mpn_toom_eval_pm1 (v2, v0, 7, ap, n, s,    pp);
+  /* A(-1)*B(-1) */ /* A(1)*B(1) */
+  TOOM8_SQR_REC(pp, v0, 2, r4, v2, n + 1, wse);
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, 0, n, 0, 0);
+
+  /* $\pm4$ */
+  mpn_toom_eval_pm2exp (v2, v0, 7, ap, n, s, 2, pp);
+  /* A(-4)*B(-4) */ /* A(+4)*B(+4) */
+  TOOM8_SQR_REC(pp, v0, 2, r2, v2, n + 1, wse);
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, 0, n, 2, 4);
+
+#undef v0
+#undef v2
+
+  /* A(0)*B(0) */
+  TOOM8_SQR_REC(pp, ap, 0, pp, ap, n, wse);
+
+  mpn_toom_interpolate_16pts (pp, r1, r3, r5, r7, n, 2 * s, 0, wse);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+#undef r6
+#undef wse
+
+}
+
+#undef TOOM8_SQR_REC
+#undef MAYBE_sqr_basecase
+#undef MAYBE_sqr_above_basecase
+#undef MAYBE_sqr_toom2
+#undef MAYBE_sqr_above_toom2
+#undef MAYBE_sqr_toom3
+#undef MAYBE_sqr_above_toom3
+#undef MAYBE_sqr_above_toom4
diff --git a/mpn/generic/toom8h_mul.c b/mpn/generic/toom8h_mul.c
new file mode 100644
index 0000000..5ba259a
--- /dev/null
+++ b/mpn/generic/toom8h_mul.c
@@ -0,0 +1,305 @@
+/* Implementation of the multiplication algorithm for Toom-Cook 8.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 29
+#error Not implemented.
+#endif
+
+#if GMP_NUMB_BITS < 43
+#define BIT_CORRECTION 1
+#define CORRECTION_BITS GMP_NUMB_BITS
+#else
+#define BIT_CORRECTION 0
+#define CORRECTION_BITS 0
+#endif
+
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom22   1
+#define MAYBE_mul_toom33   1
+#define MAYBE_mul_toom44   1
+#define MAYBE_mul_toom8h   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM33_THRESHOLD)
+#define MAYBE_mul_toom33						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM44_THRESHOLD)
+#define MAYBE_mul_toom44						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM6H_THRESHOLD)
+#define MAYBE_mul_toom8h						\
+  (MUL_FFT_THRESHOLD >= 8 * MUL_TOOM8H_THRESHOLD)
+#endif
+
+#define TOOM8H_MUL_N_REC(p, a, b, f, p2, a2, b2, n, ws)			\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD)) {			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+      if (f) mpn_mul_basecase (p2, a2, n, b2, n);			\
+    } else if (MAYBE_mul_toom22						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD)) {		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom22_mul (p2, a2, n, b2, n, ws);			\
+    } else if (MAYBE_mul_toom33						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD)) {		\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom33_mul (p2, a2, n, b2, n, ws);			\
+    } else if (MAYBE_mul_toom44						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD)) {		\
+      mpn_toom44_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom44_mul (p2, a2, n, b2, n, ws);			\
+    } else if (! MAYBE_mul_toom8h					\
+	     || BELOW_THRESHOLD (n, MUL_TOOM8H_THRESHOLD)) {		\
+      mpn_toom6h_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom6h_mul (p2, a2, n, b2, n, ws);			\
+    } else {								\
+      mpn_toom8h_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom8h_mul (p2, a2, n, b2, n, ws);			\
+    }									\
+  } while (0)
+
+#define TOOM8H_MUL_REC(p, a, na, b, nb, ws)		\
+  do { mpn_mul (p, a, na, b, nb); } while (0)
+
+/* Toom-8.5 , compute the product {pp,an+bn} <- {ap,an} * {bp,bn}
+   With: an >= bn >= 86, an*5 <  bn * 11.
+   It _may_ work with bn<=?? and bn*?? < an*? < bn*??
+
+   Evaluate in: infinity, +8,-8,+4,-4,+2,-2,+1,-1,+1/2,-1/2,+1/4,-1/4,+1/8,-1/8,0.
+*/
+/* Estimate on needed scratch:
+   S(n) <= (n+7)\8*13+5+MAX(S((n+7)\8),1+2*(n+7)\8),
+   since n>80; S(n) <= ceil(log(n/10)/log(8))*(13+5)+n*15\8 < n*15\8 + lg2(n)*6
+ */
+
+void
+mpn_toom8h_mul   (mp_ptr pp,
+		  mp_srcptr ap, mp_size_t an,
+		  mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int p, q, half;
+  int sign;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT (an >= bn);
+  /* Can not handle too small operands */
+  ASSERT (bn >= 86);
+  /* Can not handle too much unbalancement */
+  ASSERT (an <= bn*4);
+  ASSERT (GMP_NUMB_BITS > 11*3 || an*4 <= bn*11);
+  ASSERT (GMP_NUMB_BITS > 10*3 || an*1 <= bn* 2);
+  ASSERT (GMP_NUMB_BITS >  9*3 || an*2 <= bn* 3);
+
+  /* Limit num/den is a rational number between
+     (16/15)^(log(6)/log(2*6-1)) and (16/15)^(log(8)/log(2*8-1))             */
+#define LIMIT_numerator (21)
+#define LIMIT_denominat (20)
+
+  if (LIKELY (an == bn) || an * (LIMIT_denominat>>1) < LIMIT_numerator * (bn>>1) ) /* is 8*... < 8*... */
+    {
+      half = 0;
+      n = 1 + ((an - 1)>>3);
+      p = q = 7;
+      s = an - 7 * n;
+      t = bn - 7 * n;
+    }
+  else
+    {
+      if (an * 13 < 16 * bn) /* (an*7*LIMIT_numerator<LIMIT_denominat*9*bn) */
+	{ p = 9; q = 8; }
+      else if (GMP_NUMB_BITS <= 9*3 ||
+	       an *(LIMIT_denominat>>1) < (LIMIT_numerator/7*9) * (bn>>1))
+	{ p = 9; q = 7; }
+      else if (an * 10 < 33 * (bn>>1)) /* (an*3*LIMIT_numerator<LIMIT_denominat*5*bn) */
+	{ p =10; q = 7; }
+      else if (GMP_NUMB_BITS <= 10*3 ||
+	       an * (LIMIT_denominat/5) < (LIMIT_numerator/3) * bn)
+	{ p =10; q = 6; }
+      else if (an * 6 < 13 * bn) /*(an * 5 * LIMIT_numerator < LIMIT_denominat *11 * bn)*/
+	{ p =11; q = 6; }
+      else if (GMP_NUMB_BITS <= 11*3 ||
+	       an * 4 < 9 * bn)
+	{ p =11; q = 5; }
+      else if (an *(LIMIT_numerator/3) < LIMIT_denominat * bn)  /* is 4*... <12*... */
+	{ p =12; q = 5; }
+      else if (GMP_NUMB_BITS <= 12*3 ||
+	       an * 9 < 28 * bn )  /* is 4*... <12*... */
+	{ p =12; q = 4; }
+      else
+	{ p =13; q = 4; }
+
+      half = (p+q)&1;
+      n = 1 + (q * an >= p * bn ? (an - 1) / (size_t) p : (bn - 1) / (size_t) q);
+      p--; q--;
+
+      s = an - p * n;
+      t = bn - q * n;
+
+      if(half) { /* Recover from badly chosen splitting */
+	if (UNLIKELY (s<1)) {p--; s+=n; half=0;}
+	else if (UNLIKELY (t<1)) {q--; t+=n; half=0;}
+      }
+    }
+#undef LIMIT_numerator
+#undef LIMIT_denominat
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (half || s + t > 3);
+  ASSERT (n > 2);
+
+#define   r6    (pp + 3 * n)			/* 3n+1 */
+#define   r4    (pp + 7 * n)			/* 3n+1 */
+#define   r2    (pp +11 * n)			/* 3n+1 */
+#define   r0    (pp +15 * n)			/* s+t <= 2*n */
+#define   r7    (scratch)			/* 3n+1 */
+#define   r5    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r3    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   r1    (scratch + 9 * n + 3)		/* 3n+1 */
+#define   v0    (pp +11 * n)			/* n+1 */
+#define   v1    (pp +12 * n+1)			/* n+1 */
+#define   v2    (pp +13 * n+2)			/* n+1 */
+#define   v3    (scratch +12 * n + 4)		/* n+1 */
+#define   wsi   (scratch +12 * n + 4)		/* 3n+1 */
+#define   wse   (scratch +13 * n + 5)		/* 2n+1 */
+
+  /* Alloc also 3n+1 limbs for wsi... toom_interpolate_16pts may
+     need all of them  */
+/*   if (scratch == NULL) */
+/*     scratch = TMP_SALLOC_LIMBS(mpn_toom8_sqr_itch(n * 8)); */
+  ASSERT (15 * n + 6 <= mpn_toom8h_mul_itch (an, bn));
+  ASSERT (15 * n + 6 <= mpn_toom8_sqr_itch (n * 8));
+
+  /********************** evaluation and recursive calls *********************/
+
+  /* $\pm1/8$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 3, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 3, pp);
+  /* A(-1/8)*B(-1/8)*8^. */ /* A(+1/8)*B(+1/8)*8^. */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r7, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r7, 2 * n + 1 + BIT_CORRECTION, pp, sign, n, 3*(1+half), 3*(half));
+
+  /* $\pm1/4$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-1/4)*B(-1/4)*4^. */ /* A(+1/4)*B(+1/4)*4^. */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r5, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, sign, n, 2*(1+half), 2*(half));
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, p, ap, n, s, pp) ^
+	 mpn_toom_eval_pm2 (v3, v1, q, bp, n, t, pp);
+  /* A(-2)*B(-2) */ /* A(+2)*B(+2) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r3, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, sign, n, 1, 2);
+
+  /* $\pm8$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 3, pp) ^
+	 mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 3, pp);
+  /* A(-8)*B(-8) */ /* A(+8)*B(+8) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r1, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r1, 2 * n + 1 + BIT_CORRECTION, pp, sign, n, 3, 6);
+
+  /* $\pm1/2$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 1, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 1, pp);
+  /* A(-1/2)*B(-1/2)*2^. */ /* A(+1/2)*B(+1/2)*2^. */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r6, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r6, 2 * n + 1, pp, sign, n, 1+half, half);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, p, ap, n, s,    pp);
+  if (GMP_NUMB_BITS > 12*3 && UNLIKELY (q == 3))
+    sign ^= mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t,    pp);
+  else
+    sign ^= mpn_toom_eval_pm1 (v3, v1, q, bp, n, t,    pp);
+  /* A(-1)*B(-1) */ /* A(1)*B(1) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r4, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, sign, n, 0, 0);
+
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-4)*B(-4) */ /* A(+4)*B(+4) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r2, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, sign, n, 2, 4);
+
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef wse
+
+  /* A(0)*B(0) */
+  TOOM8H_MUL_N_REC(pp, ap, bp, 0, pp, ap, bp, n, wsi);
+
+  /* Infinity */
+  if (UNLIKELY (half != 0)) {
+    if (s > t) {
+      TOOM8H_MUL_REC(r0, ap + p * n, s, bp + q * n, t, wsi);
+    } else {
+      TOOM8H_MUL_REC(r0, bp + q * n, t, ap + p * n, s, wsi);
+    };
+  };
+
+  mpn_toom_interpolate_16pts (pp, r1, r3, r5, r7, n, s+t, half, wsi);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+#undef r6
+#undef wsi
+}
+
+#undef TOOM8H_MUL_N_REC
+#undef TOOM8H_MUL_REC
+#undef MAYBE_mul_basecase
+#undef MAYBE_mul_toom22
+#undef MAYBE_mul_toom33
+#undef MAYBE_mul_toom44
+#undef MAYBE_mul_toom8h
diff --git a/mpn/generic/toom_couple_handling.c b/mpn/generic/toom_couple_handling.c
new file mode 100644
index 0000000..cd253f7
--- /dev/null
+++ b/mpn/generic/toom_couple_handling.c
@@ -0,0 +1,80 @@
+/* Helper function for high degree Toom-Cook algorithms.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Gets {pp,n} and (sign?-1:1)*{np,n}. Computes at once:
+     {pp,n} <- ({pp,n}+{np,n})/2^{ps+1}
+     {pn,n} <- ({pp,n}-{np,n})/2^{ns+1}
+   Finally recompose them obtaining:
+     {pp,n+off} <- {pp,n}+{np,n}*2^{off*GMP_NUMB_BITS}
+*/
+void
+mpn_toom_couple_handling (mp_ptr pp, mp_size_t n, mp_ptr np,
+			  int nsign, mp_size_t off, int ps, int ns)
+{
+  if (nsign) {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+    mpn_rsh1sub_n (np, pp, np, n);
+#else
+    mpn_sub_n (np, pp, np, n);
+    mpn_rshift (np, np, n, 1);
+#endif
+  } else {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+    mpn_rsh1add_n (np, pp, np, n);
+#else
+    mpn_add_n (np, pp, np, n);
+    mpn_rshift (np, np, n, 1);
+#endif
+  }
+
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  if (ps == 1)
+    mpn_rsh1sub_n (pp, pp, np, n);
+  else
+#endif
+  {
+    mpn_sub_n (pp, pp, np, n);
+    if (ps > 0)
+      mpn_rshift (pp, pp, n, ps);
+  }
+  if (ns > 0)
+    mpn_rshift (np, np, n, ns);
+  pp[n] = mpn_add_n (pp+off, pp+off, np, n-off);
+  ASSERT_NOCARRY (mpn_add_1(pp+n, np+n-off, off, pp[n]) );
+}
diff --git a/mpn/generic/toom_eval_dgr3_pm1.c b/mpn/generic/toom_eval_dgr3_pm1.c
new file mode 100644
index 0000000..5f491b6
--- /dev/null
+++ b/mpn/generic/toom_eval_dgr3_pm1.c
@@ -0,0 +1,72 @@
+/* mpn_toom_eval_dgr3_pm1 -- Evaluate a degree 3 polynomial in +1 and -1
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+int
+mpn_toom_eval_dgr3_pm1 (mp_ptr xp1, mp_ptr xm1,
+			mp_srcptr xp, mp_size_t n, mp_size_t x3n, mp_ptr tp)
+{
+  int neg;
+
+  ASSERT (x3n > 0);
+  ASSERT (x3n <= n);
+
+  xp1[n] = mpn_add_n (xp1, xp, xp + 2*n, n);
+  tp[n] = mpn_add (tp, xp + n, n, xp + 3*n, x3n);
+
+  neg = (mpn_cmp (xp1, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp1, xm1, tp, xp1, n + 1);
+  else
+    mpn_add_n_sub_n (xp1, xm1, xp1, tp, n + 1);
+#else
+  if (neg)
+    mpn_sub_n (xm1, tp, xp1, n + 1);
+  else
+    mpn_sub_n (xm1, xp1, tp, n + 1);
+
+  mpn_add_n (xp1, xp1, tp, n + 1);
+#endif
+
+  ASSERT (xp1[n] <= 3);
+  ASSERT (xm1[n] <= 1);
+
+  return neg;
+}
diff --git a/mpn/generic/toom_eval_dgr3_pm2.c b/mpn/generic/toom_eval_dgr3_pm2.c
new file mode 100644
index 0000000..55e6b89
--- /dev/null
+++ b/mpn/generic/toom_eval_dgr3_pm2.c
@@ -0,0 +1,97 @@
+/* mpn_toom_eval_dgr3_pm2 -- Evaluate a degree 3 polynomial in +2 and -2
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Needs n+1 limbs of temporary storage. */
+int
+mpn_toom_eval_dgr3_pm2 (mp_ptr xp2, mp_ptr xm2,
+			mp_srcptr xp, mp_size_t n, mp_size_t x3n, mp_ptr tp)
+{
+  mp_limb_t cy;
+  int neg;
+
+  ASSERT (x3n > 0);
+  ASSERT (x3n <= n);
+
+  /* (x0 + 4 * x2) +/- (2 x1 + 8 x_3) */
+#if HAVE_NATIVE_mpn_addlsh_n || HAVE_NATIVE_mpn_addlsh2_n
+#if HAVE_NATIVE_mpn_addlsh2_n
+  xp2[n] = mpn_addlsh2_n (xp2, xp, xp + 2*n, n);
+
+  cy = mpn_addlsh2_n (tp, xp + n, xp + 3*n, x3n);
+#else /* HAVE_NATIVE_mpn_addlsh_n */
+  xp2[n] = mpn_addlsh_n (xp2, xp, xp + 2*n, n, 2);
+
+  cy = mpn_addlsh_n (tp, xp + n, xp + 3*n, x3n, 2);
+#endif
+  if (x3n < n)
+    cy = mpn_add_1 (tp + x3n, xp + n + x3n, n - x3n, cy);
+  tp[n] = cy;
+#else
+  cy = mpn_lshift (tp, xp + 2*n, n, 2);
+  xp2[n] = cy + mpn_add_n (xp2, tp, xp, n);
+
+  tp[x3n] = mpn_lshift (tp, xp + 3*n, x3n, 2);
+  if (x3n < n)
+    tp[n] = mpn_add (tp, xp + n, n, tp, x3n + 1);
+  else
+    tp[n] += mpn_add_n (tp, xp + n, tp, n);
+#endif
+  mpn_lshift (tp, tp, n+1, 1);
+
+  neg = (mpn_cmp (xp2, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp2, xm2, tp, xp2, n + 1);
+  else
+    mpn_add_n_sub_n (xp2, xm2, xp2, tp, n + 1);
+#else
+  if (neg)
+    mpn_sub_n (xm2, tp, xp2, n + 1);
+  else
+    mpn_sub_n (xm2, xp2, tp, n + 1);
+
+  mpn_add_n (xp2, xp2, tp, n + 1);
+#endif
+
+  ASSERT (xp2[n] < 15);
+  ASSERT (xm2[n] < 10);
+
+  return neg;
+}
diff --git a/mpn/generic/toom_eval_pm1.c b/mpn/generic/toom_eval_pm1.c
new file mode 100644
index 0000000..a8cfa93
--- /dev/null
+++ b/mpn/generic/toom_eval_pm1.c
@@ -0,0 +1,89 @@
+/* mpn_toom_eval_pm1 -- Evaluate a polynomial in +1 and -1
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluates a polynomial of degree k > 3, in the points +1 and -1. */
+int
+mpn_toom_eval_pm1 (mp_ptr xp1, mp_ptr xm1, unsigned k,
+		   mp_srcptr xp, mp_size_t n, mp_size_t hn, mp_ptr tp)
+{
+  unsigned i;
+  int neg;
+
+  ASSERT (k >= 4);
+
+  ASSERT (hn > 0);
+  ASSERT (hn <= n);
+
+  /* The degree k is also the number of full-size coefficients, so
+   * that last coefficient, of size hn, starts at xp + k*n. */
+
+  xp1[n] = mpn_add_n (xp1, xp, xp + 2*n, n);
+  for (i = 4; i < k; i += 2)
+    ASSERT_NOCARRY (mpn_add (xp1, xp1, n+1, xp+i*n, n));
+
+  tp[n] = mpn_add_n (tp, xp + n, xp + 3*n, n);
+  for (i = 5; i < k; i += 2)
+    ASSERT_NOCARRY (mpn_add (tp, tp, n+1, xp+i*n, n));
+
+  if (k & 1)
+    ASSERT_NOCARRY (mpn_add (tp, tp, n+1, xp+k*n, hn));
+  else
+    ASSERT_NOCARRY (mpn_add (xp1, xp1, n+1, xp+k*n, hn));
+
+  neg = (mpn_cmp (xp1, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp1, xm1, tp, xp1, n + 1);
+  else
+    mpn_add_n_sub_n (xp1, xm1, xp1, tp, n + 1);
+#else
+  if (neg)
+    mpn_sub_n (xm1, tp, xp1, n + 1);
+  else
+    mpn_sub_n (xm1, xp1, tp, n + 1);
+
+  mpn_add_n (xp1, xp1, tp, n + 1);
+#endif
+
+  ASSERT (xp1[n] <= k);
+  ASSERT (xm1[n] <= k/2 + 1);
+
+  return neg;
+}
diff --git a/mpn/generic/toom_eval_pm2.c b/mpn/generic/toom_eval_pm2.c
new file mode 100644
index 0000000..be682c7
--- /dev/null
+++ b/mpn/generic/toom_eval_pm2.c
@@ -0,0 +1,130 @@
+/* mpn_toom_eval_pm2 -- Evaluate a polynomial in +2 and -2
+
+   Contributed to the GNU project by Niels Möller and Marco Bodrato
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* DO_addlsh2(d,a,b,n,cy) computes cy,{d,n} <- {a,n} + 4*(cy,{b,n}), it
+   can be used as DO_addlsh2(d,a,d,n,d[n]), for accumulation on {d,n+1}. */
+#if HAVE_NATIVE_mpn_addlsh2_n
+#define DO_addlsh2(d, a, b, n, cy)	\
+do {					\
+  (cy) <<= 2;				\
+  (cy) += mpn_addlsh2_n(d, a, b, n);	\
+} while (0)
+#else
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_addlsh2(d, a, b, n, cy)	\
+do {					\
+  (cy) <<= 2;				\
+  (cy) += mpn_addlsh_n(d, a, b, n, 2);	\
+} while (0)
+#else
+/* The following is not a general substitute for addlsh2.
+   It is correct if d == b, but it is not if d == a.  */
+#define DO_addlsh2(d, a, b, n, cy)	\
+do {					\
+  (cy) <<= 2;				\
+  (cy) += mpn_lshift(d, b, n, 2);	\
+  (cy) += mpn_add_n(d, d, a, n);	\
+} while (0)
+#endif
+#endif
+
+/* Evaluates a polynomial of degree 2 < k < GMP_NUMB_BITS, in the
+   points +2 and -2. */
+int
+mpn_toom_eval_pm2 (mp_ptr xp2, mp_ptr xm2, unsigned k,
+		   mp_srcptr xp, mp_size_t n, mp_size_t hn, mp_ptr tp)
+{
+  int i;
+  int neg;
+  mp_limb_t cy;
+
+  ASSERT (k >= 3);
+  ASSERT (k < GMP_NUMB_BITS);
+
+  ASSERT (hn > 0);
+  ASSERT (hn <= n);
+
+  /* The degree k is also the number of full-size coefficients, so
+   * that last coefficient, of size hn, starts at xp + k*n. */
+
+  cy = 0;
+  DO_addlsh2 (xp2, xp + (k-2) * n, xp + k * n, hn, cy);
+  if (hn != n)
+    cy = mpn_add_1 (xp2 + hn, xp + (k-2) * n + hn, n - hn, cy);
+  for (i = k - 4; i >= 0; i -= 2)
+    DO_addlsh2 (xp2, xp + i * n, xp2, n, cy);
+  xp2[n] = cy;
+
+  k--;
+
+  cy = 0;
+  DO_addlsh2 (tp, xp + (k-2) * n, xp + k * n, n, cy);
+  for (i = k - 4; i >= 0; i -= 2)
+    DO_addlsh2 (tp, xp + i * n, tp, n, cy);
+  tp[n] = cy;
+
+  if (k & 1)
+    ASSERT_NOCARRY(mpn_lshift (tp , tp , n + 1, 1));
+  else
+    ASSERT_NOCARRY(mpn_lshift (xp2, xp2, n + 1, 1));
+
+  neg = (mpn_cmp (xp2, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp2, xm2, tp, xp2, n + 1);
+  else
+    mpn_add_n_sub_n (xp2, xm2, xp2, tp, n + 1);
+#else /* !HAVE_NATIVE_mpn_add_n_sub_n */
+  if (neg)
+    mpn_sub_n (xm2, tp, xp2, n + 1);
+  else
+    mpn_sub_n (xm2, xp2, tp, n + 1);
+
+  mpn_add_n (xp2, xp2, tp, n + 1);
+#endif /* !HAVE_NATIVE_mpn_add_n_sub_n */
+
+  ASSERT (xp2[n] < (1<<(k+2))-1);
+  ASSERT (xm2[n] < ((1<<(k+3))-1 - (1^k&1))/3);
+
+  neg ^= ((k & 1) - 1);
+
+  return neg;
+}
+
+#undef DO_addlsh2
diff --git a/mpn/generic/toom_eval_pm2exp.c b/mpn/generic/toom_eval_pm2exp.c
new file mode 100644
index 0000000..c3c4651
--- /dev/null
+++ b/mpn/generic/toom_eval_pm2exp.c
@@ -0,0 +1,127 @@
+/* mpn_toom_eval_pm2exp -- Evaluate a polynomial in +2^k and -2^k
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluates a polynomial of degree k > 2, in the points +2^shift and -2^shift. */
+int
+mpn_toom_eval_pm2exp (mp_ptr xp2, mp_ptr xm2, unsigned k,
+		      mp_srcptr xp, mp_size_t n, mp_size_t hn, unsigned shift,
+		      mp_ptr tp)
+{
+  unsigned i;
+  int neg;
+#if HAVE_NATIVE_mpn_addlsh_n
+  mp_limb_t cy;
+#endif
+
+  ASSERT (k >= 3);
+  ASSERT (shift*k < GMP_NUMB_BITS);
+
+  ASSERT (hn > 0);
+  ASSERT (hn <= n);
+
+  /* The degree k is also the number of full-size coefficients, so
+   * that last coefficient, of size hn, starts at xp + k*n. */
+
+#if HAVE_NATIVE_mpn_addlsh_n
+  xp2[n] = mpn_addlsh_n (xp2, xp, xp + 2*n, n, 2*shift);
+  for (i = 4; i < k; i += 2)
+    xp2[n] += mpn_addlsh_n (xp2, xp2, xp + i*n, n, i*shift);
+
+  tp[n] = mpn_lshift (tp, xp+n, n, shift);
+  for (i = 3; i < k; i+= 2)
+    tp[n] += mpn_addlsh_n (tp, tp, xp+i*n, n, i*shift);
+
+  if (k & 1)
+    {
+      cy = mpn_addlsh_n (tp, tp, xp+k*n, hn, k*shift);
+      MPN_INCR_U (tp + hn, n+1 - hn, cy);
+    }
+  else
+    {
+      cy = mpn_addlsh_n (xp2, xp2, xp+k*n, hn, k*shift);
+      MPN_INCR_U (xp2 + hn, n+1 - hn, cy);
+    }
+
+#else /* !HAVE_NATIVE_mpn_addlsh_n */
+  xp2[n] = mpn_lshift (tp, xp+2*n, n, 2*shift);
+  xp2[n] += mpn_add_n (xp2, xp, tp, n);
+  for (i = 4; i < k; i += 2)
+    {
+      xp2[n] += mpn_lshift (tp, xp + i*n, n, i*shift);
+      xp2[n] += mpn_add_n (xp2, xp2, tp, n);
+    }
+
+  tp[n] = mpn_lshift (tp, xp+n, n, shift);
+  for (i = 3; i < k; i+= 2)
+    {
+      tp[n] += mpn_lshift (xm2, xp + i*n, n, i*shift);
+      tp[n] += mpn_add_n (tp, tp, xm2, n);
+    }
+
+  xm2[hn] = mpn_lshift (xm2, xp + k*n, hn, k*shift);
+  if (k & 1)
+    mpn_add (tp, tp, n+1, xm2, hn+1);
+  else
+    mpn_add (xp2, xp2, n+1, xm2, hn+1);
+#endif /* !HAVE_NATIVE_mpn_addlsh_n */
+
+  neg = (mpn_cmp (xp2, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp2, xm2, tp, xp2, n + 1);
+  else
+    mpn_add_n_sub_n (xp2, xm2, xp2, tp, n + 1);
+#else /* !HAVE_NATIVE_mpn_add_n_sub_n */
+  if (neg)
+    mpn_sub_n (xm2, tp, xp2, n + 1);
+  else
+    mpn_sub_n (xm2, xp2, tp, n + 1);
+
+  mpn_add_n (xp2, xp2, tp, n + 1);
+#endif /* !HAVE_NATIVE_mpn_add_n_sub_n */
+
+  /* FIXME: the following asserts are useless if (k+1)*shift >= GMP_LIMB_BITS */
+  ASSERT ((k+1)*shift >= GMP_LIMB_BITS ||
+	  xp2[n] < ((CNST_LIMB(1)<<((k+1)*shift))-1)/((CNST_LIMB(1)<<shift)-1));
+  ASSERT ((k+2)*shift >= GMP_LIMB_BITS ||
+	  xm2[n] < ((CNST_LIMB(1)<<((k+2)*shift))-((k&1)?(CNST_LIMB(1)<<shift):1))/((CNST_LIMB(1)<<(2*shift))-1));
+
+  return neg;
+}
diff --git a/mpn/generic/toom_eval_pm2rexp.c b/mpn/generic/toom_eval_pm2rexp.c
new file mode 100644
index 0000000..6cd62fb
--- /dev/null
+++ b/mpn/generic/toom_eval_pm2rexp.c
@@ -0,0 +1,101 @@
+/* mpn_toom_eval_pm2rexp -- Evaluate a polynomial in +2^-k and -2^-k
+
+   Contributed to the GNU project by Marco Bodrato
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_mpn_addlsh_n(dst,src,n,s,ws) mpn_addlsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_addlsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_addmul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_add_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+/* Evaluates a polynomial of degree k >= 3. */
+int
+mpn_toom_eval_pm2rexp (mp_ptr rp, mp_ptr rm,
+		      unsigned int q, mp_srcptr ap, mp_size_t n, mp_size_t t,
+		      unsigned int s, mp_ptr ws)
+{
+  unsigned int i;
+  int neg;
+  /* {ap,q*n+t} -> {rp,n+1} {rm,n+1} , with {ws, n+1}*/
+  ASSERT (n >= t);
+  ASSERT (s != 0); /* or _eval_pm1 should be used */
+  ASSERT (q > 1);
+  ASSERT (s*q < GMP_NUMB_BITS);
+  rp[n] = mpn_lshift(rp, ap, n, s*q);
+  ws[n] = mpn_lshift(ws, ap+n, n, s*(q-1));
+  if( (q & 1) != 0) {
+    ASSERT_NOCARRY(mpn_add(ws,ws,n+1,ap+n*q,t));
+    rp[n] += DO_mpn_addlsh_n(rp, ap+n*(q-1), n, s, rm);
+  } else {
+    ASSERT_NOCARRY(mpn_add(rp,rp,n+1,ap+n*q,t));
+  }
+  for(i=2; i<q-1; i++)
+  {
+    rp[n] += DO_mpn_addlsh_n(rp, ap+n*i, n, s*(q-i), rm);
+    i++;
+    ws[n] += DO_mpn_addlsh_n(ws, ap+n*i, n, s*(q-i), rm);
+  };
+
+  neg = (mpn_cmp (rp, ws, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (rp, rm, ws, rp, n + 1);
+  else
+    mpn_add_n_sub_n (rp, rm, rp, ws, n + 1);
+#else /* !HAVE_NATIVE_mpn_add_n_sub_n */
+  if (neg)
+    mpn_sub_n (rm, ws, rp, n + 1);
+  else
+    mpn_sub_n (rm, rp, ws, n + 1);
+
+  ASSERT_NOCARRY (mpn_add_n (rp, rp, ws, n + 1));
+#endif /* !HAVE_NATIVE_mpn_add_n_sub_n */
+
+  return neg;
+}
diff --git a/mpn/generic/toom_interpolate_12pts.c b/mpn/generic/toom_interpolate_12pts.c
new file mode 100644
index 0000000..6273466
--- /dev/null
+++ b/mpn/generic/toom_interpolate_12pts.c
@@ -0,0 +1,374 @@
+/* Interpolation for the algorithm Toom-Cook 6.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2015, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 21
+#error Not implemented: Both sublsh_n(,,,20) should be corrected.
+#endif
+
+#if GMP_NUMB_BITS < 16
+#error Not implemented: divexact_by42525 needs splitting.
+#endif
+
+#if GMP_NUMB_BITS < 12
+#error Not implemented: Hard to adapt...
+#endif
+
+
+/* FIXME: tuneup should decide the best variant */
+#ifndef AORSMUL_FASTER_AORS_AORSLSH
+#define AORSMUL_FASTER_AORS_AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_AORS_2AORSLSH
+#define AORSMUL_FASTER_AORS_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_2AORSLSH
+#define AORSMUL_FASTER_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_3AORSLSH
+#define AORSMUL_FASTER_3AORSLSH 1
+#endif
+
+
+#if HAVE_NATIVE_mpn_sublsh_n
+#define DO_mpn_sublsh_n(dst,src,n,s,ws) mpn_sublsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_sublsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_submul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_sub_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_mpn_addlsh_n(dst,src,n,s,ws) mpn_addlsh_n(dst,dst,src,n,s)
+#else
+#if !defined (AORSMUL_FASTER_2AORSLSH) && !defined (AORSMUL_FASTER_AORS_2AORSLSH)
+static mp_limb_t
+DO_mpn_addlsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_addmul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_add_n(dst,dst,ws,n);
+#endif
+}
+#endif
+#endif
+
+#if HAVE_NATIVE_mpn_subrsh
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws) mpn_subrsh(dst,nd,src,ns,s)
+#else
+/* FIXME: This is not a correct definition, it assumes no carry */
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws)				\
+do {									\
+  mp_limb_t __cy;							\
+  MPN_DECR_U (dst, nd, src[0] >> s);					\
+  __cy = DO_mpn_sublsh_n (dst, src + 1, ns - 1, GMP_NUMB_BITS - s, ws);	\
+  MPN_DECR_U (dst + ns - 1, nd - ns + 1, __cy);				\
+} while (0)
+#endif
+
+
+#define BINVERT_9 \
+  ((((GMP_NUMB_MAX / 9) << (6 - GMP_NUMB_BITS % 6)) * 8 & GMP_NUMB_MAX) | 0x39)
+
+#define BINVERT_255 \
+  (GMP_NUMB_MAX - ((GMP_NUMB_MAX / 255) << (8 - GMP_NUMB_BITS % 8)))
+
+  /* FIXME: find some more general expressions for 2835^-1, 42525^-1 */
+#if GMP_LIMB_BITS == 32
+#define BINVERT_2835  (GMP_NUMB_MASK &		CNST_LIMB(0x53E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &		CNST_LIMB(0x9F314C35))
+#else
+#if GMP_LIMB_BITS == 64
+#define BINVERT_2835  (GMP_NUMB_MASK &	CNST_LIMB(0x938CC70553E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &	CNST_LIMB(0xE7B40D449F314C35))
+#endif
+#endif
+
+#ifndef mpn_divexact_by255
+#if GMP_NUMB_BITS % 8 == 0
+#define mpn_divexact_by255(dst,src,size) \
+  (255 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 255)))
+#else
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by255(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(255),BINVERT_255,0)
+#else
+#define mpn_divexact_by255(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(255))
+#endif
+#endif
+#endif
+
+#ifndef mpn_divexact_by9x4
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by9x4(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(9),BINVERT_9,2)
+#else
+#define mpn_divexact_by9x4(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(9)<<2)
+#endif
+#endif
+
+#ifndef mpn_divexact_by42525
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_42525)
+#define mpn_divexact_by42525(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(42525),BINVERT_42525,0)
+#else
+#define mpn_divexact_by42525(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(42525))
+#endif
+#endif
+
+#ifndef mpn_divexact_by2835x4
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_2835)
+#define mpn_divexact_by2835x4(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(2835),BINVERT_2835,2)
+#else
+#define mpn_divexact_by2835x4(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(2835)<<2)
+#endif
+#endif
+
+/* Interpolation for Toom-6.5 (or Toom-6), using the evaluation
+   points: infinity(6.5 only), +-4, +-2, +-1, +-1/4, +-1/2, 0. More precisely,
+   we want to compute f(2^(GMP_NUMB_BITS * n)) for a polynomial f of
+   degree 11 (or 10), given the 12 (rsp. 11) values:
+
+     r0 = limit at infinity of f(x) / x^11,
+     r1 = f(4),f(-4),
+     r2 = f(2),f(-2),
+     r3 = f(1),f(-1),
+     r4 = f(1/4),f(-1/4),
+     r5 = f(1/2),f(-1/2),
+     r6 = f(0).
+
+   All couples of the form f(n),f(-n) must be already mixed with
+   toom_couple_handling(f(n),...,f(-n),...)
+
+   The result is stored in {pp, spt + 7*n (or 6*n)}.
+   At entry, r6 is stored at {pp, 2n},
+   r4 is stored at {pp + 3n, 3n + 1}.
+   r2 is stored at {pp + 7n, 3n + 1}.
+   r0 is stored at {pp +11n, spt}.
+
+   The other values are 3n+1 limbs each (with most significant limbs small).
+
+   Negative intermediate results are stored two-complemented.
+   Inputs are destroyed.
+*/
+
+void
+mpn_toom_interpolate_12pts (mp_ptr pp, mp_ptr r1, mp_ptr r3, mp_ptr r5,
+			mp_size_t n, mp_size_t spt, int half, mp_ptr wsi)
+{
+  mp_limb_t cy;
+  mp_size_t n3;
+  mp_size_t n3p1;
+  n3 = 3 * n;
+  n3p1 = n3 + 1;
+
+#define   r4    (pp + n3)			/* 3n+1 */
+#define   r2    (pp + 7 * n)			/* 3n+1 */
+#define   r0    (pp +11 * n)			/* s+t <= 2*n */
+
+  /******************************* interpolation *****************************/
+  if (half != 0) {
+    cy = mpn_sub_n (r3, r3, r0, spt);
+    MPN_DECR_U (r3 + spt, n3p1 - spt, cy);
+
+    cy = DO_mpn_sublsh_n (r2, r0, spt, 10, wsi);
+    MPN_DECR_U (r2 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r5, n3p1, r0, spt, 2, wsi);
+
+    cy = DO_mpn_sublsh_n (r1, r0, spt, 20, wsi);
+    MPN_DECR_U (r1 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r4, n3p1, r0, spt, 4, wsi);
+  };
+
+  r4[n3] -= DO_mpn_sublsh_n (r4 + n, pp, 2 * n, 20, wsi);
+  DO_mpn_subrsh(r1 + n, 2 * n + 1, pp, 2 * n, 4, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r1, r4, r4, r1, n3p1);
+#else
+  ASSERT_NOCARRY(mpn_add_n (wsi, r1, r4, n3p1));
+  mpn_sub_n (r4, r4, r1, n3p1); /* can be negative */
+  MP_PTR_SWAP(r1, wsi);
+#endif
+
+  r5[n3] -= DO_mpn_sublsh_n (r5 + n, pp, 2 * n, 10, wsi);
+  DO_mpn_subrsh(r2 + n, 2 * n + 1, pp, 2 * n, 2, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r2, r5, r5, r2, n3p1);
+#else
+  mpn_sub_n (wsi, r5, r2, n3p1); /* can be negative */
+  ASSERT_NOCARRY(mpn_add_n (r2, r2, r5, n3p1));
+  MP_PTR_SWAP(r5, wsi);
+#endif
+
+  r3[n3] -= mpn_sub_n (r3+n, r3+n, pp, 2 * n);
+
+#if AORSMUL_FASTER_AORS_AORSLSH
+  mpn_submul_1 (r4, r5, n3p1, 257); /* can be negative */
+#else
+  mpn_sub_n (r4, r4, r5, n3p1); /* can be negative */
+  DO_mpn_sublsh_n (r4, r5, n3p1, 8, wsi); /* can be negative */
+#endif
+  /* A division by 2835x4 follows. Warning: the operand can be negative! */
+  mpn_divexact_by2835x4(r4, r4, n3p1);
+  if ((r4[n3] & (GMP_NUMB_MAX << (GMP_NUMB_BITS-3))) != 0)
+    r4[n3] |= (GMP_NUMB_MAX << (GMP_NUMB_BITS-2));
+
+#if AORSMUL_FASTER_2AORSLSH
+  mpn_addmul_1 (r5, r4, n3p1, 60); /* can be negative */
+#else
+  DO_mpn_sublsh_n (r5, r4, n3p1, 2, wsi); /* can be negative */
+  DO_mpn_addlsh_n (r5, r4, n3p1, 6, wsi); /* can give a carry */
+#endif
+  mpn_divexact_by255(r5, r5, n3p1);
+
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r2, r3, n3p1, 5, wsi));
+
+#if AORSMUL_FASTER_3AORSLSH
+  ASSERT_NOCARRY(mpn_submul_1 (r1, r2, n3p1, 100));
+#else
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r2, n3p1, 6, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r2, n3p1, 5, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r2, n3p1, 2, wsi));
+#endif
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r3, n3p1, 9, wsi));
+  mpn_divexact_by42525(r1, r1, n3p1);
+
+#if AORSMUL_FASTER_AORS_2AORSLSH
+  ASSERT_NOCARRY(mpn_submul_1 (r2, r1, n3p1, 225));
+#else
+  ASSERT_NOCARRY(mpn_sub_n (r2, r2, r1, n3p1));
+  ASSERT_NOCARRY(DO_mpn_addlsh_n (r2, r1, n3p1, 5, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r2, r1, n3p1, 8, wsi));
+#endif
+  mpn_divexact_by9x4(r2, r2, n3p1);
+
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r2, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (r4, r2, r4, n3p1);
+  r4 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_sub_n (r4, r2, r4, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r4, r4, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r2, r2, r4, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (r5, r5, r1, n3p1);
+  r5 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (r5, r5, r1, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r5, r5, n3p1, 1));
+#endif
+
+  /* last interpolation steps... */
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r1, n3p1));
+  ASSERT_NOCARRY(mpn_sub_n (r1, r1, r5, n3p1));
+  /* ... could be mixed with recomposition
+	||H-r5|M-r5|L-r5|   ||H-r1|M-r1|L-r1|
+  */
+
+  /***************************** recomposition *******************************/
+  /*
+    pp[] prior to operations:
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|____|H_r6|L r6|pp
+
+    summation scheme for remaining operations:
+    |__12|n_11|n_10|n__9|n__8|n__7|n__6|n__5|n__4|n__3|n__2|n___|n___|pp
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|____|H_r6|L r6|pp
+	||H r1|M r1|L r1|   ||H r3|M r3|L r3|   ||H_r5|M_r5|L_r5|
+  */
+
+  cy = mpn_add_n (pp + n, pp + n, r5, n);
+  cy = mpn_add_1 (pp + 2 * n, r5 + n, n, cy);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r5[n3] + mpn_add_nc(pp + n3, pp + n3, r5 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r5 + 2 * n, n + 1, cy);
+  cy = r5[n3] + mpn_add_n (pp + n3, pp + n3, r5 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + n3 + n, 2 * n + 1, cy);
+
+  pp[2 * n3]+= mpn_add_n (pp + 5 * n, pp + 5 * n, r3, n);
+  cy = mpn_add_1 (pp + 2 * n3, r3 + n, n, pp[2 * n3]);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r3[n3] + mpn_add_nc(pp + 7 * n, pp + 7 * n, r3 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r3 + 2 * n, n + 1, cy);
+  cy = r3[n3] + mpn_add_n (pp + 7 * n, pp + 7 * n, r3 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + 8 * n, 2 * n + 1, cy);
+
+  pp[10*n]+=mpn_add_n (pp + 9 * n, pp + 9 * n, r1, n);
+  if (half) {
+    cy = mpn_add_1 (pp + 10 * n, r1 + n, n, pp[10 * n]);
+#if HAVE_NATIVE_mpn_add_nc
+    if (LIKELY (spt > n)) {
+      cy = r1[n3] + mpn_add_nc(pp + 11 * n, pp + 11 * n, r1 + 2 * n, n, cy);
+      MPN_INCR_U (pp + 4 * n3, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_nc(pp + 11 * n, pp + 11 * n, r1 + 2 * n, spt, cy));
+    }
+#else
+    MPN_INCR_U (r1 + 2 * n, n + 1, cy);
+    if (LIKELY (spt > n)) {
+      cy = r1[n3] + mpn_add_n (pp + 11 * n, pp + 11 * n, r1 + 2 * n, n);
+      MPN_INCR_U (pp + 4 * n3, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_n (pp + 11 * n, pp + 11 * n, r1 + 2 * n, spt));
+    }
+#endif
+  } else {
+    ASSERT_NOCARRY(mpn_add_1 (pp + 10 * n, r1 + n, spt, pp[10 * n]));
+  }
+
+#undef   r0
+#undef   r2
+#undef   r4
+}
diff --git a/mpn/generic/toom_interpolate_16pts.c b/mpn/generic/toom_interpolate_16pts.c
new file mode 100644
index 0000000..c1457be
--- /dev/null
+++ b/mpn/generic/toom_interpolate_16pts.c
@@ -0,0 +1,545 @@
+/* Interpolation for the algorithm Toom-Cook 8.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2015, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 29
+#error Not implemented: Both sublsh_n(,,,28) should be corrected; r2 and r5 need one more LIMB.
+#endif
+
+#if GMP_NUMB_BITS < 28
+#error Not implemented: divexact_by188513325 and _by182712915 will not work.
+#endif
+
+
+/* FIXME: tuneup should decide the best variant */
+#ifndef AORSMUL_FASTER_AORS_AORSLSH
+#define AORSMUL_FASTER_AORS_AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_AORS_2AORSLSH
+#define AORSMUL_FASTER_AORS_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_2AORSLSH
+#define AORSMUL_FASTER_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_3AORSLSH
+#define AORSMUL_FASTER_3AORSLSH 1
+#endif
+
+
+#if HAVE_NATIVE_mpn_sublsh_n
+#define DO_mpn_sublsh_n(dst,src,n,s,ws) mpn_sublsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_sublsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_submul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_sub_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_mpn_addlsh_n(dst,src,n,s,ws) mpn_addlsh_n(dst,dst,src,n,s)
+#else
+#if !defined (AORSMUL_FASTER_2AORSLSH) && !defined (AORSMUL_FASTER_AORS_2AORSLSH)
+static mp_limb_t
+DO_mpn_addlsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_addmul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_add_n(dst,dst,ws,n);
+#endif
+}
+#endif
+#endif
+
+#if HAVE_NATIVE_mpn_subrsh
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws) mpn_subrsh(dst,nd,src,ns,s)
+#else
+/* FIXME: This is not a correct definition, it assumes no carry */
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws)				\
+do {									\
+  mp_limb_t __cy;							\
+  MPN_DECR_U (dst, nd, src[0] >> s);					\
+  __cy = DO_mpn_sublsh_n (dst, src + 1, ns - 1, GMP_NUMB_BITS - s, ws);	\
+  MPN_DECR_U (dst + ns - 1, nd - ns + 1, __cy);				\
+} while (0)
+#endif
+
+
+#if GMP_NUMB_BITS < 43
+#define BIT_CORRECTION 1
+#define CORRECTION_BITS GMP_NUMB_BITS
+#else
+#define BIT_CORRECTION 0
+#define CORRECTION_BITS 0
+#endif
+
+#define BINVERT_9 \
+  ((((GMP_NUMB_MAX / 9) << (6 - GMP_NUMB_BITS % 6)) * 8 & GMP_NUMB_MAX) | 0x39)
+
+#define BINVERT_255 \
+  (GMP_NUMB_MAX - ((GMP_NUMB_MAX / 255) << (8 - GMP_NUMB_BITS % 8)))
+
+  /* FIXME: find some more general expressions for inverses */
+#if GMP_LIMB_BITS == 32
+#define BINVERT_2835  (GMP_NUMB_MASK &		CNST_LIMB(0x53E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &		CNST_LIMB(0x9F314C35))
+#define BINVERT_182712915 (GMP_NUMB_MASK &	CNST_LIMB(0x550659DB))
+#define BINVERT_188513325 (GMP_NUMB_MASK &	CNST_LIMB(0xFBC333A5))
+#define BINVERT_255x182712915L (GMP_NUMB_MASK &	CNST_LIMB(0x6FC4CB25))
+#define BINVERT_255x188513325L (GMP_NUMB_MASK &	CNST_LIMB(0x6864275B))
+#if GMP_NAIL_BITS == 0
+#define BINVERT_255x182712915H CNST_LIMB(0x1B649A07)
+#define BINVERT_255x188513325H CNST_LIMB(0x06DB993A)
+#else /* GMP_NAIL_BITS != 0 */
+#define BINVERT_255x182712915H \
+  (GMP_NUMB_MASK & CNST_LIMB((0x1B649A07<<GMP_NAIL_BITS) | (0x6FC4CB25>>GMP_NUMB_BITS)))
+#define BINVERT_255x188513325H \
+  (GMP_NUMB_MASK & CNST_LIMB((0x06DB993A<<GMP_NAIL_BITS) | (0x6864275B>>GMP_NUMB_BITS)))
+#endif
+#else
+#if GMP_LIMB_BITS == 64
+#define BINVERT_2835  (GMP_NUMB_MASK &	CNST_LIMB(0x938CC70553E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &	CNST_LIMB(0xE7B40D449F314C35))
+#define BINVERT_255x182712915  (GMP_NUMB_MASK &	CNST_LIMB(0x1B649A076FC4CB25))
+#define BINVERT_255x188513325  (GMP_NUMB_MASK &	CNST_LIMB(0x06DB993A6864275B))
+#endif
+#endif
+
+#ifndef mpn_divexact_by255
+#if GMP_NUMB_BITS % 8 == 0
+#define mpn_divexact_by255(dst,src,size) \
+  (255 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 255)))
+#else
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by255(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(255),BINVERT_255,0)
+#else
+#define mpn_divexact_by255(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(255))
+#endif
+#endif
+#endif
+
+#ifndef mpn_divexact_by255x4
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by255x4(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(255),BINVERT_255,2)
+#else
+#define mpn_divexact_by255x4(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(255)<<2)
+#endif
+#endif
+
+#ifndef mpn_divexact_by9x16
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by9x16(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(9),BINVERT_9,4)
+#else
+#define mpn_divexact_by9x16(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(9)<<4)
+#endif
+#endif
+
+#ifndef mpn_divexact_by42525x16
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_42525)
+#define mpn_divexact_by42525x16(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(42525),BINVERT_42525,4)
+#else
+#define mpn_divexact_by42525x16(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(42525)<<4)
+#endif
+#endif
+
+#ifndef mpn_divexact_by2835x64
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_2835)
+#define mpn_divexact_by2835x64(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(2835),BINVERT_2835,6)
+#else
+#define mpn_divexact_by2835x64(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(2835)<<6)
+#endif
+#endif
+
+#ifndef  mpn_divexact_by255x182712915
+#if GMP_NUMB_BITS < 36
+#if HAVE_NATIVE_mpn_bdiv_q_2_pi2 && defined(BINVERT_255x182712915H)
+/* FIXME: use mpn_bdiv_q_2_pi2 */
+#endif
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_182712915)
+#define mpn_divexact_by255x182712915(dst,src,size)				\
+  do {										\
+    mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(182712915),BINVERT_182712915,0);	\
+    mpn_divexact_by255(dst,dst,size);						\
+  } while(0)
+#else
+#define mpn_divexact_by255x182712915(dst,src,size)	\
+  do {							\
+    mpn_divexact_1(dst,src,size,CNST_LIMB(182712915));	\
+    mpn_divexact_by255(dst,dst,size);			\
+  } while(0)
+#endif
+#else /* GMP_NUMB_BITS > 35 */
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_255x182712915)
+#define mpn_divexact_by255x182712915(dst,src,size) \
+  mpn_pi1_bdiv_q_1(dst,src,size,255*CNST_LIMB(182712915),BINVERT_255x182712915,0)
+#else
+#define mpn_divexact_by255x182712915(dst,src,size) mpn_divexact_1(dst,src,size,255*CNST_LIMB(182712915))
+#endif
+#endif /* GMP_NUMB_BITS >?< 36 */
+#endif
+
+#ifndef  mpn_divexact_by255x188513325
+#if GMP_NUMB_BITS < 36
+#if HAVE_NATIVE_mpn_bdiv_q_1_pi2 && defined(BINVERT_255x188513325H)
+/* FIXME: use mpn_bdiv_q_1_pi2 */
+#endif
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_188513325)
+#define mpn_divexact_by255x188513325(dst,src,size)			\
+  do {									\
+    mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(188513325),BINVERT_188513325,0);	\
+    mpn_divexact_by255(dst,dst,size);					\
+  } while(0)
+#else
+#define mpn_divexact_by255x188513325(dst,src,size)	\
+  do {							\
+    mpn_divexact_1(dst,src,size,CNST_LIMB(188513325));	\
+    mpn_divexact_by255(dst,dst,size);			\
+  } while(0)
+#endif
+#else /* GMP_NUMB_BITS > 35 */
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_255x188513325)
+#define mpn_divexact_by255x188513325(dst,src,size) \
+  mpn_pi1_bdiv_q_1(dst,src,size,255*CNST_LIMB(188513325),BINVERT_255x188513325,0)
+#else
+#define mpn_divexact_by255x188513325(dst,src,size) mpn_divexact_1(dst,src,size,255*CNST_LIMB(188513325))
+#endif
+#endif /* GMP_NUMB_BITS >?< 36 */
+#endif
+
+/* Interpolation for Toom-8.5 (or Toom-8), using the evaluation
+   points: infinity(8.5 only), +-8, +-4, +-2, +-1, +-1/4, +-1/2,
+   +-1/8, 0. More precisely, we want to compute
+   f(2^(GMP_NUMB_BITS * n)) for a polynomial f of degree 15 (or
+   14), given the 16 (rsp. 15) values:
+
+     r0 = limit at infinity of f(x) / x^15,
+     r1 = f(8),f(-8),
+     r2 = f(4),f(-4),
+     r3 = f(2),f(-2),
+     r4 = f(1),f(-1),
+     r5 = f(1/4),f(-1/4),
+     r6 = f(1/2),f(-1/2),
+     r7 = f(1/8),f(-1/8),
+     r8 = f(0).
+
+   All couples of the form f(n),f(-n) must be already mixed with
+   toom_couple_handling(f(n),...,f(-n),...)
+
+   The result is stored in {pp, spt + 7*n (or 8*n)}.
+   At entry, r8 is stored at {pp, 2n},
+   r6 is stored at {pp + 3n, 3n + 1}.
+   r4 is stored at {pp + 7n, 3n + 1}.
+   r2 is stored at {pp +11n, 3n + 1}.
+   r0 is stored at {pp +15n, spt}.
+
+   The other values are 3n+1 limbs each (with most significant limbs small).
+
+   Negative intermediate results are stored two-complemented.
+   Inputs are destroyed.
+*/
+
+void
+mpn_toom_interpolate_16pts (mp_ptr pp, mp_ptr r1, mp_ptr r3, mp_ptr r5, mp_ptr r7,
+			mp_size_t n, mp_size_t spt, int half, mp_ptr wsi)
+{
+  mp_limb_t cy;
+  mp_size_t n3;
+  mp_size_t n3p1;
+  n3 = 3 * n;
+  n3p1 = n3 + 1;
+
+#define   r6    (pp + n3)			/* 3n+1 */
+#define   r4    (pp + 7 * n)			/* 3n+1 */
+#define   r2    (pp +11 * n)			/* 3n+1 */
+#define   r0    (pp +15 * n)			/* s+t <= 2*n */
+
+  ASSERT( spt <= 2 * n );
+  /******************************* interpolation *****************************/
+  if( half != 0) {
+    cy = mpn_sub_n (r4, r4, r0, spt);
+    MPN_DECR_U (r4 + spt, n3p1 - spt, cy);
+
+    cy = DO_mpn_sublsh_n (r3, r0, spt, 14, wsi);
+    MPN_DECR_U (r3 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r6, n3p1, r0, spt, 2, wsi);
+
+    cy = DO_mpn_sublsh_n (r2, r0, spt, 28, wsi);
+    MPN_DECR_U (r2 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r5, n3p1, r0, spt, 4, wsi);
+
+    cy = DO_mpn_sublsh_n (r1 + BIT_CORRECTION, r0, spt, 42 - CORRECTION_BITS, wsi);
+#if BIT_CORRECTION
+    cy = mpn_sub_1 (r1 + spt + BIT_CORRECTION, r1 + spt + BIT_CORRECTION,
+		    n3p1 - spt - BIT_CORRECTION, cy);
+    ASSERT (BIT_CORRECTION > 0 || cy == 0);
+    /* FIXME: assumes r7[n3p1] is writable (it is if r5 follows). */
+    cy = r7[n3p1];
+    r7[n3p1] = 0x80;
+#else
+    MPN_DECR_U (r1 + spt + BIT_CORRECTION, n3p1 - spt - BIT_CORRECTION, cy);
+#endif
+    DO_mpn_subrsh(r7, n3p1 + BIT_CORRECTION, r0, spt, 6, wsi);
+#if BIT_CORRECTION
+    /* FIXME: assumes r7[n3p1] is writable. */
+    ASSERT ( BIT_CORRECTION > 0 || r7[n3p1] == 0x80 );
+    r7[n3p1] = cy;
+#endif
+  };
+
+  r5[n3] -= DO_mpn_sublsh_n (r5 + n, pp, 2 * n, 28, wsi);
+  DO_mpn_subrsh(r2 + n, 2 * n + 1, pp, 2 * n, 4, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r2, r5, r5, r2, n3p1);
+#else
+  mpn_sub_n (wsi, r5, r2, n3p1); /* can be negative */
+  ASSERT_NOCARRY(mpn_add_n (r2, r2, r5, n3p1));
+  MP_PTR_SWAP(r5, wsi);
+#endif
+
+  r6[n3] -= DO_mpn_sublsh_n (r6 + n, pp, 2 * n, 14, wsi);
+  DO_mpn_subrsh(r3 + n, 2 * n + 1, pp, 2 * n, 2, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r3, r6, r6, r3, n3p1);
+#else
+  ASSERT_NOCARRY(mpn_add_n (wsi, r3, r6, n3p1));
+  mpn_sub_n (r6, r6, r3, n3p1); /* can be negative */
+  MP_PTR_SWAP(r3, wsi);
+#endif
+
+  cy = DO_mpn_sublsh_n (r7 + n + BIT_CORRECTION, pp, 2 * n, 42 - CORRECTION_BITS, wsi);
+#if BIT_CORRECTION
+  MPN_DECR_U (r1 + n, 2 * n + 1, pp[0] >> 6);
+  cy = DO_mpn_sublsh_n (r1 + n, pp + 1, 2 * n - 1, GMP_NUMB_BITS - 6, wsi);
+  cy = mpn_sub_1(r1 + 3 * n - 1, r1 + 3 * n - 1, 2, cy);
+  ASSERT ( BIT_CORRECTION > 0 || cy != 0 );
+#else
+  r7[n3] -= cy;
+  DO_mpn_subrsh(r1 + n, 2 * n + 1, pp, 2 * n, 6, wsi);
+#endif
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r1, r7, r7, r1, n3p1);
+#else
+  mpn_sub_n (wsi, r7, r1, n3p1); /* can be negative */
+  mpn_add_n (r1, r1, r7, n3p1);  /* if BIT_CORRECTION != 0, can give a carry. */
+  MP_PTR_SWAP(r7, wsi);
+#endif
+
+  r4[n3] -= mpn_sub_n (r4+n, r4+n, pp, 2 * n);
+
+#if AORSMUL_FASTER_2AORSLSH
+  mpn_submul_1 (r5, r6, n3p1, 1028); /* can be negative */
+#else
+  DO_mpn_sublsh_n (r5, r6, n3p1, 2, wsi); /* can be negative */
+  DO_mpn_sublsh_n (r5, r6, n3p1,10, wsi); /* can be negative */
+#endif
+
+  mpn_submul_1 (r7, r5, n3p1, 1300); /* can be negative */
+#if AORSMUL_FASTER_3AORSLSH
+  mpn_submul_1 (r7, r6, n3p1, 1052688); /* can be negative */
+#else
+  DO_mpn_sublsh_n (r7, r6, n3p1, 4, wsi); /* can be negative */
+  DO_mpn_sublsh_n (r7, r6, n3p1,12, wsi); /* can be negative */
+  DO_mpn_sublsh_n (r7, r6, n3p1,20, wsi); /* can be negative */
+#endif
+  mpn_divexact_by255x188513325(r7, r7, n3p1);
+
+  mpn_submul_1 (r5, r7, n3p1, 12567555); /* can be negative */
+  /* A division by 2835x64 follows. Warning: the operand can be negative! */
+  mpn_divexact_by2835x64(r5, r5, n3p1);
+  if ((r5[n3] & (GMP_NUMB_MAX << (GMP_NUMB_BITS-7))) != 0)
+    r5[n3] |= (GMP_NUMB_MAX << (GMP_NUMB_BITS-6));
+
+#if AORSMUL_FASTER_AORS_AORSLSH
+  mpn_submul_1 (r6, r7, n3p1, 4095); /* can be negative */
+#else
+  mpn_add_n (r6, r6, r7, n3p1); /* can give a carry */
+  DO_mpn_sublsh_n (r6, r7, n3p1, 12, wsi); /* can be negative */
+#endif
+#if AORSMUL_FASTER_2AORSLSH
+  mpn_addmul_1 (r6, r5, n3p1, 240); /* can be negative */
+#else
+  DO_mpn_addlsh_n (r6, r5, n3p1, 8, wsi); /* can give a carry */
+  DO_mpn_sublsh_n (r6, r5, n3p1, 4, wsi); /* can be negative */
+#endif
+  /* A division by 255x4 follows. Warning: the operand can be negative! */
+  mpn_divexact_by255x4(r6, r6, n3p1);
+  if ((r6[n3] & (GMP_NUMB_MAX << (GMP_NUMB_BITS-3))) != 0)
+    r6[n3] |= (GMP_NUMB_MAX << (GMP_NUMB_BITS-2));
+
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r3, r4, n3p1, 7, wsi));
+
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r2, r4, n3p1, 13, wsi));
+  ASSERT_NOCARRY(mpn_submul_1 (r2, r3, n3p1, 400));
+
+  /* If GMP_NUMB_BITS < 42 next operations on r1 can give a carry!*/
+  DO_mpn_sublsh_n (r1, r4, n3p1, 19, wsi);
+  mpn_submul_1 (r1, r2, n3p1, 1428);
+  mpn_submul_1 (r1, r3, n3p1, 112896);
+  mpn_divexact_by255x182712915(r1, r1, n3p1);
+
+  ASSERT_NOCARRY(mpn_submul_1 (r2, r1, n3p1, 15181425));
+  mpn_divexact_by42525x16(r2, r2, n3p1);
+
+#if AORSMUL_FASTER_AORS_2AORSLSH
+  ASSERT_NOCARRY(mpn_submul_1 (r3, r1, n3p1, 3969));
+#else
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r1, n3p1));
+  ASSERT_NOCARRY(DO_mpn_addlsh_n (r3, r1, n3p1, 7, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r3, r1, n3p1, 12, wsi));
+#endif
+  ASSERT_NOCARRY(mpn_submul_1 (r3, r2, n3p1, 900));
+  mpn_divexact_by9x16(r3, r3, n3p1);
+
+  ASSERT_NOCARRY(mpn_sub_n (r4, r4, r1, n3p1));
+  ASSERT_NOCARRY(mpn_sub_n (r4, r4, r3, n3p1));
+  ASSERT_NOCARRY(mpn_sub_n (r4, r4, r2, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (r6, r2, r6, n3p1);
+  r6 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (r6, r2, r6, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r6, r6, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r2, r2, r6, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (r5, r3, r5, n3p1);
+  r5 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_sub_n (r5, r3, r5, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r5, r5, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r5, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (r7, r1, r7, n3p1);
+  r7 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (r7, r1, r7, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r7, r7, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r1, r1, r7, n3p1));
+
+  /* last interpolation steps... */
+  /* ... could be mixed with recomposition
+	||H-r7|M-r7|L-r7|   ||H-r5|M-r5|L-r5|
+  */
+
+  /***************************** recomposition *******************************/
+  /*
+    pp[] prior to operations:
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|___||H r6|M r6|L r6|____|H_r8|L r8|pp
+
+    summation scheme for remaining operations:
+    |__16|n_15|n_14|n_13|n_12|n_11|n_10|n__9|n__8|n__7|n__6|n__5|n__4|n__3|n__2|n___|n___|pp
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|___||H r6|M r6|L r6|____|H_r8|L r8|pp
+	||H r1|M r1|L r1|   ||H r3|M r3|L r3|   ||H_r5|M_r5|L_r5|   ||H r7|M r7|L r7|
+  */
+
+  cy = mpn_add_n (pp + n, pp + n, r7, n);
+  cy = mpn_add_1 (pp + 2 * n, r7 + n, n, cy);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r7[n3] + mpn_add_nc(pp + n3, pp + n3, r7 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r7 + 2 * n, n + 1, cy);
+  cy = r7[n3] + mpn_add_n (pp + n3, pp + n3, r7 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + 4 * n, 2 * n + 1, cy);
+
+  pp[2 * n3]+= mpn_add_n (pp + 5 * n, pp + 5 * n, r5, n);
+  cy = mpn_add_1 (pp + 2 * n3, r5 + n, n, pp[2 * n3]);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r5[n3] + mpn_add_nc(pp + 7 * n, pp + 7 * n, r5 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r5 + 2 * n, n + 1, cy);
+  cy = r5[n3] + mpn_add_n (pp + 7 * n, pp + 7 * n, r5 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + 8 * n, 2 * n + 1, cy);
+
+  pp[10 * n]+= mpn_add_n (pp + 9 * n, pp + 9 * n, r3, n);
+  cy = mpn_add_1 (pp + 10 * n, r3 + n, n, pp[10 * n]);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r3[n3] + mpn_add_nc(pp +11 * n, pp +11 * n, r3 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r3 + 2 * n, n + 1, cy);
+  cy = r3[n3] + mpn_add_n (pp +11 * n, pp +11 * n, r3 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp +12 * n, 2 * n + 1, cy);
+
+  pp[14 * n]+=mpn_add_n (pp +13 * n, pp +13 * n, r1, n);
+  if ( half ) {
+    cy = mpn_add_1 (pp + 14 * n, r1 + n, n, pp[14 * n]);
+#if HAVE_NATIVE_mpn_add_nc
+    if(LIKELY(spt > n)) {
+      cy = r1[n3] + mpn_add_nc(pp + 15 * n, pp + 15 * n, r1 + 2 * n, n, cy);
+      MPN_INCR_U (pp + 16 * n, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_nc(pp + 15 * n, pp + 15 * n, r1 + 2 * n, spt, cy));
+    }
+#else
+    MPN_INCR_U (r1 + 2 * n, n + 1, cy);
+    if(LIKELY(spt > n)) {
+      cy = r1[n3] + mpn_add_n (pp + 15 * n, pp + 15 * n, r1 + 2 * n, n);
+      MPN_INCR_U (pp + 16 * n, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_n (pp + 15 * n, pp + 15 * n, r1 + 2 * n, spt));
+    }
+#endif
+  } else {
+    ASSERT_NOCARRY(mpn_add_1 (pp + 14 * n, r1 + n, spt, pp[14 * n]));
+  }
+
+#undef   r0
+#undef   r2
+#undef   r4
+#undef   r6
+}
diff --git a/mpn/generic/toom_interpolate_5pts.c b/mpn/generic/toom_interpolate_5pts.c
new file mode 100644
index 0000000..466ab85
--- /dev/null
+++ b/mpn/generic/toom_interpolate_5pts.c
@@ -0,0 +1,198 @@
+/* mpn_toom_interpolate_5pts -- Interpolate for toom3, 33, 42.
+
+   Contributed to the GNU project by Robert Harley.
+   Improvements by Paul Zimmermann and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2000-2003, 2005-2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_toom_interpolate_5pts (mp_ptr c, mp_ptr v2, mp_ptr vm1,
+			   mp_size_t k, mp_size_t twor, int sa,
+			   mp_limb_t vinf0)
+{
+  mp_limb_t cy, saved;
+  mp_size_t twok;
+  mp_size_t kk1;
+  mp_ptr c1, v1, c3, vinf;
+
+  twok = k + k;
+  kk1 = twok + 1;
+
+  c1 = c  + k;
+  v1 = c1 + k;
+  c3 = v1 + k;
+  vinf = c3 + k;
+
+#define v0 (c)
+  /* (1) v2 <- v2-vm1 < v2+|vm1|,       (16 8 4 2 1) - (1 -1 1 -1  1) =
+     thus 0 <= v2 < 50*B^(2k) < 2^6*B^(2k)             (15 9 3  3  0)
+  */
+  if (sa)
+    ASSERT_NOCARRY (mpn_add_n (v2, v2, vm1, kk1));
+  else
+    ASSERT_NOCARRY (mpn_sub_n (v2, v2, vm1, kk1));
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0       v1       hi(vinf)       |vm1|     v2-vm1      EMPTY */
+
+  ASSERT_NOCARRY (mpn_divexact_by3 (v2, v2, kk1));    /* v2 <- v2 / 3 */
+						      /* (5 3 1 1 0)*/
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0       v1      hi(vinf)       |vm1|     (v2-vm1)/3    EMPTY */
+
+  /* (2) vm1 <- tm1 := (v1 - vm1) / 2  [(1 1 1 1 1) - (1 -1 1 -1 1)] / 2 =
+     tm1 >= 0                                         (0  1 0  1 0)
+     No carry comes out from {v1, kk1} +/- {vm1, kk1},
+     and the division by two is exact.
+     If (sa!=0) the sign of vm1 is negative */
+  if (sa)
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (vm1, v1, vm1, kk1);
+#else
+      ASSERT_NOCARRY (mpn_add_n (vm1, v1, vm1, kk1));
+      ASSERT_NOCARRY (mpn_rshift (vm1, vm1, kk1, 1));
+#endif
+    }
+  else
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (vm1, v1, vm1, kk1);
+#else
+      ASSERT_NOCARRY (mpn_sub_n (vm1, v1, vm1, kk1));
+      ASSERT_NOCARRY (mpn_rshift (vm1, vm1, kk1, 1));
+#endif
+    }
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0       v1        hi(vinf)       tm1     (v2-vm1)/3    EMPTY */
+
+  /* (3) v1 <- t1 := v1 - v0    (1 1 1 1 1) - (0 0 0 0 1) = (1 1 1 1 0)
+     t1 >= 0
+  */
+  vinf[0] -= mpn_sub_n (v1, v1, c, twok);
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0     v1-v0        hi(vinf)       tm1     (v2-vm1)/3    EMPTY */
+
+  /* (4) v2 <- t2 := ((v2-vm1)/3-t1)/2 = (v2-vm1-3*t1)/6
+     t2 >= 0                  [(5 3 1 1 0) - (1 1 1 1 0)]/2 = (2 1 0 0 0)
+  */
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (v2, v2, v1, kk1);
+#else
+  ASSERT_NOCARRY (mpn_sub_n (v2, v2, v1, kk1));
+  ASSERT_NOCARRY (mpn_rshift (v2, v2, kk1, 1));
+#endif
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0     v1-v0        hi(vinf)     tm1    (v2-vm1-3t1)/6    EMPTY */
+
+  /* (5) v1 <- t1-tm1           (1 1 1 1 0) - (0 1 0 1 0) = (1 0 1 0 0)
+     result is v1 >= 0
+  */
+  ASSERT_NOCARRY (mpn_sub_n (v1, v1, vm1, kk1));
+
+  /* We do not need to read the value in vm1, so we add it in {c+k, ...} */
+  cy = mpn_add_n (c1, c1, vm1, kk1);
+  MPN_INCR_U (c3 + 1, twor + k - 1, cy); /* 2n-(3k+1) = 2r+k-1 */
+  /* Memory allocated for vm1 is now free, it can be recycled ...*/
+
+  /* (6) v2 <- v2 - 2*vinf,     (2 1 0 0 0) - 2*(1 0 0 0 0) = (0 1 0 0 0)
+     result is v2 >= 0 */
+  saved = vinf[0];       /* Remember v1's highest byte (will be overwritten). */
+  vinf[0] = vinf0;       /* Set the right value for vinf0                     */
+#ifdef HAVE_NATIVE_mpn_sublsh1_n_ip1
+  cy = mpn_sublsh1_n_ip1 (v2, vinf, twor);
+#else
+  /* Overwrite unused vm1 */
+  cy = mpn_lshift (vm1, vinf, twor, 1);
+  cy += mpn_sub_n (v2, v2, vm1, twor);
+#endif
+  MPN_DECR_U (v2 + twor, kk1 - twor, cy);
+
+  /* Current matrix is
+     [1 0 0 0 0; vinf
+      0 1 0 0 0; v2
+      1 0 1 0 0; v1
+      0 1 0 1 0; vm1
+      0 0 0 0 1] v0
+     Some values already are in-place (we added vm1 in the correct position)
+     | vinf|  v1 |  v0 |
+	      | vm1 |
+     One still is in a separated area
+	| +v2 |
+     We have to compute v1-=vinf; vm1 -= v2,
+	   |-vinf|
+	      | -v2 |
+     Carefully reordering operations we can avoid to compute twice the sum
+     of the high half of v2 plus the low half of vinf.
+  */
+
+  /* Add the high half of t2 in {vinf} */
+  if ( LIKELY(twor > k + 1) ) { /* This is the expected flow  */
+    cy = mpn_add_n (vinf, vinf, v2 + k, k + 1);
+    MPN_INCR_U (c3 + kk1, twor - k - 1, cy); /* 2n-(5k+1) = 2r-k-1 */
+  } else { /* triggered only by very unbalanced cases like
+	      (k+k+(k-2))x(k+k+1) , should be handled by toom32 */
+    ASSERT_NOCARRY (mpn_add_n (vinf, vinf, v2 + k, twor));
+  }
+  /* (7) v1 <- v1 - vinf,       (1 0 1 0 0) - (1 0 0 0 0) = (0 0 1 0 0)
+     result is >= 0 */
+  /* Side effect: we also subtracted (high half) vm1 -= v2 */
+  cy = mpn_sub_n (v1, v1, vinf, twor);          /* vinf is at most twor long.  */
+  vinf0 = vinf[0];                     /* Save again the right value for vinf0 */
+  vinf[0] = saved;
+  MPN_DECR_U (v1 + twor, kk1 - twor, cy);       /* Treat the last bytes.       */
+
+  /* (8) vm1 <- vm1-v2          (0 1 0 1 0) - (0 1 0 0 0) = (0 0 0 1 0)
+     Operate only on the low half.
+  */
+  cy = mpn_sub_n (c1, c1, v2, k);
+  MPN_DECR_U (v1, kk1, cy);
+
+  /********************* Beginning the final phase **********************/
+
+  /* Most of the recomposition was done */
+
+  /* add t2 in {c+3k, ...}, but only the low half */
+  cy = mpn_add_n (c3, c3, v2, k);
+  vinf[0] += cy;
+  ASSERT(vinf[0] >= cy); /* No carry */
+  MPN_INCR_U (vinf, twor, vinf0); /* Add vinf0, propagate carry. */
+
+#undef v0
+}
diff --git a/mpn/generic/toom_interpolate_6pts.c b/mpn/generic/toom_interpolate_6pts.c
new file mode 100644
index 0000000..eb23661
--- /dev/null
+++ b/mpn/generic/toom_interpolate_6pts.c
@@ -0,0 +1,241 @@
+/* mpn_toom_interpolate_6pts -- Interpolate for toom43, 52
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define BINVERT_3 MODLIMB_INVERSE_3
+
+/* For odd divisors, mpn_divexact_1 works fine with two's complement. */
+#ifndef mpn_divexact_by3
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by3(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,3,BINVERT_3,0)
+#else
+#define mpn_divexact_by3(dst,src,size) mpn_divexact_1(dst,src,size,3)
+#endif
+#endif
+
+/* Interpolation for Toom-3.5, using the evaluation points: infinity,
+   1, -1, 2, -2. More precisely, we want to compute
+   f(2^(GMP_NUMB_BITS * n)) for a polynomial f of degree 5, given the
+   six values
+
+     w5 = f(0),
+     w4 = f(-1),
+     w3 = f(1)
+     w2 = f(-2),
+     w1 = f(2),
+     w0 = limit at infinity of f(x) / x^5,
+
+   The result is stored in {pp, 5*n + w0n}. At entry, w5 is stored at
+   {pp, 2n}, w3 is stored at {pp + 2n, 2n+1}, and w0 is stored at
+   {pp + 5n, w0n}. The other values are 2n + 1 limbs each (with most
+   significant limbs small). f(-1) and f(-2) may be negative, signs
+   determined by the flag bits. All intermediate results are positive.
+   Inputs are destroyed.
+
+   Interpolation sequence was taken from the paper: "Integer and
+   Polynomial Multiplication: Towards Optimal Toom-Cook Matrices".
+   Some slight variations were introduced: adaptation to "gmp
+   instruction set", and a final saving of an operation by interlacing
+   interpolation and recomposition phases.
+*/
+
+void
+mpn_toom_interpolate_6pts (mp_ptr pp, mp_size_t n, enum toom6_flags flags,
+			   mp_ptr w4, mp_ptr w2, mp_ptr w1,
+			   mp_size_t w0n)
+{
+  mp_limb_t cy;
+  /* cy6 can be stored in w1[2*n], cy4 in w4[0], embankment in w2[0] */
+  mp_limb_t cy4, cy6, embankment;
+
+  ASSERT( n > 0 );
+  ASSERT( 2*n >= w0n && w0n > 0 );
+
+#define w5  pp					/* 2n   */
+#define w3  (pp + 2 * n)			/* 2n+1 */
+#define w0  (pp + 5 * n)			/* w0n  */
+
+  /* Interpolate with sequence:
+     W2 =(W1 - W2)>>2
+     W1 =(W1 - W5)>>1
+     W1 =(W1 - W2)>>1
+     W4 =(W3 - W4)>>1
+     W2 =(W2 - W4)/3
+     W3 = W3 - W4 - W5
+     W1 =(W1 - W3)/3
+     // Last steps are mixed with recomposition...
+     W2 = W2 - W0<<2
+     W4 = W4 - W2
+     W3 = W3 - W1
+     W2 = W2 - W0
+  */
+
+  /* W2 =(W1 - W2)>>2 */
+  if (flags & toom6_vm2_neg)
+    mpn_add_n (w2, w1, w2, 2 * n + 1);
+  else
+    mpn_sub_n (w2, w1, w2, 2 * n + 1);
+  mpn_rshift (w2, w2, 2 * n + 1, 2);
+
+  /* W1 =(W1 - W5)>>1 */
+  w1[2*n] -= mpn_sub_n (w1, w1, w5, 2*n);
+  mpn_rshift (w1, w1, 2 * n + 1, 1);
+
+  /* W1 =(W1 - W2)>>1 */
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (w1, w1, w2, 2 * n + 1);
+#else
+  mpn_sub_n (w1, w1, w2, 2 * n + 1);
+  mpn_rshift (w1, w1, 2 * n + 1, 1);
+#endif
+
+  /* W4 =(W3 - W4)>>1 */
+  if (flags & toom6_vm1_neg)
+    {
+#if HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (w4, w3, w4, 2 * n + 1);
+#else
+      mpn_add_n (w4, w3, w4, 2 * n + 1);
+      mpn_rshift (w4, w4, 2 * n + 1, 1);
+#endif
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (w4, w3, w4, 2 * n + 1);
+#else
+      mpn_sub_n (w4, w3, w4, 2 * n + 1);
+      mpn_rshift (w4, w4, 2 * n + 1, 1);
+#endif
+    }
+
+  /* W2 =(W2 - W4)/3 */
+  mpn_sub_n (w2, w2, w4, 2 * n + 1);
+  mpn_divexact_by3 (w2, w2, 2 * n + 1);
+
+  /* W3 = W3 - W4 - W5 */
+  mpn_sub_n (w3, w3, w4, 2 * n + 1);
+  w3[2 * n] -= mpn_sub_n (w3, w3, w5, 2 * n);
+
+  /* W1 =(W1 - W3)/3 */
+  mpn_sub_n (w1, w1, w3, 2 * n + 1);
+  mpn_divexact_by3 (w1, w1, 2 * n + 1);
+
+  /*
+    [1 0 0 0 0 0;
+     0 1 0 0 0 0;
+     1 0 1 0 0 0;
+     0 1 0 1 0 0;
+     1 0 1 0 1 0;
+     0 0 0 0 0 1]
+
+    pp[] prior to operations:
+     |_H w0__|_L w0__|______||_H w3__|_L w3__|_H w5__|_L w5__|
+
+    summation scheme for remaining operations:
+     |______________5|n_____4|n_____3|n_____2|n______|n______|pp
+     |_H w0__|_L w0__|______||_H w3__|_L w3__|_H w5__|_L w5__|
+				    || H w4  | L w4  |
+		    || H w2  | L w2  |
+	    || H w1  | L w1  |
+			    ||-H w1  |-L w1  |
+		     |-H w0  |-L w0 ||-H w2  |-L w2  |
+  */
+  cy = mpn_add_n (pp + n, pp + n, w4, 2 * n + 1);
+  MPN_INCR_U (pp + 3 * n + 1, n, cy);
+
+  /* W2 -= W0<<2 */
+#if HAVE_NATIVE_mpn_sublsh_n || HAVE_NATIVE_mpn_sublsh2_n_ip1
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+  cy = mpn_sublsh2_n_ip1 (w2, w0, w0n);
+#else
+  cy = mpn_sublsh_n (w2, w2, w0, w0n, 2);
+#endif
+#else
+  /* {W4,2*n+1} is now free and can be overwritten. */
+  cy = mpn_lshift(w4, w0, w0n, 2);
+  cy+= mpn_sub_n(w2, w2, w4, w0n);
+#endif
+  MPN_DECR_U (w2 + w0n, 2 * n + 1 - w0n, cy);
+
+  /* W4L = W4L - W2L */
+  cy = mpn_sub_n (pp + n, pp + n, w2, n);
+  MPN_DECR_U (w3, 2 * n + 1, cy);
+
+  /* W3H = W3H + W2L */
+  cy4 = w3[2 * n] + mpn_add_n (pp + 3 * n, pp + 3 * n, w2, n);
+  /* W1L + W2H */
+  cy = w2[2 * n] + mpn_add_n (pp + 4 * n, w1, w2 + n, n);
+  MPN_INCR_U (w1 + n, n + 1, cy);
+
+  /* W0 = W0 + W1H */
+  if (LIKELY (w0n > n))
+    cy6 = w1[2 * n] + mpn_add_n (w0, w0, w1 + n, n);
+  else
+    cy6 = mpn_add_n (w0, w0, w1 + n, w0n);
+
+  /*
+    summation scheme for the next operation:
+     |...____5|n_____4|n_____3|n_____2|n______|n______|pp
+     |...w0___|_w1_w2_|_H w3__|_L w3__|_H w5__|_L w5__|
+		     ...-w0___|-w1_w2 |
+  */
+  /* if(LIKELY(w0n>n)) the two operands below DO overlap! */
+  cy = mpn_sub_n (pp + 2 * n, pp + 2 * n, pp + 4 * n, n + w0n);
+
+  /* embankment is a "dirty trick" to avoid carry/borrow propagation
+     beyond allocated memory */
+  embankment = w0[w0n - 1] - 1;
+  w0[w0n - 1] = 1;
+  if (LIKELY (w0n > n)) {
+    if (cy4 > cy6)
+      MPN_INCR_U (pp + 4 * n, w0n + n, cy4 - cy6);
+    else
+      MPN_DECR_U (pp + 4 * n, w0n + n, cy6 - cy4);
+    MPN_DECR_U (pp + 3 * n + w0n, 2 * n, cy);
+    MPN_INCR_U (w0 + n, w0n - n, cy6);
+  } else {
+    MPN_INCR_U (pp + 4 * n, w0n + n, cy4);
+    MPN_DECR_U (pp + 3 * n + w0n, 2 * n, cy + cy6);
+  }
+  w0[w0n - 1] += embankment;
+
+#undef w5
+#undef w3
+#undef w0
+
+}
diff --git a/mpn/generic/toom_interpolate_7pts.c b/mpn/generic/toom_interpolate_7pts.c
new file mode 100644
index 0000000..167c45b
--- /dev/null
+++ b/mpn/generic/toom_interpolate_7pts.c
@@ -0,0 +1,274 @@
+/* mpn_toom_interpolate_7pts -- Interpolate for toom44, 53, 62.
+
+   Contributed to the GNU project by Niels Möller.
+   Improvements by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006, 2007, 2009, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define BINVERT_3 MODLIMB_INVERSE_3
+
+#define BINVERT_9 \
+  ((((GMP_NUMB_MAX / 9) << (6 - GMP_NUMB_BITS % 6)) * 8 & GMP_NUMB_MAX) | 0x39)
+
+#define BINVERT_15 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 4)) / 15) * 14 * 16 & GMP_NUMB_MAX) + 15)
+
+/* For the various mpn_divexact_byN here, fall back to using either
+   mpn_pi1_bdiv_q_1 or mpn_divexact_1.  The former has less overhead and is
+   many faster if it is native.  For now, since mpn_divexact_1 is native on
+   several platforms where mpn_pi1_bdiv_q_1 does not yet exist, do not use
+   mpn_pi1_bdiv_q_1 unconditionally.  FIXME.  */
+
+/* For odd divisors, mpn_divexact_1 works fine with two's complement. */
+#ifndef mpn_divexact_by3
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by3(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,3,BINVERT_3,0)
+#else
+#define mpn_divexact_by3(dst,src,size) mpn_divexact_1(dst,src,size,3)
+#endif
+#endif
+
+#ifndef mpn_divexact_by9
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by9(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,9,BINVERT_9,0)
+#else
+#define mpn_divexact_by9(dst,src,size) mpn_divexact_1(dst,src,size,9)
+#endif
+#endif
+
+#ifndef mpn_divexact_by15
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by15(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,15,BINVERT_15,0)
+#else
+#define mpn_divexact_by15(dst,src,size) mpn_divexact_1(dst,src,size,15)
+#endif
+#endif
+
+/* Interpolation for toom4, using the evaluation points 0, infinity,
+   1, -1, 2, -2, 1/2. More precisely, we want to compute
+   f(2^(GMP_NUMB_BITS * n)) for a polynomial f of degree 6, given the
+   seven values
+
+     w0 = f(0),
+     w1 = f(-2),
+     w2 = f(1),
+     w3 = f(-1),
+     w4 = f(2)
+     w5 = 64 * f(1/2)
+     w6 = limit at infinity of f(x) / x^6,
+
+   The result is 6*n + w6n limbs. At entry, w0 is stored at {rp, 2n },
+   w2 is stored at { rp + 2n, 2n+1 }, and w6 is stored at { rp + 6n,
+   w6n }. The other values are 2n + 1 limbs each (with most
+   significant limbs small). f(-1) and f(-1/2) may be negative, signs
+   determined by the flag bits. Inputs are destroyed.
+
+   Needs (2*n + 1) limbs of temporary storage.
+*/
+
+void
+mpn_toom_interpolate_7pts (mp_ptr rp, mp_size_t n, enum toom7_flags flags,
+			   mp_ptr w1, mp_ptr w3, mp_ptr w4, mp_ptr w5,
+			   mp_size_t w6n, mp_ptr tp)
+{
+  mp_size_t m;
+  mp_limb_t cy;
+
+  m = 2*n + 1;
+#define w0 rp
+#define w2 (rp + 2*n)
+#define w6 (rp + 6*n)
+
+  ASSERT (w6n > 0);
+  ASSERT (w6n <= 2*n);
+
+  /* Using formulas similar to Marco Bodrato's
+
+     W5 = W5 + W4
+     W1 =(W4 - W1)/2
+     W4 = W4 - W0
+     W4 =(W4 - W1)/4 - W6*16
+     W3 =(W2 - W3)/2
+     W2 = W2 - W3
+
+     W5 = W5 - W2*65      May be negative.
+     W2 = W2 - W6 - W0
+     W5 =(W5 + W2*45)/2   Now >= 0 again.
+     W4 =(W4 - W2)/3
+     W2 = W2 - W4
+
+     W1 = W5 - W1         May be negative.
+     W5 =(W5 - W3*8)/9
+     W3 = W3 - W5
+     W1 =(W1/15 + W5)/2   Now >= 0 again.
+     W5 = W5 - W1
+
+     where W0 = f(0), W1 = f(-2), W2 = f(1), W3 = f(-1),
+	   W4 = f(2), W5 = f(1/2), W6 = f(oo),
+
+     Note that most intermediate results are positive; the ones that
+     may be negative are represented in two's complement. We must
+     never shift right a value that may be negative, since that would
+     invalidate the sign bit. On the other hand, divexact by odd
+     numbers work fine with two's complement.
+  */
+
+  mpn_add_n (w5, w5, w4, m);
+  if (flags & toom7_w1_neg)
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (w1, w1, w4, m);
+#else
+      mpn_add_n (w1, w1, w4, m);  ASSERT (!(w1[0] & 1));
+      mpn_rshift (w1, w1, m, 1);
+#endif
+    }
+  else
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (w1, w4, w1, m);
+#else
+      mpn_sub_n (w1, w4, w1, m);  ASSERT (!(w1[0] & 1));
+      mpn_rshift (w1, w1, m, 1);
+#endif
+    }
+  mpn_sub (w4, w4, m, w0, 2*n);
+  mpn_sub_n (w4, w4, w1, m);  ASSERT (!(w4[0] & 3));
+  mpn_rshift (w4, w4, m, 2); /* w4>=0 */
+
+  tp[w6n] = mpn_lshift (tp, w6, w6n, 4);
+  mpn_sub (w4, w4, m, tp, w6n+1);
+
+  if (flags & toom7_w3_neg)
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (w3, w3, w2, m);
+#else
+      mpn_add_n (w3, w3, w2, m);  ASSERT (!(w3[0] & 1));
+      mpn_rshift (w3, w3, m, 1);
+#endif
+    }
+  else
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (w3, w2, w3, m);
+#else
+      mpn_sub_n (w3, w2, w3, m);  ASSERT (!(w3[0] & 1));
+      mpn_rshift (w3, w3, m, 1);
+#endif
+    }
+
+  mpn_sub_n (w2, w2, w3, m);
+
+  mpn_submul_1 (w5, w2, m, 65);
+  mpn_sub (w2, w2, m, w6, w6n);
+  mpn_sub (w2, w2, m, w0, 2*n);
+
+  mpn_addmul_1 (w5, w2, m, 45);  ASSERT (!(w5[0] & 1));
+  mpn_rshift (w5, w5, m, 1);
+  mpn_sub_n (w4, w4, w2, m);
+
+  mpn_divexact_by3 (w4, w4, m);
+  mpn_sub_n (w2, w2, w4, m);
+
+  mpn_sub_n (w1, w5, w1, m);
+  mpn_lshift (tp, w3, m, 3);
+  mpn_sub_n (w5, w5, tp, m);
+  mpn_divexact_by9 (w5, w5, m);
+  mpn_sub_n (w3, w3, w5, m);
+
+  mpn_divexact_by15 (w1, w1, m);
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (w1, w1, w5, m);
+  w1[m - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (w1, w1, w5, m);  ASSERT (!(w1[0] & 1));
+  mpn_rshift (w1, w1, m, 1); /* w1>=0 now */
+#endif
+
+  mpn_sub_n (w5, w5, w1, m);
+
+  /* These bounds are valid for the 4x4 polynomial product of toom44,
+   * and they are conservative for toom53 and toom62. */
+  ASSERT (w1[2*n] < 2);
+  ASSERT (w2[2*n] < 3);
+  ASSERT (w3[2*n] < 4);
+  ASSERT (w4[2*n] < 3);
+  ASSERT (w5[2*n] < 2);
+
+  /* Addition chain. Note carries and the 2n'th limbs that need to be
+   * added in.
+   *
+   * Special care is needed for w2[2n] and the corresponding carry,
+   * since the "simple" way of adding it all together would overwrite
+   * the limb at wp[2*n] and rp[4*n] (same location) with the sum of
+   * the high half of w3 and the low half of w4.
+   *
+   *         7    6    5    4    3    2    1    0
+   *    |    |    |    |    |    |    |    |    |
+   *                  ||w3 (2n+1)|
+   *             ||w4 (2n+1)|
+   *        ||w5 (2n+1)|        ||w1 (2n+1)|
+   *  + | w6 (w6n)|        ||w2 (2n+1)| w0 (2n) |  (share storage with r)
+   *  -----------------------------------------------
+   *  r |    |    |    |    |    |    |    |    |
+   *        c7   c6   c5   c4   c3                 Carries to propagate
+   */
+
+  cy = mpn_add_n (rp + n, rp + n, w1, m);
+  MPN_INCR_U (w2 + n + 1, n , cy);
+  cy = mpn_add_n (rp + 3*n, rp + 3*n, w3, n);
+  MPN_INCR_U (w3 + n, n + 1, w2[2*n] + cy);
+  cy = mpn_add_n (rp + 4*n, w3 + n, w4, n);
+  MPN_INCR_U (w4 + n, n + 1, w3[2*n] + cy);
+  cy = mpn_add_n (rp + 5*n, w4 + n, w5, n);
+  MPN_INCR_U (w5 + n, n + 1, w4[2*n] + cy);
+  if (w6n > n + 1)
+    {
+      cy = mpn_add_n (rp + 6*n, rp + 6*n, w5 + n, n + 1);
+      MPN_INCR_U (rp + 7*n + 1, w6n - n - 1, cy);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n (rp + 6*n, rp + 6*n, w5 + n, w6n));
+#if WANT_ASSERT
+      {
+	mp_size_t i;
+	for (i = w6n; i <= n; i++)
+	  ASSERT (w5[n + i] == 0);
+      }
+#endif
+    }
+}
diff --git a/mpn/generic/toom_interpolate_8pts.c b/mpn/generic/toom_interpolate_8pts.c
new file mode 100644
index 0000000..5e65fab
--- /dev/null
+++ b/mpn/generic/toom_interpolate_8pts.c
@@ -0,0 +1,211 @@
+/* mpn_toom_interpolate_8pts -- Interpolate for toom54, 63, 72.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define BINVERT_3 MODLIMB_INVERSE_3
+
+#define BINVERT_15 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 4)) / 15) * 14 * 16 & GMP_NUMB_MAX) + 15)
+
+#define BINVERT_45 ((BINVERT_15 * BINVERT_3) & GMP_NUMB_MASK)
+
+#ifndef mpn_divexact_by3
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by3(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,3,BINVERT_3,0)
+#else
+#define mpn_divexact_by3(dst,src,size) mpn_divexact_1(dst,src,size,3)
+#endif
+#endif
+
+#ifndef mpn_divexact_by45
+#if GMP_NUMB_BITS % 12 == 0
+#define mpn_divexact_by45(dst,src,size) \
+  (63 & 19 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 45)))
+#else
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by45(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,45,BINVERT_45,0)
+#else
+#define mpn_divexact_by45(dst,src,size) mpn_divexact_1(dst,src,size,45)
+#endif
+#endif
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+#define DO_mpn_sublsh2_n(dst,src,n,ws) mpn_sublsh2_n_ip1(dst,src,n)
+#else
+#define DO_mpn_sublsh2_n(dst,src,n,ws) DO_mpn_sublsh_n(dst,src,n,2,ws)
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_n
+#define DO_mpn_sublsh_n(dst,src,n,s,ws) mpn_sublsh_n (dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_sublsh_n (mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_submul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift (ws,src,n,s);
+  return __cy + mpn_sub_n (dst,dst,ws,n);
+#endif
+}
+#endif
+
+
+#if HAVE_NATIVE_mpn_subrsh
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws) mpn_subrsh (dst,nd,src,ns,s)
+#else
+/* This is not a correct definition, it assumes no carry */
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws)				\
+do {									\
+  mp_limb_t __cy;							\
+  MPN_DECR_U (dst, nd, src[0] >> s);					\
+  __cy = DO_mpn_sublsh_n (dst, src + 1, ns - 1, GMP_NUMB_BITS - s, ws);	\
+  MPN_DECR_U (dst + ns - 1, nd - ns + 1, __cy);				\
+} while (0)
+#endif
+
+/* Interpolation for Toom-4.5 (or Toom-4), using the evaluation
+   points: infinity(4.5 only), 4, -4, 2, -2, 1, -1, 0. More precisely,
+   we want to compute f(2^(GMP_NUMB_BITS * n)) for a polynomial f of
+   degree 7 (or 6), given the 8 (rsp. 7) values:
+
+     r1 = limit at infinity of f(x) / x^7,
+     r2 = f(4),
+     r3 = f(-4),
+     r4 = f(2),
+     r5 = f(-2),
+     r6 = f(1),
+     r7 = f(-1),
+     r8 = f(0).
+
+   All couples of the form f(n),f(-n) must be already mixed with
+   toom_couple_handling(f(n),...,f(-n),...)
+
+   The result is stored in {pp, spt + 7*n (or 6*n)}.
+   At entry, r8 is stored at {pp, 2n},
+   r5 is stored at {pp + 3n, 3n + 1}.
+
+   The other values are 2n+... limbs each (with most significant limbs small).
+
+   All intermediate results are positive.
+   Inputs are destroyed.
+*/
+
+void
+mpn_toom_interpolate_8pts (mp_ptr pp, mp_size_t n,
+			   mp_ptr r3, mp_ptr r7,
+			   mp_size_t spt, mp_ptr ws)
+{
+  mp_limb_signed_t cy;
+  mp_ptr r5, r1;
+  r5 = (pp + 3 * n);			/* 3n+1 */
+  r1 = (pp + 7 * n);			/* spt */
+
+  /******************************* interpolation *****************************/
+
+  DO_mpn_subrsh(r3+n, 2 * n + 1, pp, 2 * n, 4, ws);
+  cy = DO_mpn_sublsh_n (r3, r1, spt, 12, ws);
+  MPN_DECR_U (r3 + spt, 3 * n + 1 - spt, cy);
+
+  DO_mpn_subrsh(r5+n, 2 * n + 1, pp, 2 * n, 2, ws);
+  cy = DO_mpn_sublsh_n (r5, r1, spt, 6, ws);
+  MPN_DECR_U (r5 + spt, 3 * n + 1 - spt, cy);
+
+  r7[3*n] -= mpn_sub_n (r7+n, r7+n, pp, 2 * n);
+  cy = mpn_sub_n (r7, r7, r1, spt);
+  MPN_DECR_U (r7 + spt, 3 * n + 1 - spt, cy);
+
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r5, 3 * n + 1));
+  ASSERT_NOCARRY(mpn_rshift(r3, r3, 3 * n + 1, 2));
+
+  ASSERT_NOCARRY(mpn_sub_n (r5, r5, r7, 3 * n + 1));
+
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r5, 3 * n + 1));
+
+  mpn_divexact_by45 (r3, r3, 3 * n + 1);
+
+  ASSERT_NOCARRY(mpn_divexact_by3 (r5, r5, 3 * n + 1));
+
+  ASSERT_NOCARRY(DO_mpn_sublsh2_n (r5, r3, 3 * n + 1, ws));
+
+  /* last interpolation steps... */
+  /* ... are mixed with recomposition */
+
+  /***************************** recomposition *******************************/
+  /*
+    pp[] prior to operations:
+     |_H r1|_L r1|____||_H r5|_M_r5|_L r5|_____|_H r8|_L r8|pp
+
+    summation scheme for remaining operations:
+     |____8|n___7|n___6|n___5|n___4|n___3|n___2|n____|n____|pp
+     |_H r1|_L r1|____||_H*r5|_M r5|_L r5|_____|_H_r8|_L r8|pp
+	  ||_H r3|_M r3|_L*r3|
+				  ||_H_r7|_M_r7|_L_r7|
+		      ||-H r3|-M r3|-L*r3|
+				  ||-H*r5|-M_r5|-L_r5|
+  */
+
+  cy = mpn_add_n (pp + n, pp + n, r7, n); /* Hr8+Lr7-Lr5 */
+  cy-= mpn_sub_n (pp + n, pp + n, r5, n);
+  if (cy > 0) {
+    MPN_INCR_U (r7 + n, 2*n + 1, 1);
+    cy = 0;
+  }
+
+  cy = mpn_sub_nc (pp + 2*n, r7 + n, r5 + n, n, -cy); /* Mr7-Mr5 */
+  MPN_DECR_U (r7 + 2*n, n + 1, cy);
+
+  cy = mpn_add_n (pp + 3*n, r5, r7+ 2*n, n+1); /* Hr7+Lr5 */
+  r5[3*n]+= mpn_add_n (r5 + 2*n, r5 + 2*n, r3, n); /* Hr5+Lr3 */
+  cy-= mpn_sub_n (pp + 3*n, pp + 3*n, r5 + 2*n, n+1); /* Hr7-Hr5+Lr5-Lr3 */
+  if (UNLIKELY(0 > cy))
+    MPN_DECR_U (r5 + n + 1, 2*n, 1);
+  else
+    MPN_INCR_U (r5 + n + 1, 2*n, cy);
+
+  ASSERT_NOCARRY(mpn_sub_n(pp + 4*n, r5 + n, r3 + n, 2*n +1)); /* Mr5-Mr3,Hr5-Hr3 */
+
+  cy = mpn_add_1 (pp + 6*n, r3 + n, n, pp[6*n]);
+  MPN_INCR_U (r3 + 2*n, n + 1, cy);
+  cy = mpn_add_n (pp + 7*n, pp + 7*n, r3 + 2*n, n);
+  if (LIKELY(spt != n))
+    MPN_INCR_U (pp + 8*n, spt - n, cy + r3[3*n]);
+  else
+    ASSERT (r3[3*n] + cy == 0);
+}
diff --git a/mpn/generic/trialdiv.c b/mpn/generic/trialdiv.c
new file mode 100644
index 0000000..65e089f
--- /dev/null
+++ b/mpn/generic/trialdiv.c
@@ -0,0 +1,131 @@
+/* mpn_trialdiv -- find small factors of an mpn number using trial division.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+   This function finds the first (smallest) factor represented in
+   trialdivtab.h.  It does not stop the factoring effort just because it has
+   reached some sensible limit, such as the square root of the input number.
+
+   The caller can limit the factoring effort by passing NPRIMES.  The function
+   will then divide until that limit, or perhaps a few primes more.  A position
+   which only mpn_trialdiv can make sense of is returned in the WHERE
+   parameter.  It can be used for restarting the factoring effort; the first
+   call should pass 0 here.
+
+   Input:        1. A non-negative number T = {tp,tn}
+                 2. NPRIMES as described above,
+                 3. *WHERE as described above.
+   Output:       1. *WHERE updated as described above.
+                 2. Return value is non-zero if we found a factor, else zero
+                    To get the actual prime factor, compute the mod B inverse
+                    of the return value.
+*/
+
+#include "gmp-impl.h"
+
+struct gmp_primes_dtab {
+  mp_limb_t binv;
+  mp_limb_t lim;
+};
+
+struct gmp_primes_ptab {
+  mp_limb_t ppp;	/* primes, multiplied together */
+  mp_limb_t cps[7];	/* ppp values pre-computed for mpn_mod_1s_4p */
+  gmp_uint_least32_t idx:24;	/* index of  first primes in dtab */
+  gmp_uint_least32_t np :8;	/* number of primes related to this entry */
+};
+
+
+static const struct gmp_primes_dtab gmp_primes_dtab[] =
+{
+#define WANT_dtab
+#define P(p,inv,lim) {inv,lim}
+#include "trialdivtab.h"
+#undef WANT_dtab
+#undef P
+  {0,0}
+};
+
+static const struct gmp_primes_ptab gmp_primes_ptab[] =
+{
+#define WANT_ptab
+#include "trialdivtab.h"
+#undef WANT_ptab
+};
+
+#define PTAB_LINES (sizeof (gmp_primes_ptab) / sizeof (gmp_primes_ptab[0]))
+
+/* FIXME: We could optimize out one of the outer loop conditions if we
+   had a final ptab entry with a huge np field.  */
+mp_limb_t
+mpn_trialdiv (mp_srcptr tp, mp_size_t tn, mp_size_t nprimes, int *where)
+{
+  mp_limb_t ppp;
+  const mp_limb_t *cps;
+  const struct gmp_primes_dtab *dp;
+  long i, j, idx, np;
+  mp_limb_t r, q;
+
+  ASSERT (tn >= 1);
+
+  for (i = *where; i < PTAB_LINES; i++)
+    {
+      ppp = gmp_primes_ptab[i].ppp;
+      cps = gmp_primes_ptab[i].cps;
+
+      r = mpn_mod_1s_4p (tp, tn, ppp << cps[1], cps);
+
+      idx = gmp_primes_ptab[i].idx;
+      np = gmp_primes_ptab[i].np;
+
+      /* Check divisibility by individual primes.  */
+      dp = &gmp_primes_dtab[idx] + np;
+      for (j = -np; j < 0; j++)
+	{
+	  q = r * dp[j].binv;
+	  if (q <= dp[j].lim)
+	    {
+	      *where = i;
+	      return dp[j].binv;
+	    }
+	}
+
+      nprimes -= np;
+      if (nprimes <= 0)
+	return 0;
+    }
+  return 0;
+}
diff --git a/mpn/generic/udiv_w_sdiv.c b/mpn/generic/udiv_w_sdiv.c
new file mode 100644
index 0000000..7907135
--- /dev/null
+++ b/mpn/generic/udiv_w_sdiv.c
@@ -0,0 +1,141 @@
+/* mpn_udiv_w_sdiv -- implement udiv_qrnnd on machines with only signed
+   division.
+
+   Contributed by Peter L. Montgomery.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY SAFE
+   TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THIS FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE
+   GNU MP RELEASE.
+
+
+Copyright 1992, 1994, 1996, 2000, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_udiv_w_sdiv (mp_limb_t *rp, mp_limb_t a1, mp_limb_t a0, mp_limb_t d)
+{
+  mp_limb_t q, r;
+  mp_limb_t c0, c1, b1;
+
+  ASSERT (d != 0);
+  ASSERT (a1 < d);
+
+  if ((mp_limb_signed_t) d >= 0)
+    {
+      if (a1 < d - a1 - (a0 >> (GMP_LIMB_BITS - 1)))
+	{
+	  /* dividend, divisor, and quotient are nonnegative */
+	  sdiv_qrnnd (q, r, a1, a0, d);
+	}
+      else
+	{
+	  /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
+	  sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (GMP_LIMB_BITS - 1));
+	  /* Divide (c1*2^32 + c0) by d */
+	  sdiv_qrnnd (q, r, c1, c0, d);
+	  /* Add 2^31 to quotient */
+	  q += (mp_limb_t) 1 << (GMP_LIMB_BITS - 1);
+	}
+    }
+  else
+    {
+      b1 = d >> 1;			/* d/2, between 2^30 and 2^31 - 1 */
+      c1 = a1 >> 1;			/* A/2 */
+      c0 = (a1 << (GMP_LIMB_BITS - 1)) + (a0 >> 1);
+
+      if (a1 < b1)			/* A < 2^32*b1, so A/2 < 2^31*b1 */
+	{
+	  sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+	  r = 2*r + (a0 & 1);		/* Remainder from A/(2*b1) */
+	  if ((d & 1) != 0)
+	    {
+	      if (r >= q)
+		r = r - q;
+	      else if (q - r <= d)
+		{
+		  r = r - q + d;
+		  q--;
+		}
+	      else
+		{
+		  r = r - q + 2*d;
+		  q -= 2;
+		}
+	    }
+	}
+      else if (c1 < b1)			/* So 2^31 <= (A/2)/b1 < 2^32 */
+	{
+	  c1 = (b1 - 1) - c1;
+	  c0 = ~c0;			/* logical NOT */
+
+	  sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+	  q = ~q;			/* (A/2)/b1 */
+	  r = (b1 - 1) - r;
+
+	  r = 2*r + (a0 & 1);		/* A/(2*b1) */
+
+	  if ((d & 1) != 0)
+	    {
+	      if (r >= q)
+		r = r - q;
+	      else if (q - r <= d)
+		{
+		  r = r - q + d;
+		  q--;
+		}
+	      else
+		{
+		  r = r - q + 2*d;
+		  q -= 2;
+		}
+	    }
+	}
+      else				/* Implies c1 = b1 */
+	{				/* Hence a1 = d - 1 = 2*b1 - 1 */
+	  if (a0 >= -d)
+	    {
+	      q = -CNST_LIMB(1);
+	      r = a0 + d;
+	    }
+	  else
+	    {
+	      q = -CNST_LIMB(2);
+	      r = a0 + 2*d;
+	    }
+	}
+    }
+
+  *rp = r;
+  return q;
+}
diff --git a/mpn/generic/zero.c b/mpn/generic/zero.c
new file mode 100644
index 0000000..1a05453
--- /dev/null
+++ b/mpn/generic/zero.c
@@ -0,0 +1,41 @@
+/* mpn_zero
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_zero (mp_ptr rp, mp_size_t n)
+{
+  mp_size_t i;
+
+  rp += n;
+  for (i = -n; i != 0; i++)
+    rp[i] = 0;
+}
diff --git a/mpn/generic/zero_p.c b/mpn/generic/zero_p.c
new file mode 100644
index 0000000..c92f9b8
--- /dev/null
+++ b/mpn/generic/zero_p.c
@@ -0,0 +1,33 @@
+/* mpn_zero_p (x,xsize) -- Return 1 if X is zero, 0 if it is non-zero.
+
+Copyright 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_zero_p 1
+
+#include "gmp-impl.h"
diff --git a/mpn/x86/aors_n.asm b/mpn/x86/aors_n.asm
new file mode 100644
index 0000000..1f97b39
--- /dev/null
+++ b/mpn/x86/aors_n.asm
@@ -0,0 +1,202 @@
+dnl  x86 mpn_add_n/mpn_sub_n -- mpn addition and subtraction.
+
+dnl  Copyright 1992, 1994-1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb
+C P5	3.375
+C P6	3.125
+C K6	3.5
+C K7	2.25
+C P4	8.75
+
+
+ifdef(`OPERATION_add_n',`
+	define(M4_inst,        adcl)
+	define(M4_function_n,  mpn_add_n)
+	define(M4_function_nc, mpn_add_nc)
+
+',`ifdef(`OPERATION_sub_n',`
+	define(M4_inst,        sbbl)
+	define(M4_function_n,  mpn_sub_n)
+	define(M4_function_nc, mpn_sub_nc)
+
+',`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+
+C mp_limb_t M4_function_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size);
+C mp_limb_t M4_function_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C	                    mp_size_t size, mp_limb_t carry);
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(M4_function_nc)
+deflit(`FRAME',0)
+
+	pushl	%edi		FRAME_pushl()
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC1,%esi
+	movl	PARAM_SRC2,%edx
+	movl	PARAM_SIZE,%ecx
+
+	movl	%ecx,%eax
+	shrl	$3,%ecx			C compute count for unrolled loop
+	negl	%eax
+	andl	$7,%eax			C get index where to start loop
+	jz	L(oopgo)		C necessary special case for 0
+	incl	%ecx			C adjust loop count
+	shll	$2,%eax			C adjustment for pointers...
+	subl	%eax,%edi		C ... since they are offset ...
+	subl	%eax,%esi		C ... by a constant when we ...
+	subl	%eax,%edx		C ... enter the loop
+	shrl	$2,%eax			C restore previous value
+
+ifdef(`PIC',`
+	C Calculate start address in loop for PIC.  Due to limitations in
+	C old gas, LF(M4_function_n,oop)-L(0a)-3 cannot be put into the leal
+	call	L(0a)
+L(0a):	leal	(%eax,%eax,8),%eax
+	addl	(%esp),%eax
+	addl	$L(oop)-L(0a)-3,%eax
+	addl	$4,%esp
+',`
+	C Calculate start address in loop for non-PIC.
+	leal	L(oop)-3(%eax,%eax,8),%eax
+')
+
+	C These lines initialize carry from the 5th parameter.  Should be
+	C possible to simplify.
+	pushl	%ebp		FRAME_pushl()
+	movl	PARAM_CARRY,%ebp
+	shrl	%ebp			C shift bit 0 into carry
+	popl	%ebp		FRAME_popl()
+
+	jmp	*%eax			C jump into loop
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(M4_function_n)
+deflit(`FRAME',0)
+
+	pushl	%edi		FRAME_pushl()
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC1,%esi
+	movl	PARAM_SRC2,%edx
+	movl	PARAM_SIZE,%ecx
+
+	movl	%ecx,%eax
+	shrl	$3,%ecx			C compute count for unrolled loop
+	negl	%eax
+	andl	$7,%eax			C get index where to start loop
+	jz	L(oop)			C necessary special case for 0
+	incl	%ecx			C adjust loop count
+	shll	$2,%eax			C adjustment for pointers...
+	subl	%eax,%edi		C ... since they are offset ...
+	subl	%eax,%esi		C ... by a constant when we ...
+	subl	%eax,%edx		C ... enter the loop
+	shrl	$2,%eax			C restore previous value
+
+ifdef(`PIC',`
+	C Calculate start address in loop for PIC.  Due to limitations in
+	C some assemblers, L(oop)-L(0b)-3 cannot be put into the leal
+	call	L(0b)
+L(0b):	leal	(%eax,%eax,8),%eax
+	addl	(%esp),%eax
+	addl	$L(oop)-L(0b)-3,%eax
+	addl	$4,%esp
+',`
+	C Calculate start address in loop for non-PIC.
+	leal	L(oop)-3(%eax,%eax,8),%eax
+')
+	jmp	*%eax			C jump into loop
+
+L(oopgo):
+	pushl	%ebp		FRAME_pushl()
+	movl	PARAM_CARRY,%ebp
+	shrl	%ebp			C shift bit 0 into carry
+	popl	%ebp		FRAME_popl()
+
+	ALIGN(16)
+L(oop):	movl	(%esi),%eax
+	M4_inst	(%edx),%eax
+	movl	%eax,(%edi)
+	movl	4(%esi),%eax
+	M4_inst	4(%edx),%eax
+	movl	%eax,4(%edi)
+	movl	8(%esi),%eax
+	M4_inst	8(%edx),%eax
+	movl	%eax,8(%edi)
+	movl	12(%esi),%eax
+	M4_inst	12(%edx),%eax
+	movl	%eax,12(%edi)
+	movl	16(%esi),%eax
+	M4_inst	16(%edx),%eax
+	movl	%eax,16(%edi)
+	movl	20(%esi),%eax
+	M4_inst	20(%edx),%eax
+	movl	%eax,20(%edi)
+	movl	24(%esi),%eax
+	M4_inst	24(%edx),%eax
+	movl	%eax,24(%edi)
+	movl	28(%esi),%eax
+	M4_inst	28(%edx),%eax
+	movl	%eax,28(%edi)
+	leal	32(%edi),%edi
+	leal	32(%esi),%esi
+	leal	32(%edx),%edx
+	decl	%ecx
+	jnz	L(oop)
+
+	sbbl	%eax,%eax
+	negl	%eax
+
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/aorsmul_1.asm b/mpn/x86/aorsmul_1.asm
new file mode 100644
index 0000000..ee7b774
--- /dev/null
+++ b/mpn/x86/aorsmul_1.asm
@@ -0,0 +1,214 @@
+dnl  x86 __gmpn_addmul_1 (for 386 and 486) -- Multiply a limb vector with a
+dnl  limb and add the result to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1997, 1999-2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C			    cycles/limb
+C P5				
+C P6 model 0-8,10-12		
+C P6 model 9  (Banias)		
+C P6 model 13 (Dothan)		
+C P4 model 0  (Willamette)	
+C P4 model 1  (?)		
+C P4 model 2  (Northwood)	
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom
+C AMD K6			
+C AMD K7			
+C AMD K8			 3.875
+C AMD K10
+
+
+ifdef(`OPERATION_addmul_1',`
+      define(ADDSUB,        addl)
+      define(M4_function_1,  mpn_addmul_1)
+      define(M4_function_1c, mpn_addmul_1c)
+
+',`ifdef(`OPERATION_submul_1',`
+      define(ADDSUB,        subl)
+      define(M4_function_1,  mpn_submul_1)
+
+',`m4_error(`Need OPERATION_addmul_1 or OPERATION_submul_1
+')')')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1 mpn_addmul_1c)
+
+
+C mp_limb_t M4_function_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                          mp_limb_t mult);
+
+define(PARAM_CARRY,      `FRAME+20(%esp)')
+define(PARAM_MULTIPLIER, `FRAME+16(%esp)')
+define(PARAM_SIZE,       `FRAME+12(%esp)')
+define(PARAM_SRC,        `FRAME+8(%esp)')
+define(PARAM_DST,        `FRAME+4(%esp)')
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(M4_function_1)
+deflit(`FRAME',0)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_DST, %edi
+
+	movl	(%esi), %eax
+	mull	PARAM_MULTIPLIER
+
+	testb	$1, %cl
+	jnz	L(bx1)
+
+L(bx0):	movl	%eax, %ebx
+	movl	%edx, %ebp
+	shrl	$2, %ecx
+	jnc	L(lo0)
+
+L(b10):	leal	-8(%esi), %esi
+	leal	-8(%edi), %edi
+	incl	%ecx
+	jmp	L(lo2)
+
+L(bx1):	movl	%eax, %ebp
+	movl	%edx, %ebx
+	shrl	$2, %ecx
+	jc	L(b11)
+
+L(b01):	leal	4(%edi), %edi
+	jz	L(end)
+	leal	4(%esi), %esi
+	jmp	L(top)
+
+L(b11):	leal	-4(%esi), %esi
+	leal	-4(%edi), %edi
+	incl	%ecx
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	movl	(%esi), %eax
+	mull	PARAM_MULTIPLIER
+	ADDSUB	%ebp, -4(%edi)
+	adcl	%eax, %ebx
+	movl	$0, %ebp
+	adcl	%edx, %ebp
+L(lo0):	movl	4(%esi), %eax
+	mull	PARAM_MULTIPLIER
+	ADDSUB	%ebx, (%edi)
+	adcl	%eax, %ebp
+	movl	$0, %ebx
+	adcl	%edx, %ebx
+L(lo3):	movl	8(%esi), %eax
+	mull	PARAM_MULTIPLIER
+	ADDSUB	%ebp, 4(%edi)
+	adcl	%eax, %ebx
+	movl	$0, %ebp
+	adcl	%edx, %ebp
+L(lo2):	movl	12(%esi), %eax
+	mull	PARAM_MULTIPLIER
+	ADDSUB	%ebx, 8(%edi)
+	adcl	%eax, %ebp
+	movl	$0, %ebx
+	adcl	%edx, %ebx
+
+	leal	16(%esi), %esi
+	leal	16(%edi), %edi
+	decl	%ecx
+	jnz	L(top)
+
+L(end):	xor	%eax, %eax
+	ADDSUB	%ebp, -4(%edi)
+	adcl	%ebx, %eax
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
+ifdef(`OPERATION_addmul_1',`
+	ALIGN(32)
+PROLOGUE(M4_function_1c)
+deflit(`FRAME',0)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_DST, %edi
+
+	movl	(%esi), %eax
+	mull	PARAM_MULTIPLIER
+
+	testb	$1, %cl
+	jnz	L(cx1)
+
+	movl	PARAM_CARRY, %ebx
+	xorl	%ebp, %ebp
+
+L(cx0):	addl	%eax, %ebx
+	adcl	%edx, %ebp
+	shrl	$2, %ecx
+	jnc	L(lo0)
+
+L(c10):	leal	-8(%esi), %esi
+	leal	-8(%edi), %edi
+	incl	%ecx
+	jmp	L(lo2)
+
+L(cx1):	movl	PARAM_CARRY, %ebp
+	xorl	%ebx, %ebx
+
+	addl	%eax, %ebp
+	adcl	%edx, %ebx
+	shrl	$2, %ecx
+	jc	L(c11)
+
+L(c01):	leal	4(%edi), %edi
+	jz	L(end)
+	leal	4(%esi), %esi
+	jmp	L(top)
+
+L(c11):	leal	-4(%esi), %esi
+	leal	-4(%edi), %edi
+	incl	%ecx
+	jmp	L(lo3)
+EPILOGUE()
+')
diff --git a/mpn/x86/bdiv_dbm1c.asm b/mpn/x86/bdiv_dbm1c.asm
new file mode 100644
index 0000000..291a783
--- /dev/null
+++ b/mpn/x86/bdiv_dbm1c.asm
@@ -0,0 +1,129 @@
+dnl  x86 mpn_bdiv_dbm1.
+
+dnl  Copyright 2008, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12)
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 5.1
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)	13.67
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom
+C AMD K6
+C AMD K7			 3.5
+C AMD K8
+C AMD K10
+
+
+C TODO
+C  * Optimize for more x86 processors
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	mov	16(%esp), %ecx		C d
+	push	%esi
+	mov	12(%esp), %esi		C ap
+	push	%edi
+	mov	12(%esp), %edi		C qp
+	push	%ebp
+	mov	24(%esp), %ebp		C n
+	push	%ebx
+
+	mov	(%esi), %eax
+	mul	%ecx
+	mov	36(%esp), %ebx
+	sub	%eax, %ebx
+	mov	%ebx, (%edi)
+	sbb	%edx, %ebx
+
+	mov	%ebp, %eax
+	and	$3, %eax
+	jz	L(b0)
+	cmp	$2, %eax
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	lea	-8(%esi), %esi
+	lea	8(%edi), %edi
+	add	$-3, %ebp
+	jmp	L(3)
+
+L(b0):	mov	4(%esi), %eax
+	lea	-4(%esi), %esi
+	lea	12(%edi), %edi
+	add	$-4, %ebp
+	jmp	L(0)
+
+L(b2):	mov	4(%esi), %eax
+	lea	4(%esi), %esi
+	lea	4(%edi), %edi
+	add	$-2, %ebp
+	jmp	L(2)
+
+	ALIGN(8)
+L(top):	mov	4(%esi), %eax
+	mul	%ecx
+	lea	16(%edi), %edi
+	sub	%eax, %ebx
+	mov	8(%esi), %eax
+	mov	%ebx, -12(%edi)
+	sbb	%edx, %ebx
+L(0):	mul	%ecx
+	sub	%eax, %ebx
+	mov	%ebx, -8(%edi)
+	sbb	%edx, %ebx
+L(3):	mov	12(%esi), %eax
+	mul	%ecx
+	sub	%eax, %ebx
+	mov	%ebx, -4(%edi)
+	mov	16(%esi), %eax
+	lea	16(%esi), %esi
+	sbb	%edx, %ebx
+L(2):	mul	%ecx
+	sub	%eax, %ebx
+	mov	%ebx, 0(%edi)
+	sbb	%edx, %ebx
+L(b1):	add	$-4, %ebp
+	jns	L(top)
+
+	mov	%ebx, %eax
+	pop	%ebx
+	pop	%ebp
+	pop	%edi
+	pop	%esi
+	ret
+EPILOGUE()
diff --git a/mpn/x86/bdiv_q_1.asm b/mpn/x86/bdiv_q_1.asm
new file mode 100644
index 0000000..7e2a493
--- /dev/null
+++ b/mpn/x86/bdiv_q_1.asm
@@ -0,0 +1,208 @@
+dnl  x86 mpn_bdiv_q_1 -- mpn by limb exact division.
+
+dnl  Rearranged from mpn/x86/dive_1.asm by Marco Bodrato.
+
+dnl  Copyright 2001, 2002, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb
+C P54    30.0
+C P55    29.0
+C P6     13.0 odd divisor, 12.0 even (strangely)
+C K6     14.0
+C K7     12.0
+C P4     42.0
+
+MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+
+defframe(PARAM_SHIFT,  24)
+defframe(PARAM_INVERSE,20)
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_SRC')
+
+	TEXT
+
+C mp_limb_t
+C mpn_pi1_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C		    mp_limb_t inverse, int shift)
+
+	ALIGN(16)
+PROLOGUE(mpn_pi1_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SHIFT, %ecx
+	pushl	%ebp	FRAME_pushl()
+
+	movl	PARAM_INVERSE, %eax
+	movl	PARAM_SIZE, %ebp
+	pushl	%ebx	FRAME_pushl()
+L(common):
+	pushl	%edi	FRAME_pushl()
+	pushl	%esi	FRAME_pushl()
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	movl	%eax, VAR_INVERSE
+	movl	(%esi,%ebp,4), %eax	C src[0]
+
+	xorl	%ebx, %ebx
+	xorl	%edx, %edx
+
+	incl	%ebp
+	jz	L(one)
+
+	movl	(%esi,%ebp,4), %edx	C src[1]
+
+	shrdl(	%cl, %edx, %eax)
+
+	movl	VAR_INVERSE, %edx
+	jmp	L(entry)
+
+
+	ALIGN(8)
+	nop	C k6 code alignment
+	nop
+L(top):
+	C eax	q
+	C ebx	carry bit, 0 or -1
+	C ecx	shift
+	C edx	carry limb
+	C esi	src end
+	C edi	dst end
+	C ebp	counter, limbs, negative
+
+	movl	-4(%esi,%ebp,4), %eax
+	subl	%ebx, %edx		C accumulate carry bit
+
+	movl	(%esi,%ebp,4), %ebx
+
+	shrdl(	%cl, %ebx, %eax)
+
+	subl	%edx, %eax		C apply carry limb
+	movl	VAR_INVERSE, %edx
+
+	sbbl	%ebx, %ebx
+
+L(entry):
+	imull	%edx, %eax
+
+	movl	%eax, -4(%edi,%ebp,4)
+	movl	PARAM_DIVISOR, %edx
+
+	mull	%edx
+
+	incl	%ebp
+	jnz	L(top)
+
+
+	movl	-4(%esi), %eax		C src high limb
+L(one):
+	shrl	%cl, %eax
+	popl	%esi	FRAME_popl()
+
+	addl	%ebx, %eax		C apply carry bit
+
+	subl	%edx, %eax		C apply carry limb
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+
+	popl	%edi
+	popl	%ebx
+	popl	%ebp
+
+	ret
+
+EPILOGUE()
+
+C mp_limb_t mpn_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	pushl	%ebp	FRAME_pushl()
+
+	movl	$-1, %ecx		C shift count
+	movl	PARAM_SIZE, %ebp
+
+	pushl	%ebx	FRAME_pushl()
+
+L(strip_twos):
+	incl	%ecx
+
+	shrl	%eax
+	jnc	L(strip_twos)
+
+	leal	1(%eax,%eax), %ebx	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	leal	(%eax,%eax), %edx	C 2*inv
+	movl	%ebx, PARAM_DIVISOR	C d without twos
+	imull	%eax, %eax		C inv*inv
+	imull	%ebx, %eax		C inv*inv*d
+	subl	%eax, %edx		C inv = 2*inv - inv*inv*d
+
+	leal	(%edx,%edx), %eax	C 2*inv
+	imull	%edx, %edx		C inv*inv
+	imull	%ebx, %edx		C inv*inv*d
+	subl	%edx, %eax		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	jmp	L(common)
+EPILOGUE()
+ASM_END()
diff --git a/mpn/x86/cnd_aors_n.asm b/mpn/x86/cnd_aors_n.asm
new file mode 100644
index 0000000..f47786a
--- /dev/null
+++ b/mpn/x86/cnd_aors_n.asm
@@ -0,0 +1,124 @@
+dnl  X86 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9   (Banias)		 ?
+C P6 model 13  (Dothan)		 5.4
+C P4 model 0-1 (Willamette)	 ?
+C P4 model 2   (Northwood)	14.5
+C P4 model 3-4 (Prescott)	21
+C Intel atom			11
+C AMD K6			 ?
+C AMD K7			 3.4
+C AMD K8			 ?
+
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebp')
+define(`n',   `%ecx')
+define(`cnd', `20(%esp)')
+define(`cy',  `%edx')
+
+ifdef(`OPERATION_cnd_add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	add	$-16, %esp
+	mov	%ebp, (%esp)
+	mov	%ebx, 4(%esp)
+	mov	%esi, 8(%esp)
+	mov	%edi, 12(%esp)
+
+	C make cnd into a full mask
+	mov	cnd, %eax
+	neg	%eax
+	sbb	%eax, %eax
+	mov	%eax, cnd
+
+	C load parameters into registers
+	mov	24(%esp), rp
+	mov	28(%esp), up
+	mov	32(%esp), vp
+	mov	36(%esp), n
+
+	mov	(vp), %eax
+	mov	(up), %ebx
+
+	C put operand pointers just beyond their last limb
+	lea	(vp,n,4), vp
+	lea	(up,n,4), up
+	lea	-4(rp,n,4), rp
+	neg	n
+
+	and	cnd, %eax
+	ADDSUB	%eax, %ebx
+	sbb	cy, cy
+	inc	n
+	je	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp,n,4), %eax
+	and	cnd, %eax
+	mov	%ebx, (rp,n,4)
+	mov	(up,n,4), %ebx
+	add	cy, cy
+	ADCSBB	%eax, %ebx
+	sbb	cy, cy
+	inc	n
+	jne	L(top)
+
+L(end):	mov	%ebx, (rp)
+	xor	%eax, %eax
+	sub	cy, %eax
+
+	mov	(%esp), %ebp
+	mov	4(%esp), %ebx
+	mov	8(%esp), %esi
+	mov	12(%esp), %edi
+	add	$16, %esp
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/mpn/x86/copyd.asm b/mpn/x86/copyd.asm
new file mode 100644
index 0000000..e7f3d61
--- /dev/null
+++ b/mpn/x86/copyd.asm
@@ -0,0 +1,91 @@
+dnl  x86 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb  startup (approx)
+C P5	  1.0	      40
+C P6	  2.4	      70
+C K6	  1.0	      55
+C K7	  1.3	      75
+C P4	  2.6	     175
+C
+C (Startup time includes some function call overheads.)
+
+
+C void mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Copy src,size to dst,size, working from high to low addresses.
+C
+C The code here is very generic and can be expected to be reasonable on all
+C the x86 family.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_copyd)
+	C eax	saved esi
+	C ebx
+	C ecx	counter
+	C edx	saved edi
+	C esi	src
+	C edi	dst
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+	movl	%esi, %eax
+
+	movl	PARAM_SRC, %esi
+	movl	%edi, %edx
+
+	movl	PARAM_DST, %edi
+	leal	-4(%esi,%ecx,4), %esi
+
+	leal	-4(%edi,%ecx,4), %edi
+
+	std
+
+	rep
+	movsl
+
+	cld
+
+	movl	%eax, %esi
+	movl	%edx, %edi
+
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/copyi.asm b/mpn/x86/copyi.asm
new file mode 100644
index 0000000..df0d5b1
--- /dev/null
+++ b/mpn/x86/copyi.asm
@@ -0,0 +1,99 @@
+dnl  x86 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb  startup (approx)
+C P5	  1.0	      35
+C P6	  0.75	      45
+C K6	  1.0	      30
+C K7	  1.3	      65
+C P4	  1.0	     120
+C
+C (Startup time includes some function call overheads.)
+
+
+C void mpn_copyi (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Copy src,size to dst,size, working from low to high addresses.
+C
+C The code here is very generic and can be expected to be reasonable on all
+C the x86 family.
+C
+C P6 -  An MMX based copy was tried, but was found to be slower than a rep
+C       movs in all cases.  The fastest MMX found was 0.8 cycles/limb (when
+C       fully aligned).  A rep movs seems to have a startup time of about 15
+C       cycles, but doing something special for small sizes could lead to a
+C       branch misprediction that would destroy any saving.  For now a plain
+C       rep movs seems ok.
+C
+C K62 - We used to have a big chunk of code doing an MMX copy at 0.56 c/l if
+C       aligned or a 1.0 rep movs if not.  But that seemed excessive since
+C       it only got an advantage half the time, and even then only showed it
+C       above 50 limbs or so.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+	TEXT
+	ALIGN(32)
+
+	C eax	saved esi
+	C ebx
+	C ecx	counter
+	C edx	saved edi
+	C esi	src
+	C edi	dst
+	C ebp
+
+PROLOGUE(mpn_copyi)
+
+	movl	PARAM_SIZE, %ecx
+	movl	%esi, %eax
+
+	movl	PARAM_SRC, %esi
+	movl	%edi, %edx
+
+	movl	PARAM_DST, %edi
+
+	cld	C better safe than sorry, see mpn/x86/README
+
+	rep
+	movsl
+
+	movl	%eax, %esi
+	movl	%edx, %edi
+
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/dive_1.asm b/mpn/x86/dive_1.asm
new file mode 100644
index 0000000..b9084e7
--- /dev/null
+++ b/mpn/x86/dive_1.asm
@@ -0,0 +1,190 @@
+dnl  x86 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb
+C P54    30.0
+C P55    29.0
+C P6     13.0 odd divisor, 12.0 even (strangely)
+C K6     14.0
+C K7     12.0
+C P4     42.0
+
+
+C mp_limb_t mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_SRC')
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	pushl	%ebp	FRAME_pushl()
+
+	movl	PARAM_SIZE, %ebp
+	pushl	%edi	FRAME_pushl()
+
+	pushl	%ebx	FRAME_pushl()
+	movl	$-1, %ecx		C shift count
+
+	pushl	%esi	FRAME_pushl()
+
+L(strip_twos):
+	incl	%ecx
+
+	shrl	%eax
+	jnc	L(strip_twos)
+
+	leal	1(%eax,%eax), %ebx	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	leal	(%eax,%eax), %edx	C 2*inv
+	movl	%ebx, PARAM_DIVISOR	C d without twos
+
+	imull	%eax, %eax		C inv*inv
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	imull	%ebx, %eax		C inv*inv*d
+
+	subl	%eax, %edx		C inv = 2*inv - inv*inv*d
+	leal	(%edx,%edx), %eax	C 2*inv
+
+	imull	%edx, %edx		C inv*inv
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	imull	%ebx, %edx		C inv*inv*d
+
+	subl	%edx, %eax		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	movl	%eax, VAR_INVERSE
+	movl	(%esi,%ebp,4), %eax	C src[0]
+
+	xorl	%ebx, %ebx
+	xorl	%edx, %edx
+
+	incl	%ebp
+	jz	L(one)
+
+	movl	(%esi,%ebp,4), %edx	C src[1]
+
+	shrdl(	%cl, %edx, %eax)
+
+	movl	VAR_INVERSE, %edx
+	jmp	L(entry)
+
+
+	ALIGN(8)
+	nop	C k6 code alignment
+	nop
+L(top):
+	C eax	q
+	C ebx	carry bit, 0 or -1
+	C ecx	shift
+	C edx	carry limb
+	C esi	src end
+	C edi	dst end
+	C ebp	counter, limbs, negative
+
+	movl	-4(%esi,%ebp,4), %eax
+	subl	%ebx, %edx		C accumulate carry bit
+
+	movl	(%esi,%ebp,4), %ebx
+
+	shrdl(	%cl, %ebx, %eax)
+
+	subl	%edx, %eax		C apply carry limb
+	movl	VAR_INVERSE, %edx
+
+	sbbl	%ebx, %ebx
+
+L(entry):
+	imull	%edx, %eax
+
+	movl	%eax, -4(%edi,%ebp,4)
+	movl	PARAM_DIVISOR, %edx
+
+	mull	%edx
+
+	incl	%ebp
+	jnz	L(top)
+
+
+	movl	-4(%esi), %eax		C src high limb
+L(one):
+	shrl	%cl, %eax
+	popl	%esi	FRAME_popl()
+
+	addl	%ebx, %eax		C apply carry bit
+	popl	%ebx	FRAME_popl()
+
+	subl	%edx, %eax		C apply carry limb
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+
+	popl	%edi
+	popl	%ebp
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/mpn/x86/divrem_1.asm b/mpn/x86/divrem_1.asm
new file mode 100644
index 0000000..2d618f1
--- /dev/null
+++ b/mpn/x86/divrem_1.asm
@@ -0,0 +1,233 @@
+dnl  x86 mpn_divrem_1 -- mpn by limb division extending to fractional quotient.
+
+dnl  Copyright 1999-2003, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C       cycles/limb
+C 486   approx 43 maybe
+C P5        44
+C P6        39
+C P6MMX     39
+C K6        22
+C K7        42
+C P4        58
+
+
+C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                         mp_srcptr src, mp_size_t size, mp_limb_t divisor);
+C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
+C                          mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C                          mp_limb_t carry);
+C
+C Divide src,size by divisor and store the quotient in dst+xsize,size.
+C Extend the division to fractional quotient limbs in dst,xsize.  Return the
+C remainder.  Either or both xsize and size can be 0.
+C
+C mpn_divrem_1c takes a carry parameter which is an initial high limb,
+C effectively one extra limb at the top of src,size.  Must have
+C carry<divisor.
+C
+C
+C Essentially the code is the same as the division based part of
+C mpn/generic/divrem_1.c, but has the advantage that we get the desired divl
+C instruction even when gcc is not being used (when longlong.h only has the
+C rather slow generic C udiv_qrnnd().
+C
+C A test is done to see if the high limb is less than the divisor, and if so
+C one less div is done.  A div is between 20 and 40 cycles on the various
+C x86s, so assuming high<divisor about half the time, then this test saves
+C half that amount.  The branch misprediction penalty on each chip is less
+C than half a div.
+C
+C
+C Notes for P5:
+C
+C It might be thought that moving the load down to pair with the store would
+C save 1 cycle, but that doesn't seem to happen in practice, and in any case
+C would be a mere 2.2% saving, so it's hardly worth bothering about.
+C
+C A mul-by-inverse might be a possibility for P5, as done in
+C mpn/x86/pentium/mod_1.asm.  The number of auxiliary instructions required
+C is a hinderance, but there could be a 10-15% speedup available.
+C
+C
+C Notes for K6:
+C
+C K6 has its own version of this code, using loop and paying attention to
+C cache line boundary crossings.  The target 20 c/l can be had with the
+C decl+jnz of the present code by pairing up the load and store in the
+C loops.  But it's considered easier not to introduce complexity just for
+C that, but instead let k6 have its own code.
+C
+
+defframe(PARAM_CARRY,  24)
+defframe(PARAM_DIVISOR,20)
+defframe(PARAM_SIZE,   16)
+defframe(PARAM_SRC,    12)
+defframe(PARAM_XSIZE,  8)
+defframe(PARAM_DST,    4)
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_divrem_1c)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %edi
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %esi
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_DST, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_XSIZE, %ebp
+	orl	%ecx, %ecx
+
+	movl	PARAM_CARRY, %edx
+	jz	L(fraction)
+
+	leal	-4(%ebx,%ebp,4), %ebx	C dst one limb below integer part
+	jmp	L(integer_top)
+
+EPILOGUE()
+
+
+PROLOGUE(mpn_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %edi
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %esi
+	orl	%ecx,%ecx
+
+	jz	L(size_zero)
+	pushl	%ebx		FRAME_pushl()
+
+	movl	-4(%edi,%ecx,4), %eax	C src high limb
+	xorl	%edx, %edx
+
+	movl	PARAM_DST, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_XSIZE, %ebp
+	cmpl	%esi, %eax
+
+	leal	-4(%ebx,%ebp,4), %ebx	C dst one limb below integer part
+	jae	L(integer_entry)
+
+
+	C high<divisor, so high of dst is zero, and avoid one div
+
+	movl	%edx, (%ebx,%ecx,4)
+	decl	%ecx
+
+	movl	%eax, %edx
+	jz	L(fraction)
+
+
+L(integer_top):
+	C eax	scratch (quotient)
+	C ebx	dst+4*xsize-4
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	divisor
+	C edi	src
+	C ebp	xsize
+
+	movl	-4(%edi,%ecx,4), %eax
+L(integer_entry):
+
+	divl	%esi
+
+	movl	%eax, (%ebx,%ecx,4)
+	decl	%ecx
+	jnz	L(integer_top)
+
+
+L(fraction):
+	orl	%ebp, %ecx
+	jz	L(done)
+
+	movl	PARAM_DST, %ebx
+
+
+L(fraction_top):
+	C eax	scratch (quotient)
+	C ebx	dst
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	divisor
+	C edi
+	C ebp
+
+	xorl	%eax, %eax
+
+	divl	%esi
+
+	movl	%eax, -4(%ebx,%ecx,4)
+	decl	%ecx
+	jnz	L(fraction_top)
+
+
+L(done):
+	popl	%ebp
+	movl	%edx, %eax
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+
+L(size_zero):
+deflit(`FRAME',8)
+	movl	PARAM_XSIZE, %ecx
+	xorl	%eax, %eax
+
+	movl	PARAM_DST, %edi
+
+	cld	C better safe than sorry, see mpn/x86/README
+
+	rep
+	stosl
+
+	popl	%esi
+	popl	%edi
+	ret
+EPILOGUE()
diff --git a/mpn/x86/divrem_2.asm b/mpn/x86/divrem_2.asm
new file mode 100644
index 0000000..8da72c7
--- /dev/null
+++ b/mpn/x86/divrem_2.asm
@@ -0,0 +1,199 @@
+dnl  x86 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C		norm	frac
+C 486
+C P5
+C P6-13		29.2
+C P6-15		*26
+C K6
+C K7		22
+C K8		*19
+C P4-f1
+C P4-f2		*65
+C P4-f3
+C P4-f4		*72
+
+C A star means numbers not updated for the latest version of the code.
+
+
+C TODO
+C  * Perhaps keep ecx or esi in stack slot, freeing up a reg for q0.
+C  * The loop has not been carefully tuned.  We should at the very least do
+C    some local insn swapping.
+C  * The code outside the main loop is what gcc generated.  Clean up!
+C  * Clean up stack slot usage.
+
+C INPUT PARAMETERS
+C qp
+C fn
+C up_param
+C un_param
+C dp
+
+
+C eax ebx ecx edx esi edi ebp
+C         cnt         qp
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divrem_2)
+	push	%ebp
+	push	%edi
+	push	%esi
+	push	%ebx
+	sub	$36, %esp
+	mov	68(%esp), %ecx		C un
+	mov	72(%esp), %esi		C dp
+	movl	$0, 32(%esp)
+	lea	0(,%ecx,4), %edi
+	add	64(%esp), %edi		C up
+	mov	(%esi), %ebx
+	mov	4(%esi), %eax
+	mov	%ebx, 20(%esp)
+	sub	$12, %edi
+	mov	%eax, 24(%esp)
+	mov	%edi, 12(%esp)
+	mov	8(%edi), %ebx
+	mov	4(%edi), %ebp
+	cmp	%eax, %ebx
+	jb	L(8)
+	seta	%dl
+	cmp	20(%esp), %ebp
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	jne	L(35)
+L(8):
+	mov	60(%esp), %esi		C fn
+	lea	-3(%esi,%ecx), %edi
+	test	%edi, %edi
+	js	L(9)
+	mov	24(%esp), %edx
+	mov	$-1, %esi
+	mov	%esi, %eax
+	mov	%esi, %ecx
+	not	%edx
+	divl	24(%esp)
+	mov	%eax, %esi
+	imul	24(%esp), %eax
+	mov	%eax, (%esp)
+	mov	%esi, %eax
+	mull	20(%esp)
+	mov	(%esp), %eax
+	add	20(%esp), %eax
+	adc	$0, %ecx
+	add	%eax, %edx
+	adc	$0, %ecx
+	mov	%ecx, %eax
+	js	L(32)
+L(36):	dec	%esi
+	sub	24(%esp), %edx
+	sbb	$0, %eax
+	jns	L(36)
+L(32):
+	mov	%esi, 16(%esp)		C di
+	mov	%edi, %ecx		C un
+	mov	12(%esp), %esi		C up
+	mov	24(%esp), %eax
+	neg	%eax
+	mov	%eax, 4(%esp)		C -d1
+	ALIGN(16)
+	nop
+
+C eax ebx ecx edx esi edi ebp  0    4   8   12  16  20  24  28  32   56  60
+C     n2  un      up      n1   q0  -d1          di  d0  d1      msl  qp  fn
+
+L(loop):
+	mov	16(%esp), %eax		C di
+	mul	%ebx
+	add	%ebp, %eax
+	mov	%eax, (%esp)		C q0
+	adc	%ebx, %edx
+	mov	%edx, %edi		C q
+	imul	4(%esp), %edx
+	mov	20(%esp), %eax
+	lea	(%edx, %ebp), %ebx	C n1 -= ...
+	mul	%edi
+	xor	%ebp, %ebp
+	cmp	60(%esp), %ecx
+	jl	L(19)
+	mov	(%esi), %ebp
+	sub	$4, %esi
+L(19):	sub	20(%esp), %ebp
+	sbb	24(%esp), %ebx
+	sub	%eax, %ebp
+	sbb	%edx, %ebx
+	mov	20(%esp), %eax		C d1
+	inc	%edi
+	xor	%edx, %edx
+	cmp	(%esp), %ebx
+	adc	$-1, %edx		C mask
+	add	%edx, %edi		C q--
+	and	%edx, %eax		C d0 or 0
+	and	24(%esp), %edx		C d1 or 0
+	add	%eax, %ebp
+	adc	%edx, %ebx
+	cmp	24(%esp), %ebx
+	jae	L(fix)
+L(bck):	mov	56(%esp), %edx
+	mov	%edi, (%edx, %ecx, 4)
+	dec	%ecx
+	jns	L(loop)
+
+L(9):	mov	64(%esp), %esi		C up
+	mov	%ebp, (%esi)
+	mov	%ebx, 4(%esi)
+	mov	32(%esp), %eax
+	add	$36, %esp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	pop	%ebp
+	ret
+
+L(fix):	seta	%dl
+	cmp	20(%esp), %ebp
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	%edi
+	sub	20(%esp), %ebp
+	sbb	24(%esp), %ebx
+	jmp	L(bck)
+
+L(35):	sub	20(%esp), %ebp
+	sbb	24(%esp), %ebx
+	movl	$1, 32(%esp)
+	jmp	L(8)
+EPILOGUE()
diff --git a/mpn/x86/gcd_11.asm b/mpn/x86/gcd_11.asm
new file mode 100644
index 0000000..699996e
--- /dev/null
+++ b/mpn/x86/gcd_11.asm
@@ -0,0 +1,126 @@
+dnl  x86 mpn_gcd_11 optimised for processors with slow BSF.
+
+dnl  Based on C version.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+dnl  Rudimentary code for x86-32, i.e. for CPUs without cmov.  Also, the bsf
+dnl  instruction is assumed to be so slow it is useless.  Instead a teble is
+dnl  used.
+dnl
+dnl  The loop benefits from OoO, in-order CPUs might want a different loop.
+dnl  The ebx and ecx registers could be combined if the assigment of ecx were
+dnl  postponed until ebx died, but that would at least hurt in-order CPUs.
+
+C	     cycles/bit (approx)
+C AMD K7	 ?
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 ?
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4-2	 ?
+C Intel P4-3/4	 ?
+C Intel P6/13	 ?
+C Intel CNR	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+C Numbers measured with: speed -CD -s8-32 -t24 mpn_gcd_1
+
+deflit(MAXSHIFT, 6)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u0',    `%eax')
+define(`v0',    `%edx')
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	push	%edi
+	push	%esi
+	push	%ebx
+
+	mov	16(%esp), u0
+	mov	20(%esp), v0
+	LEAL(	ctz_table, %esi)
+	sub	v0, u0			C u = u - v		0
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	sbb	%ebx, %ebx		C mask			1
+	mov	u0, %edi		C			1
+	mov	u0, %ecx		C			1
+	and	%ebx, %edi		C			2
+	xor	%ebx, u0		C			2
+	add	%edi, v0		C v = min(u.v)		3
+	sub	%ebx, u0		C u = |u - v|		3
+L(mid):	and	$MASK, %ecx		C			2
+	movzbl	(%esi,%ecx), %ecx	C			3
+	jz	L(shift_alot)
+	shr	%cl, u0			C			4
+	sub	v0, u0			C u = u - v		0,5
+	jnz	L(top)
+
+L(end):	mov	v0, %eax
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+
+L(shift_alot):
+	shr	$MAXSHIFT, u0
+	mov	u0, %ecx
+	jmp	L(mid)
+EPILOGUE()
+ASM_END()
diff --git a/mpn/x86/gmp-mparam.h b/mpn/x86/gmp-mparam.h
new file mode 100644
index 0000000..2cb1984
--- /dev/null
+++ b/mpn/x86/gmp-mparam.h
@@ -0,0 +1,38 @@
+/* Generic x86 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* Generic x86 mpn_divexact_1 is faster than generic x86 mpn_divrem_1 on all
+   of p5, p6, k6 and k7, so use it always.  It's probably slower on 386 and
+   486, but that's too bad.  */
+#define DIVEXACT_1_THRESHOLD  0
diff --git a/mpn/x86/lshift.asm b/mpn/x86/lshift.asm
new file mode 100644
index 0000000..bdfc987
--- /dev/null
+++ b/mpn/x86/lshift.asm
@@ -0,0 +1,106 @@
+dnl  x86 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1992, 1994, 1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb
+C P54	 7.5
+C P55	 7.0
+C P6	 2.5
+C K6	 4.5
+C K7	 5.0
+C P4	14.5
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_lshift)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+deflit(`FRAME',12)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%edx
+	movl	PARAM_SHIFT,%ecx
+
+	subl	$4,%esi			C adjust src
+
+	movl	(%esi,%edx,4),%ebx	C read most significant limb
+	xorl	%eax,%eax
+	shldl(	%cl, %ebx, %eax)	C compute carry limb
+	decl	%edx
+	jz	L(end)
+	pushl	%eax			C push carry limb onto stack
+	testb	$1,%dl
+	jnz	L(1)			C enter loop in the middle
+	movl	%ebx,%eax
+
+	ALIGN(8)
+L(oop):	movl	(%esi,%edx,4),%ebx	C load next lower limb
+	shldl(	%cl, %ebx, %eax)	C compute result limb
+	movl	%eax,(%edi,%edx,4)	C store it
+	decl	%edx
+L(1):	movl	(%esi,%edx,4),%eax
+	shldl(	%cl, %eax, %ebx)
+	movl	%ebx,(%edi,%edx,4)
+	decl	%edx
+	jnz	L(oop)
+
+	shll	%cl,%eax		C compute least significant limb
+	movl	%eax,(%edi)		C store it
+
+	popl	%eax			C pop carry limb
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+L(end):	shll	%cl,%ebx		C compute least significant limb
+	movl	%ebx,(%edi)		C store it
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/mod_34lsub1.asm b/mpn/x86/mod_34lsub1.asm
new file mode 100644
index 0000000..5a6c653
--- /dev/null
+++ b/mpn/x86/mod_34lsub1.asm
@@ -0,0 +1,183 @@
+dnl  Generic x86 mpn_mod_34lsub1 -- mpn remainder modulo 2^24-1.
+
+dnl  Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C      cycles/limb
+C P5	  3.0
+C P6	  3.66
+C K6	  3.0
+C K7	  1.3
+C P4	  9
+
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX, `PARAM_SRC')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+
+	subl	$2, %ecx
+	ja	L(three_or_more)
+
+	movl	(%edx), %eax
+	jb	L(one)
+
+	movl	4(%edx), %ecx
+	movl	%eax, %edx
+	shrl	$24, %eax		C src[0] low
+
+	andl	$0xFFFFFF, %edx		C src[0] high
+	addl	%edx, %eax
+	movl	%ecx, %edx
+
+	andl	$0xFFFF, %ecx
+	shrl	$16, %edx		C src[1] high
+	addl	%edx, %eax
+
+	shll	$8, %ecx		C src[1] low
+	addl	%ecx, %eax
+
+L(one):
+	ret
+
+
+L(three_or_more):
+	C eax
+	C ebx
+	C ecx	size-2
+	C edx	src
+	C esi
+	C edi
+	C ebp
+
+	movl	%ebx, SAVE_EBX		C and arrange 16-byte loop alignment
+	xorl	%ebx, %ebx
+
+	pushl	%esi	FRAME_pushl()
+	xorl	%esi, %esi
+
+	pushl	%edi	FRAME_pushl()
+	xorl	%eax, %eax		C and clear carry flag
+
+
+	C offset 0x40 here
+L(top):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx	counter, limbs
+	C edx	src
+	C esi	acc 2mod3
+	C edi
+	C ebp
+
+	leal	12(%edx), %edx
+	leal	-2(%ecx), %ecx
+
+	adcl	-12(%edx), %eax
+	adcl	-8(%edx), %ebx
+	adcl	-4(%edx), %esi
+
+	decl	%ecx
+	jg	L(top)
+
+
+	C ecx is -2, -1 or 0 representing 0, 1 or 2 more limbs, respectively
+
+	movl	$0xFFFFFFFF, %edi
+	incl	%ecx
+	js	L(combine)
+
+	adcl	(%edx), %eax
+	movl	$0xFFFFFF00, %edi
+	decl	%ecx
+	js	L(combine)
+
+	adcl	4(%edx), %ebx
+	movl	$0xFFFF0000, %edi
+
+
+L(combine):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx
+	C edx
+	C esi	acc 2mod3
+	C edi	mask
+	C ebp
+
+	sbbl	%ecx, %ecx		C carry
+	movl	%eax, %edx		C 0mod3
+
+	shrl	$24, %eax		C 0mod3 high
+	andl	%edi, %ecx		C carry masked
+
+	subl	%ecx, %eax		C apply carry
+	movl	%ebx, %edi		C 1mod3
+
+	shrl	$16, %ebx		C 1mod3 high
+	andl	$0x00FFFFFF, %edx	C 0mod3 low
+
+	addl	%edx, %eax		C apply 0mod3 low
+	andl	$0xFFFF, %edi
+
+	shll	$8, %edi		C 1mod3 low
+	addl	%ebx, %eax		C apply 1mod3 high
+
+	addl	%edi, %eax		C apply 1mod3 low
+	movl	%esi, %edx		C 2mod3
+
+	shrl	$8, %esi		C 2mod3 high
+	andl	$0xFF, %edx		C 2mod3 low
+
+	shll	$16, %edx		C 2mod3 low
+	addl	%esi, %eax		C apply 2mod3 high
+
+	addl	%edx, %eax		C apply 2mod3 low
+	popl	%edi	FRAME_popl()
+
+	movl	SAVE_EBX, %ebx
+	popl	%esi	FRAME_popl()
+
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/mul_1.asm b/mpn/x86/mul_1.asm
new file mode 100644
index 0000000..e760ccb
--- /dev/null
+++ b/mpn/x86/mul_1.asm
@@ -0,0 +1,140 @@
+dnl  x86 mpn_mul_1 (for 386, 486, and Pentium Pro) -- Multiply a limb vector
+dnl  with a limb and store the result in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1997-2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C			    cycles/limb
+C P5				12.5
+C P6 model 0-8,10-12		 5.5
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 5.25
+C P4 model 0  (Willamette)	19.0
+C P4 model 1  (?)		19.0
+C P4 model 2  (Northwood)	19.0
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6			10.5
+C AMD K7			 4.5
+C AMD K8
+
+
+C mp_limb_t mpn_mul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t multiplier);
+
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_mul_1)
+deflit(`FRAME',0)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%ecx
+
+	xorl	%ebx,%ebx
+	andl	$3,%ecx
+	jz	L(end0)
+
+L(oop0):
+	movl	(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	leal	4(%esi),%esi
+	addl	%ebx,%eax
+	movl	$0,%ebx
+	adcl	%ebx,%edx
+	movl	%eax,(%edi)
+	movl	%edx,%ebx	C propagate carry into cylimb
+
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oop0)
+
+L(end0):
+	movl	PARAM_SIZE,%ecx
+	shrl	$2,%ecx
+	jz	L(end)
+
+
+	ALIGN(8)
+L(oop):	movl	(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	addl	%eax,%ebx
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	4(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	movl	%ebx,(%edi)
+	addl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	8(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	movl	%ebp,4(%edi)
+	addl	%eax,%ebx	C new lo + cylimb
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	12(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	movl	%ebx,8(%edi)
+	addl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	%ebp,12(%edi)
+
+	leal	16(%esi),%esi
+	leal	16(%edi),%edi
+	decl	%ecx
+	jnz	L(oop)
+
+L(end):	movl	%ebx,%eax
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/mul_basecase.asm b/mpn/x86/mul_basecase.asm
new file mode 100644
index 0000000..82a2980
--- /dev/null
+++ b/mpn/x86/mul_basecase.asm
@@ -0,0 +1,223 @@
+dnl  x86 mpn_mul_basecase -- Multiply two limb vectors and store the result
+dnl  in a third limb vector.
+
+dnl  Copyright 1996-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/crossproduct
+C P5	  15
+C P6	   7.5
+C K6	  12.5
+C K7	   5.5
+C P4	  24
+
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xsize,
+C                        mp_srcptr yp, mp_size_t ysize);
+C
+C This was written in a haste since the Pentium optimized code that was used
+C for all x86 machines was slow for the Pentium II.  This code would benefit
+C from some cleanup.
+C
+C To shave off some percentage of the run-time, one should make 4 variants
+C of the Louter loop, for the four different outcomes of un mod 4.  That
+C would avoid Loop0 altogether.  Code expansion would be > 4-fold for that
+C part of the function, but since it is not very large, that would be
+C acceptable.
+C
+C The mul loop (at L(oopM)) might need some tweaking.  It's current speed is
+C unknown.
+
+defframe(PARAM_YSIZE,20)
+defframe(PARAM_YP,   16)
+defframe(PARAM_XSIZE,12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+defframe(VAR_MULTIPLIER, -4)
+defframe(VAR_COUNTER,    -8)
+deflit(VAR_STACK_SPACE,  8)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_mul_basecase)
+deflit(`FRAME',0)
+
+	subl	$VAR_STACK_SPACE,%esp
+	pushl	%esi
+	pushl	%ebp
+	pushl	%edi
+deflit(`FRAME',eval(VAR_STACK_SPACE+12))
+
+	movl	PARAM_XP,%esi
+	movl	PARAM_WP,%edi
+	movl	PARAM_YP,%ebp
+
+	movl	(%esi),%eax		C load xp[0]
+	mull	(%ebp)			C multiply by yp[0]
+	movl	%eax,(%edi)		C store to wp[0]
+	movl	PARAM_XSIZE,%ecx	C xsize
+	decl	%ecx			C If xsize = 1, ysize = 1 too
+	jz	L(done)
+
+	pushl	%ebx
+FRAME_pushl()
+	movl	%edx,%ebx
+
+	leal	4(%esi),%esi
+	leal	4(%edi),%edi
+
+L(oopM):
+	movl	(%esi),%eax		C load next limb at xp[j]
+	leal	4(%esi),%esi
+	mull	(%ebp)
+	addl	%ebx,%eax
+	movl	%edx,%ebx
+	adcl	$0,%ebx
+	movl	%eax,(%edi)
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oopM)
+
+	movl	%ebx,(%edi)		C most significant limb of product
+	addl	$4,%edi			C increment wp
+	movl	PARAM_XSIZE,%eax
+	shll	$2,%eax
+	subl	%eax,%edi
+	subl	%eax,%esi
+
+	movl	PARAM_YSIZE,%eax	C ysize
+	decl	%eax
+	jz	L(skip)
+	movl	%eax,VAR_COUNTER	C set index i to ysize
+
+L(outer):
+	movl	PARAM_YP,%ebp		C yp
+	addl	$4,%ebp			C make ebp point to next v limb
+	movl	%ebp,PARAM_YP
+	movl	(%ebp),%eax		C copy y limb ...
+	movl	%eax,VAR_MULTIPLIER	C ... to stack slot
+	movl	PARAM_XSIZE,%ecx
+
+	xorl	%ebx,%ebx
+	andl	$3,%ecx
+	jz	L(end0)
+
+L(oop0):
+	movl	(%esi),%eax
+	mull	VAR_MULTIPLIER
+	leal	4(%esi),%esi
+	addl	%ebx,%eax
+	movl	$0,%ebx
+	adcl	%ebx,%edx
+	addl	%eax,(%edi)
+	adcl	%edx,%ebx		C propagate carry into cylimb
+
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oop0)
+
+L(end0):
+	movl	PARAM_XSIZE,%ecx
+	shrl	$2,%ecx
+	jz	L(endX)
+
+	ALIGN(8)
+L(oopX):
+	movl	(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%eax,%ebx
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	4(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%ebx,(%edi)
+	adcl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	8(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%ebp,4(%edi)
+	adcl	%eax,%ebx	C new lo + cylimb
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	12(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%ebx,8(%edi)
+	adcl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	addl	%ebp,12(%edi)
+	adcl	$0,%ebx		C propagate carry into cylimb
+
+	leal	16(%esi),%esi
+	leal	16(%edi),%edi
+	decl	%ecx
+	jnz	L(oopX)
+
+L(endX):
+	movl	%ebx,(%edi)
+	addl	$4,%edi
+
+	C we incremented wp and xp in the loop above; compensate
+	movl	PARAM_XSIZE,%eax
+	shll	$2,%eax
+	subl	%eax,%edi
+	subl	%eax,%esi
+
+	movl	VAR_COUNTER,%eax
+	decl	%eax
+	movl	%eax,VAR_COUNTER
+	jnz	L(outer)
+
+L(skip):
+	popl	%ebx
+	popl	%edi
+	popl	%ebp
+	popl	%esi
+	addl	$8,%esp
+	ret
+
+L(done):
+	movl	%edx,4(%edi)	   C store to wp[1]
+	popl	%edi
+	popl	%ebp
+	popl	%esi
+	addl	$8,%esp
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/rshift.asm b/mpn/x86/rshift.asm
new file mode 100644
index 0000000..dd5b7ce
--- /dev/null
+++ b/mpn/x86/rshift.asm
@@ -0,0 +1,108 @@
+dnl  x86 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1992, 1994, 1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C     cycles/limb
+C P54	 7.5
+C P55	 7.0
+C P6	 2.5
+C K6	 4.5
+C K7	 5.0
+C P4	16.5
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_rshift)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+deflit(`FRAME',12)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%edx
+	movl	PARAM_SHIFT,%ecx
+
+	leal	-4(%edi,%edx,4),%edi
+	leal	(%esi,%edx,4),%esi
+	negl	%edx
+
+	movl	(%esi,%edx,4),%ebx	C read least significant limb
+	xorl	%eax,%eax
+	shrdl(	%cl, %ebx, %eax)	C compute carry limb
+	incl	%edx
+	jz	L(end)
+	pushl	%eax			C push carry limb onto stack
+	testb	$1,%dl
+	jnz	L(1)			C enter loop in the middle
+	movl	%ebx,%eax
+
+	ALIGN(8)
+L(oop):	movl	(%esi,%edx,4),%ebx	C load next higher limb
+	shrdl(	%cl, %ebx, %eax)	C compute result limb
+	movl	%eax,(%edi,%edx,4)	C store it
+	incl	%edx
+L(1):	movl	(%esi,%edx,4),%eax
+	shrdl(	%cl, %eax, %ebx)
+	movl	%ebx,(%edi,%edx,4)
+	incl	%edx
+	jnz	L(oop)
+
+	shrl	%cl,%eax		C compute most significant limb
+	movl	%eax,(%edi)		C store it
+
+	popl	%eax			C pop carry limb
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+L(end):	shrl	%cl,%ebx		C compute most significant limb
+	movl	%ebx,(%edi)		C store it
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/sec_tabselect.asm b/mpn/x86/sec_tabselect.asm
new file mode 100644
index 0000000..a71ff16
--- /dev/null
+++ b/mpn/x86/sec_tabselect.asm
@@ -0,0 +1,106 @@
+dnl  x86 mpn_sec_tabselect.
+
+dnl  Copyright 2011, 2021 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9  (Banias)		 ?
+C P6 model 13 (Dothan)		 ?
+C P4 model 0  (Willamette)	 ?
+C P4 model 1  (?)		 ?
+C P4 model 2  (Northwood)	 4.5
+C P4 model 3  (Prescott)	 ?
+C P4 model 4  (Nocona)		 ?
+C Intel Atom			 ?
+C AMD K6			 ?
+C AMD K7			 3.4
+C AMD K8			 ?
+C AMD K10			 ?
+
+C NOTES
+C  * This has not been tuned for any specific processor.  Its speed should not
+C    be too bad, though.
+C  * Using SSE2 could result in many-fold speedup.
+
+C mpn_sec_tabselect (mp_limb_t *rp, mp_limb_t *tp, mp_size_t n, mp_size_t nents, mp_size_t which)
+define(`rp',     `%edi')
+define(`tp',     `%esi')
+define(`n',      `%ebx')
+define(`nents',  `32(%esp)')
+define(`which',  `36(%esp)')
+
+define(`i',      `%ebp')
+define(`mask',   `%ecx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sec_tabselect)
+	push	%edi
+	push	%esi
+	push	%ebx
+	push	%ebp
+	mov	20(%esp), rp
+	mov	24(%esp), tp
+	mov	28(%esp), n
+
+	lea	(rp,n,4), rp
+	lea	(tp,n,4), tp
+L(outer):
+	subl	$1, which
+	sbb	mask, mask
+
+	mov	n, i
+	neg	i
+
+	ALIGN(16)
+L(top):	mov	(tp,i,4), %eax
+	mov	(rp,i,4), %edx
+	xor	%edx, %eax
+	and	mask, %eax
+	xor	%edx, %eax
+	mov	%eax, (rp,i,4)
+	inc	i
+	js	L(top)
+
+L(end):	lea	(tp,n,4), tp
+	decl	nents
+	jne	L(outer)
+
+L(outer_end):
+	pop	%ebp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
diff --git a/mpn/x86/sqr_basecase.asm b/mpn/x86/sqr_basecase.asm
new file mode 100644
index 0000000..7027f99
--- /dev/null
+++ b/mpn/x86/sqr_basecase.asm
@@ -0,0 +1,359 @@
+dnl  x86 generic mpn_sqr_basecase -- square an mpn number.
+
+dnl  Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`config.m4')
+
+
+C     cycles/crossproduct  cycles/triangleproduct
+C P5
+C P6
+C K6
+C K7
+C P4
+
+
+C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The algorithm is basically the same as mpn/generic/sqr_basecase.c, but a
+C lot of function call overheads are avoided, especially when the size is
+C small.
+C
+C The mul1 loop is not unrolled like mul_1.asm, it doesn't seem worth the
+C code size to do so here.
+C
+C Enhancements:
+C
+C The addmul loop here is also not unrolled like aorsmul_1.asm and
+C mul_basecase.asm are.  Perhaps it should be done.  It'd add to the
+C complexity, but if it's worth doing in the other places then it should be
+C worthwhile here.
+C
+C A fully-unrolled style like other sqr_basecase.asm versions (k6, k7, p6)
+C might be worth considering.  That'd add quite a bit to the code size, but
+C only as much as is used would be dragged into L1 cache.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_sqr_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+
+	movl	PARAM_SRC, %eax
+
+	cmpl	$2, %edx
+	movl	PARAM_DST, %ecx
+
+	je	L(two_limbs)
+	ja	L(three_or_more)
+
+
+C -----------------------------------------------------------------------------
+C one limb only
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx
+
+	movl	(%eax), %eax
+	mull	%eax
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(two_limbs):
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx
+
+	pushl	%ebx
+	pushl	%ebp
+
+	movl	%eax, %ebx
+	movl	(%eax), %eax
+
+	mull	%eax		C src[0]^2
+
+	pushl	%esi
+	pushl	%edi
+
+	movl	%edx, %esi	C dst[1]
+	movl	%eax, (%ecx)	C dst[0]
+
+	movl	4(%ebx), %eax
+	mull	%eax		C src[1]^2
+
+	movl	%eax, %edi	C dst[2]
+	movl	%edx, %ebp	C dst[3]
+
+	movl	(%ebx), %eax
+	mull	4(%ebx)		C src[0]*src[1]
+
+	addl	%eax, %esi
+
+	adcl	%edx, %edi
+
+	adcl	$0, %ebp
+	addl	%esi, %eax
+
+	adcl	%edi, %edx
+	movl	%eax, 4(%ecx)
+
+	adcl	$0, %ebp
+
+	movl	%edx, 8(%ecx)
+	movl	%ebp, 12(%ecx)
+
+	popl	%edi
+	popl	%esi
+
+	popl	%ebp
+	popl	%ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(three_or_more):
+deflit(`FRAME',0)
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx	size
+
+	pushl	%ebx	FRAME_pushl()
+	pushl	%edi	FRAME_pushl()
+
+	pushl	%esi	FRAME_pushl()
+	pushl	%ebp	FRAME_pushl()
+
+	leal	(%ecx,%edx,4), %edi	C &dst[size], end of this mul1
+	leal	(%eax,%edx,4), %esi	C &src[size]
+
+C First multiply src[0]*src[1..size-1] and store at dst[1..size].
+
+	movl	(%eax), %ebp		C src[0], multiplier
+	movl	%edx, %ecx
+
+	negl	%ecx			C -size
+	xorl	%ebx, %ebx		C clear carry limb
+
+	incl	%ecx			C -(size-1)
+
+L(mul1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter, limbs, negative
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+	mull	%ebp
+	addl	%eax, %ebx
+	adcl	$0, %edx
+	movl	%ebx, (%edi,%ecx,4)
+	movl	%edx, %ebx
+	incl	%ecx
+	jnz	L(mul1)
+
+	movl	%ebx, (%edi)
+
+
+	C Add products src[n]*src[n+1..size-1] at dst[2*n-1...], for
+	C n=1..size-2.
+	C
+	C The last products src[size-2]*src[size-1], which is the end corner
+	C of the product triangle, is handled separately at the end to save
+	C looping overhead.  If size is 3 then it's only this that needs to
+	C be done.
+	C
+	C In the outer loop %esi is a constant, and %edi just advances by 1
+	C limb each time.  The size of the operation decreases by 1 limb
+	C each time.
+
+	C eax
+	C ebx	carry (needing carry flag added)
+	C ecx
+	C edx
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+	subl	$3, %ecx
+	jz	L(corner)
+
+	negl	%ecx
+
+dnl  re-use parameter space
+define(VAR_OUTER,`PARAM_DST')
+
+L(outer):
+	C eax
+	C ebx
+	C ecx
+	C edx	outer loop counter, -(size-3) to -1
+	C esi	&src[size]
+	C edi	dst, pointing at stored carry limb of previous loop
+	C ebp
+
+	movl	%ecx, VAR_OUTER
+	addl	$4, %edi		C advance dst end
+
+	movl	-8(%esi,%ecx,4), %ebp	C next multiplier
+	subl	$1, %ecx
+
+	xorl	%ebx, %ebx		C initial carry limb
+
+L(inner):
+	C eax	scratch
+	C ebx	carry (needing carry flag added)
+	C ecx	counter, -n-1 to -1
+	C edx	scratch
+	C esi	&src[size]
+	C edi	dst end of this addmul
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+	mull	%ebp
+	addl	%ebx, %eax
+	adcl	$0, %edx
+	addl	%eax, (%edi,%ecx,4)
+	adcl	$0, %edx
+	movl	%edx, %ebx
+	addl	$1, %ecx
+	jl	L(inner)
+
+
+	movl	%ebx, (%edi)
+	movl	VAR_OUTER, %ecx
+	incl	%ecx
+	jnz	L(outer)
+
+
+L(corner):
+	C esi	&src[size]
+	C edi	&dst[2*size-3]
+
+	movl	-4(%esi), %eax
+	mull	-8(%esi)		C src[size-1]*src[size-2]
+	addl	%eax, 0(%edi)
+	adcl	$0, %edx
+	movl	%edx, 4(%edi)		C dst high limb
+
+
+C -----------------------------------------------------------------------------
+C Left shift of dst[1..2*size-2], high bit shifted out becomes dst[2*size-1].
+
+	movl	PARAM_SIZE, %eax
+	negl	%eax
+	addl	$1, %eax		C -(size-1) and clear carry
+
+L(lshift):
+	C eax	counter, negative
+	C ebx	next limb
+	C ecx
+	C edx
+	C esi
+	C edi	&dst[2*size-4]
+	C ebp
+
+	rcll	8(%edi,%eax,8)
+	rcll	12(%edi,%eax,8)
+	incl	%eax
+	jnz	L(lshift)
+
+
+	adcl	%eax, %eax		C high bit out
+	movl	%eax, 8(%edi)		C dst most significant limb
+
+
+C Now add in the squares on the diagonal, namely src[0]^2, src[1]^2, ...,
+C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
+C low limb of src[0]^2.
+
+	movl	PARAM_SRC, %esi
+	movl	(%esi), %eax		C src[0]
+	mull	%eax			C src[0]^2
+
+	movl	PARAM_SIZE, %ecx
+	leal	(%esi,%ecx,4), %esi	C src end
+
+	negl	%ecx			C -size
+	movl	%edx, %ebx		C initial carry
+
+	movl	%eax, 12(%edi,%ecx,8)	C dst[0]
+	incl	%ecx			C -(size-1)
+
+L(diag):
+	C eax	scratch (low product)
+	C ebx	carry limb
+	C ecx	counter, -(size-1) to -1
+	C edx	scratch (high product)
+	C esi	&src[size]
+	C edi	&dst[2*size-3]
+	C ebp	scratch (fetched dst limbs)
+
+	movl	(%esi,%ecx,4), %eax
+	mull	%eax
+
+	addl	%ebx, 8(%edi,%ecx,8)
+	movl	%edx, %ebx
+
+	adcl	%eax, 12(%edi,%ecx,8)
+	adcl	$0, %ebx
+
+	incl	%ecx
+	jnz	L(diag)
+
+
+	addl	%ebx, 8(%edi)		C dst most significant limb
+
+	popl	%ebp
+	popl	%esi
+
+	popl	%edi
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86/udiv.asm b/mpn/x86/udiv.asm
new file mode 100644
index 0000000..85a68a8
--- /dev/null
+++ b/mpn/x86/udiv.asm
@@ -0,0 +1,52 @@
+dnl  x86 mpn_udiv_qrnnd -- 2 by 1 limb division
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C mp_limb_t mpn_udiv_qrnnd (mp_limb_t *remptr, mp_limb_t high, mp_limb_t low,
+C                           mp_limb_t divisor);
+
+defframe(PARAM_DIVISOR, 16)
+defframe(PARAM_LOW,     12)
+defframe(PARAM_HIGH,    8)
+defframe(PARAM_REMPTR,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_udiv_qrnnd)
+deflit(`FRAME',0)
+	movl	PARAM_LOW, %eax
+	movl	PARAM_HIGH, %edx
+	divl	PARAM_DIVISOR
+	movl	PARAM_REMPTR, %ecx
+	movl	%edx, (%ecx)
+	ret
+EPILOGUE()
diff --git a/mpn/x86/umul.asm b/mpn/x86/umul.asm
new file mode 100644
index 0000000..0e703ac
--- /dev/null
+++ b/mpn/x86/umul.asm
@@ -0,0 +1,51 @@
+dnl  mpn_umul_ppmm -- 1x1->2 limb multiplication
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C mp_limb_t mpn_umul_ppmm (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2);
+C
+
+defframe(PARAM_M2,    12)
+defframe(PARAM_M1,     8)
+defframe(PARAM_LOWPTR, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_umul_ppmm)
+deflit(`FRAME',0)
+	movl	PARAM_LOWPTR, %ecx
+	movl	PARAM_M1, %eax
+	mull	PARAM_M2
+	movl	%eax, (%ecx)
+	movl	%edx, %eax
+	ret
+EPILOGUE()
diff --git a/mpn/x86/x86-defs.m4 b/mpn/x86/x86-defs.m4
new file mode 100644
index 0000000..81309b2
--- /dev/null
+++ b/mpn/x86/x86-defs.m4
@@ -0,0 +1,1024 @@
+divert(-1)
+
+dnl  m4 macros for x86 assembler.
+
+dnl  Copyright 1999-2003, 2007, 2010, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Notes:
+dnl
+dnl  m4 isn't perfect for processing BSD style x86 assembler code, the main
+dnl  problems are,
+dnl
+dnl  1. Doing define(foo,123) and then using foo in an addressing mode like
+dnl     foo(%ebx) expands as a macro rather than a constant.  This is worked
+dnl     around by using deflit() from asm-defs.m4, instead of define().
+dnl
+dnl  2. Immediates in macro definitions need a space or `' to stop the $
+dnl     looking like a macro parameter.  For example,
+dnl
+dnl	        define(foo, `mov $ 123, %eax')
+dnl
+dnl     This is only a problem in macro definitions, not in ordinary text,
+dnl     and not in macro parameters like text passed to forloop() or ifdef().
+
+
+deflit(GMP_LIMB_BYTES, 4)
+
+
+dnl  Libtool gives -DPIC -DDLL_EXPORT to indicate a cygwin or mingw DLL.  We
+dnl  undefine PIC since we don't need to be position independent in this
+dnl  case and definitely don't want the ELF style _GLOBAL_OFFSET_TABLE_ etc.
+
+ifdef(`DLL_EXPORT',`undefine(`PIC')')
+
+
+dnl  Usage: CPUVEC_FUNCS_LIST
+dnl
+dnl  A list of the functions from gmp-impl.h x86 struct cpuvec_t, in the
+dnl  order they appear in that structure.
+
+define(CPUVEC_FUNCS_LIST,
+``add_n',
+`addlsh1_n',
+`addlsh2_n',
+`addmul_1',
+`addmul_2',
+`bdiv_dbm1c',
+`cnd_add_n',
+`cnd_sub_n',
+`com',
+`copyd',
+`copyi',
+`divexact_1',
+`divrem_1',
+`gcd_11',
+`lshift',
+`lshiftc',
+`mod_1',
+`mod_1_1p',
+`mod_1_1p_cps',
+`mod_1s_2p',
+`mod_1s_2p_cps',
+`mod_1s_4p',
+`mod_1s_4p_cps',
+`mod_34lsub1',
+`modexact_1c_odd',
+`mul_1',
+`mul_basecase',
+`mullo_basecase',
+`preinv_divrem_1',
+`preinv_mod_1',
+`redc_1',
+`redc_2',
+`rshift',
+`sqr_basecase',
+`sub_n',
+`sublsh1_n',
+`submul_1'')
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  In the x86 code we use explicit TEXT and ALIGN() calls in the code,
+dnl  since different alignments are wanted in various circumstances.  So for
+dnl  instance,
+dnl
+dnl                  TEXT
+dnl                  ALIGN(16)
+dnl          PROLOGUE(mpn_add_n)
+dnl          ...
+dnl          EPILOGUE()
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+m4_assert_defined(`WANT_PROFILING')
+	`GLOBL	$1
+	TYPE($1,`function')
+	COFF_TYPE($1)
+$1:
+ifelse(WANT_PROFILING,`prof',      `	call_mcount')
+ifelse(WANT_PROFILING,`gprof',     `	call_mcount')
+ifelse(WANT_PROFILING,`instrument',`	call_instrument(enter)')
+')
+
+
+dnl  Usage: COFF_TYPE(GSYM_PREFIX`'foo)
+dnl
+dnl  Emit COFF style ".def ... .endef" type information for a function, when
+dnl  supported.  The argument should include any GSYM_PREFIX.
+dnl
+dnl  See autoconf macro GMP_ASM_COFF_TYPE for HAVE_COFF_TYPE.
+
+define(COFF_TYPE,
+m4_assert_numargs(1)
+m4_assert_defined(`HAVE_COFF_TYPE')
+`ifelse(HAVE_COFF_TYPE,yes,
+	`.def	$1
+	.scl	2
+	.type	32
+	.endef')')
+
+
+dnl  Usage: call_mcount
+dnl
+dnl  For `gprof' style profiling, %ebp is setup as a frame pointer.  None of
+dnl  the assembler routines use %ebp this way, so it's done only for the
+dnl  benefit of mcount.  glibc sysdeps/i386/i386-mcount.S shows how mcount
+dnl  gets the current function from (%esp) and the parent from 4(%ebp).
+dnl
+dnl  For `prof' style profiling gcc generates mcount calls without setting
+dnl  up %ebp, and the same is done here.
+
+define(`call_mcount',
+m4_assert_numargs(-1)
+m4_assert_defined(`WANT_PROFILING')
+m4_assert_defined(`MCOUNT_PIC_REG')
+m4_assert_defined(`MCOUNT_NONPIC_REG')
+m4_assert_defined(`MCOUNT_PIC_CALL')
+m4_assert_defined(`MCOUNT_NONPIC_CALL')
+`ifelse(ifdef(`PIC',`MCOUNT_PIC_REG',`MCOUNT_NONPIC_REG'),,,
+`	DATA
+	ALIGN(4)
+L(mcount_data_`'mcount_counter):
+	W32	0
+	TEXT
+')dnl
+ifelse(WANT_PROFILING,`gprof',
+`	pushl	%ebp
+	movl	%esp, %ebp
+')dnl
+ifdef(`PIC',
+`	pushl	%ebx
+	call_movl_eip_to_ebx
+L(mcount_here_`'mcount_counter):
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(mcount_here_`'mcount_counter)], %ebx
+ifelse(MCOUNT_PIC_REG,,,
+`	leal	L(mcount_data_`'mcount_counter)@GOTOFF(%ebx), MCOUNT_PIC_REG')
+MCOUNT_PIC_CALL
+	popl	%ebx
+',`dnl non-PIC
+ifelse(MCOUNT_NONPIC_REG,,,
+`	movl	`$'L(mcount_data_`'mcount_counter), MCOUNT_NONPIC_REG
+')dnl
+MCOUNT_NONPIC_CALL
+')dnl
+ifelse(WANT_PROFILING,`gprof',
+`	popl	%ebp
+')
+define(`mcount_counter',incr(mcount_counter))
+')
+
+define(mcount_counter,1)
+
+
+dnl  Usage: call_instrument(enter|exit)
+dnl
+dnl  Call __cyg_profile_func_enter or __cyg_profile_func_exit.
+dnl
+dnl  For PIC, most routines don't require _GLOBAL_OFFSET_TABLE_ themselves
+dnl  so %ebx is just setup for these calls.  It's a bit wasteful to repeat
+dnl  the setup for the exit call having done it earlier for the enter, but
+dnl  there's nowhere very convenient to hold %ebx through the length of a
+dnl  routine, in general.
+dnl
+dnl  For PIC, because instrument_current_function will be within the current
+dnl  object file we can get it just as an offset from %eip, there's no need
+dnl  to use the GOT.
+dnl
+dnl  No attempt is made to maintain the stack alignment gcc generates with
+dnl  -mpreferred-stack-boundary.  This wouldn't be hard, but it seems highly
+dnl  unlikely the instrumenting functions would be doing anything that'd
+dnl  benefit from alignment, in particular they're unlikely to be using
+dnl  doubles or long doubles on the stack.
+dnl
+dnl  The FRAME scheme is used to conveniently account for the register saves
+dnl  before accessing the return address.  Any previous value is saved and
+dnl  restored, since plenty of code keeps a value across a "ret" in the
+dnl  middle of a routine.
+
+define(call_instrument,
+m4_assert_numargs(1)
+`	pushdef(`FRAME',0)
+ifelse($1,exit,
+`	pushl	%eax	FRAME_pushl()	C return value
+')
+ifdef(`PIC',
+`	pushl	%ebx	FRAME_pushl()
+	call_movl_eip_to_ebx
+L(instrument_here_`'instrument_count):
+	movl	%ebx, %ecx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(instrument_here_`'instrument_count)], %ebx
+	C use addl rather than leal to avoid old gas bugs, see mpn/x86/README
+	addl	$instrument_current_function-L(instrument_here_`'instrument_count), %ecx
+	pushl	m4_empty_if_zero(FRAME)(%esp)	FRAME_pushl()	C return addr
+	pushl	%ecx				FRAME_pushl()	C this function
+	call	GSYM_PREFIX`'__cyg_profile_func_$1@PLT
+	addl	$`'8, %esp
+	popl	%ebx
+',
+`	C non-PIC
+	pushl	m4_empty_if_zero(FRAME)(%esp)	FRAME_pushl()	C return addr
+	pushl	$instrument_current_function	FRAME_pushl()	C this function
+	call	GSYM_PREFIX`'__cyg_profile_func_$1
+	addl	$`'8, %esp
+')
+ifelse($1,exit,
+`	popl	%eax			C return value
+')
+	popdef(`FRAME')
+define(`instrument_count',incr(instrument_count))
+')
+define(instrument_count,1)
+
+
+dnl  Usage: instrument_current_function
+dnl
+dnl  Return the current function name for instrumenting purposes.  This is
+dnl  PROLOGUE_current_function, but it sticks at the first such name seen.
+dnl
+dnl  Sticking to the first name seen ensures that multiple-entrypoint
+dnl  functions like mpn_add_nc and mpn_add_n will make enter and exit calls
+dnl  giving the same function address.
+
+define(instrument_current_function,
+m4_assert_numargs(-1)
+`ifdef(`instrument_current_function_seen',
+`instrument_current_function_seen',
+`define(`instrument_current_function_seen',PROLOGUE_current_function)dnl
+PROLOGUE_current_function')')
+
+
+dnl  Usage: call_movl_eip_to_ebx
+dnl
+dnl  Generate a call to L(movl_eip_to_ebx), and record the need for that
+dnl  routine.
+
+define(call_movl_eip_to_ebx,
+m4_assert_numargs(-1)
+`call	L(movl_eip_to_ebx)
+define(`movl_eip_to_ebx_needed',1)')
+
+dnl  Usage: generate_movl_eip_to_ebx
+dnl
+dnl  Emit a L(movl_eip_to_ebx) routine, if needed and not already generated.
+
+define(generate_movl_eip_to_ebx,
+m4_assert_numargs(-1)
+`ifelse(movl_eip_to_ebx_needed,1,
+`ifelse(movl_eip_to_ebx_done,1,,
+`L(movl_eip_to_ebx):
+	movl	(%esp), %ebx
+	ret_internal
+define(`movl_eip_to_ebx_done',1)
+')')')
+
+
+dnl  Usage: ret
+dnl
+dnl  Generate a "ret", but if doing instrumented profiling then call
+dnl  __cyg_profile_func_exit first.
+
+define(ret,
+m4_assert_numargs(-1)
+m4_assert_defined(`WANT_PROFILING')
+`ifelse(WANT_PROFILING,instrument,
+`ret_instrument',
+`ret_internal')
+generate_movl_eip_to_ebx
+')
+
+
+dnl  Usage: ret_internal
+dnl
+dnl  A plain "ret", without any __cyg_profile_func_exit call.  This can be
+dnl  used for a return which is internal to some function, such as when
+dnl  getting %eip for PIC.
+
+define(ret_internal,
+m4_assert_numargs(-1)
+``ret'')
+
+
+dnl  Usage: ret_instrument
+dnl
+dnl  Generate call to __cyg_profile_func_exit and then a ret.  If a ret has
+dnl  already been seen from this function then jump to that chunk of code,
+dnl  rather than emitting it again.
+
+define(ret_instrument,
+m4_assert_numargs(-1)
+`ifelse(m4_unquote(ret_instrument_seen_`'instrument_current_function),1,
+`jmp	L(instrument_exit_`'instrument_current_function)',
+`define(ret_instrument_seen_`'instrument_current_function,1)
+L(instrument_exit_`'instrument_current_function):
+call_instrument(exit)
+	ret_internal')')
+
+
+dnl  Usage: _GLOBAL_OFFSET_TABLE_
+dnl
+dnl  Expand to _GLOBAL_OFFSET_TABLE_ plus any necessary underscore prefix.
+dnl  This lets us write plain _GLOBAL_OFFSET_TABLE_ in SVR4 style, but still
+dnl  work with systems requiring an extra underscore such as OpenBSD.
+dnl
+dnl  deflit is used so "leal _GLOBAL_OFFSET_TABLE_(%eax), %ebx" will come
+dnl  out right, though that form doesn't work properly in gas (see
+dnl  mpn/x86/README).
+
+deflit(_GLOBAL_OFFSET_TABLE_,
+m4_assert_defined(`GOT_GSYM_PREFIX')
+`GOT_GSYM_PREFIX`_GLOBAL_OFFSET_TABLE_'')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Various x86 macros.
+dnl
+
+
+dnl  Usage: ALIGN_OFFSET(bytes,offset)
+dnl
+dnl  Align to `offset' away from a multiple of `bytes'.
+dnl
+dnl  This is useful for testing, for example align to something very strict
+dnl  and see what effect offsets from it have, "ALIGN_OFFSET(256,32)".
+dnl
+dnl  Generally you wouldn't execute across the padding, but it's done with
+dnl  nop's so it'll work.
+
+define(ALIGN_OFFSET,
+m4_assert_numargs(2)
+`ALIGN($1)
+forloop(`i',1,$2,`	nop
+')')
+
+
+dnl  Usage: defframe(name,offset)
+dnl
+dnl  Make a definition like the following with which to access a parameter
+dnl  or variable on the stack.
+dnl
+dnl         define(name,`FRAME+offset(%esp)')
+dnl
+dnl  Actually m4_empty_if_zero(FRAME+offset) is used, which will save one
+dnl  byte if FRAME+offset is zero, by putting (%esp) rather than 0(%esp).
+dnl  Use define(`defframe_empty_if_zero_disabled',1) if for some reason the
+dnl  zero offset is wanted.
+dnl
+dnl  The new macro also gets a check that when it's used FRAME is actually
+dnl  defined, and that the final %esp offset isn't negative, which would
+dnl  mean an attempt to access something below the current %esp.
+dnl
+dnl  deflit() is used rather than a plain define(), so the new macro won't
+dnl  delete any following parenthesized expression.  name(%edi) will come
+dnl  out say as 16(%esp)(%edi).  This isn't valid assembler and should
+dnl  provoke an error, which is better than silently giving just 16(%esp).
+dnl
+dnl  See README for more on the suggested way to access the stack frame.
+
+define(defframe,
+m4_assert_numargs(2)
+`deflit(`$1',
+m4_assert_defined(`FRAME')
+`defframe_check_notbelow(`$1',$2,FRAME)dnl
+defframe_empty_if_zero(FRAME+($2))(%esp)')')
+
+dnl  Called: defframe_empty_if_zero(expression)
+define(defframe_empty_if_zero,
+m4_assert_numargs(1)
+`ifelse(defframe_empty_if_zero_disabled,1,
+`eval($1)',
+`m4_empty_if_zero($1)')')
+
+dnl  Called: defframe_check_notbelow(`name',offset,FRAME)
+define(defframe_check_notbelow,
+m4_assert_numargs(3)
+`ifelse(eval(($3)+($2)<0),1,
+`m4_error(`$1 at frame offset $2 used when FRAME is only $3 bytes
+')')')
+
+
+dnl  Usage: FRAME_pushl()
+dnl         FRAME_popl()
+dnl         FRAME_addl_esp(n)
+dnl         FRAME_subl_esp(n)
+dnl
+dnl  Adjust FRAME appropriately for a pushl or popl, or for an addl or subl
+dnl  %esp of n bytes.
+dnl
+dnl  Using these macros is completely optional.  Sometimes it makes more
+dnl  sense to put explicit deflit(`FRAME',N) forms, especially when there's
+dnl  jumps and different sequences of FRAME values need to be used in
+dnl  different places.
+
+define(FRAME_pushl,
+m4_assert_numargs(0)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME+4))')
+
+define(FRAME_popl,
+m4_assert_numargs(0)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME-4))')
+
+define(FRAME_addl_esp,
+m4_assert_numargs(1)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME-($1)))')
+
+define(FRAME_subl_esp,
+m4_assert_numargs(1)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME+($1)))')
+
+
+dnl  Usage: defframe_pushl(name)
+dnl
+dnl  Do a combination FRAME_pushl() and a defframe() to name the stack
+dnl  location just pushed.  This should come after a pushl instruction.
+dnl  Putting it on the same line works and avoids lengthening the code.  For
+dnl  example,
+dnl
+dnl         pushl   %eax     defframe_pushl(VAR_COUNTER)
+dnl
+dnl  Notice the defframe() is done with an unquoted -FRAME thus giving its
+dnl  current value without tracking future changes.
+
+define(defframe_pushl,
+m4_assert_numargs(1)
+`FRAME_pushl()defframe(`$1',-FRAME)')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Assembler instruction macros.
+dnl
+
+
+dnl  Usage: emms_or_femms
+dnl         femms_available_p
+dnl
+dnl  femms_available_p expands to 1 or 0 according to whether the AMD 3DNow
+dnl  femms instruction is available.  emms_or_femms expands to femms if
+dnl  available, or emms if not.
+dnl
+dnl  emms_or_femms is meant for use in the K6 directory where plain K6
+dnl  (without femms) and K6-2 and K6-3 (with a slightly faster femms) are
+dnl  supported together.
+dnl
+dnl  On K7 femms is no longer faster and is just an alias for emms, so plain
+dnl  emms may as well be used.
+
+define(femms_available_p,
+m4_assert_numargs(-1)
+`m4_ifdef_anyof_p(
+	`HAVE_HOST_CPU_k62',
+	`HAVE_HOST_CPU_k63',
+	`HAVE_HOST_CPU_athlon')')
+
+define(emms_or_femms,
+m4_assert_numargs(-1)
+`ifelse(femms_available_p,1,`femms',`emms')')
+
+
+dnl  Usage: femms
+dnl
+dnl  Gas 2.9.1 which comes with FreeBSD 3.4 doesn't support femms, so the
+dnl  following is a replacement using .byte.
+
+define(femms,
+m4_assert_numargs(-1)
+`.byte	15,14	C AMD 3DNow femms')
+
+
+dnl  Usage: jadcl0(op)
+dnl
+dnl  Generate a jnc/incl as a substitute for adcl $0,op.  Note this isn't an
+dnl  exact replacement, since it doesn't set the flags like adcl does.
+dnl
+dnl  This finds a use in K6 mpn_addmul_1, mpn_submul_1, mpn_mul_basecase and
+dnl  mpn_sqr_basecase because on K6 an adcl is slow, the branch
+dnl  misprediction penalty is small, and the multiply algorithm used leads
+dnl  to a carry bit on average only 1/4 of the time.
+dnl
+dnl  jadcl0_disabled can be set to 1 to instead generate an ordinary adcl
+dnl  for comparison.  For example,
+dnl
+dnl		define(`jadcl0_disabled',1)
+dnl
+dnl  When using a register operand, eg. "jadcl0(%edx)", the jnc/incl code is
+dnl  the same size as an adcl.  This makes it possible to use the exact same
+dnl  computed jump code when testing the relative speed of the two.
+
+define(jadcl0,
+m4_assert_numargs(1)
+`ifelse(jadcl0_disabled,1,
+	`adcl	$`'0, $1',
+	`jnc	L(jadcl0_`'jadcl0_counter)
+	incl	$1
+L(jadcl0_`'jadcl0_counter):
+define(`jadcl0_counter',incr(jadcl0_counter))')')
+
+define(jadcl0_counter,1)
+
+
+dnl  Usage: x86_lookup(target, key,value, key,value, ...)
+dnl         x86_lookup_p(target, key,value, key,value, ...)
+dnl
+dnl  Look for `target' among the `key' parameters.
+dnl
+dnl  x86_lookup expands to the corresponding `value', or generates an error
+dnl  if `target' isn't found.
+dnl
+dnl  x86_lookup_p expands to 1 if `target' is found, or 0 if not.
+
+define(x86_lookup,
+m4_assert_numargs_range(1,999)
+`ifelse(eval($#<3),1,
+`m4_error(`unrecognised part of x86 instruction: $1
+')',
+`ifelse(`$1',`$2', `$3',
+`x86_lookup(`$1',shift(shift(shift($@))))')')')
+
+define(x86_lookup_p,
+m4_assert_numargs_range(1,999)
+`ifelse(eval($#<3),1, `0',
+`ifelse(`$1',`$2',    `1',
+`x86_lookup_p(`$1',shift(shift(shift($@))))')')')
+
+
+dnl  Usage: x86_opcode_reg32(reg)
+dnl         x86_opcode_reg32_p(reg)
+dnl
+dnl  x86_opcode_reg32 expands to the standard 3 bit encoding for the given
+dnl  32-bit register, eg. `%ebp' turns into 5.
+dnl
+dnl  x86_opcode_reg32_p expands to 1 if reg is a valid 32-bit register, or 0
+dnl  if not.
+
+define(x86_opcode_reg32,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_reg32_list)')
+
+define(x86_opcode_reg32_p,
+m4_assert_onearg()
+`x86_lookup_p(`$1',x86_opcode_reg32_list)')
+
+define(x86_opcode_reg32_list,
+``%eax',0,
+`%ecx',1,
+`%edx',2,
+`%ebx',3,
+`%esp',4,
+`%ebp',5,
+`%esi',6,
+`%edi',7')
+
+
+dnl  Usage: x86_opcode_tttn(cond)
+dnl
+dnl  Expand to the 4-bit "tttn" field value for the given x86 branch
+dnl  condition (like `c', `ae', etc).
+
+define(x86_opcode_tttn,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_ttn_list)')
+
+define(x86_opcode_tttn_list,
+``o',  0,
+`no',  1,
+`b',   2, `c',  2, `nae',2,
+`nb',  3, `nc', 3, `ae', 3,
+`e',   4, `z',  4,
+`ne',  5, `nz', 5,
+`be',  6, `na', 6,
+`nbe', 7, `a',  7,
+`s',   8,
+`ns',  9,
+`p',  10, `pe', 10, `npo',10,
+`np', 11, `npe',11, `po', 11,
+`l',  12, `nge',12,
+`nl', 13, `ge', 13,
+`le', 14, `ng', 14,
+`nle',15, `g',  15')
+
+
+dnl  Usage: cmovCC(%srcreg,%dstreg)
+dnl
+dnl  Emit a cmov instruction, using a .byte sequence, since various past
+dnl  versions of gas don't know cmov.  For example,
+dnl
+dnl         cmovz(  %eax, %ebx)
+dnl
+dnl  The source operand can only be a plain register.  (m4 code implementing
+dnl  full memory addressing modes exists, believe it or not, but isn't
+dnl  currently needed and isn't included.)
+dnl
+dnl  All the standard conditions are defined.  Attempting to use one without
+dnl  the macro parentheses, such as just "cmovbe %eax, %ebx", will provoke
+dnl  an error.  This protects against writing something old gas wouldn't
+dnl  understand.
+
+dnl  Called: define_cmov_many(cond,tttn,cond,tttn,...)
+define(define_cmov_many,
+`ifelse(m4_length(`$1'),0,,
+`define_cmov(`$1',`$2')define_cmov_many(shift(shift($@)))')')
+
+dnl  Called: define_cmov(cond,tttn)
+dnl  Emit basically define(cmov<cond>,`cmov_internal(<cond>,<ttn>,`$1',`$2')')
+define(define_cmov,
+m4_assert_numargs(2)
+`define(`cmov$1',
+m4_instruction_wrapper()
+m4_assert_numargs(2)
+`cmov_internal'(m4_doublequote($`'0),``$2'',dnl
+m4_doublequote($`'1),m4_doublequote($`'2)))')
+
+define_cmov_many(x86_opcode_tttn_list)
+
+dnl  Called: cmov_internal(name,tttn,src,dst)
+define(cmov_internal,
+m4_assert_numargs(4)
+`.byte	dnl
+15, dnl
+eval(64+$2), dnl
+eval(192+8*x86_opcode_reg32(`$4')+x86_opcode_reg32(`$3')) dnl
+	C `$1 $3, $4'')
+
+
+dnl  Usage: x86_opcode_regmmx(reg)
+dnl
+dnl  Validate the given mmx register, and return its number, 0 to 7.
+
+define(x86_opcode_regmmx,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_regmmx_list)')
+
+define(x86_opcode_regmmx_list,
+``%mm0',0,
+`%mm1',1,
+`%mm2',2,
+`%mm3',3,
+`%mm4',4,
+`%mm5',5,
+`%mm6',6,
+`%mm7',7')
+
+
+dnl  Usage: psadbw(%srcreg,%dstreg)
+dnl
+dnl  Oldish versions of gas don't know psadbw, in particular gas 2.9.1 on
+dnl  FreeBSD 3.3 and 3.4 doesn't, so instead emit .byte sequences.  For
+dnl  example,
+dnl
+dnl         psadbw( %mm1, %mm2)
+dnl
+dnl  Only register->register forms are supported here, which suffices for
+dnl  the current code.
+
+define(psadbw,
+m4_instruction_wrapper()
+m4_assert_numargs(2)
+`.byte 0x0f,0xf6,dnl
+eval(192+x86_opcode_regmmx(`$2')*8+x86_opcode_regmmx(`$1')) dnl
+	C `psadbw $1, $2'')
+
+
+dnl  Usage: Zdisp(inst,op,op,op)
+dnl
+dnl  Generate explicit .byte sequences if necessary to force a byte-sized
+dnl  zero displacement on an instruction.  For example,
+dnl
+dnl         Zdisp(  movl,   0,(%esi), %eax)
+dnl
+dnl  expands to
+dnl
+dnl                 .byte   139,70,0  C movl 0(%esi), %eax
+dnl
+dnl  If the displacement given isn't 0, then normal assembler code is
+dnl  generated.  For example,
+dnl
+dnl         Zdisp(  movl,   4,(%esi), %eax)
+dnl
+dnl  expands to
+dnl
+dnl                 movl    4(%esi), %eax
+dnl
+dnl  This means a single Zdisp() form can be used with an expression for the
+dnl  displacement, and .byte will be used only if necessary.  The
+dnl  displacement argument is eval()ed.
+dnl
+dnl  Because there aren't many places a 0(reg) form is wanted, Zdisp is
+dnl  implemented with a table of instructions and encodings.  A new entry is
+dnl  needed for any different operation or registers.  The table is split
+dnl  into separate macros to avoid overflowing BSD m4 macro expansion space.
+
+define(Zdisp,
+m4_assert_numargs(4)
+`define(`Zdisp_found',0)dnl
+Zdisp_1($@)dnl
+Zdisp_2($@)dnl
+Zdisp_3($@)dnl
+Zdisp_4($@)dnl
+ifelse(Zdisp_found,0,
+`m4_error(`unrecognised instruction in Zdisp: $1 $2 $3 $4
+')')')
+
+define(Zdisp_1,`dnl
+Zdisp_match( adcl, 0,(%edx), %eax,        `0x13,0x42,0x00',           $@)`'dnl
+Zdisp_match( adcl, 0,(%edx), %ebx,        `0x13,0x5a,0x00',           $@)`'dnl
+Zdisp_match( adcl, 0,(%edx), %esi,        `0x13,0x72,0x00',           $@)`'dnl
+Zdisp_match( addl, %ebx, 0,(%edi),        `0x01,0x5f,0x00',           $@)`'dnl
+Zdisp_match( addl, %ecx, 0,(%edi),        `0x01,0x4f,0x00',           $@)`'dnl
+Zdisp_match( addl, %esi, 0,(%edi),        `0x01,0x77,0x00',           $@)`'dnl
+Zdisp_match( sbbl, 0,(%edx), %eax,        `0x1b,0x42,0x00',           $@)`'dnl
+Zdisp_match( sbbl, 0,(%edx), %esi,        `0x1b,0x72,0x00',           $@)`'dnl
+Zdisp_match( subl, %ecx, 0,(%edi),        `0x29,0x4f,0x00',           $@)`'dnl
+Zdisp_match( movzbl, 0,(%eax,%ebp), %eax, `0x0f,0xb6,0x44,0x28,0x00', $@)`'dnl
+Zdisp_match( movzbl, 0,(%ecx,%edi), %edi, `0x0f,0xb6,0x7c,0x39,0x00', $@)`'dnl
+Zdisp_match( adc, 0,(%ebx,%ecx,4), %eax,  `0x13,0x44,0x8b,0x00',      $@)`'dnl
+Zdisp_match( sbb, 0,(%ebx,%ecx,4), %eax,  `0x1b,0x44,0x8b,0x00',      $@)`'dnl
+')
+define(Zdisp_2,`dnl
+Zdisp_match( movl, %eax, 0,(%edi),        `0x89,0x47,0x00',           $@)`'dnl
+Zdisp_match( movl, %ebx, 0,(%edi),        `0x89,0x5f,0x00',           $@)`'dnl
+Zdisp_match( movl, %esi, 0,(%edi),        `0x89,0x77,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%ebx), %eax,        `0x8b,0x43,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%ebx), %esi,        `0x8b,0x73,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%edx), %eax,        `0x8b,0x42,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%esi), %eax,        `0x8b,0x46,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%esi,%ecx,4), %eax, `0x8b,0x44,0x8e,0x00',      $@)`'dnl
+Zdisp_match( mov, 0,(%esi,%ecx,4), %eax,  `0x8b,0x44,0x8e,0x00',      $@)`'dnl
+Zdisp_match( mov, %eax, 0,(%edi,%ecx,4),  `0x89,0x44,0x8f,0x00',      $@)`'dnl
+')
+define(Zdisp_3,`dnl
+Zdisp_match( movq, 0,(%eax,%ecx,8), %mm0, `0x0f,0x6f,0x44,0xc8,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%ebx,%eax,4), %mm0, `0x0f,0x6f,0x44,0x83,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%ebx,%eax,4), %mm2, `0x0f,0x6f,0x54,0x83,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%ebx,%ecx,4), %mm0, `0x0f,0x6f,0x44,0x8b,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%edx), %mm0,        `0x0f,0x6f,0x42,0x00',      $@)`'dnl
+Zdisp_match( movq, 0,(%esi), %mm0,        `0x0f,0x6f,0x46,0x00',      $@)`'dnl
+Zdisp_match( movq, %mm0, 0,(%edi),        `0x0f,0x7f,0x47,0x00',      $@)`'dnl
+Zdisp_match( movq, %mm2, 0,(%ecx,%eax,4), `0x0f,0x7f,0x54,0x81,0x00', $@)`'dnl
+Zdisp_match( movq, %mm2, 0,(%edx,%eax,4), `0x0f,0x7f,0x54,0x82,0x00', $@)`'dnl
+Zdisp_match( movq, %mm0, 0,(%edx,%ecx,8), `0x0f,0x7f,0x44,0xca,0x00', $@)`'dnl
+')
+define(Zdisp_4,`dnl
+Zdisp_match( movd, 0,(%eax,%ecx,4), %mm0, `0x0f,0x6e,0x44,0x88,0x00', $@)`'dnl
+Zdisp_match( movd, 0,(%eax,%ecx,8), %mm1, `0x0f,0x6e,0x4c,0xc8,0x00', $@)`'dnl
+Zdisp_match( movd, 0,(%edx,%ecx,8), %mm0, `0x0f,0x6e,0x44,0xca,0x00', $@)`'dnl
+Zdisp_match( movd, %mm0, 0,(%eax,%ecx,4), `0x0f,0x7e,0x44,0x88,0x00', $@)`'dnl
+Zdisp_match( movd, %mm0, 0,(%ecx,%eax,4), `0x0f,0x7e,0x44,0x81,0x00', $@)`'dnl
+Zdisp_match( movd, %mm2, 0,(%ecx,%eax,4), `0x0f,0x7e,0x54,0x81,0x00', $@)`'dnl
+Zdisp_match( movd, %mm0, 0,(%edx,%ecx,4), `0x0f,0x7e,0x44,0x8a,0x00', $@)`'dnl
+')
+
+define(Zdisp_match,
+m4_assert_numargs(9)
+`ifelse(eval(m4_stringequal_p(`$1',`$6')
+	&& m4_stringequal_p(`$2',0)
+	&& m4_stringequal_p(`$3',`$8')
+	&& m4_stringequal_p(`$4',`$9')),1,
+`define(`Zdisp_found',1)dnl
+ifelse(eval(`$7'),0,
+`	.byte	$5  C `$1 0$3, $4'',
+`	$6	$7$8, $9')',
+
+`ifelse(eval(m4_stringequal_p(`$1',`$6')
+	&& m4_stringequal_p(`$2',`$7')
+	&& m4_stringequal_p(`$3',0)
+	&& m4_stringequal_p(`$4',`$9')),1,
+`define(`Zdisp_found',1)dnl
+ifelse(eval(`$8'),0,
+`	.byte	$5  C `$1 $2, 0$4'',
+`	$6	$7, $8$9')')')')
+
+
+dnl  Usage: shldl(count,src,dst)
+dnl         shrdl(count,src,dst)
+dnl         shldw(count,src,dst)
+dnl         shrdw(count,src,dst)
+dnl
+dnl  Generate a double-shift instruction, possibly omitting a %cl count
+dnl  parameter if that's what the assembler requires, as indicated by
+dnl  WANT_SHLDL_CL in config.m4.  For example,
+dnl
+dnl         shldl(  %cl, %eax, %ebx)
+dnl
+dnl  turns into either
+dnl
+dnl         shldl   %cl, %eax, %ebx
+dnl  or
+dnl         shldl   %eax, %ebx
+dnl
+dnl  Immediate counts are always passed through unchanged.  For example,
+dnl
+dnl         shrdl(  $2, %esi, %edi)
+dnl  becomes
+dnl         shrdl   $2, %esi, %edi
+dnl
+dnl
+dnl  If you forget to use the macro form "shldl( ...)" and instead write
+dnl  just a plain "shldl ...", an error results.  This ensures the necessary
+dnl  variant treatment of %cl isn't accidentally bypassed.
+
+define(define_shd_instruction,
+m4_assert_numargs(1)
+`define($1,
+m4_instruction_wrapper()
+m4_assert_numargs(3)
+`shd_instruction'(m4_doublequote($`'0),m4_doublequote($`'1),dnl
+m4_doublequote($`'2),m4_doublequote($`'3)))')
+
+dnl  Effectively: define(shldl,`shd_instruction(`$0',`$1',`$2',`$3')') etc
+define_shd_instruction(shldl)
+define_shd_instruction(shrdl)
+define_shd_instruction(shldw)
+define_shd_instruction(shrdw)
+
+dnl  Called: shd_instruction(op,count,src,dst)
+define(shd_instruction,
+m4_assert_numargs(4)
+m4_assert_defined(`WANT_SHLDL_CL')
+`ifelse(eval(m4_stringequal_p(`$2',`%cl') && !WANT_SHLDL_CL),1,
+``$1'	`$3', `$4'',
+``$1'	`$2', `$3', `$4'')')
+
+
+dnl  Usage: ASSERT([cond][,instructions])
+dnl
+dnl  If WANT_ASSERT is 1, output the given instructions and expect the given
+dnl  flags condition to then be satisfied.  For example,
+dnl
+dnl         ASSERT(ne, `cmpl %eax, %ebx')
+dnl
+dnl  The instructions can be omitted to just assert a flags condition with
+dnl  no extra calculation.  For example,
+dnl
+dnl         ASSERT(nc)
+dnl
+dnl  When `instructions' is not empty, a pushf/popf is added to preserve the
+dnl  flags, but the instructions themselves must preserve any registers that
+dnl  matter.  FRAME is adjusted for the push and pop, so the instructions
+dnl  given can use defframe() stack variables.
+dnl
+dnl  The condition can be omitted to just output the given instructions when
+dnl  assertion checking is wanted.  In this case the pushf/popf is omitted.
+dnl  For example,
+dnl
+dnl         ASSERT(, `movl %eax, VAR_KEEPVAL')
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+`ifelse(`$1',,
+	`$2',
+	`C ASSERT
+ifelse(`$2',,,`	pushf	ifdef(`FRAME',`FRAME_pushl()')')
+	$2
+	j`$1'	L(ASSERT_ok`'ASSERT_counter)
+	ud2	C assertion failed
+L(ASSERT_ok`'ASSERT_counter):
+ifelse(`$2',,,`	popf	ifdef(`FRAME',`FRAME_popl()')')
+define(`ASSERT_counter',incr(ASSERT_counter))')')')
+
+define(ASSERT_counter,1)
+
+
+dnl  Usage: movl_text_address(label,register)
+dnl
+dnl  Get the address of a text segment label, using either a plain movl or a
+dnl  position-independent calculation, as necessary.  For example,
+dnl
+dnl         movl_code_address(L(foo),%eax)
+dnl
+dnl  This macro is only meant for use in ASSERT()s or when testing, since
+dnl  the PIC sequence it generates will want to be done with a ret balancing
+dnl  the call on CPUs with return address branch prediction.
+dnl
+dnl  The addl generated here has a backward reference to the label, and so
+dnl  won't suffer from the two forwards references bug in old gas (described
+dnl  in mpn/x86/README).
+
+define(movl_text_address,
+m4_assert_numargs(2)
+`ifdef(`PIC',
+	`call	L(movl_text_address_`'movl_text_address_counter)
+L(movl_text_address_`'movl_text_address_counter):
+	popl	$2	C %eip
+	addl	`$'$1-L(movl_text_address_`'movl_text_address_counter), $2
+define(`movl_text_address_counter',incr(movl_text_address_counter))',
+	`movl	`$'$1, $2')')
+
+define(movl_text_address_counter,1)
+
+
+dnl  Usage: notl_or_xorl_GMP_NUMB_MASK(reg)
+dnl
+dnl  Expand to either "notl `reg'" or "xorl $GMP_NUMB_BITS,`reg'" as
+dnl  appropriate for nails in use or not.
+
+define(notl_or_xorl_GMP_NUMB_MASK,
+m4_assert_numargs(1)
+`ifelse(GMP_NAIL_BITS,0,
+`notl	`$1'',
+`xorl	$GMP_NUMB_MASK, `$1'')')
+
+
+dnl  Usage LEA(symbol,reg)
+dnl  Usage LEAL(symbol_local_to_file,reg)
+
+define(`LEA',
+m4_assert_numargs(2)
+`ifdef(`PIC',`dnl
+ifelse(index(defn(`load_eip'), `$2'),-1,
+`m4append(`load_eip',
+`	TEXT
+	ALIGN(16)
+L(movl_eip_`'substr($2,1)):
+	movl	(%esp), $2
+	ret_internal
+')')dnl
+	call	L(movl_eip_`'substr($2,1))
+	addl	$_GLOBAL_OFFSET_TABLE_, $2
+	movl	$1@GOT($2), $2
+',`
+	movl	`$'$1, $2
+')')
+
+define(`LEAL',
+m4_assert_numargs(2)
+`ifdef(`PIC',`dnl
+ifelse(index(defn(`load_eip'), `$2'),-1,
+`m4append(`load_eip',
+`	TEXT
+	ALIGN(16)
+L(movl_eip_`'substr($2,1)):
+	movl	(%esp), $2
+	ret_internal
+')')dnl
+	call	L(movl_eip_`'substr($2,1))
+	addl	$_GLOBAL_OFFSET_TABLE_, $2
+	leal	$1@GOTOFF($2), $2
+',`
+	movl	`$'$1, $2
+')')
+
+dnl ASM_END
+
+define(`ASM_END',`load_eip')
+
+define(`load_eip', `')		dnl updated in LEA/LEAL
+
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+	`RODATA
+	ALIGN(ifelse($#,1,2,$2))
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	SIZE(`$1',.-`$1')')
+
+dnl  Usage: CALL(funcname)
+dnl
+
+define(`CALL',
+m4_assert_numargs(1)
+`ifdef(`PIC',
+  `call	GSYM_PREFIX`'$1@PLT',
+  `call	GSYM_PREFIX`'$1')')
+
+ifdef(`PIC',
+`define(`PIC_WITH_EBX')',
+`undefine(`PIC_WITH_EBX')')
+
+divert`'dnl
diff --git a/mpn/x86_64/aorrlsh1_n.asm b/mpn/x86_64/aorrlsh1_n.asm
new file mode 100644
index 0000000..af317fd
--- /dev/null
+++ b/mpn/x86_64/aorrlsh1_n.asm
@@ -0,0 +1,170 @@
+dnl  AMD64 mpn_addlsh1_n -- rp[] = up[] + (vp[] << 1)
+dnl  AMD64 mpn_rsblsh1_n -- rp[] = (vp[] << 1) - up[]
+
+dnl  Copyright 2003, 2005-2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2
+C AMD K10	 2
+C AMD bd1	 ?
+C AMD bobcat	 ?
+C Intel P4	 13
+C Intel core2	 3.45
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C Sometimes speed degenerates, supposedly related to that some operand
+C alignments cause cache conflicts.
+
+C The speed is limited by decoding/issue bandwidth.  There are 22 instructions
+C in the loop, which corresponds to ceil(22/3)/4 = 1.83 c/l.
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n', `%rcx')
+
+ifdef(`OPERATION_addlsh1_n', `
+  define(ADDSUB,	add)
+  define(ADCSBB,	adc)
+  define(func,		mpn_addlsh1_n)')
+ifdef(`OPERATION_rsblsh1_n', `
+  define(ADDSUB,	sub)
+  define(ADCSBB,	sbb)
+  define(func,		mpn_rsblsh1_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_rsblsh1_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbp
+
+	mov	(vp), %r8
+	mov	R32(n), R32(%rax)
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+	xor	R32(%rbp), R32(%rbp)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	sbb	R32(%rax), R32(%rax)	C save scy
+	ADDSUB	(up,n,8), %r8
+	ADCSBB	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+	ADCSBB	16(up,n,8), %r10
+	mov	%r10, 16(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$3, n
+	jmp	L(ent)
+
+L(b10):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	sbb	R32(%rax), R32(%rax)	C save scy
+	ADDSUB	(up,n,8), %r8
+	ADCSBB	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$2, n
+	jmp	L(ent)
+
+L(b01):	add	%r8, %r8
+	sbb	R32(%rax), R32(%rax)	C save scy
+	ADDSUB	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	inc	n
+L(ent):	jns	L(end)
+
+	ALIGN(16)
+L(top):	add	R32(%rax), R32(%rax)	C restore scy
+
+	mov	(vp,n,8), %r8
+L(b00):	adc	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	mov	24(vp,n,8), %r11
+	adc	%r11, %r11
+
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+
+	ADCSBB	(up,n,8), %r8
+	nop				C Hammer speedup!
+	ADCSBB	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+	ADCSBB	16(up,n,8), %r10
+	ADCSBB	24(up,n,8), %r11
+	mov	%r10, 16(rp,n,8)
+	mov	%r11, 24(rp,n,8)
+
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$4, n
+	js	L(top)
+
+L(end):
+ifdef(`OPERATION_addlsh1_n',`
+	add	R32(%rbp), R32(%rax)
+	neg	R32(%rax)')
+ifdef(`OPERATION_rsblsh1_n',`
+	sub	R32(%rax), R32(%rbp)
+	movslq	R32(%rbp), %rax')
+
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aorrlsh2_n.asm b/mpn/x86_64/aorrlsh2_n.asm
new file mode 100644
index 0000000..6c17830
--- /dev/null
+++ b/mpn/x86_64/aorrlsh2_n.asm
@@ -0,0 +1,53 @@
+dnl  AMD64 mpn_addlsh2_n -- rp[] = up[] + (vp[] << 2)
+dnl  AMD64 mpn_rsblsh2_n -- rp[] = (vp[] << 2) - up[]
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009-2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+define(LSH, 2)
+define(RSH, 62)
+
+ifdef(`OPERATION_addlsh2_n',`
+  define(ADDSUB,	add)
+  define(ADCSBB,	adc)
+  define(func,		mpn_addlsh2_n)')
+ifdef(`OPERATION_rsblsh2_n',`
+  define(ADDSUB,	sub)
+  define(ADCSBB,	sbb)
+  define(func,		mpn_rsblsh2_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_rsblsh2_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/aorrlshC_n.asm')
diff --git a/mpn/x86_64/aorrlshC_n.asm b/mpn/x86_64/aorrlshC_n.asm
new file mode 100644
index 0000000..de00154
--- /dev/null
+++ b/mpn/x86_64/aorrlshC_n.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_addlshC_n -- rp[] = up[] + (vp[] << C)
+dnl  AMD64 mpn_rsblshC_n -- rp[] = (vp[] << C) - up[]
+
+dnl  Copyright 2009-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.1
+C AMD K10	 2.0
+C AMD bd1	~2.7
+C AMD bd2	~2.7
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 2.0
+C AMD bt1	 3.3
+C AMD bt2	 3.0
+C Intel P4	 ?
+C Intel PNR	 3.0
+C Intel NHM	 2.75
+C Intel SBR	 2.55
+C Intel IBR	 2.49
+C Intel HWL	 2.25
+C Intel BWL	 1.89
+C Intel SKL	 1.90
+C Intel atom	 8.4
+C Intel SLM	 4.0
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+
+define(M, eval(m4_lshift(1,LSH)))
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(vp), %r8
+	lea	(,%r8,M), %r12
+	shr	$RSH, %r8
+
+	mov	R32(n), R32(%rax)
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+	and	$3, R8(%rax)
+	je	L(b00)
+	cmp	$2, R8(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	mov	8(vp,n,8), %r10
+	lea	(%r8,%r10,M), %r14
+	shr	$RSH, %r10
+	mov	16(vp,n,8), %r11
+	lea	(%r10,%r11,M), %r15
+	shr	$RSH, %r11
+	ADDSUB	(up,n,8), %r12
+	ADCSBB	8(up,n,8), %r14
+	ADCSBB	16(up,n,8), %r15
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r12, (rp,n,8)
+	mov	%r14, 8(rp,n,8)
+	mov	%r15, 16(rp,n,8)
+	add	$3, n
+	js	L(top)
+	jmp	L(end)
+
+L(b01):	mov	%r8, %r11
+	ADDSUB	(up,n,8), %r12
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r12, (rp,n,8)
+	add	$1, n
+	js	L(top)
+	jmp	L(end)
+
+L(b10):	mov	8(vp,n,8), %r11
+	lea	(%r8,%r11,M), %r15
+	shr	$RSH, %r11
+	ADDSUB	(up,n,8), %r12
+	ADCSBB	8(up,n,8), %r15
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r12, (rp,n,8)
+	mov	%r15, 8(rp,n,8)
+	add	$2, n
+	js	L(top)
+	jmp	L(end)
+
+L(b00):	mov	8(vp,n,8), %r9
+	mov	16(vp,n,8), %r10
+	jmp	L(e00)
+
+	ALIGN(16)
+L(top):	mov	16(vp,n,8), %r10
+	mov	(vp,n,8), %r8
+	mov	8(vp,n,8), %r9
+	lea	(%r11,%r8,M), %r12
+	shr	$RSH, %r8
+L(e00):	lea	(%r8,%r9,M), %r13
+	shr	$RSH, %r9
+	mov	24(vp,n,8), %r11
+	lea	(%r9,%r10,M), %r14
+	shr	$RSH, %r10
+	lea	(%r10,%r11,M), %r15
+	shr	$RSH, %r11
+	add	R32(%rax), R32(%rax)		  C restore carry
+	ADCSBB	(up,n,8), %r12
+	ADCSBB	8(up,n,8), %r13
+	ADCSBB	16(up,n,8), %r14
+	ADCSBB	24(up,n,8), %r15
+	mov	%r12, (rp,n,8)
+	mov	%r13, 8(rp,n,8)
+	mov	%r14, 16(rp,n,8)
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r15, 24(rp,n,8)
+	add	$4, n
+	js	L(top)
+L(end):
+
+ifelse(ADDSUB,add,`
+	sub	R32(%r11), R32(%rax)
+	neg	R32(%rax)
+',`
+	add	R32(%r11), R32(%rax)
+	movslq	R32(%rax), %rax
+')
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aorrlsh_n.asm b/mpn/x86_64/aorrlsh_n.asm
new file mode 100644
index 0000000..eb94d2f
--- /dev/null
+++ b/mpn/x86_64/aorrlsh_n.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_addlsh_n and mpn_rsblsh_n.  R = V2^k +- U.
+
+dnl  Copyright 2006, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 3.1	< 3.85 for lshift + add_n
+C AMD K10	 3.1	< 3.85 for lshift + add_n
+C Intel P4	14.6	> 7.33 for lshift + add_n
+C Intel core2	 3.87	> 3.27 for lshift + add_n
+C Intel NHM	 4	> 3.75 for lshift + add_n
+C Intel SBR	(5.8)	> 3.46 for lshift + add_n
+C Intel atom	(7.75)	< 8.75 for lshift + add_n
+C VIA nano	 4.7	< 6.25 for lshift + add_n
+
+C This was written quickly and not optimized at all.  Surely one could get
+C closer to 3 c/l or perhaps even under 3 c/l.  Ideas:
+C   1) Use indexing to save the 3 LEA
+C   2) Write reasonable feed-in code
+C   3) Be more clever about register usage
+C   4) Unroll more, handling CL negation, carry save/restore cost much now
+C   5) Reschedule
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+
+ifdef(`OPERATION_addlsh_n',`
+  define(ADCSBB,       `adc')
+  define(func, mpn_addlsh_n)
+')
+ifdef(`OPERATION_rsblsh_n',`
+  define(ADCSBB,       `sbb')
+  define(func, mpn_rsblsh_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%rbp
+	push	%rbx
+
+	mov	n, %rax
+	xor	R32(%rbx), R32(%rbx)	C clear carry save register
+	mov	R32(%r8), R32(%rcx)	C shift count
+	xor	R32(%rbp), R32(%rbp)	C limb carry
+
+	mov	R32(%rax), R32(%r11)
+	and	$3, R32(%r11)
+	je	L(4)
+	sub	$1, R32(%r11)
+
+L(012):	mov	(vp), %r8
+	mov	%r8, %r12
+	shl	R8(%rcx), %r8
+	or	%rbp, %r8
+	neg	R8(%rcx)
+	mov	%r12, %rbp
+	shr	R8(%rcx), %rbp
+	neg	R8(%rcx)
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	sbb	R32(%rbx), R32(%rbx)
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	sub	$1, R32(%r11)
+	jnc	L(012)
+
+L(4):	sub	$4, %rax
+	jc	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+	mov	%r8, %r12
+	mov	8(vp), %r9
+	mov	%r9, %r13
+	mov	16(vp), %r10
+	mov	%r10, %r14
+	mov	24(vp), %r11
+
+	shl	R8(%rcx), %r8
+	shl	R8(%rcx), %r9
+	shl	R8(%rcx), %r10
+	or	%rbp, %r8
+	mov	%r11, %rbp
+	shl	R8(%rcx), %r11
+
+	neg	R8(%rcx)
+
+	shr	R8(%rcx), %r12
+	shr	R8(%rcx), %r13
+	shr	R8(%rcx), %r14
+	shr	R8(%rcx), %rbp		C used next iteration
+
+	or	%r12, %r9
+	or	%r13, %r10
+	or	%r14, %r11
+
+	neg	R8(%rcx)
+
+	add	R32(%rbx), R32(%rbx)	C restore carry flag
+
+	ADCSBB	(up), %r8
+	ADCSBB	8(up), %r9
+	ADCSBB	16(up), %r10
+	ADCSBB	24(up), %r11
+
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+
+	sbb	R32(%rbx), R32(%rbx)	C save carry flag
+
+	lea	32(up), up
+	lea	32(vp), vp
+	lea	32(rp), rp
+
+	sub	$4, %rax
+	jnc	L(top)
+
+L(end):	add	R32(%rbx), R32(%rbx)
+	ADCSBB	$0, %rbp
+	mov	%rbp, %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aors_err1_n.asm b/mpn/x86_64/aors_err1_n.asm
new file mode 100644
index 0000000..5bc1e27
--- /dev/null
+++ b/mpn/x86_64/aors_err1_n.asm
@@ -0,0 +1,225 @@
+dnl  AMD64 mpn_add_err1_n, mpn_sub_err1_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.75 (degenerates to 3 c/l for some alignments)
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp',	`%r8')
+define(`n',	`%r9')
+define(`cy_param',	`8(%rsp)')
+
+define(`el',	`%rbx')
+define(`eh',	`%rbp')
+define(`t0',	`%r10')
+define(`t1',	`%r11')
+define(`t2',	`%r12')
+define(`t3',	`%r13')
+define(`w0',	`%r14')
+define(`w1',	`%r15')
+
+ifdef(`OPERATION_add_err1_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err1_n)')
+ifdef(`OPERATION_sub_err1_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err1_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err1_n mpn_sub_err1_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, %rax
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	lea	(rp,n,8), rp
+
+	mov	R32(n), R32(%r10)
+	and	$3, R32(%r10)
+	jz	L(0mod4)
+	cmp	$2, R32(%r10)
+	jc	L(1mod4)
+	jz	L(2mod4)
+L(3mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	xor	R32(t0), R32(t0)
+	xor	R32(t1), R32(t1)
+	lea	-24(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	16(yp), el
+	ADCSBB	8(vp,n,8), w1
+	mov	w1, 8(rp,n,8)
+	cmovc	8(yp), t0
+	mov	16(up,n,8), w0
+	ADCSBB	16(vp,n,8), w0
+	mov	w0, 16(rp,n,8)
+	cmovc	(yp), t1
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+	add	t1, el
+	adc	$0, eh
+
+	add	$3, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(16)
+L(0mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	lea	(yp,n,8), yp
+	neg	n
+	jmp	L(loop)
+
+	ALIGN(16)
+L(1mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	lea	-8(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	(yp), el
+	setc	%al		   C save carry
+
+	add	$1, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(16)
+L(2mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	xor	R32(t0), R32(t0)
+	lea	-16(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	8(yp), el
+	ADCSBB	8(vp,n,8), w1
+	mov	w1, 8(rp,n,8)
+	cmovc	(yp), t0
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+
+	add	$2, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(32)
+L(loop):
+	shr	$1, %al		   C restore carry
+	mov	-8(yp), t0
+	mov	$0, R32(t3)
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	cmovnc	t3, t0
+	ADCSBB	8(vp,n,8), w1
+	mov	-16(yp), t1
+	mov	w0, (rp,n,8)
+	mov	16(up,n,8), w0
+	mov	w1, 8(rp,n,8)
+	cmovnc	t3, t1
+	mov	-24(yp), t2
+	ADCSBB	16(vp,n,8), w0
+	cmovnc	t3, t2
+	mov	24(up,n,8), w1
+	ADCSBB	24(vp,n,8), w1
+	cmovc	-32(yp), t3
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+	add	t1, el
+	adc	$0, eh
+	add	t2, el
+	adc	$0, eh
+	mov	w0, 16(rp,n,8)
+	add	t3, el
+	lea	-32(yp), yp
+	adc	$0, eh
+	mov	w1, 24(rp,n,8)
+	add	$4, n
+	jnz	L(loop)
+
+L(end):
+	mov	el, (ep)
+	mov	eh, 8(ep)
+
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aors_err2_n.asm b/mpn/x86_64/aors_err2_n.asm
new file mode 100644
index 0000000..a222117
--- /dev/null
+++ b/mpn/x86_64/aors_err2_n.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_add_err2_n, mpn_sub_err2_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.5
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 6.9
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp1',	`%r8')
+define(`yp2',   `%r9')
+define(`n_param',     `8(%rsp)')
+define(`cy_param',    `16(%rsp)')
+
+define(`cy1',   `%r14')
+define(`cy2',   `%rax')
+
+define(`n',     `%r10')
+
+define(`w',     `%rbx')
+define(`e1l',	`%rbp')
+define(`e1h',	`%r11')
+define(`e2l',	`%r12')
+define(`e2h',	`%r13')
+
+
+ifdef(`OPERATION_add_err2_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err2_n)')
+ifdef(`OPERATION_sub_err2_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err2_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err2_n mpn_sub_err2_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, cy2
+	mov	n_param, n
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+
+	xor	R32(e1l), R32(e1l)
+	xor	R32(e1h), R32(e1h)
+	xor	R32(e2l), R32(e2l)
+	xor	R32(e2h), R32(e2h)
+
+	sub	yp1, yp2
+
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+
+	test	$1, n
+	jnz	L(odd)
+
+	lea	-8(yp1,n,8), yp1
+	neg	n
+	jmp	L(top)
+
+	ALIGN(16)
+L(odd):
+	lea	-16(yp1,n,8), yp1
+	neg	n
+	shr	$1, cy2
+	mov	(up,n,8), w
+	ADCSBB	(vp,n,8), w
+	cmovc	8(yp1), e1l
+	cmovc	8(yp1,yp2), e2l
+	mov	w, (rp,n,8)
+	sbb	cy2, cy2
+	inc	n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):
+	mov	(up,n,8), w
+	shr	$1, cy2		C restore carry
+	ADCSBB	(vp,n,8), w
+	mov	w, (rp,n,8)
+	sbb	cy1, cy1	C generate mask, preserve CF
+
+	mov	8(up,n,8), w
+	ADCSBB	8(vp,n,8), w
+	mov	w, 8(rp,n,8)
+	sbb	cy2, cy2	C generate mask, preserve CF
+
+	mov	(yp1), w	C (e1h:e1l) += cy1 * yp1 limb
+	and	cy1, w
+	add	w, e1l
+	adc	$0, e1h
+
+	and	(yp1,yp2), cy1	C (e2h:e2l) += cy1 * yp2 limb
+	add	cy1, e2l
+	adc	$0, e2h
+
+	mov	-8(yp1), w	C (e1h:e1l) += cy2 * next yp1 limb
+	and	cy2, w
+	add	w, e1l
+	adc	$0, e1h
+
+	mov	-8(yp1,yp2), w	C (e2h:e2l) += cy2 * next yp2 limb
+	and	cy2, w
+	add	w, e2l
+	adc	$0, e2h
+
+	add	$2, n
+	lea	-16(yp1), yp1
+	jnz	L(top)
+L(end):
+
+	mov	e1l, (ep)
+	mov	e1h, 8(ep)
+	mov	e2l, 16(ep)
+	mov	e2h, 24(ep)
+
+	and	$1, %eax	C return carry
+
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aors_err3_n.asm b/mpn/x86_64/aors_err3_n.asm
new file mode 100644
index 0000000..5df1b46
--- /dev/null
+++ b/mpn/x86_64/aors_err3_n.asm
@@ -0,0 +1,156 @@
+dnl  AMD64 mpn_add_err3_n, mpn_sub_err3_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 7.0
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp1',	`%r8')
+define(`yp2',   `%r9')
+define(`yp3_param',   `8(%rsp)')
+define(`n_param',     `16(%rsp)')
+define(`cy_param',    `24(%rsp)')
+
+define(`n',     `%r10')
+define(`yp3',   `%rcx')
+define(`t',     `%rbx')
+
+define(`e1l',	`%rbp')
+define(`e1h',	`%r11')
+define(`e2l',	`%r12')
+define(`e2h',	`%r13')
+define(`e3l',   `%r14')
+define(`e3h',   `%r15')
+
+
+
+ifdef(`OPERATION_add_err3_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err3_n)')
+ifdef(`OPERATION_sub_err3_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err3_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err3_n mpn_sub_err3_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, %rax
+	mov	n_param, n
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	push	ep
+	mov	64(%rsp), yp3       C load from yp3_param
+
+	xor	R32(e1l), R32(e1l)
+	xor	R32(e1h), R32(e1h)
+	xor	R32(e2l), R32(e2l)
+	xor	R32(e2h), R32(e2h)
+	xor	R32(e3l), R32(e3l)
+	xor	R32(e3h), R32(e3h)
+
+	sub	yp1, yp2
+	sub	yp1, yp3
+
+	lea	-8(yp1,n,8), yp1
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+
+	ALIGN(16)
+L(top):
+	shr	$1, %rax		C restore carry
+	mov	(up,n,8), %rax
+	ADCSBB	(vp,n,8), %rax
+	mov	%rax, (rp,n,8)
+	sbb	%rax, %rax		C save carry and generate mask
+
+	mov	(yp1), t
+	and	%rax, t
+	add	t, e1l
+	adc	$0, e1h
+
+	mov	(yp1,yp2), t
+	and	%rax, t
+	add	t, e2l
+	adc	$0, e2h
+
+	mov	(yp1,yp3), t
+	and	%rax, t
+	add	t, e3l
+	adc	$0, e3h
+
+	lea	-8(yp1), yp1
+	inc	n
+	jnz     L(top)
+
+L(end):
+	and	$1, %eax
+	pop	ep
+
+	mov	e1l, (ep)
+	mov	e1h, 8(ep)
+	mov	e2l, 16(ep)
+	mov	e2h, 24(ep)
+	mov	e3l, 32(ep)
+	mov	e3h, 40(ep)
+
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aors_n.asm b/mpn/x86_64/aors_n.asm
new file mode 100644
index 0000000..b63c250
--- /dev/null
+++ b/mpn/x86_64/aors_n.asm
@@ -0,0 +1,178 @@
+dnl  AMD64 mpn_add_n, mpn_sub_n
+
+dnl  Copyright 2003-2005, 2007, 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1.5
+C AMD K10	 1.5
+C AMD bd1	 1.8
+C AMD bd2	 1.74
+C AMD bd3	 ?
+C AMD bd4	 1.78
+C AMD zen	 1.5
+C AMD bt1	 2.54
+C AMD bt2	 2.15
+C Intel P4	11.5
+C Intel core2	 4.9
+C Intel NHM	 5.53
+C Intel SBR	 1.59
+C Intel IBR	 1.55
+C Intel HWL	 1.44
+C Intel BWL	 1.14
+C Intel SKL	 1.21
+C Intel atom	 4
+C Intel SLM	 3
+C VIA nano	 3.25
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')	C rcx
+define(`up',	`%rsi')	C rdx
+define(`vp',	`%rdx')	C r8
+define(`n',	`%rcx')	C r9
+define(`cy',	`%r8')	C rsp+40    (mpn_add_nc and mpn_sub_nc)
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	mov	R32(n), R32(%rax)
+	shr	$2, n
+	and	$3, R32(%rax)
+	bt	$0, %r8			C cy flag <- carry parameter
+	jrcxz	L(lt4)
+
+	mov	(up), %r8
+	mov	8(up), %r9
+	dec	n
+	jmp	L(mid)
+
+EPILOGUE()
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	R32(n), R32(%rax)
+	shr	$2, n
+	and	$3, R32(%rax)
+	jrcxz	L(lt4)
+
+	mov	(up), %r8
+	mov	8(up), %r9
+	dec	n
+	jmp	L(mid)
+
+L(lt4):	dec	R32(%rax)
+	mov	(up), %r8
+	jnz	L(2)
+	ADCSBB	(vp), %r8
+	mov	%r8, (rp)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+L(2):	dec	R32(%rax)
+	mov	8(up), %r9
+	jnz	L(3)
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+L(3):	mov	16(up), %r10
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	setc	R8(%rax)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(top):	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	ADCSBB	24(vp), %r11
+	mov	%r8, (rp)
+	lea	32(up), up
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	dec	n
+	mov	%r11, 24(rp)
+	lea	32(vp), vp
+	mov	(up), %r8
+	mov	8(up), %r9
+	lea	32(rp), rp
+L(mid):	mov	16(up), %r10
+	mov	24(up), %r11
+	jnz	L(top)
+
+L(end):	lea	32(up), up
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	ADCSBB	24(vp), %r11
+	lea	32(vp), vp
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+	lea	32(rp), rp
+
+	inc	R32(%rax)
+	dec	R32(%rax)
+	jnz	L(lt4)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/aorsmul_1.asm b/mpn/x86_64/aorsmul_1.asm
new file mode 100644
index 0000000..3e9705a
--- /dev/null
+++ b/mpn/x86_64/aorsmul_1.asm
@@ -0,0 +1,190 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.52
+C AMD K10	 2.51
+C AMD bd1	 4.43
+C AMD bd2	 5.03	 5.63
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 ?
+C AMD bobcat	 6.20
+C AMD jaguar	 5.57	 6.56
+C Intel P4	14.9	17.1
+C Intel core2	 5.15
+C Intel NHM	 4.93
+C Intel SBR	 3.95
+C Intel IBR	 3.75
+C Intel HWL	 3.62
+C Intel BWL	 2.53
+C Intel SKL	 2.53
+C Intel atom	21.3
+C Intel SLM	 9.0
+C VIA nano	 5.0
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * The loop is great, but the prologue and epilogue code was quickly written.
+C    Tune it!
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vl',      `%rcx')   C r9
+
+define(`n',       `%r11')
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',  `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+IFDOS(`	define(`up', ``%rsi'')	') dnl
+IFDOS(`	define(`rp', ``%rcx'')	') dnl
+IFDOS(`	define(`vl', ``%r9'')	') dnl
+IFDOS(`	define(`r9', ``rdi'')	') dnl
+IFDOS(`	define(`n',  ``%r8'')	') dnl
+IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	mov	(up), %rax		C read first u limb early
+	push	%rbx
+IFSTD(`	mov	n_param, %rbx   ')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %rbx         ')
+	mul	vl
+IFSTD(`	mov	%rbx, n         ')
+
+	and	$3, R32(%rbx)
+	jz	L(b0)
+	cmp	$2, R32(%rbx)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	dec	n
+	jne	L(gt1)
+	ADDSUB	%rax, (rp)
+	jmp	L(ret)
+L(gt1):	lea	8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r9
+	mov	(up,n,8), %rax
+	mov	%rdx, %r8
+	jmp	L(L1)
+
+L(b0):	lea	(up,n,8), up
+	lea	-16(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	mov	%rax, %r8
+	mov	%rdx, %rbx
+	jmp	 L(L0)
+
+L(b3):	lea	-8(up,n,8), up
+	lea	-24(rp,n,8), rp
+	neg	n
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	jmp	L(L3)
+
+L(b2):	lea	-16(up,n,8), up
+	lea	-32(rp,n,8), rp
+	neg	n
+	xor	%r8, %r8
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%rdx, %r9
+	jmp	L(L2)
+
+	ALIGN(16)
+L(top):	ADDSUB	%r10, (rp,n,8)
+	adc	%rax, %r9
+	mov	(up,n,8), %rax
+	adc	%rdx, %r8
+	mov	$0, R32(%r10)
+L(L1):	mul	vl
+	ADDSUB	%r9, 8(rp,n,8)
+	adc	%rax, %r8
+	adc	%rdx, %rbx
+L(L0):	mov	8(up,n,8), %rax
+	mul	vl
+	ADDSUB	%r8, 16(rp,n,8)
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+L(L3):	mov	16(up,n,8), %rax
+	mul	vl
+	ADDSUB	%rbx, 24(rp,n,8)
+	mov	$0, R32(%r8)		C zero
+	mov	%r8, %rbx		C zero
+	adc	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%r8, %r9		C zero
+	adc	%rdx, %r9
+L(L2):	mul	vl
+	add	$4, n
+	js	 L(top)
+
+	ADDSUB	%r10, (rp,n,8)
+	adc	%rax, %r9
+	adc	%r8, %rdx
+	ADDSUB	%r9, 8(rp,n,8)
+L(ret):	adc	$0, %rdx
+	mov	%rdx, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/bdiv_dbm1c.asm b/mpn/x86_64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..bbfa9e0
--- /dev/null
+++ b/mpn/x86_64/bdiv_dbm1c.asm
@@ -0,0 +1,106 @@
+dnl  x86_64 mpn_bdiv_dbm1.
+
+dnl  Copyright 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.25
+C AMD K10	 2.25
+C Intel P4	12.5
+C Intel core2	 4
+C Intel NHM	 3.75
+C Intel SBR	 3.6
+C Intel atom	20
+C VIA nano	 4
+
+C TODO
+C  * Optimise feed-in code.
+
+C INPUT PARAMETERS
+define(`qp',	  `%rdi')
+define(`up',	  `%rsi')
+define(`n_param', `%rdx')
+define(`bd',	  `%rcx')
+define(`cy',	  `%r8')
+
+define(`n',       `%r9')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	mov	(up), %rax
+	mov	n_param, n
+	mov	R32(n_param), R32(%r11)
+	mul	bd
+	lea	(up,n,8), up
+	lea	(qp,n,8), qp
+	neg	n
+	and	$3, R32(%r11)
+	jz	L(lo0)
+	lea	-4(n,%r11), n
+	cmp	$2, R32(%r11)
+	jc	L(lo1)
+	jz	L(lo2)
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mov	(up,n,8), %rax
+	mul	bd
+L(lo0):	sub	%rax, %r8
+	mov	%r8, (qp,n,8)
+	sbb	%rdx, %r8
+	mov	8(up,n,8), %rax
+	mul	bd
+L(lo3):	sub	%rax, %r8
+	mov	%r8, 8(qp,n,8)
+	sbb	%rdx, %r8
+	mov	16(up,n,8), %rax
+	mul	bd
+L(lo2):	sub	%rax, %r8
+	mov	%r8, 16(qp,n,8)
+	sbb	%rdx, %r8
+	mov	24(up,n,8), %rax
+	mul	bd
+L(lo1):	sub	%rax, %r8
+	mov	%r8, 24(qp,n,8)
+	sbb	%rdx, %r8
+	add	$4, n
+	jnz	L(top)
+
+	mov	%r8, %rax
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/bdiv_q_1.asm b/mpn/x86_64/bdiv_q_1.asm
new file mode 100644
index 0000000..a6b36e9
--- /dev/null
+++ b/mpn/x86_64/bdiv_q_1.asm
@@ -0,0 +1,195 @@
+dnl  AMD64 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Copyright 2001, 2002, 2004-2006, 2010-2012, 2017 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	    cycles/limb    cycles/limb
+C	       norm	       unorm
+C AMD K8,K9	11		11
+C AMD K10	11		11
+C AMD bull	13.5		14
+C AMD pile	14		15
+C AMD steam
+C AMD excavator
+C AMD bobcat	14		14
+C AMD jaguar	14.5		15
+C Intel P4	33		33
+C Intel core2	13.5		13.25
+C Intel NHM	14		14
+C Intel SBR	8		8.25
+C Intel IBR	7.75		7.85
+C Intel HWL	8		8
+C Intel BWL	8		8
+C Intel SKL	8		8
+C Intel atom	34		36
+C Intel SLM	13.7		13.5
+C VIA nano	19.25		19.25	needs re-measuring
+
+C INPUT PARAMETERS
+define(`rp',		`%rdi')
+define(`up',		`%rsi')
+define(`n',		`%rdx')
+define(`d',		`%rcx')
+define(`di',		`%r8')		C	just mpn_pi1_bdiv_q_1
+define(`ncnt',		`%r9')		C	just mpn_pi1_bdiv_q_1
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	%rcx, %rax
+	xor	R32(%rcx), R32(%rcx)	C ncnt count
+	mov	%rdx, %r10
+
+	bt	$0, R32(%rax)
+	jnc	L(evn)			C skip bsf unless divisor is even
+
+L(odd):	mov	%rax, %rbx
+	shr	R32(%rax)
+	and	$127, R32(%rax)		C d/2, 7 bits
+
+	LEA(	binvert_limb_table, %rdx)
+
+	movzbl	(%rdx,%rax), R32(%rax)	C inv 8 bits
+
+	mov	%rbx, %r11		C d without twos
+
+	lea	(%rax,%rax), R32(%rdx)	C 2*inv
+	imul	R32(%rax), R32(%rax)	C inv*inv
+	imul	R32(%rbx), R32(%rax)	C inv*inv*d
+	sub	R32(%rax), R32(%rdx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rdx,%rdx), R32(%rax)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+	imul	R32(%rbx), R32(%rdx)	C inv*inv*d
+	sub	R32(%rdx), R32(%rax)	C inv = 2*inv - inv*inv*d, 32 bits
+
+	lea	(%rax,%rax), %r8	C 2*inv
+	imul	%rax, %rax		C inv*inv
+	imul	%rbx, %rax		C inv*inv*d
+	sub	%rax, %r8		C inv = 2*inv - inv*inv*d, 64 bits
+
+	jmp	L(pi1)
+
+L(evn):	bsf	%rax, %rcx
+	shr	R8(%rcx), %rax
+	jmp	L(odd)
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	push	%rbx
+
+	mov	%rcx, %r11		C d
+	mov	%rdx, %r10		C n
+	mov	%r9, %rcx		C ncnt
+
+L(pi1):	mov	(up), %rax		C up[0]
+
+	dec	%r10
+	jz	L(one)
+
+	lea	8(up,%r10,8), up	C up end
+	lea	(rp,%r10,8), rp		C rp end
+	neg	%r10			C -n
+
+	test	R32(%rcx), R32(%rcx)
+	jnz	L(unorm)		C branch if count != 0
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(nent)
+
+	ALIGN(8)
+L(ntop):mul	%r11			C carry limb in rdx	0 10
+	mov	-8(up,%r10,8), %rax	C
+	sub	%rbx, %rax		C apply carry bit
+	setc	R8(%rbx)		C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, R32(%rbx)		C			6
+L(nent):imul	%r8, %rax		C			6
+	mov	%rax, (rp,%r10,8)	C
+	inc	%r10			C
+	jnz	L(ntop)
+
+	mov	-8(up), %r9		C up high limb
+	jmp	L(com)
+
+L(unorm):
+	mov	(up,%r10,8), %r9	C up[1]
+	shr	R8(%rcx), %rax		C
+	neg	R32(%rcx)
+	shl	R8(%rcx), %r9		C
+	neg	R32(%rcx)
+	or	%r9, %rax
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(uent)
+
+	ALIGN(8)
+L(utop):mul	%r11			C carry limb in rdx	0 10
+	mov	(up,%r10,8), %rax	C
+	shl	R8(%rcx), %rax		C
+	neg	R32(%rcx)
+	or	%r9, %rax
+	sub	%rbx, %rax		C apply carry bit
+	setc	R8(%rbx)		C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, R32(%rbx)		C			6
+L(uent):imul	%r8, %rax		C			6
+	mov	(up,%r10,8), %r9	C
+	shr	R8(%rcx), %r9		C
+	neg	R32(%rcx)
+	mov	%rax, (rp,%r10,8)	C
+	inc	%r10			C
+	jnz	L(utop)
+
+L(com):	mul	%r11			C carry limb in rdx
+	sub	%rbx, %r9		C apply carry bit
+	sub	%rdx, %r9		C apply carry limb
+	imul	%r8, %r9
+	mov	%r9, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(one):	shr	R8(%rcx), %rax
+	imul	%r8, %rax
+	mov	%rax, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/cnd_aors_n.asm b/mpn/x86_64/cnd_aors_n.asm
new file mode 100644
index 0000000..36b2e84
--- /dev/null
+++ b/mpn/x86_64/cnd_aors_n.asm
@@ -0,0 +1,183 @@
+dnl  AMD64 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2
+C AMD K10	 2
+C AMD bd1	 2.32
+C AMD bobcat	 3
+C Intel P4	13
+C Intel core2	 2.9
+C Intel NHM	 2.8
+C Intel SBR	 2.4
+C Intel atom	 5.33
+C VIA nano	 3
+
+C NOTES
+C  * It might seem natural to use the cmov insn here, but since this function
+C    is supposed to have the exact same execution pattern for cnd true and
+C    false, and since cmov's documentation is not clear about whether it
+C    actually reads both source operands and writes the register for a false
+C    condition, we cannot use it.
+C  * Two cases could be optimised: (1) cnd_add_n could use ADCSBB-from-memory
+C    to save one insn/limb, and (2) when up=rp cnd_add_n and cnd_sub_n could use
+C    ADCSBB-to-memory, again saving 1 insn/limb.
+C  * This runs optimally at decoder bandwidth on K10.  It has not been tuned
+C    for any other processor.
+
+C INPUT PARAMETERS
+define(`cnd',	`%rdi')	dnl rcx
+define(`rp',	`%rsi')	dnl rdx
+define(`up',	`%rdx')	dnl r8
+define(`vp',	`%rcx')	dnl r9
+define(`n',	`%r8')	dnl rsp+40
+
+ifdef(`OPERATION_cnd_add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), R32(%r8)')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+
+	neg	cnd
+	sbb	cnd, cnd		C make cnd mask
+
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+
+	mov	R32(n), R32(%rax)
+	neg	n
+	and	$3, R32(%rax)
+	jz	L(top)			C carry-save reg rax = 0 in this arc
+	cmp	$2, R32(%rax)
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	mov	(vp,n,8), %r12
+	mov	8(vp,n,8), %r13
+	mov	16(vp,n,8), %r14
+	and	cnd, %r12
+	mov	(up,n,8), %r10
+	and	cnd, %r13
+	mov	8(up,n,8), %rbx
+	and	cnd, %r14
+	mov	16(up,n,8), %rbp
+	ADDSUB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	ADCSBB	%r13, %rbx
+	mov	%rbx, 8(rp,n,8)
+	ADCSBB	%r14, %rbp
+	mov	%rbp, 16(rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$3, n
+	js	L(top)
+	jmp	L(end)
+
+L(b2):	mov	(vp,n,8), %r12
+	mov	8(vp,n,8), %r13
+	mov	(up,n,8), %r10
+	and	cnd, %r12
+	mov	8(up,n,8), %rbx
+	and	cnd, %r13
+	ADDSUB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	ADCSBB	%r13, %rbx
+	mov	%rbx, 8(rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$2, n
+	js	L(top)
+	jmp	L(end)
+
+L(b1):	mov	(vp,n,8), %r12
+	mov	(up,n,8), %r10
+	and	cnd, %r12
+	ADDSUB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$1, n
+	jns	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp,n,8), %r12
+	mov	8(vp,n,8), %r13
+	mov	16(vp,n,8), %r14
+	mov	24(vp,n,8), %r11
+	and	cnd, %r12
+	mov	(up,n,8), %r10
+	and	cnd, %r13
+	mov	8(up,n,8), %rbx
+	and	cnd, %r14
+	mov	16(up,n,8), %rbp
+	and	cnd, %r11
+	mov	24(up,n,8), %r9
+	add	R32(%rax), R32(%rax)	C restore carry
+	ADCSBB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	ADCSBB	%r13, %rbx
+	mov	%rbx, 8(rp,n,8)
+	ADCSBB	%r14, %rbp
+	mov	%rbp, 16(rp,n,8)
+	ADCSBB	%r11, %r9
+	mov	%r9, 24(rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$4, n
+	js	L(top)
+
+L(end):	neg	R32(%rax)
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/com.asm b/mpn/x86_64/com.asm
new file mode 100644
index 0000000..31bc4b6
--- /dev/null
+++ b/mpn/x86_64/com.asm
@@ -0,0 +1,95 @@
+dnl  AMD64 mpn_com.
+
+dnl  Copyright 2004-2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	    cycles/limb
+C AMD K8,K9	 1.25
+C AMD K10	 1.25
+C Intel P4	 2.78
+C Intel core2	 1.1
+C Intel corei	 1.5
+C Intel atom	 ?
+C VIA nano	 2
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`n',`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_com)
+	FUNC_ENTRY(3)
+	movq	(up), %r8
+	movl	R32(%rdx), R32(%rax)
+	leaq	(up,n,8), up
+	leaq	(rp,n,8), rp
+	negq	n
+	andl	$3, R32(%rax)
+	je	L(b00)
+	cmpl	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	notq	%r8
+	movq	%r8, (rp,n,8)
+	decq	n
+	jmp	L(e11)
+L(b10):	addq	$-2, n
+	jmp	L(e10)
+	.byte	0x90,0x90,0x90,0x90,0x90,0x90
+L(b01):	notq	%r8
+	movq	%r8, (rp,n,8)
+	incq	n
+	jz	L(ret)
+
+L(oop):	movq	(up,n,8), %r8
+L(b00):	movq	8(up,n,8), %r9
+	notq	%r8
+	notq	%r9
+	movq	%r8, (rp,n,8)
+	movq	%r9, 8(rp,n,8)
+L(e11):	movq	16(up,n,8), %r8
+L(e10):	movq	24(up,n,8), %r9
+	notq	%r8
+	notq	%r9
+	movq	%r8, 16(rp,n,8)
+	movq	%r9, 24(rp,n,8)
+	addq	$4, n
+	jnc	L(oop)
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/copyd.asm b/mpn/x86_64/copyd.asm
new file mode 100644
index 0000000..c8f9d84
--- /dev/null
+++ b/mpn/x86_64/copyd.asm
@@ -0,0 +1,93 @@
+dnl  AMD64 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1
+C AMD K10	 1
+C AMD bd1	 1.36
+C AMD bobcat	 1.71
+C Intel P4	 2-3
+C Intel core2	 1
+C Intel NHM	 1
+C Intel SBR	 1
+C Intel atom	 2
+C VIA nano	 2
+
+
+IFSTD(`define(`rp',`%rdi')')
+IFSTD(`define(`up',`%rsi')')
+IFSTD(`define(`n', `%rdx')')
+
+IFDOS(`define(`rp',`%rcx')')
+IFDOS(`define(`up',`%rdx')')
+IFDOS(`define(`n', `%r8')')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_copyd)
+	lea	-8(up,n,8), up
+	lea	(rp,n,8), rp
+	sub	$4, n
+	jc	L(end)
+	nop
+
+L(top):	mov	(up), %rax
+	mov	-8(up), %r9
+	lea	-32(rp), rp
+	mov	-16(up), %r10
+	mov	-24(up), %r11
+	lea	-32(up), up
+	mov	%rax, 24(rp)
+	mov	%r9, 16(rp)
+	sub	$4, n
+	mov	%r10, 8(rp)
+	mov	%r11, (rp)
+	jnc	L(top)
+
+L(end):	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	%rax, -8(rp)
+	lea	-8(rp), rp
+	lea	-8(up), up
+1:	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	-8(up), %r9
+	mov	%rax, -8(rp)
+	mov	%r9, -16(rp)
+1:	ret
+EPILOGUE()
diff --git a/mpn/x86_64/copyi.asm b/mpn/x86_64/copyi.asm
new file mode 100644
index 0000000..9258bc5
--- /dev/null
+++ b/mpn/x86_64/copyi.asm
@@ -0,0 +1,92 @@
+dnl  AMD64 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1
+C AMD K10	 1
+C AMD bd1	 1.36
+C AMD bobcat	 1.71
+C Intel P4	 2-3
+C Intel core2	 1
+C Intel NHM	 1
+C Intel SBR	 1
+C Intel atom	 2
+C VIA nano	 2
+
+
+IFSTD(`define(`rp',`%rdi')')
+IFSTD(`define(`up',`%rsi')')
+IFSTD(`define(`n', `%rdx')')
+
+IFDOS(`define(`rp',`%rcx')')
+IFDOS(`define(`up',`%rdx')')
+IFDOS(`define(`n', `%r8')')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+	.byte	0,0,0,0,0,0
+PROLOGUE(mpn_copyi)
+	lea	-8(rp), rp
+	sub	$4, n
+	jc	L(end)
+
+L(top):	mov	(up), %rax
+	mov	8(up), %r9
+	lea	32(rp), rp
+	mov	16(up), %r10
+	mov	24(up), %r11
+	lea	32(up), up
+	mov	%rax, -24(rp)
+	mov	%r9, -16(rp)
+	sub	$4, n
+	mov	%r10, -8(rp)
+	mov	%r11, (rp)
+	jnc	L(top)
+
+L(end):	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	%rax, 8(rp)
+	lea	8(rp), rp
+	lea	8(up), up
+1:	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	8(up), %r9
+	mov	%rax, 8(rp)
+	mov	%r9, 16(rp)
+1:	ret
+EPILOGUE()
diff --git a/mpn/x86_64/darwin.m4 b/mpn/x86_64/darwin.m4
new file mode 100644
index 0000000..7771476
--- /dev/null
+++ b/mpn/x86_64/darwin.m4
@@ -0,0 +1,82 @@
+divert(-1)
+dnl  Copyright 2008, 2011, 2012 Free Software Foundation, Inc.
+dnl
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`DARWIN')
+
+define(`LEA',`dnl
+ifdef(`PIC',
+	`lea	$1(%rip), $2'
+,
+	`movabs	`$'$1, $2')
+')
+
+dnl  Usage: CALL(funcname)
+dnl
+dnl  Simply override the definition in x86_64-defs.m4.
+
+define(`CALL',`call	GSYM_PREFIX`'$1')
+define(`TCALL',`jmp	GSYM_PREFIX`'$1')
+
+
+dnl  Usage: JUMPTABSECT
+dnl
+dnl  CAUTION: Do not put anything sensible here, like RODATA.  That works with
+dnl  some Darwin tool chains, but silently breaks with other.  (Note that
+dnl  putting jump tables in the text segment is a really poor idea for many PC
+dnl  processors, since they cannot cache the same thing in both L1D and L2I.)
+
+define(`JUMPTABSECT', `.text')
+
+
+dnl  Usage: JMPENT(targlabel,tablabel)
+
+define(`JMPENT',`dnl
+ifdef(`PIC',
+	`.set	$1_tmp, $1-$2
+	.long	$1_tmp'
+,
+	`.quad	$1'
+)')
+
+dnl  Target ABI macros.  For Darwin we override IFELF (and leave default for
+dnl  IFDOS and IFSTD).
+
+define(`IFELF',   `')
+
+
+dnl  Usage: PROTECT(symbol)
+dnl
+dnl  Used for private GMP symbols that should never be overridden by users.
+dnl  This can save reloc entries and improve shlib sharing as well as
+dnl  application startup times
+
+define(`PROTECT',  `.private_extern $1')
+
+
+divert`'dnl
diff --git a/mpn/x86_64/div_qr_1n_pi1.asm b/mpn/x86_64/div_qr_1n_pi1.asm
new file mode 100644
index 0000000..66c4f32
--- /dev/null
+++ b/mpn/x86_64/div_qr_1n_pi1.asm
@@ -0,0 +1,247 @@
+dnl  x86-64 mpn_div_qr_1n_pi1
+dnl  -- Divide an mpn number by a normalized single-limb number,
+dnl     using a single-limb inverse.
+
+dnl  Contributed to the GNU project by Niels Möller
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C		c/l
+C AMD K8,K9	13
+C AMD K10	13
+C AMD bull	16.5
+C AMD pile	15
+C AMD steam	 ?
+C AMD bobcat	16
+C AMD jaguar	 ?
+C Intel P4	47	poor
+C Intel core	19.25
+C Intel NHM	18
+C Intel SBR	15	poor
+C Intel IBR	13
+C Intel HWL	11.7
+C Intel BWL	 ?
+C Intel atom	52	very poor
+C VIA nano	19
+
+
+C INPUT Parameters
+define(`QP', `%rdi')
+define(`UP', `%rsi')
+define(`UN_INPUT', `%rdx')
+define(`U1', `%rcx')	C Also in %rax
+define(`D', `%r8')
+define(`DINV', `%r9')
+
+C Invariants
+define(`B2', `%rbp')
+define(`B2md', `%rbx')
+
+C Variables
+define(`UN', `%r8')	C Overlaps D input
+define(`T', `%r10')
+define(`U0', `%r11')
+define(`U2', `%r12')
+define(`Q0', `%r13')
+define(`Q1', `%r14')
+define(`Q2', `%r15')
+
+ABI_SUPPORT(STD64)
+
+	ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_div_qr_1n_pi1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	dec	UN_INPUT
+	jnz	L(first)
+
+	C Just a single 2/1 division.
+	C T, U0 are allocated in scratch registers
+	lea	1(U1), T
+	mov	U1, %rax
+	mul	DINV
+	mov	(UP), U0
+	add	U0, %rax
+	adc	T, %rdx
+	mov	%rdx, T
+	imul	D, %rdx
+	sub	%rdx, U0
+	cmp	U0, %rax
+	lea	(U0, D), %rax
+	cmovnc	U0, %rax
+	sbb	$0, T
+	cmp	D, %rax
+	jc	L(single_div_done)
+	sub	D, %rax
+	add	$1, T
+L(single_div_done):
+	mov	T, (QP)
+	FUNC_EXIT()
+	ret
+L(first):
+	C FIXME: Could delay some of these until we enter the loop.
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+	push	%rbp
+
+	mov	D, B2
+	imul	DINV, B2
+	neg	B2
+	mov	B2, B2md
+	sub	D, B2md
+
+	C D not needed until final reduction
+	push	D
+	mov	UN_INPUT, UN	C Clobbers D
+
+	mov	DINV, %rax
+	mul	U1
+	mov	%rax, Q0
+	add	U1, %rdx
+	mov	%rdx, T
+
+	mov	B2, %rax
+	mul	U1
+	mov	-8(UP, UN, 8), U0
+	mov	(UP, UN, 8), U1
+	mov	T, (QP, UN, 8)
+	add	%rax, U0
+	adc	%rdx, U1
+	sbb	U2, U2
+	dec	UN
+	mov	U1, %rax
+	jz	L(final)
+
+	ALIGN(16)
+
+	C Loop is 28 instructions, 30 decoder slots, should run in 10 cycles.
+	C At entry, %rax holds an extra copy of U1
+L(loop):
+	C {Q2, Q1, Q0} <-- DINV * U1 + B (Q0 + U2 DINV) + B^2 U2
+	C Remains to add in B (U1 + c)
+	mov	DINV, Q1
+	mov	U2, Q2
+	and	U2, Q1
+	neg	Q2
+	mul	DINV
+	add	%rdx, Q1
+	adc	$0, Q2
+	add	Q0, Q1
+	mov	%rax, Q0
+	mov	B2, %rax
+	lea	(B2md, U0), T
+	adc	$0, Q2
+
+	C {U2, U1, U0} <-- (U0 + U2 B2 -c U) B + U1 B2 + u
+	mul	U1
+	and	B2, U2
+	add	U2, U0
+	cmovnc	U0, T
+
+	C {QP+UN, ...} <-- {QP+UN, ...} + {Q2, Q1} + U1 + c
+	adc	U1, Q1
+	mov	-8(UP, UN, 8), U0
+	adc	Q2, 8(QP, UN, 8)
+	jc	L(q_incr)
+L(q_incr_done):
+	add	%rax, U0
+	mov	T, %rax
+	adc	%rdx, %rax
+	mov	Q1, (QP, UN, 8)
+	sbb	U2, U2
+	dec	UN
+	mov	%rax, U1
+	jnz	L(loop)
+
+L(final):
+	pop	D
+
+	mov	U2, Q1
+	and	D, U2
+	sub	U2, %rax
+	neg	Q1
+
+	mov	%rax, U1
+	sub	D, %rax
+	cmovc	U1, %rax
+	sbb	$-1, Q1
+
+	lea	1(%rax), T
+	mul	DINV
+	add	U0, %rax
+	adc	T, %rdx
+	mov	%rdx, T
+	imul	D, %rdx
+	sub	%rdx, U0
+	cmp	U0, %rax
+	lea	(U0, D), %rax
+	cmovnc	U0, %rax
+	sbb	$0, T
+	cmp	D, %rax
+	jc	L(div_done)
+	sub	D, %rax
+	add	$1, T
+L(div_done):
+	add	T, Q0
+	mov	Q0, (QP)
+	adc	Q1, 8(QP)
+	jnc	L(done)
+L(final_q_incr):
+	addq	$1, 16(QP)
+	lea	8(QP), QP
+	jc	L(final_q_incr)
+
+L(done):
+	pop	%rbp
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(q_incr):
+	C U1 is not live, so use it for indexing
+	lea	16(QP, UN, 8), U1
+L(q_incr_loop):
+	addq	$1, (U1)
+	jnc	L(q_incr_done)
+	lea	8(U1), U1
+	jmp	L(q_incr_loop)
+EPILOGUE()
diff --git a/mpn/x86_64/div_qr_2n_pi1.asm b/mpn/x86_64/div_qr_2n_pi1.asm
new file mode 100644
index 0000000..6b1f5b1
--- /dev/null
+++ b/mpn/x86_64/div_qr_2n_pi1.asm
@@ -0,0 +1,158 @@
+dnl  x86-64 mpn_div_qr_2n_pi1
+dnl  -- Divide an mpn number by a normalized 2-limb number,
+dnl     using a single-limb inverse.
+
+dnl  Copyright 2007, 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C		c/l
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`rp',		`%rsi')
+define(`up_param',	`%rdx')
+define(`un',		`%rcx')
+define(`d1',		`%r8')
+define(`d0',		`%r9')
+define(`di_param',	`8(%rsp)')
+
+define(`di',		`%r10')
+define(`up',		`%r11')
+define(`u2',		`%rbx')
+define(`u1',		`%r12')
+define(`t1',		`%r13')
+define(`t0',		`%r14')
+define(`md1',		`%r15')
+
+C TODO
+C * Store qh in the same stack slot as di_param, instead of pushing
+C   it. (we could put it in register %rbp, but then we would need to
+C   save and restore that instead, which doesn't seem like a win).
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_div_qr_2n_pi1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+IFDOS(`define(`di_param', `72(%rsp)')')
+	mov	di_param, di
+	mov	up_param, up
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+
+	mov	-16(up, un, 8), u1
+	mov	-8(up, un, 8), u2
+
+	mov	u1, t0
+	mov	u2, t1
+	sub	d0, t0
+	sbb	d1, t1
+	cmovnc  t0, u1
+	cmovnc	t1, u2
+	C push qh which is !carry
+	sbb	%rax, %rax
+	inc	%rax
+	push	%rax
+	lea	-2(un), un
+	mov	d1, md1
+	neg	md1
+
+	jmp	L(next)
+
+	ALIGN(16)
+L(loop):
+	C udiv_qr_3by2 (q,u2,u1,u2,u1,n0, d1,d0,di)
+	C Based on the optimized divrem_2.asm code.
+
+	mov	di, %rax
+	mul	u2
+	mov	u1, t0
+	add	%rax, t0	C q0 in t0
+	adc	u2, %rdx
+	mov	%rdx, t1	C q in t1
+	imul	md1, %rdx
+	mov	d0, %rax
+	lea	(%rdx, u1), u2
+	mul	t1
+	mov	(up, un, 8), u1
+	sub	d0, u1
+	sbb	d1, u2
+	sub	%rax, u1
+	sbb	%rdx, u2
+	xor	R32(%rax), R32(%rax)
+	xor	R32(%rdx), R32(%rdx)
+	cmp	t0, u2
+	cmovnc	d0, %rax
+	cmovnc	d1, %rdx
+	adc	$0, t1
+	nop
+	add	%rax, u1
+	adc	%rdx, u2
+	cmp	d1, u2
+	jae	L(fix)
+L(bck):
+	mov	t1, (qp, un, 8)
+L(next):
+	sub	$1, un
+	jnc	L(loop)
+L(end):
+	mov	u2, 8(rp)
+	mov	u1, (rp)
+
+	C qh on stack
+	pop	%rax
+
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(fix):	C Unlikely update. u2 >= d1
+	seta	%dl
+	cmp	d0, u1
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	t1
+	sub	d0, u1
+	sbb	d1, u2
+	jmp	L(bck)
+EPILOGUE()
diff --git a/mpn/x86_64/div_qr_2u_pi1.asm b/mpn/x86_64/div_qr_2u_pi1.asm
new file mode 100644
index 0000000..2561fd4
--- /dev/null
+++ b/mpn/x86_64/div_qr_2u_pi1.asm
@@ -0,0 +1,200 @@
+dnl  x86-64 mpn_div_qr_2u_pi1
+dnl  -- Divide an mpn number by an unnormalized 2-limb number,
+dnl     using a single-limb inverse and shifting the dividend on the fly.
+
+dnl  Copyright 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C		c/l
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`rp',		`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx') dnl %rcx needed for shift count
+define(`d1',		`%r8')
+define(`d0',		`%r9')
+define(`shift_param',	`FRAME+8(%rsp)')
+define(`di_param',	`FRAME+16(%rsp)')
+
+define(`di',		`%r10')
+define(`up',		`%r11')
+define(`un',		`%rbp')
+define(`u2',		`%rbx')
+define(`u1',		`%r12')
+define(`u0',		`%rsi') dnl Same as rp, which is saved and restored.
+define(`t1',		`%r13')
+define(`t0',		`%r14')
+define(`md1',		`%r15')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+deflit(`FRAME', 0)
+PROLOGUE(mpn_div_qr_2u_pi1)
+	mov	di_param, di
+	mov	up_param, up
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+	push	%rbp
+	push	rp
+deflit(`FRAME', 56)
+	lea	-2(un_param), un
+	mov	d1, md1
+	neg	md1
+
+	C int parameter, 32 bits only
+	movl	shift_param, R32(%rcx)
+
+	C FIXME: Different code for SHLD_SLOW
+
+	xor	R32(u2), R32(u2)
+	mov	8(up, un, 8), u1
+	shld	%cl, u1, u2
+	C Remains to read (up, un, 8) and shift u1, u0
+	C udiv_qr_3by2 (qh,u2,u1,u2,u1,n0, d1,d0,di)
+	mov	di, %rax
+	mul	u2
+	mov	(up, un, 8), u0
+	shld	%cl, u0, u1
+	mov	u1, t0
+	add	%rax, t0	C q0 in t0
+	adc	u2, %rdx
+	mov	%rdx, t1	C q in t1
+	imul	md1, %rdx
+	mov	d0, %rax
+	lea	(%rdx, u1), u2
+	mul	t1
+	mov	u0, u1
+	shl	%cl, u1
+	sub	d0, u1
+	sbb	d1, u2
+	sub	%rax, u1
+	sbb	%rdx, u2
+	xor	R32(%rax), R32(%rax)
+	xor	R32(%rdx), R32(%rdx)
+	cmp	t0, u2
+	cmovnc	d0, %rax
+	cmovnc	d1, %rdx
+	adc	$0, t1
+	nop
+	add	%rax, u1
+	adc	%rdx, u2
+	cmp	d1, u2
+	jae	L(fix_qh)
+L(bck_qh):
+	push	t1	C push qh on stack
+
+	jmp	L(next)
+
+	ALIGN(16)
+L(loop):
+	C udiv_qr_3by2 (q,u2,u1,u2,u1,n0, d1,d0,di)
+	C Based on the optimized divrem_2.asm code.
+
+	mov	di, %rax
+	mul	u2
+	mov	(up, un, 8), u0
+	xor	R32(t1), R32(t1)
+	shld	%cl, u0, t1
+	or	t1, u1
+	mov	u1, t0
+	add	%rax, t0	C q0 in t0
+	adc	u2, %rdx
+	mov	%rdx, t1	C q in t1
+	imul	md1, %rdx
+	mov	d0, %rax
+	lea	(%rdx, u1), u2
+	mul	t1
+	mov	u0, u1
+	shl	%cl, u1
+	sub	d0, u1
+	sbb	d1, u2
+	sub	%rax, u1
+	sbb	%rdx, u2
+	xor	R32(%rax), R32(%rax)
+	xor	R32(%rdx), R32(%rdx)
+	cmp	t0, u2
+	cmovnc	d0, %rax
+	cmovnc	d1, %rdx
+	adc	$0, t1
+	nop
+	add	%rax, u1
+	adc	%rdx, u2
+	cmp	d1, u2
+	jae	L(fix)
+L(bck):
+	mov	t1, (qp, un, 8)
+L(next):
+	sub	$1, un
+	jnc	L(loop)
+L(end):
+	C qh on stack
+	pop	%rax
+	pop	rp
+	shrd	%cl, u2, u1
+	shr	%cl, u2
+	mov	u2, 8(rp)
+	mov	u1, (rp)
+
+	pop	%rbp
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	ret
+
+L(fix):	C Unlikely update. u2 >= d1
+	seta	%dl
+	cmp	d0, u1
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	t1
+	sub	d0, u1
+	sbb	d1, u2
+	jmp	L(bck)
+
+C Duplicated, just jumping back to a different address.
+L(fix_qh):	C Unlikely update. u2 >= d1
+	seta	%dl
+	cmp	d0, u1
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck_qh)
+	inc	t1
+	sub	d0, u1
+	sbb	d1, u2
+	jmp	L(bck_qh)
+EPILOGUE()
diff --git a/mpn/x86_64/dive_1.asm b/mpn/x86_64/dive_1.asm
new file mode 100644
index 0000000..d9a30b1
--- /dev/null
+++ b/mpn/x86_64/dive_1.asm
@@ -0,0 +1,158 @@
+dnl  AMD64 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2004-2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	10
+C AMD K10	10
+C Intel P4	33
+C Intel core2	13.25
+C Intel corei	14
+C Intel atom	42
+C VIA nano	43
+
+C A quick adoption of the 32-bit K7 code.
+
+
+C INPUT PARAMETERS
+C rp		rdi
+C up		rsi
+C n		rdx
+C divisor	rcx
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	%rcx, %rax
+	xor	R32(%rcx), R32(%rcx)	C shift count
+	mov	%rdx, %r8
+
+	bt	$0, R32(%rax)
+	jnc	L(evn)			C skip bsfq unless divisor is even
+
+L(odd):	mov	%rax, %rbx
+	shr	R32(%rax)
+	and	$127, R32(%rax)		C d/2, 7 bits
+
+	LEA(	binvert_limb_table, %rdx)
+
+	movzbl	(%rdx,%rax), R32(%rax)	C inv 8 bits
+
+	mov	%rbx, %r11		C d without twos
+
+	lea	(%rax,%rax), R32(%rdx)	C 2*inv
+	imul	R32(%rax), R32(%rax)	C inv*inv
+	imul	R32(%rbx), R32(%rax)	C inv*inv*d
+	sub	R32(%rax), R32(%rdx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rdx,%rdx), R32(%rax)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+	imul	R32(%rbx), R32(%rdx)	C inv*inv*d
+	sub	R32(%rdx), R32(%rax)	C inv = 2*inv - inv*inv*d, 32 bits
+
+	lea	(%rax,%rax), %r10	C 2*inv
+	imul	%rax, %rax		C inv*inv
+	imul	%rbx, %rax		C inv*inv*d
+	sub	%rax, %r10		C inv = 2*inv - inv*inv*d, 64 bits
+
+	lea	(%rsi,%r8,8), %rsi	C up end
+	lea	-8(%rdi,%r8,8), %rdi	C rp end
+	neg	%r8			C -n
+
+	mov	(%rsi,%r8,8), %rax	C up[0]
+
+	inc	%r8
+	jz	L(one)
+
+	mov	(%rsi,%r8,8), %rdx	C up[1]
+
+	shrd	R8(%rcx), %rdx, %rax
+
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(ent)
+
+L(evn):	bsf	%rax, %rcx
+	shr	R8(%rcx), %rax
+	jmp	L(odd)
+
+	ALIGN(8)
+L(top):
+	C rax	q
+	C rbx	carry bit, 0 or 1
+	C rcx	shift
+	C rdx
+	C rsi	up end
+	C rdi	rp end
+	C r8	counter, limbs, negative
+	C r10	d^(-1) mod 2^64
+	C r11	d, shifted down
+
+	mul	%r11			C carry limb in rdx	0 10
+	mov	-8(%rsi,%r8,8), %rax	C
+	mov	(%rsi,%r8,8), %r9	C
+	shrd	R8(%rcx), %r9, %rax	C
+	nop				C
+	sub	%rbx, %rax		C apply carry bit
+	setc	%bl			C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, %rbx		C			6
+L(ent):	imul	%r10, %rax		C			6
+	mov	%rax, (%rdi,%r8,8)	C
+	inc	%r8			C
+	jnz	L(top)
+
+	mul	%r11			C carry limb in rdx
+	mov	-8(%rsi), %rax		C up high limb
+	shr	R8(%rcx), %rax
+	sub	%rbx, %rax		C apply carry bit
+	sub	%rdx, %rax		C apply carry limb
+	imul	%r10, %rax
+	mov	%rax, (%rdi)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(one):	shr	R8(%rcx), %rax
+	imul	%r10, %rax
+	mov	%rax, (%rdi)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+EPILOGUE()
diff --git a/mpn/x86_64/divrem_1.asm b/mpn/x86_64/divrem_1.asm
new file mode 100644
index 0000000..a93e34f
--- /dev/null
+++ b/mpn/x86_64/divrem_1.asm
@@ -0,0 +1,314 @@
+dnl  x86-64 mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 2004, 2005, 2007-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C		norm	unorm	frac
+C AMD K8,K9	13	13	12
+C AMD K10	13	13	12
+C Intel P4	43	44	43
+C Intel core2	24.5	24.5	19.5
+C Intel corei	20.5	19.5	18
+C Intel atom	43	46	36
+C VIA nano	25.5	25.5	24
+
+C mp_limb_t
+C mpn_divrem_1 (mp_ptr qp, mp_size_t fn,
+C               mp_srcptr np, mp_size_t nn, mp_limb_t d)
+
+C mp_limb_t
+C mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t fn,
+C                      mp_srcptr np, mp_size_t nn, mp_limb_t d,
+C                      mp_limb_t dinv, int cnt)
+
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`fn_param',	`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx')
+define(`d',		`%r8')
+define(`dinv',		`%r9')		C only for mpn_preinv_divrem_1
+C       shift passed on stack		C only for mpn_preinv_divrem_1
+
+define(`cnt',		`%rcx')
+define(`up',		`%rsi')
+define(`fn',		`%r12')
+define(`un',		`%rbx')
+
+
+C rax rbx rcx rdx rsi rdi rbp r8  r9  r10 r11 r12 r13 r14 r15
+C         cnt         qp      d  dinv
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFSTD(`define(`CNTOFF',		`40($1)')')
+IFDOS(`define(`CNTOFF',		`104($1)')')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_preinv_divrem_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	xor	R32(%rax), R32(%rax)
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	fn_param, fn
+	mov	un_param, un
+	add	fn_param, un_param
+	mov	up_param, up
+
+	lea	-8(qp,un_param,8), qp
+
+	test	d, d
+	js	L(nent)
+
+	mov	CNTOFF(%rsp), R8(cnt)
+	shl	R8(cnt), d
+	jmp	L(uent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_divrem_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	xor	R32(%rax), R32(%rax)
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	fn_param, fn
+	mov	un_param, un
+	add	fn_param, un_param
+	mov	up_param, up
+	je	L(ret)
+
+	lea	-8(qp,un_param,8), qp
+	xor	R32(%rbp), R32(%rbp)
+
+	test	d, d
+	jns	L(unnormalized)
+
+L(normalized):
+	test	un, un
+	je	L(8)			C un == 0
+	mov	-8(up,un,8), %rbp
+	dec	un
+	mov	%rbp, %rax
+	sub	d, %rbp
+	cmovc	%rax, %rbp
+	sbb	R32(%rax), R32(%rax)
+	inc	R32(%rax)
+	mov	%rax, (qp)
+	lea	-8(qp), qp
+L(8):
+IFSTD(`	push	%rdi		')
+IFSTD(`	push	%rsi		')
+	push	%r8
+IFSTD(`	mov	d, %rdi		')
+IFDOS(`	sub	$32, %rsp	')
+IFDOS(`	mov	d, %rcx		')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	pop	%r8
+IFSTD(`	pop	%rsi		')
+IFSTD(`	pop	%rdi		')
+
+	mov	%rax, dinv
+	mov	%rbp, %rax
+	jmp	L(nent)
+
+	ALIGN(16)
+L(ntop):mov	(up,un,8), %r10		C	    K8-K10  P6-CNR P6-NHM  P4
+	mul	dinv			C	      0,13   0,20   0,18   0,45
+	add	%r10, %rax		C	      4      8      3     12
+	adc	%rbp, %rdx		C	      5      9     10     13
+	mov	%rax, %rbp		C	      5      9      4     13
+	mov	%rdx, %r13		C	      6     11     12     23
+	imul	d, %rdx			C	      6     11     11     23
+	sub	%rdx, %r10		C	     10     16     14     33
+	mov	d, %rax			C
+	add	%r10, %rax		C	     11     17     15     34
+	cmp	%rbp, %r10		C	     11     17     15     34
+	cmovc	%r10, %rax		C	     12     18     16     35
+	adc	$-1, %r13		C
+	cmp	d, %rax			C
+	jae	L(nfx)			C
+L(nok):	mov	%r13, (qp)		C
+	sub	$8, qp			C
+L(nent):lea	1(%rax), %rbp		C
+	dec	un			C
+	jns	L(ntop)			C
+
+	xor	R32(%rcx), R32(%rcx)
+	jmp	L(frac)
+
+L(nfx):	sub	d, %rax
+	inc	%r13
+	jmp	L(nok)
+
+L(unnormalized):
+	test	un, un
+	je	L(44)
+	mov	-8(up,un,8), %rax
+	cmp	d, %rax
+	jae	L(44)
+	mov	%rbp, (qp)
+	mov	%rax, %rbp
+	lea	-8(qp), qp
+	je	L(ret)
+	dec	un
+L(44):
+	bsr	d, %rcx
+	not	R32(%rcx)
+	shl	R8(%rcx), d
+	shl	R8(%rcx), %rbp
+
+	push	%rcx
+IFSTD(`	push	%rdi		')
+IFSTD(`	push	%rsi		')
+	push	%r8
+IFSTD(`	sub	$8, %rsp	')
+IFSTD(`	mov	d, %rdi		')
+IFDOS(`	sub	$40, %rsp	')
+IFDOS(`	mov	d, %rcx		')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+	pop	%r8
+IFSTD(`	pop	%rsi		')
+IFSTD(`	pop	%rdi		')
+	pop	%rcx
+
+	mov	%rax, dinv
+	mov	%rbp, %rax
+	test	un, un
+	je	L(frac)
+
+L(uent):dec	un
+	mov	(up,un,8), %rbp
+	neg	R32(%rcx)
+	shr	R8(%rcx), %rbp
+	neg	R32(%rcx)
+	or	%rbp, %rax
+	jmp	L(ent)
+
+	ALIGN(16)
+L(utop):mov	(up,un,8), %r10
+	shl	R8(%rcx), %rbp
+	neg	R32(%rcx)
+	shr	R8(%rcx), %r10
+	neg	R32(%rcx)
+	or	%r10, %rbp
+	mul	dinv
+	add	%rbp, %rax
+	adc	%r11, %rdx
+	mov	%rax, %r11
+	mov	%rdx, %r13
+	imul	d, %rdx
+	sub	%rdx, %rbp
+	mov	d, %rax
+	add	%rbp, %rax
+	cmp	%r11, %rbp
+	cmovc	%rbp, %rax
+	adc	$-1, %r13
+	cmp	d, %rax
+	jae	L(ufx)
+L(uok):	mov	%r13, (qp)
+	sub	$8, qp
+L(ent):	mov	(up,un,8), %rbp
+	dec	un
+	lea	1(%rax), %r11
+	jns	L(utop)
+
+L(uend):shl	R8(%rcx), %rbp
+	mul	dinv
+	add	%rbp, %rax
+	adc	%r11, %rdx
+	mov	%rax, %r11
+	mov	%rdx, %r13
+	imul	d, %rdx
+	sub	%rdx, %rbp
+	mov	d, %rax
+	add	%rbp, %rax
+	cmp	%r11, %rbp
+	cmovc	%rbp, %rax
+	adc	$-1, %r13
+	cmp	d, %rax
+	jae	L(efx)
+L(eok):	mov	%r13, (qp)
+	sub	$8, qp
+	jmp	L(frac)
+
+L(ufx):	sub	d, %rax
+	inc	%r13
+	jmp	L(uok)
+L(efx):	sub	d, %rax
+	inc	%r13
+	jmp	L(eok)
+
+L(frac):mov	d, %rbp
+	neg	%rbp
+	jmp	L(fent)
+
+	ALIGN(16)			C	    K8-K10  P6-CNR P6-NHM  P4
+L(ftop):mul	dinv			C	      0,12   0,17   0,17
+	add	%r11, %rdx		C	      5      8     10
+	mov	%rax, %r11		C	      4      8      3
+	mov	%rdx, %r13		C	      6      9     11
+	imul	%rbp, %rdx		C	      6      9     11
+	mov	d, %rax			C
+	add	%rdx, %rax		C	     10     14     14
+	cmp	%r11, %rdx		C	     10     14     14
+	cmovc	%rdx, %rax		C	     11     15     15
+	adc	$-1, %r13		C
+	mov	%r13, (qp)		C
+	sub	$8, qp			C
+L(fent):lea	1(%rax), %r11		C
+	dec	fn			C
+	jns	L(ftop)			C
+
+	shr	R8(%rcx), %rax
+L(ret):	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/divrem_2.asm b/mpn/x86_64/divrem_2.asm
new file mode 100644
index 0000000..9bf137f
--- /dev/null
+++ b/mpn/x86_64/divrem_2.asm
@@ -0,0 +1,192 @@
+dnl  x86-64 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008, 2010, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb	best
+C AMD K8,K9	18
+C AMD K10	18
+C AMD bull
+C AMD pile
+C AMD bobcat
+C AMD jaguar
+C Intel P4	68
+C Intel core	34
+C Intel NHM	30.25
+C Intel SBR	21.3
+C Intel IBR	21.4
+C Intel HWL	20.6
+C Intel BWL
+C Intel atom	73
+C VIA nano	33
+
+
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`fn',		`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx')
+define(`dp',		`%r8')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divrem_2)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	lea	-24(%rdx,%rcx,8), %r12	C r12 = &up[un-1]
+	mov	%rsi, %r13
+	push	%rbp
+	mov	%rdi, %rbp
+	push	%rbx
+	mov	8(%r8), %r11		C d1
+	mov	16(%r12), %rbx
+	mov	(%r8), %r8		C d0
+	mov	8(%r12), %r10
+
+	xor	R32(%r15), R32(%r15)
+	cmp	%rbx, %r11
+	ja	L(2)
+	setb	%dl
+	cmp	%r10, %r8
+	setbe	%al
+	orb	%al, %dl		C "orb" form to placate Sun tools
+	je	L(2)
+	inc	R32(%r15)
+	sub	%r8, %r10
+	sbb	%r11, %rbx
+L(2):
+	lea	-3(%rcx,%r13), %r14	C un + fn - 3
+	test	%r14, %r14
+	js	L(end)
+
+	push	%r8
+	push	%r10
+	push	%r11
+IFSTD(`	mov	%r11, %rdi	')
+IFDOS(`	mov	%r11, %rcx	')
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	pop	%r11
+	pop	%r10
+	pop	%r8
+
+	mov	%r11, %rdx
+	mov	%rax, %rdi
+	imul	%rax, %rdx
+	mov	%rdx, %r9
+	mul	%r8
+	xor	R32(%rcx), R32(%rcx)
+	add	%r8, %r9
+	adc	$-1, %rcx
+	add	%rdx, %r9
+	adc	$0, %rcx
+	js	2f
+1:	dec	%rdi
+	sub	%r11, %r9
+	sbb	$0, %rcx
+	jns	1b
+2:
+
+	lea	(%rbp,%r14,8), %rbp
+	mov	%r11, %rsi
+	neg	%rsi			C -d1
+
+C rax rbx rcx rdx rsi rdi  rbp r8 r9 r10 r11 r12 r13 r14 r15
+C     n2  un      -d1 dinv qp  d0 q0     d1  up  fn      msl
+
+	ALIGN(16)
+L(top):	mov	%rdi, %rax		C di		ncp
+	mul	%rbx			C		0, 17
+	mov	%r10, %rcx		C
+	add	%rax, %rcx		C		4
+	adc	%rbx, %rdx		C		5
+	mov	%rdx, %r9		C q		6
+	imul	%rsi, %rdx		C		6
+	mov	%r8, %rax		C		ncp
+	lea	(%rdx, %r10), %rbx	C n1 -= ...	10
+	xor	R32(%r10), R32(%r10)	C
+	mul	%r9			C		7
+	cmp	%r14, %r13		C
+	jg	L(19)			C
+	mov	(%r12), %r10		C
+	sub	$8, %r12		C
+L(19):	sub	%r8, %r10		C		ncp
+	sbb	%r11, %rbx		C		11
+	sub	%rax, %r10		C		11
+	sbb	%rdx, %rbx		C		12
+	xor	R32(%rax), R32(%rax)	C
+	xor	R32(%rdx), R32(%rdx)	C
+	cmp	%rcx, %rbx		C		13
+	cmovnc	%r8, %rax		C		14
+	cmovnc	%r11, %rdx		C		14
+	adc	$0, %r9			C adjust q	14
+	nop
+	add	%rax, %r10		C		15
+	adc	%rdx, %rbx		C		16
+	cmp	%r11, %rbx		C
+	jae	L(fix)			C
+L(bck):	mov	%r9, (%rbp)		C
+	sub	$8, %rbp		C
+	dec	%r14
+	jns	L(top)
+
+L(end):	mov	%r10, 8(%r12)
+	mov	%rbx, 16(%r12)
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	mov	%r15, %rax
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(fix):	seta	%dl
+	cmp	%r8, %r10
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	%r9
+	sub	%r8, %r10
+	sbb	%r11, %rbx
+	jmp	L(bck)
+EPILOGUE()
diff --git a/mpn/x86_64/dos64.m4 b/mpn/x86_64/dos64.m4
new file mode 100644
index 0000000..0da1b36
--- /dev/null
+++ b/mpn/x86_64/dos64.m4
@@ -0,0 +1,101 @@
+divert(-1)
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`HOST_DOS64')
+
+
+dnl  On DOS64 we always generate position-independent-code
+dnl
+
+define(`PIC')
+
+
+define(`LEA',`
+	lea	$1(%rip), $2
+')
+
+
+dnl  Usage: CALL(funcname)
+dnl
+dnl  Simply override the definition in x86_64-defs.m4.
+
+define(`CALL',`call	GSYM_PREFIX`'$1')
+define(`TCALL',`jmp	GSYM_PREFIX`'$1')
+
+
+dnl  Usage: JUMPTABSECT
+
+define(`JUMPTABSECT', `RODATA')
+
+
+dnl  Usage: JMPENT(targlabel,tablabel)
+
+define(`JMPENT', `.long	$1-$2')
+
+
+dnl  Usage: FUNC_ENTRY(nregparmas)
+dnl  Usage: FUNC_EXIT()
+
+dnl  FUNC_ENTRY and FUNC_EXIT provide an easy path for adoption of standard
+dnl  ABI assembly to the DOS64 ABI.
+
+define(`FUNC_ENTRY',
+	`push	%rdi
+	push	%rsi
+	mov	%rcx, %rdi
+ifelse(eval($1>=2),1,`dnl
+	mov	%rdx, %rsi
+ifelse(eval($1>=3),1,`dnl
+	mov	%r8, %rdx
+ifelse(eval($1>=4),1,`dnl
+	mov	%r9, %rcx
+')')')')
+
+define(`FUNC_EXIT',
+	`pop	%rsi
+	pop	%rdi')
+
+
+dnl  Target ABI macros.  For DOS64 we override the defaults.
+
+define(`IFDOS',   `$1')
+define(`IFSTD',   `')
+define(`IFELF',   `')
+
+
+dnl  Usage: PROTECT(symbol)
+dnl
+dnl  Used for private GMP symbols that should never be overridden by users.
+dnl  This can save reloc entries and improve shlib sharing as well as
+dnl  application startup times
+
+define(`PROTECT',  `')
+
+
+divert`'dnl
diff --git a/mpn/x86_64/gcd_11.asm b/mpn/x86_64/gcd_11.asm
new file mode 100644
index 0000000..e78b5dd
--- /dev/null
+++ b/mpn/x86_64/gcd_11.asm
@@ -0,0 +1,114 @@
+dnl  AMD64 mpn_gcd_11 -- 1 x 1 gcd.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for AMD64 by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2017 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 5.5
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 7.1
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4	 ?
+C Intel CNR	 ?
+C Intel PNR	 ?
+C Intel NHM	 ?
+C Intel WSM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 9.1
+C Intel SLM	 6.9
+C Intel GLM	 6.0
+C Intel GLM+	 5.8
+C VIA nano	 ?
+
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 7)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u0',    `%rdi')
+define(`v0',    `%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	FUNC_ENTRY(2)
+	LEA(	ctz_table, %r8)
+	jmp	L(ent)
+
+	ALIGN(16)
+L(top):	cmovc	%rdx, u0		C u = |u - v|
+	cmovc	%rax, v0		C v = min(u,v)
+L(mid):	and	$MASK, R32(%rdx)
+	movzbl	(%r8,%rdx), R32(%rcx)
+	jz	L(shift_alot)
+	shr	R8(%rcx), u0
+L(ent):	mov	u0, %rax
+	mov	v0, %rdx
+	sub	u0, %rdx
+	sub	v0, u0
+	jnz	L(top)
+
+L(end):	C rax = result
+	C rdx = 0 for the benefit of internal gcd_22 call
+	FUNC_EXIT()
+	ret
+
+L(shift_alot):
+	shr	$MAXSHIFT, u0
+	mov	u0, %rdx
+	jmp	L(mid)
+EPILOGUE()
diff --git a/mpn/x86_64/gcd_22.asm b/mpn/x86_64/gcd_22.asm
new file mode 100644
index 0000000..08909d6
--- /dev/null
+++ b/mpn/x86_64/gcd_22.asm
@@ -0,0 +1,163 @@
+dnl  AMD64 mpn_gcd_22.  Assumes useless bsf, useless shrd, no tzcnt, no shlx.
+dnl  We actually use tzcnt here, when table cannot count bits, as tzcnt always
+dnl  works for our use, and helps a lot for certain CPUs.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 8.9
+C AMD K10	 8.8
+C AMD bd1	 9.7
+C AMD bd2	 7.8
+C AMD bd3	 ?
+C AMD bd4	 7.4
+C AMD bt1	 9.2
+C AMD bt2	 9.1
+C AMD zn1	 7.5
+C AMD zn2	 7.5
+C Intel P4	 ?
+C Intel CNR	10.5
+C Intel PNR	10.5
+C Intel NHM	 9.7
+C Intel WSM	 9.7
+C Intel SBR	10.7
+C Intel IBR	 ?
+C Intel HWL	 9.5
+C Intel BWL	 8.7
+C Intel SKL	 8.6
+C Intel atom	18.9
+C Intel SLM	14.0
+C Intel GLM	 9.8
+C Intel GLM+	 8.8
+C VIA nano	 ?
+
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 8)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u1',    `%rdi')
+define(`u0',    `%rsi')
+define(`v1',    `%rdx')
+define(`v0_param', `%rcx')
+
+define(`v0',    `%rax')
+define(`cnt',   `%rcx')
+
+define(`s0',    `%r8')
+define(`s1',    `%r9')
+define(`t0',    `%rcx')
+define(`t1',    `%r11')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_22)
+	FUNC_ENTRY(4)
+	mov	v0_param, v0
+
+	LEA(	ctz_table, %r10)
+
+	ALIGN(16)
+L(top):	mov	v0, t0
+	sub	u0, t0
+	jz	L(lowz)		C	jump when low limb result = 0
+	mov	v1, t1
+	sbb	u1, t1
+
+	mov	u0, s0
+	mov	u1, s1
+
+	sub	v0, u0
+	sbb	v1, u1
+
+L(bck):	cmovc	t0, u0		C u = |u - v|
+	cmovc	t1, u1		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	cmovc	s1, v1		C v = min(u,v)
+
+	and	$MASK, R32(t0)
+	movzbl	(%r10,t0), R32(cnt)
+	jz	L(count_better)
+C Rightshift (u1,,u0) into (u1,,u0)
+L(shr):	shr	R8(cnt), u0
+	mov	u1, t1
+	shr	R8(cnt), u1
+	neg	cnt
+	shl	R8(cnt), t1
+	or	t1, u0
+
+	test	v1, v1
+	jnz	L(top)
+	test	u1, u1
+	jnz	L(top)
+
+L(gcd_11):
+	mov	v0, %rdi
+C	mov	u0, %rsi
+	TCALL(	mpn_gcd_11)
+
+L(count_better):
+	rep;bsf	u0, cnt		C tzcnt!
+	jmp	L(shr)
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	mov	v1, t0
+	sub	u1, t0
+	je	L(end)
+
+	xor	t1, t1
+	mov	u0, s0
+	mov	u1, s1
+	mov	u1, u0
+	xor	u1, u1
+	sub	v1, u0
+	jmp	L(bck)
+
+L(end):	C mov	v0, %rax
+	C mov	v1, %rdx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/gmp-mparam.h b/mpn/x86_64/gmp-mparam.h
new file mode 100644
index 0000000..db94fb7
--- /dev/null
+++ b/mpn/x86_64/gmp-mparam.h
@@ -0,0 +1,217 @@
+/* AMD K8-K10 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        14
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        28
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      7
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           15
+
+#define MUL_TOOM22_THRESHOLD                27
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               234
+#define MUL_TOOM6H_THRESHOLD               418
+#define MUL_TOOM8H_THRESHOLD               466
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     160
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     145
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     175
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 36
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                327
+#define SQR_TOOM6_THRESHOLD                446
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define POWM_SEC_TABLE  2,67,322,991
+
+#define MUL_FFT_MODF_THRESHOLD             570  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    570, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     25, 8}, {     13, 7}, {     29, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 7}, {     43, 8}, \
+    {     23, 7}, {     47, 8}, {     25, 7}, {     51, 8}, \
+    {     29, 9}, {     15, 8}, {     37, 9}, {     19, 8}, \
+    {     43, 9}, {     23, 8}, {     51, 9}, {     27, 8}, \
+    {     55,10}, {     15, 9}, {     43,10}, {     23, 9}, \
+    {     55,10}, {     31, 9}, {     63, 5}, {   1023, 4}, \
+    {   2431, 5}, {   1279, 6}, {    671, 7}, {    367, 8}, \
+    {    189, 9}, {     95, 8}, {    195, 9}, {    111,11}, \
+    {     31, 9}, {    131,10}, {     71, 9}, {    155,10}, \
+    {     79, 9}, {    159,10}, {     87,11}, {     47,10}, \
+    {    111,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    167,11}, {     95,10}, {    191,11}, {    111,12}, \
+    {     63,11}, {    143,10}, {    287,11}, {    159,10}, \
+    {    319,11}, {    175,12}, {     95,11}, {    207,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,12}, {    159,11}, {    319,10}, {    639,11}, \
+    {    335,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,13}, {    127,12}, {    255,11}, {    543,12}, \
+    {    287,11}, {    575,10}, {   1151,11}, {    607,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    671,12}, \
+    {    351,11}, {    703,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,12}, {    447,14}, \
+    {    127,13}, {    255,12}, {    543,11}, {   1087,12}, \
+    {    607,11}, {   1215,13}, {    319,12}, {    671,11}, \
+    {   1343,12}, {    735,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    799,11}, {   1599,12}, {    831,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,13}, {    639,12}, {   1343,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1599,13}, \
+    {    831,12}, {   1663,13}, {    895,12}, {   1791,13}, \
+    {    959,15}, {    255,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1215,14}, {    639,13}, {   1471,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1855,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,14}, {   1279,13}, {   2687,14}, {   1407,15}, \
+    {    767,14}, {   1535,13}, {   3071,14}, {   1791,16}, \
+    {    511,15}, {   1023,14}, {   2431,15}, {   1279,14}, \
+    {   2815,15}, {   1535,14}, {   3199,15}, {   1791,14}, \
+    {   3583,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 185
+#define MUL_FFT_THRESHOLD                 7552
+
+#define SQR_FFT_MODF_THRESHOLD             460  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    460, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     27, 7}, {     14, 6}, \
+    {     29, 7}, {     15, 6}, {     31, 7}, {     29, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 7}, {     43, 8}, \
+    {     25, 7}, {     51, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     43, 9}, {     23, 8}, \
+    {     51, 9}, {     27, 8}, {     55,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     43,10}, {     23, 9}, \
+    {     55,11}, {     15,10}, {     31, 9}, {     71,10}, \
+    {     39, 9}, {     83,10}, {     47, 6}, {    767, 4}, \
+    {   3263, 5}, {   1727, 4}, {   3455, 5}, {   1791, 6}, \
+    {    927, 7}, {    479, 6}, {    959, 7}, {    511, 8}, \
+    {    271, 9}, {    147,10}, {     87,11}, {     47,10}, \
+    {     95,12}, {     31,11}, {     63,10}, {    135,11}, \
+    {     79,10}, {    167,11}, {     95,10}, {    191,11}, \
+    {    111,12}, {     63,11}, {    127,10}, {    255,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,12}, {     95,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399,11}, {    207,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    639,10}, \
+    {   1279,11}, {    671,12}, {    351,11}, {    703,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    447,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    671,11}, {   1343,12}, \
+    {    703,11}, {   1407,12}, {    735,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    799,11}, {   1599,12}, \
+    {    831,13}, {    447,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1087,13}, {    575,12}, {   1215,13}, \
+    {    639,12}, {   1343,13}, {    703,12}, {   1407,14}, \
+    {    383,13}, {    767,12}, {   1599,13}, {    831,12}, \
+    {   1663,13}, {    895,12}, {   1791,13}, {    959,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1215,14}, {    639,13}, {   1471,14}, {    767,13}, \
+    {   1663,14}, {    895,13}, {   1855,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2303,14}, \
+    {   1279,13}, {   2559,14}, {   1407,15}, {    767,14}, \
+    {   1535,13}, {   3071,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2303,15}, {   1279,14}, {   2687,15}, \
+    {   1535,14}, {   3199,15}, {   1791,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 203
+#define SQR_FFT_THRESHOLD                 5248
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  35
+#define MULLO_MUL_N_THRESHOLD            15604
+
+#define DC_DIV_QR_THRESHOLD                 56
+#define DC_DIVAPPR_Q_THRESHOLD             220
+#define DC_BDIV_QR_THRESHOLD                52
+#define DC_BDIV_Q_THRESHOLD                152
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               226
+#define INV_APPR_THRESHOLD                 214
+
+#define BINV_NEWTON_THRESHOLD              327
+#define REDC_1_TO_REDC_2_THRESHOLD           4
+#define REDC_2_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1895
+#define MU_DIVAPPR_Q_THRESHOLD            1895
+#define MUPI_DIV_QR_THRESHOLD              106
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1718
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD_THRESHOLD                     125
+#define HGCD_APPR_THRESHOLD                173
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   555
+#define GCDEXT_DC_THRESHOLD                478
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               248
+#define SET_STR_PRECOMPUTE_THRESHOLD      1648
+
+#define FAC_DSC_THRESHOLD                 1075
+#define FAC_ODD_THRESHOLD                    0  /* always */
diff --git a/mpn/x86_64/invert_limb.asm b/mpn/x86_64/invert_limb.asm
new file mode 100644
index 0000000..136e67b
--- /dev/null
+++ b/mpn/x86_64/invert_limb.asm
@@ -0,0 +1,112 @@
+dnl  AMD64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Niels Möller.
+
+dnl  Copyright 2004, 2007-2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb (approx)	div
+C AMD K8,K9	 48			 71
+C AMD K10	 48			 77
+C Intel P4	135			161
+C Intel core2	 69			116
+C Intel corei	 55			 89
+C Intel atom	129			191
+C VIA nano	 79			157
+
+C rax rcx rdx rdi rsi r8
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+PROTECT(`mpn_invert_limb_table')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_invert_limb)		C			Kn	C2	Ci
+	FUNC_ENTRY(1)
+	mov	%rdi, %rax		C			 0	 0	 0
+	shr	$55, %rax		C			 1	 1	 1
+ifdef(`DARWIN',`
+	lea	mpn_invert_limb_table(%rip), %r8
+	add	$-512, %r8
+',`
+	lea	-512+mpn_invert_limb_table(%rip), %r8
+')
+	movzwl	(%r8,%rax,2), R32(%rcx)	C	%rcx = v0
+
+	C v1 = (v0 << 11) - (v0*v0*d40 >> 40) - 1
+	mov	%rdi, %rsi		C			 0	 0	 0
+	mov	R32(%rcx), R32(%rax)	C			 4	 5	 5
+	imul	R32(%rcx), R32(%rcx)	C			 4	 5	 5
+	shr	$24, %rsi		C			 1	 1	 1
+	inc	%rsi			C	%rsi = d40
+	imul	%rsi, %rcx		C			 8	10	 8
+	shr	$40, %rcx		C			12	15	11
+	sal	$11, R32(%rax)		C			 5	 6	 6
+	dec	R32(%rax)
+	sub	R32(%rcx), R32(%rax)	C	%rax = v1
+
+	C v2 = (v1 << 13) + (v1 * (2^60 - v1*d40) >> 47)
+	mov	$0x1000000000000000, %rcx
+	imul	%rax, %rsi		C			14	17	13
+	sub	%rsi, %rcx
+	imul	%rax, %rcx
+	sal	$13, %rax
+	shr	$47, %rcx
+	add	%rax, %rcx		C	%rcx = v2
+
+	C v3 = (v2 << 31) + (v2 * (2^96 - v2 * d63 + ((v2 >> 1) & mask)) >> 65)
+	mov	%rdi, %rsi		C			 0	 0	 0
+	shr	%rsi			C d/2
+	sbb	%rax, %rax		C -d0 = -(d mod 2)
+	sub	%rax, %rsi		C d63 = ceil(d/2)
+	imul	%rcx, %rsi		C v2 * d63
+	and	%rcx, %rax		C v2 * d0
+	shr	%rax			C (v2>>1) * d0
+	sub	%rsi, %rax		C (v2>>1) * d0 - v2 * d63
+	mul	%rcx
+	sal	$31, %rcx
+	shr	%rdx
+	add	%rdx, %rcx		C	%rcx = v3
+
+	mov	%rdi, %rax
+	mul	%rcx
+	add	%rdi, %rax
+	mov	%rcx, %rax
+	adc	%rdi, %rdx
+	sub	%rdx, %rax
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/mpn/x86_64/invert_limb_table.asm b/mpn/x86_64/invert_limb_table.asm
new file mode 100644
index 0000000..9f637ef
--- /dev/null
+++ b/mpn/x86_64/invert_limb_table.asm
@@ -0,0 +1,50 @@
+dnl  Table used for mpn_invert_limb
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Niels Möller.
+
+dnl  Copyright 2004, 2007-2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+PROTECT(`mpn_invert_limb_table')
+
+ASM_START()
+C Table entry X contains floor (0x7fd00 / (0x100 + X))
+
+	RODATA
+	ALIGN(2)
+	GLOBL mpn_invert_limb_table
+mpn_invert_limb_table:
+forloop(i,256,512-1,dnl
+`	.value	eval(0x7fd00/i)
+')dnl
+ASM_END()
diff --git a/mpn/x86_64/logops_n.asm b/mpn/x86_64/logops_n.asm
new file mode 100644
index 0000000..7b29a96
--- /dev/null
+++ b/mpn/x86_64/logops_n.asm
@@ -0,0 +1,260 @@
+dnl  AMD64 logops.
+
+dnl  Copyright 2004-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C		c/l	c/l	c/l	good
+C	       var-1   var-2   var-3  for cpu?
+C AMD K8,K9	 1.5	 1.5	 1.5	 y
+C AMD K10	 1.5	 1.5	 1.5	 y
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD bt1	 2.67	~2.79	~2.67
+C AMD bt2	 2.0	 2.28	 2.28	 y
+C AMD zen	 1.5	 1.5	 1.5	 =
+C Intel P4	 2.8	 3.35	 3.6
+C Intel PNR	 2.0	 2.0	 2.0	 =
+C Intel NHM	 2.0	 2.0	 2.0	 =
+C Intel SBR	 1.5	 1.75	 1.75	 n
+C Intel IBR	 1.48	 1.71	 1.72	 n
+C Intel HWL	 1.5	 1.5	 1.5	 n
+C Intel BWL	 1.5	 1.5	 1.5	 n
+C Intel SKL	 1.5	 1.5	 1.5	 n
+C Intel atom	 3.82	 3.82	 3.82	 n
+C Intel SLM	 3.0	 3.0	 3.0	 =
+C VIA nano	 3.25
+
+ifdef(`OPERATION_and_n',`
+  define(`func',`mpn_and_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',`mpn_andn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',`mpn_nand_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',`mpn_ior_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',`mpn_iorn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',`mpn_nior_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',`mpn_xor_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`xor')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',`mpn_xnor_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`xor')')
+
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n',`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+
+ifdef(`VARIANT_1',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	mov	R32(%rcx), R32(%rax)
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	dec	n
+	jmp	L(e11)
+L(b10):	add	$-2, n
+	jmp	L(e10)
+L(b01):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	inc	n
+	jz	L(ret)
+
+L(top):	mov	(vp,n,8), %r8
+L(b00):	mov	8(vp,n,8), %r9
+	LOGOP	(up,n,8), %r8
+	LOGOP	8(up,n,8), %r9
+	nop				C K8/K9/K10 concession
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+L(e11):	mov	16(vp,n,8), %r8
+L(e10):	mov	24(vp,n,8), %r9
+	LOGOP	16(up,n,8), %r8
+	LOGOP	24(up,n,8), %r9
+	mov	%r8, 16(rp,n,8)
+	mov	%r9, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
+
+ifdef(`VARIANT_2',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	not	%r8
+	mov	R32(%rcx), R32(%rax)
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	dec	n
+	jmp	L(e11)
+L(b10):	add	$-2, n
+	jmp	L(e10)
+	.byte	0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90
+L(b01):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	inc	n
+	jz	L(ret)
+
+L(top):	mov	(vp,n,8), %r8
+	not	%r8
+L(b00):	mov	8(vp,n,8), %r9
+	not	%r9
+	LOGOP	(up,n,8), %r8
+	LOGOP	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+L(e11):	mov	16(vp,n,8), %r8
+	not	%r8
+L(e10):	mov	24(vp,n,8), %r9
+	not	%r9
+	LOGOP	16(up,n,8), %r8
+	LOGOP	24(up,n,8), %r9
+	mov	%r8, 16(rp,n,8)
+	mov	%r9, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
+
+ifdef(`VARIANT_3',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	mov	R32(%rcx), R32(%rax)
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up,n,8), %r8
+	not	%r8
+	mov	%r8, (rp,n,8)
+	dec	n
+	jmp	L(e11)
+L(b10):	add	$-2, n
+	jmp	L(e10)
+	.byte	0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90
+L(b01):	LOGOP	(up,n,8), %r8
+	not	%r8
+	mov	%r8, (rp,n,8)
+	inc	n
+	jz	L(ret)
+
+L(top):	mov	(vp,n,8), %r8
+L(b00):	mov	8(vp,n,8), %r9
+	LOGOP	(up,n,8), %r8
+	not	%r8
+	LOGOP	8(up,n,8), %r9
+	not	%r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+L(e11):	mov	16(vp,n,8), %r8
+L(e10):	mov	24(vp,n,8), %r9
+	LOGOP	16(up,n,8), %r8
+	not	%r8
+	LOGOP	24(up,n,8), %r9
+	not	%r9
+	mov	%r8, 16(rp,n,8)
+	mov	%r9, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
diff --git a/mpn/x86_64/lshift.asm b/mpn/x86_64/lshift.asm
new file mode 100644
index 0000000..aa9e196
--- /dev/null
+++ b/mpn/x86_64/lshift.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 2003, 2005, 2007, 2009, 2011, 2012, 2018 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb   cycles/limb cnt=1
+C AMD K8,K9	 2.375		 1.375
+C AMD K10	 2.375		 1.375
+C Intel P4	 8		10.5
+C Intel core2	 2.11		 4.28
+C Intel corei	 ?		 ?
+C Intel atom	 5.75		 3.5
+C VIA nano	 3.5		 2.25
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_lshift)
+	FUNC_ENTRY(4)
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-8(up,n,8), %rax
+	shr	R8(%rcx), %rax		C function return value
+
+	neg	R32(%rcx)		C put lsh count in cl
+	lea	1(n), R32(%r8)
+	and	$3, R32(%r8)
+	je	L(rlx)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	jmp	L(rll)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	neg	R32(%rcx)		C put lsh count in cl
+L(1x):
+	cmp	$1, n
+	je	L(ast)
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	mov	-24(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, -8(rp,n,8)
+	mov	%r11, -16(rp,n,8)
+	sub	$2, n
+
+L(rll):	neg	R32(%rcx)		C put lsh count in cl
+L(rlx):	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+
+	sub	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(16)
+L(top):
+	C finish stuff from lsh block
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, 24(rp,n,8)
+	mov	%r11, 16(rp,n,8)
+	C start two new rsh
+	mov	0(up,n,8), %r8
+	mov	-8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	shr	R8(%rcx), %r9
+
+	C finish stuff from rsh block
+	neg	R32(%rcx)		C put lsh count in cl
+	mov	8(up,n,8), %r10
+	mov	0(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	or	%r10, %r8
+	shl	R8(%rcx), %r11
+	or	%r11, %r9
+	mov	%r8, 8(rp,n,8)
+	mov	%r9, 0(rp,n,8)
+	C start two new lsh
+	mov	-8(up,n,8), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	shl	R8(%rcx), %r11
+
+	sub	$4, n
+	jae	L(top)			C				      2
+L(end):
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	8(up), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	(up), %r9
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, 16(rp)
+	mov	%r11, 8(rp)
+
+	neg	R32(%rcx)		C put lsh count in cl
+L(ast):	mov	(up), %r10
+	shl	R8(%rcx), %r10
+	mov	%r10, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/lshiftc.asm b/mpn/x86_64/lshiftc.asm
new file mode 100644
index 0000000..4f3c7c3
--- /dev/null
+++ b/mpn/x86_64/lshiftc.asm
@@ -0,0 +1,182 @@
+dnl  AMD64 mpn_lshiftc -- mpn left shift with complement.
+
+dnl  Copyright 2003, 2005, 2006, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.75
+C AMD K10	 2.75
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 3.75
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_lshiftc)
+	FUNC_ENTRY(4)
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-8(up,n,8), %rax
+	shr	R8(%rcx), %rax		C function return value
+
+	neg	R32(%rcx)		C put lsh count in cl
+	lea	1(n), R32(%r8)
+	and	$3, R32(%r8)
+	je	L(rlx)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	not	%r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	jmp	L(rll)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	not	%r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	neg	R32(%rcx)		C put lsh count in cl
+L(1x):
+	cmp	$1, n
+	je	L(ast)
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	mov	-24(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	not	%r10
+	not	%r11
+	mov	%r10, -8(rp,n,8)
+	mov	%r11, -16(rp,n,8)
+	sub	$2, n
+
+L(rll):	neg	R32(%rcx)		C put lsh count in cl
+L(rlx):	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+
+	sub	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(16)
+L(top):
+	C finish stuff from lsh block
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	not	%r10
+	not	%r11
+	mov	%r10, 24(rp,n,8)
+	mov	%r11, 16(rp,n,8)
+	C start two new rsh
+	mov	0(up,n,8), %r8
+	mov	-8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	shr	R8(%rcx), %r9
+
+	C finish stuff from rsh block
+	neg	R32(%rcx)		C put lsh count in cl
+	mov	8(up,n,8), %r10
+	mov	0(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	or	%r10, %r8
+	shl	R8(%rcx), %r11
+	or	%r11, %r9
+	not	%r8
+	not	%r9
+	mov	%r8, 8(rp,n,8)
+	mov	%r9, 0(rp,n,8)
+	C start two new lsh
+	mov	-8(up,n,8), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	shl	R8(%rcx), %r11
+
+	sub	$4, n
+	jae	L(top)			C				      2
+L(end):
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	8(up), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	(up), %r9
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	not	%r10
+	not	%r11
+	mov	%r10, 16(rp)
+	mov	%r11, 8(rp)
+
+	neg	R32(%rcx)		C put lsh count in cl
+L(ast):	mov	(up), %r10
+	shl	R8(%rcx), %r10
+	not	%r10
+	mov	%r10, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/lshsub_n.asm b/mpn/x86_64/lshsub_n.asm
new file mode 100644
index 0000000..50bbc66
--- /dev/null
+++ b/mpn/x86_64/lshsub_n.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_lshsub_n.  R = 2^k(U - V).
+
+dnl  Copyright 2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 3.15	(mpn_sub_n + mpn_lshift costs about 4 c/l)
+C AMD K10	 3.15	(mpn_sub_n + mpn_lshift costs about 4 c/l)
+C Intel P4	16.5
+C Intel core2	 4.35
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C This was written quickly and not optimized at all, but it runs very well on
+C K8.  But perhaps one could get under 3 c/l.  Ideas:
+C   1) Use indexing to save the 3 LEA
+C   2) Write reasonable feed-in code
+C   3) Be more clever about register usage
+C   4) Unroll more, handling CL negation, carry save/restore cost much now
+C   5) Reschedule
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshsub_n)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	push	%rbx
+
+	mov	n, %rax
+	xor	R32(%rbx), R32(%rbx)	C clear carry save register
+	mov	R32(%r8), R32(%rcx)	C shift count
+	xor	R32(%r15), R32(%r15)	C limb carry
+
+	mov	R32(%rax), R32(%r11)
+	and	$3, R32(%r11)
+	je	L(4)
+	sub	$1, R32(%r11)
+
+L(oopette):
+	add	R32(%rbx), R32(%rbx)	C restore carry flag
+	mov	0(up), %r8
+	lea	8(up), up
+	sbb	0(vp), %r8
+	mov	%r8, %r12
+	sbb	R32(%rbx), R32(%rbx)	C save carry flag
+	shl	R8(%rcx), %r8
+	or	%r15, %r8
+	mov	%r12, %r15
+	lea	8(vp), vp
+	neg	R8(%rcx)
+	shr	R8(%rcx), %r15
+	neg	R8(%rcx)
+	mov	%r8, 0(rp)
+	lea	8(rp), rp
+	sub	$1, R32(%r11)
+	jnc	L(oopette)
+
+L(4):
+	sub	$4, %rax
+	jc	L(end)
+
+	ALIGN(16)
+L(oop):
+	add	R32(%rbx), R32(%rbx)	C restore carry flag
+
+	mov	0(up), %r8
+	mov	8(up), %r9
+	mov	16(up), %r10
+	mov	24(up), %r11
+
+	lea	32(up), up
+
+	sbb	0(vp), %r8
+	mov	%r8, %r12
+	sbb	8(vp), %r9
+	mov	%r9, %r13
+	sbb	16(vp), %r10
+	mov	%r10, %r14
+	sbb	24(vp), %r11
+
+	sbb	R32(%rbx), R32(%rbx)	C save carry flag
+
+	shl	R8(%rcx), %r8
+	shl	R8(%rcx), %r9
+	shl	R8(%rcx), %r10
+	or	%r15, %r8
+	mov	%r11, %r15
+	shl	R8(%rcx), %r11
+
+	lea	32(vp), vp
+
+	neg	R8(%rcx)
+
+	shr	R8(%rcx), %r12
+	shr	R8(%rcx), %r13
+	shr	R8(%rcx), %r14
+	shr	R8(%rcx), %r15		C used next loop
+
+	or	%r12, %r9
+	or	%r13, %r10
+	or	%r14, %r11
+
+	neg	R8(%rcx)
+
+	mov	%r8, 0(rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+
+	lea	32(rp), rp
+
+	sub	$4, %rax
+	jnc	L(oop)
+L(end):
+	neg	R32(%rbx)
+	shl	R8(%rcx), %rbx
+	adc	%r15, %rbx
+	mov	%rbx, %rax
+	pop	%rbx
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/missing-call.m4 b/mpn/x86_64/missing-call.m4
new file mode 100644
index 0000000..c024f0e
--- /dev/null
+++ b/mpn/x86_64/missing-call.m4
@@ -0,0 +1,53 @@
+dnl  AMD64 MULX/ADX simulation support, function call version.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+define(`adox',`
+	push	$1
+	push	$2
+	call	__gmp_adox
+	pop	$2
+')
+
+define(`adcx',`
+	push	$1
+	push	$2
+	call	__gmp_adcx
+	pop	$2
+')
+
+define(`mulx',`
+	push	$1
+	call	__gmp_mulx
+	pop	$2
+	pop	$3
+')
diff --git a/mpn/x86_64/missing-inline.m4 b/mpn/x86_64/missing-inline.m4
new file mode 100644
index 0000000..bd1df13
--- /dev/null
+++ b/mpn/x86_64/missing-inline.m4
@@ -0,0 +1,100 @@
+dnl  AMD64 MULX/ADX simulation support, inline version.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+define(`adox',`
+	push	$2
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	$1, %rcx
+	pushfq
+	pushfq
+C copy 0(%rsp):11 to 0(%rsp):0
+	mov	(%rsp), %rbx
+	shr	%rbx
+	bt	$`'10, %rbx
+	adc	%rbx, %rbx
+	mov	%rbx, (%rsp)
+C put manipulated flags into eflags, execute a plain adc
+	popfq
+	adc	%rcx, 32(%rsp)
+C copy CF to 0(%rsp):11
+	mov	(%rsp), %rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$`'0x800, R32(%rax)
+	and	$`'0xfffffffffffff7ff, %rbx
+	or	%rax, %rbx
+	mov	%rbx, (%rsp)
+C put manipulated flags into eflags
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	pop	$2
+')
+
+define(`adcx',`
+	push	$2
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	$1, %rcx
+	pushfq
+	adc	%rcx, 32(%rsp)
+	mov	(%rsp), %rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$`'0xfffffffffffffffe, %rbx
+	sub	%rax, %rbx
+	mov	%rbx, (%rsp)
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	pop	$2
+')
+
+define(`mulx',`
+	lea	-16(%rsp), %rsp
+	push	%rax
+	push	%rdx
+	pushfq			C preserve all flags
+	mov	$1, %rax
+	mul	%rdx
+	mov	%rax, 24(%rsp)
+	mov	%rdx, 32(%rsp)
+	popfq			C restore eflags
+	pop	%rdx
+	pop	%rax
+	pop	$2
+	pop	$3
+')
diff --git a/mpn/x86_64/missing.asm b/mpn/x86_64/missing.asm
new file mode 100644
index 0000000..48c2b8a
--- /dev/null
+++ b/mpn/x86_64/missing.asm
@@ -0,0 +1,130 @@
+
+	dnl  AMD64 MULX/ADX simulation support.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`config.m4')
+
+ASM_START()
+
+C Fake the MULX instruction
+C
+C Accept the single explicit parameter on the stack, return the two result
+C words on the stack.  This calling convention means that we need to move the
+C return address up.
+C
+PROLOGUE(__gmp_mulx)
+	lea	-8(%rsp), %rsp
+	push	%rax
+	push	%rdx
+	pushfq				C preserve all flags
+	mov	32(%rsp), %rax		C move retaddr...
+	mov	%rax, 24(%rsp)		C ...up the stack
+	mov	40(%rsp), %rax		C input parameter
+	mul	%rdx
+	mov	%rax, 32(%rsp)
+	mov	%rdx, 40(%rsp)
+	popfq				C restore eflags
+	pop	%rdx
+	pop	%rax
+	ret
+EPILOGUE()
+PROTECT(__gmp_mulx)
+
+
+C Fake the ADOX instruction
+C
+C Accept the two parameters on the stack, return the result word on the stack.
+C This calling convention means that we need to move the return address down.
+C
+PROLOGUE(__gmp_adox)
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	32(%rsp), %rcx		C src2
+	mov	24(%rsp), %rax		C move retaddr...
+	mov	%rax, 32(%rsp)		C ...down the stack
+	pushfq
+C copy 0(%rsp):11 to 0(%rsp):0
+	mov	(%rsp), %rbx
+	shr	%rbx
+	bt	$10, %rbx
+	adc	%rbx, %rbx
+	push	%rbx
+C put manipulated flags into eflags, execute a plain adc
+	popfq
+	adc	%rcx, 48(%rsp)
+C copy CF to 0(%rsp):11
+	pop	%rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$0x800, R32(%rax)
+	and	$0xfffffffffffff7ff, %rbx
+	or	%rax, %rbx
+	push	%rbx
+C put manipulated flags into eflags
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	lea	8(%rsp), %rsp
+	ret
+EPILOGUE()
+PROTECT(__gmp_adox)
+
+
+C Fake the ADCX instruction
+C
+C Accept the two parameters on the stack, return the result word on the stack.
+C This calling convention means that we need to move the return address down.
+C
+PROLOGUE(__gmp_adcx)
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	32(%rsp), %rcx		C src2
+	mov	24(%rsp), %rax		C move retaddr...
+	mov	%rax, 32(%rsp)		C ...down the stack
+	pushfq
+	adc	%rcx, 48(%rsp)
+	pop	%rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$`'0xfffffffffffffffe, %rbx
+	sub	%rax, %rbx
+	push	%rbx
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	lea	8(%rsp), %rsp
+	ret
+EPILOGUE()
+PROTECT(__gmp_adcx)
diff --git a/mpn/x86_64/mod_1_1.asm b/mpn/x86_64/mod_1_1.asm
new file mode 100644
index 0000000..50a6692
--- /dev/null
+++ b/mpn/x86_64/mod_1_1.asm
@@ -0,0 +1,238 @@
+dnl  AMD64 mpn_mod_1_1p
+
+dnl  Contributed to the GNU project by Torbjörn Granlund and Niels Möller.
+
+dnl  Copyright 2009-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 6
+C AMD K10	 6
+C Intel P4	26
+C Intel core2	12.5
+C Intel NHM	11.3
+C Intel SBR	 8.4	(slowdown, old code took 8.0)
+C Intel atom	26
+C VIA nano	13
+
+define(`B2mb',   `%r10')
+define(`B2modb', `%r11')
+define(`ap',     `%rdi')
+define(`n',      `%rsi')
+define(`pre',    `%r8')
+define(`b',      `%rbx')
+
+define(`r0',     `%rbp') C r1 kept in %rax
+define(`r2',	 `%rcx')  C kept negated. Also used as shift count
+define(`t0',     `%r9')
+
+C mp_limb_t
+C mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, mp_limb_t bmodb[4])
+C                       %rdi         %rsi         %rdx                %rcx
+C The pre array contains bi, cnt, B1modb, B2modb
+C Note: This implementation needs B1modb only when cnt > 0
+
+C The iteration is almost as follows,
+C
+C   r_2 B^3 + r_1 B^2 + r_0 B + u = r_1 B2modb + (r_0 + r_2 B2mod) B + u
+C
+C where r2 is a single bit represented as a mask. But to make sure that the
+C result fits in two limbs and a bit, carry from the addition
+C
+C   r_0 + r_2 B2mod
+C
+C is handled specially. On carry, we subtract b to cancel the carry,
+C and we use instead the value
+C
+C   r_0 + B2mb (mod B)
+C
+C This addition can be issued early since it doesn't depend on r2, and it is
+C the source of the cmov in the loop.
+C
+C We have the invariant that r_2 B^2 + r_1 B + r_0 < B^2 + B b
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1_1p)
+	FUNC_ENTRY(4)
+	push	%rbp
+	push	%rbx
+	mov	%rdx, b
+	mov	%rcx, pre
+
+	mov	-8(ap, n, 8), %rax
+	cmp	$3, n
+	jnc	L(first)
+	mov	-16(ap, n, 8), r0
+	jmp	L(reduce_two)
+
+L(first):
+	C First iteration, no r2
+	mov	24(pre), B2modb
+	mul	B2modb
+	mov	-24(ap, n, 8), r0
+	add	%rax, r0
+	mov	-16(ap, n, 8), %rax
+	adc	%rdx, %rax
+	sbb	r2, r2
+	sub	$4, n
+	jc	L(reduce_three)
+
+	mov	B2modb, B2mb
+	sub	b, B2mb
+
+	ALIGN(16)
+L(top):	and	B2modb, r2
+	lea	(B2mb, r0), t0
+	mul	B2modb
+	add	r0, r2
+	mov	(ap, n, 8), r0
+	cmovc	t0, r2
+	add	%rax, r0
+	mov	r2, %rax
+	adc	%rdx, %rax
+	sbb	r2, r2
+	sub	$1, n
+	jnc	L(top)
+
+L(reduce_three):
+	C Eliminate r2
+	and	b, r2
+	sub	r2, %rax
+
+L(reduce_two):
+	mov	8(pre), R32(%rcx)
+	test	R32(%rcx), R32(%rcx)
+	jz	L(normalized)
+
+	C Unnormalized, use B1modb to reduce to size < B (b+1)
+	mulq	16(pre)
+	xor	t0, t0
+	add	%rax, r0
+	adc	%rdx, t0
+	mov	t0, %rax
+
+	C Left-shift to normalize
+ifdef(`SHLD_SLOW',`
+	shl	R8(%rcx), %rax
+	mov	r0, t0
+	neg	R32(%rcx)
+	shr	R8(%rcx), t0
+	or	t0, %rax
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), r0, %rax
+')
+	shl	R8(%rcx), r0
+	jmp	L(udiv)
+
+L(normalized):
+	mov	%rax, t0
+	sub	b, t0
+	cmovnc	t0, %rax
+
+L(udiv):
+	lea	1(%rax), t0
+	mulq	(pre)
+	add	r0, %rax
+	adc	t0, %rdx
+	imul	b, %rdx
+	sub	%rdx, r0
+	cmp	r0, %rax
+	lea	(b, r0), %rax
+	cmovnc	r0, %rax
+	cmp	b, %rax
+	jnc	L(fix)
+L(ok):	shr	R8(%rcx), %rax
+
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+L(fix):	sub	b, %rax
+	jmp	L(ok)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1_1p_cps)
+	FUNC_ENTRY(2)
+	push	%rbp
+	bsr	%rsi, %rcx
+	push	%rbx
+	mov	%rdi, %rbx
+	push	%r12
+	xor	$63, R32(%rcx)
+	mov	%rsi, %r12
+	mov	R32(%rcx), R32(%rbp)
+	sal	R8(%rcx), %r12
+IFSTD(`	mov	%r12, %rdi	')	C pass parameter
+IFDOS(`	mov	%r12, %rcx	')	C pass parameter
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	neg	%r12
+	mov	%r12, %r8
+	mov	%rax, (%rbx)		C store bi
+	mov	%rbp, 8(%rbx)		C store cnt
+	imul	%rax, %r12
+	mov	%r12, 24(%rbx)		C store B2modb
+	mov	R32(%rbp), R32(%rcx)
+	test	R32(%rcx), R32(%rcx)
+	jz	L(z)
+
+	mov	$1, R32(%rdx)
+ifdef(`SHLD_SLOW',`
+	C Destroys %rax, unlike shld. Otherwise, we could do B1modb
+	C before B2modb, and get rid of the move %r12, %r8 above.
+
+	shl	R8(%rcx), %rdx
+	neg	R32(%rcx)
+	shr	R8(%rcx), %rax
+	or	%rax, %rdx
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), %rax, %rdx
+')
+	imul	%rdx, %r8
+	shr	R8(%rcx), %r8
+	mov	%r8, 16(%rbx)		C store B1modb
+L(z):
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/mpn/x86_64/mod_1_2.asm b/mpn/x86_64/mod_1_2.asm
new file mode 100644
index 0000000..1879d73
--- /dev/null
+++ b/mpn/x86_64/mod_1_2.asm
@@ -0,0 +1,241 @@
+dnl  AMD64 mpn_mod_1s_2p
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4
+C AMD K10	 4
+C Intel P4	19
+C Intel core2	 8
+C Intel NHM	 6.5
+C Intel SBR	 4.5
+C Intel atom	28
+C VIA nano	 8
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_2p)
+	FUNC_ENTRY(4)
+	push	%r14
+	test	$1, R8(%rsi)
+	mov	%rdx, %r14
+	push	%r13
+	mov	%rcx, %r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+	mov	16(%rcx), %r10
+	mov	24(%rcx), %rbx
+	mov	32(%rcx), %rbp
+	je	L(b0)
+	dec	%rsi
+	je	L(one)
+	mov	-8(%rdi,%rsi,8), %rax
+	mul	%r10
+	mov	%rax, %r9
+	mov	%rdx, %r8
+	mov	(%rdi,%rsi,8), %rax
+	add	-16(%rdi,%rsi,8), %r9
+	adc	$0, %r8
+	mul	%rbx
+	add	%rax, %r9
+	adc	%rdx, %r8
+	jmp	L(11)
+
+L(b0):	mov	-8(%rdi,%rsi,8), %r8
+	mov	-16(%rdi,%rsi,8), %r9
+
+L(11):	sub	$4, %rsi
+	jb	L(ed2)
+	lea	40(%rdi,%rsi,8), %rdi
+	mov	-40(%rdi), %r11
+	mov	-32(%rdi), %rax
+	jmp	L(m0)
+
+	ALIGN(16)
+L(top):	mov	-24(%rdi), %r9
+	add	%rax, %r11
+	mov	-16(%rdi), %rax
+	adc	%rdx, %r12
+	mul	%r10
+	add	%rax, %r9
+	mov	%r11, %rax
+	mov	%rdx, %r8
+	adc	$0, %r8
+	mul	%rbx
+	add	%rax, %r9
+	mov	%r12, %rax
+	adc	%rdx, %r8
+	mul	%rbp
+	sub	$2, %rsi
+	jb	L(ed1)
+	mov	-40(%rdi), %r11
+	add	%rax, %r9
+	mov	-32(%rdi), %rax
+	adc	%rdx, %r8
+L(m0):	mul	%r10
+	add	%rax, %r11
+	mov	%r9, %rax
+	mov	%rdx, %r12
+	adc	$0, %r12
+	mul	%rbx
+	add	%rax, %r11
+	lea	-32(%rdi), %rdi		C ap -= 4
+	mov	%r8, %rax
+	adc	%rdx, %r12
+	mul	%rbp
+	sub	$2, %rsi
+	jae	L(top)
+
+L(ed0):	mov	%r11, %r9
+	mov	%r12, %r8
+L(ed1):	add	%rax, %r9
+	adc	%rdx, %r8
+L(ed2):	mov	8(%r13), R32(%rdi)		C cnt
+	mov	%r8, %rax
+	mov	%r9, %r8
+	mul	%r10
+	add	%rax, %r8
+	adc	$0, %rdx
+L(1):	xor	R32(%rcx), R32(%rcx)
+	mov	%r8, %r9
+	sub	R32(%rdi), R32(%rcx)
+	shr	R8(%rcx), %r9
+	mov	R32(%rdi), R32(%rcx)
+	sal	R8(%rcx), %rdx
+	or	%rdx, %r9
+	sal	R8(%rcx), %r8
+	mov	%r9, %rax
+	mulq	(%r13)
+	mov	%rax, %rsi
+	inc	%r9
+	add	%r8, %rsi
+	adc	%r9, %rdx
+	imul	%r14, %rdx
+	sub	%rdx, %r8
+	lea	(%r8,%r14), %rax
+	cmp	%r8, %rsi
+	cmovc	%rax, %r8
+	mov	%r8, %rax
+	sub	%r14, %rax
+	cmovc	%r8, %rax
+	mov	R32(%rdi), R32(%rcx)
+	shr	R8(%rcx), %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	FUNC_EXIT()
+	ret
+L(one):
+	mov	(%rdi), %r8
+	mov	8(%rcx), R32(%rdi)
+	xor	%rdx, %rdx
+	jmp	L(1)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_2p_cps)
+	FUNC_ENTRY(2)
+	push	%rbp
+	bsr	%rsi, %rcx
+	push	%rbx
+	mov	%rdi, %rbx
+	push	%r12
+	xor	$63, R32(%rcx)
+	mov	%rsi, %r12
+	mov	R32(%rcx), R32(%rbp)	C preserve cnt over call
+	sal	R8(%rcx), %r12		C b << cnt
+IFSTD(`	mov	%r12, %rdi	')	C pass parameter
+IFDOS(`	mov	%r12, %rcx	')	C pass parameter
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	mov	%r12, %r8
+	mov	%rax, %r11
+	mov	%rax, (%rbx)		C store bi
+	mov	%rbp, 8(%rbx)		C store cnt
+	neg	%r8
+	mov	R32(%rbp), R32(%rcx)
+	mov	$1, R32(%rsi)
+ifdef(`SHLD_SLOW',`
+	shl	R8(%rcx), %rsi
+	neg	R32(%rcx)
+	mov	%rax, %rbp
+	shr	R8(%rcx), %rax
+	or	%rax, %rsi
+	mov	%rbp, %rax
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), %rax, %rsi	C FIXME: Slow on Atom and Nano
+')
+	imul	%r8, %rsi
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 16(%rbx)		C store B1modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 24(%rbx)		C store B2modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	add	%rdx, %r12
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %r12
+
+	shr	R8(%rcx), %r12
+	mov	%r12, 32(%rbx)		C store B3modb
+
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/mod_1_4.asm b/mpn/x86_64/mod_1_4.asm
new file mode 100644
index 0000000..168d80a
--- /dev/null
+++ b/mpn/x86_64/mod_1_4.asm
@@ -0,0 +1,272 @@
+dnl  AMD64 mpn_mod_1s_4p
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 3
+C AMD K10	 3
+C Intel P4	15.5
+C Intel core2	 5
+C Intel corei	 4
+C Intel atom	23
+C VIA nano	 4.75
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p)
+	FUNC_ENTRY(4)
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	%rdx, %r15
+	mov	%rcx, %r14
+	mov	16(%rcx), %r11		C B1modb
+	mov	24(%rcx), %rbx		C B2modb
+	mov	32(%rcx), %rbp		C B3modb
+	mov	40(%rcx), %r13		C B4modb
+	mov	48(%rcx), %r12		C B5modb
+	xor	R32(%r8), R32(%r8)
+	mov	R32(%rsi), R32(%rdx)
+	and	$3, R32(%rdx)
+	je	L(b0)
+	cmp	$2, R32(%rdx)
+	jc	L(b1)
+	je	L(b2)
+
+L(b3):	lea	-24(%rdi,%rsi,8), %rdi
+	mov	8(%rdi), %rax
+	mul	%r11
+	mov	(%rdi), %r9
+	add	%rax, %r9
+	adc	%rdx, %r8
+	mov	16(%rdi), %rax
+	mul	%rbx
+	jmp	L(m0)
+
+	ALIGN(8)
+L(b0):	lea	-32(%rdi,%rsi,8), %rdi
+	mov	8(%rdi), %rax
+	mul	%r11
+	mov	(%rdi), %r9
+	add	%rax, %r9
+	adc	%rdx, %r8
+	mov	16(%rdi), %rax
+	mul	%rbx
+	add	%rax, %r9
+	adc	%rdx, %r8
+	mov	24(%rdi), %rax
+	mul	%rbp
+	jmp	L(m0)
+
+	ALIGN(8)
+L(b1):	lea	-8(%rdi,%rsi,8), %rdi
+	mov	(%rdi), %r9
+	jmp	L(m1)
+
+	ALIGN(8)
+L(b2):	lea	-16(%rdi,%rsi,8), %rdi
+	mov	8(%rdi), %r8
+	mov	(%rdi), %r9
+	jmp	L(m1)
+
+	ALIGN(16)
+L(top):	mov	-24(%rdi), %rax
+	mov	-32(%rdi), %r10
+	mul	%r11			C up[1] * B1modb
+	add	%rax, %r10
+	mov	-16(%rdi), %rax
+	mov	$0, R32(%rcx)
+	adc	%rdx, %rcx
+	mul	%rbx			C up[2] * B2modb
+	add	%rax, %r10
+	mov	-8(%rdi), %rax
+	adc	%rdx, %rcx
+	sub	$32, %rdi
+	mul	%rbp			C up[3] * B3modb
+	add	%rax, %r10
+	mov	%r13, %rax
+	adc	%rdx, %rcx
+	mul	%r9			C rl * B4modb
+	add	%rax, %r10
+	mov	%r12, %rax
+	adc	%rdx, %rcx
+	mul	%r8			C rh * B5modb
+	mov	%r10, %r9
+	mov	%rcx, %r8
+L(m0):	add	%rax, %r9
+	adc	%rdx, %r8
+L(m1):	sub	$4, %rsi
+	ja	L(top)
+
+L(end):	mov	8(%r14), R32(%rsi)
+	mov	%r8, %rax
+	mul	%r11
+	mov	%rax, %r8
+	add	%r9, %r8
+	adc	$0, %rdx
+	xor	R32(%rcx), R32(%rcx)
+	sub	R32(%rsi), R32(%rcx)
+	mov	%r8, %rdi
+	shr	R8(%rcx), %rdi
+	mov	R32(%rsi), R32(%rcx)
+	sal	R8(%rcx), %rdx
+	or	%rdx, %rdi
+	mov	%rdi, %rax
+	mulq	(%r14)
+	mov	%r15, %rbx
+	mov	%rax, %r9
+	sal	R8(%rcx), %r8
+	inc	%rdi
+	add	%r8, %r9
+	adc	%rdi, %rdx
+	imul	%rbx, %rdx
+	sub	%rdx, %r8
+	lea	(%r8,%rbx), %rax
+	cmp	%r8, %r9
+	cmovc	%rax, %r8
+	mov	%r8, %rax
+	sub	%rbx, %rax
+	cmovc	%r8, %rax
+	shr	R8(%rcx), %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p_cps)
+	FUNC_ENTRY(2)
+	push	%rbp
+	bsr	%rsi, %rcx
+	push	%rbx
+	mov	%rdi, %rbx
+	push	%r12
+	xor	$63, R32(%rcx)
+	mov	%rsi, %r12
+	mov	R32(%rcx), R32(%rbp)	C preserve cnt over call
+	sal	R8(%rcx), %r12		C b << cnt
+IFSTD(`	mov	%r12, %rdi	')	C pass parameter
+IFDOS(`	mov	%r12, %rcx	')	C pass parameter
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	mov	%r12, %r8
+	mov	%rax, %r11
+	mov	%rax, (%rbx)		C store bi
+	mov	%rbp, 8(%rbx)		C store cnt
+	neg	%r8
+	mov	R32(%rbp), R32(%rcx)
+	mov	$1, R32(%rsi)
+ifdef(`SHLD_SLOW',`
+	shl	R8(%rcx), %rsi
+	neg	R32(%rcx)
+	mov	%rax, %rbp
+	shr	R8(%rcx), %rax
+	or	%rax, %rsi
+	mov	%rbp, %rax
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), %rax, %rsi	C FIXME: Slow on Atom and Nano
+')
+	imul	%r8, %rsi
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 16(%rbx)		C store B1modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 24(%rbx)		C store B2modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 32(%rbx)		C store B3modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 40(%rbx)		C store B4modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	add	%rdx, %r12
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %r12
+
+	shr	R8(%rcx), %r12
+	mov	%r12, 48(%rbx)		C store B5modb
+
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/mod_34lsub1.asm b/mpn/x86_64/mod_34lsub1.asm
new file mode 100644
index 0000000..3dd7721
--- /dev/null
+++ b/mpn/x86_64/mod_34lsub1.asm
@@ -0,0 +1,215 @@
+dnl  AMD64 mpn_mod_34lsub1 -- remainder modulo 2^48-1.
+
+dnl  Copyright 2000-2002, 2004, 2005, 2007, 2009-2012 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	    cycles/limb
+C AMD K8,K9	 0.67	   0.583 is possible with zero-reg instead of $0, 4-way
+C AMD K10	 0.67	   this seems hard to beat
+C AMD bd1	 1
+C AMD bd2	 1
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 0.62
+C AMD bobcat	 1.07
+C AMD jaguar	 1
+C Intel P4	 7.35	   terrible, use old code
+C Intel core2	 1.25	   1+epsilon with huge unrolling
+C Intel NHM	 1.15	   this seems hard to beat
+C Intel SBR	 0.93
+C Intel IBR	 0.93
+C Intel HWL	 0.82
+C Intel BWL	 0.64
+C Intel SKY	 0.60
+C Intel atom	 2.5
+C Intel SLM      1.59
+C VIA nano	 1.25	   this seems hard to beat
+
+C INPUT PARAMETERS
+define(`ap',	%rdi)
+define(`n',	%rsi)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * Review feed-in and wind-down code.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	FUNC_ENTRY(2)
+
+	mov	$0x0000FFFFFFFFFFFF, %r11
+
+	mov	(ap), %rax
+
+	cmp	$2, %rsi
+	ja	L(gt2)
+
+	jb	L(one)
+
+	mov	8(ap), %rsi
+	mov	%rax, %rdx
+	shr	$48, %rax		C src[0] low
+
+	and	%r11, %rdx		C src[0] high
+	add	%rdx, %rax
+	mov	R32(%rsi), R32(%rdx)
+
+	shr	$32, %rsi		C src[1] high
+	add	%rsi, %rax
+
+	shl	$16, %rdx		C src[1] low
+	add	%rdx, %rax
+L(one):	FUNC_EXIT()
+	ret
+
+
+C Don't change this, the wind-down code is not able to handle greater values
+define(UNROLL,3)
+
+L(gt2):	mov	8(ap), %rcx
+	mov	16(ap), %rdx
+	xor	%r9, %r9
+	add	$24, ap
+	sub	$eval(UNROLL*3+3), %rsi
+	jc	L(end)
+	ALIGN(16)
+L(top):
+	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+forloop(i,1,UNROLL-1,`dnl
+	add	eval(i*24)(ap), %rax
+	adc	eval(i*24+8)(ap), %rcx
+	adc	eval(i*24+16)(ap), %rdx
+	adc	$0, %r9
+')dnl
+	add	$eval(UNROLL*24), ap
+	sub	$eval(UNROLL*3), %rsi
+	jnc	L(top)
+
+L(end):
+	lea	L(tab)(%rip), %r8
+ifdef(`PIC',
+`	movslq	36(%r8,%rsi,4), %r10
+	add	%r10, %r8
+	jmp	*%r8
+',`
+	jmp	*72(%r8,%rsi,8)
+')
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(4), L(tab))
+	JMPENT(	L(5), L(tab))
+	JMPENT(	L(6), L(tab))
+	JMPENT(	L(7), L(tab))
+	JMPENT(	L(8), L(tab))
+	TEXT
+
+L(6):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(3):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	jmp	L(cj1)
+
+L(7):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(4):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(1):	add	(ap), %rax
+	adc	$0, %rcx
+	jmp	L(cj2)
+
+L(8):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(5):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(2):	add	(ap), %rax
+	adc	8(ap), %rcx
+
+L(cj2):	adc	$0, %rdx
+L(cj1):	adc	$0, %r9
+L(0):	add	%r9, %rax
+	adc	$0, %rcx
+	adc	$0, %rdx
+	adc	$0, %rax
+
+	mov	%rax, %rdi		C 0mod3
+	shr	$48, %rax		C 0mod3 high
+
+	and	%r11, %rdi		C 0mod3 low
+	mov	R32(%rcx), R32(%r10)	C 1mod3
+
+	shr	$32, %rcx		C 1mod3 high
+
+	add	%rdi, %rax		C apply 0mod3 low
+	movzwl	%dx, R32(%rdi)		C 2mod3
+	shl	$16, %r10		C 1mod3 low
+
+	add	%rcx, %rax		C apply 1mod3 high
+	shr	$16, %rdx		C 2mod3 high
+
+	add	%r10, %rax		C apply 1mod3 low
+	shl	$32, %rdi		C 2mod3 low
+
+	add	%rdx, %rax		C apply 2mod3 high
+	add	%rdi, %rax		C apply 2mod3 low
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/mode1o.asm b/mpn/x86_64/mode1o.asm
new file mode 100644
index 0000000..a1775e3
--- /dev/null
+++ b/mpn/x86_64/mode1o.asm
@@ -0,0 +1,171 @@
+dnl  AMD64 mpn_modexact_1_odd -- Hensel norm remainder.
+
+dnl  Copyright 2000-2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	10
+C AMD K10	10
+C Intel P4	33
+C Intel core2	13
+C Intel corei	14.5
+C Intel atom	35
+C VIA nano	 ?
+
+
+C The dependent chain in the main loop is
+C
+C                            cycles
+C	sub	%rdx, %rax	1
+C	imul	%r9, %rax	4
+C	mul	%r8		5
+C			      ----
+C       total		       10
+C
+C The mov load from src seems to need to be scheduled back before the jz to
+C achieve this speed, out-of-order execution apparently can't completely hide
+C the latency otherwise.
+C
+C The l=src[i]-cbit step is rotated back too, since that allows us to avoid it
+C for the first iteration (where there's no cbit).
+C
+C The code alignment used (32-byte) for the loop also seems necessary.  Without
+C that the non-PIC case has adc crossing the 0x60 offset, apparently making it
+C run at 11 cycles instead of 10.
+
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_modexact_1_odd)
+	FUNC_ENTRY(3)
+	mov	$0, R32(%rcx)
+IFDOS(`	jmp	L(ent)		')
+
+PROLOGUE(mpn_modexact_1c_odd)
+	FUNC_ENTRY(4)
+L(ent):
+	C rdi	src
+	C rsi	size
+	C rdx	divisor
+	C rcx	carry
+
+	mov	%rdx, %r8		C d
+	shr	R32(%rdx)		C d/2
+
+	LEA(	binvert_limb_table, %r9)
+
+	and	$127, R32(%rdx)
+	mov	%rcx, %r10		C initial carry
+
+	movzbl	(%r9,%rdx), R32(%rdx)	C inv 8 bits
+
+	mov	(%rdi), %rax		C src[0]
+	lea	(%rdi,%rsi,8), %r11	C src end
+	mov	%r8, %rdi		C d, made available to imull
+
+	lea	(%rdx,%rdx), R32(%rcx)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+
+	neg	%rsi			C -size
+
+	imul	R32(%rdi), R32(%rdx)	C inv*inv*d
+
+	sub	R32(%rdx), R32(%rcx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rcx,%rcx), R32(%rdx)	C 2*inv
+	imul	R32(%rcx), R32(%rcx)	C inv*inv
+
+	imul	R32(%rdi), R32(%rcx)	C inv*inv*d
+
+	sub	R32(%rcx), R32(%rdx)	C inv = 2*inv - inv*inv*d, 32 bits
+	xor	R32(%rcx), R32(%rcx)	C initial cbit
+
+	lea	(%rdx,%rdx), %r9	C 2*inv
+	imul	%rdx, %rdx		C inv*inv
+
+	imul	%r8, %rdx		C inv*inv*d
+
+	sub	%rdx, %r9		C inv = 2*inv - inv*inv*d, 64 bits
+	mov	%r10, %rdx		C initial climb
+
+	ASSERT(e,`	C d*inv == 1 mod 2^64
+	mov	%r8, %r10
+	imul	%r9, %r10
+	cmp	$1, %r10')
+
+	inc	%rsi
+	jz	L(one)
+
+
+	ALIGN(16)
+L(top):
+	C rax	l = src[i]-cbit
+	C rcx	new cbit, 0 or 1
+	C rdx	climb, high of last product
+	C rsi	counter, limbs, negative
+	C rdi
+	C r8	divisor
+	C r9	inverse
+	C r11	src end ptr
+
+	sub	%rdx, %rax		C l = src[i]-cbit - climb
+
+	adc	$0, %rcx		C more cbit
+	imul	%r9, %rax		C q = l * inverse
+
+	mul	%r8			C climb = high (q * d)
+
+	mov	(%r11,%rsi,8), %rax	C src[i+1]
+	sub	%rcx, %rax		C next l = src[i+1] - cbit
+	setc	R8(%rcx)		C new cbit
+
+	inc	%rsi
+	jnz	L(top)
+
+
+L(one):
+	sub	%rdx, %rax		C l = src[i]-cbit - climb
+
+	adc	$0, %rcx		C more cbit
+	imul	%r9, %rax		C q = l * inverse
+
+	mul	%r8			C climb = high (q * d)
+
+	lea	(%rcx,%rdx), %rax	C climb+cbit
+	FUNC_EXIT()
+	ret
+
+EPILOGUE(mpn_modexact_1c_odd)
+EPILOGUE(mpn_modexact_1_odd)
diff --git a/mpn/x86_64/mul_1.asm b/mpn/x86_64/mul_1.asm
new file mode 100644
index 0000000..02f6531
--- /dev/null
+++ b/mpn/x86_64/mul_1.asm
@@ -0,0 +1,192 @@
+dnl  AMD64 mpn_mul_1.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      2.54
+C AMD K10        2.54
+C AMD bull       4.98
+C AMD pile       4.80
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.37
+C AMD jaguar     6.16
+C Intel P4      12.6
+C Intel core2    4.05
+C Intel NHM      4.0
+C Intel SBR      2.91
+C Intel IBR      2.73
+C Intel HWL      2.44
+C Intel BWL      2.39
+C Intel SKL      2.44
+C Intel atom    19.8
+C Intel SLM      9.0
+C VIA nano       4.25
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * The loop is great, but the prologue and epilogue code was quickly written.
+C    Tune it!
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vl',      `%rcx')   C r9
+
+define(`n',       `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFDOS(`	define(`up', ``%rsi'')	') dnl
+IFDOS(`	define(`rp', ``%rcx'')	') dnl
+IFDOS(`	define(`vl', ``%r9'')	') dnl
+IFDOS(`	define(`r9', ``rdi'')	') dnl
+IFDOS(`	define(`n',  ``%r8'')	') dnl
+IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1c)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+	push	%rbx
+IFSTD(`	mov	%r8, %r10')
+IFDOS(`	mov	64(%rsp), %r10')	C 40 + 3*8  (3 push insns)
+	jmp	L(common)
+EPILOGUE()
+
+PROLOGUE(mpn_mul_1)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	push	%rbx
+	xor	%r10, %r10
+L(common):
+	mov	(up), %rax		C read first u limb early
+IFSTD(`	mov	n_param, %rbx   ')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %rbx         ')
+	mul	vl
+IFSTD(`	mov	%rbx, n         ')
+
+	add	%r10, %rax
+	adc	$0, %rdx
+
+	and	$3, R32(%rbx)
+	jz	L(b0)
+	cmp	$2, R32(%rbx)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	dec	n
+	jne	L(gt1)
+	mov	%rax, (rp)
+	jmp	L(ret)
+L(gt1):	lea	8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r9
+	mov	(up,n,8), %rax
+	mov	%rdx, %r8
+	jmp	L(L1)
+
+L(b0):	lea	(up,n,8), up
+	lea	-16(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	mov	%rax, %r8
+	mov	%rdx, %rbx
+	jmp	 L(L0)
+
+L(b3):	lea	-8(up,n,8), up
+	lea	-24(rp,n,8), rp
+	neg	n
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	jmp	L(L3)
+
+L(b2):	lea	-16(up,n,8), up
+	lea	-32(rp,n,8), rp
+	neg	n
+	xor	%r8, %r8
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%rdx, %r9
+	jmp	L(L2)
+
+	ALIGN(16)
+L(top):	mov	%r10, (rp,n,8)
+	add	%rax, %r9
+	mov	(up,n,8), %rax
+	adc	%rdx, %r8
+	mov	$0, R32(%r10)
+L(L1):	mul	vl
+	mov	%r9, 8(rp,n,8)
+	add	%rax, %r8
+	adc	%rdx, %rbx
+L(L0):	mov	8(up,n,8), %rax
+	mul	vl
+	mov	%r8, 16(rp,n,8)
+	add	%rax, %rbx
+	adc	%rdx, %r10
+L(L3):	mov	16(up,n,8), %rax
+	mul	vl
+	mov	%rbx, 24(rp,n,8)
+	mov	$0, R32(%r8)		C zero
+	mov	%r8, %rbx		C zero
+	add	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%r8, %r9		C zero
+	adc	%rdx, %r9
+L(L2):	mul	vl
+	add	$4, n
+	js	 L(top)
+
+	mov	%r10, (rp,n,8)
+	add	%rax, %r9
+	adc	%r8, %rdx
+	mov	%r9, 8(rp,n,8)
+	add	%r8, %rdx
+L(ret):	mov	%rdx, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/mul_2.asm b/mpn/x86_64/mul_2.asm
new file mode 100644
index 0000000..1a9bc2c
--- /dev/null
+++ b/mpn/x86_64/mul_2.asm
@@ -0,0 +1,204 @@
+dnl  AMD64 mpn_mul_2 -- Multiply an n-limb vector with a 2-limb vector and
+dnl  store the result in a third limb vector.
+
+dnl  Copyright 2008, 2011, 2012, 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      4.53
+C AMD K10        4.53
+C AMD bull       9.76   10.37
+C AMD pile       9.22
+C AMD steam
+C AMD excavator
+C AMD bobcat    11.3
+C AMD jaguar    11.9
+C Intel P4      25.0
+C Intel core2    8.05
+C Intel NHM      7.72
+C Intel SBR      6.33
+C Intel IBR      6.15
+C Intel HWL      6.00
+C Intel BWL      4.44
+C Intel SKL      4.54
+C Intel atom    39.0
+C Intel SLM     24.0
+C VIA nano
+
+C This code is the result of running a code generation and optimization tool
+C suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Work on feed-in and wind-down code.
+C  * Convert "mov $0" to "xor".
+C  * Adjust initial lea to save some bytes.
+C  * Perhaps adjust n from n_param&3 value?
+C  * Replace with 2.25 c/l sequence.
+
+C INPUT PARAMETERS
+define(`rp',	 `%rdi')
+define(`up',	 `%rsi')
+define(`n_param',`%rdx')
+define(`vp',	 `%rcx')
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	(up), %rax
+
+	mov	n_param, n
+	neg	n
+	lea	-8(up,n_param,8), up
+	lea	-8(rp,n_param,8), rp
+
+	and	$3, R32(n_param)
+	jz	L(m2p0)
+	cmp	$2, R32(n_param)
+	jc	L(m2p1)
+	jz	L(m2p2)
+L(m2p3):
+	mul	v0
+	xor	R32(w3), R32(w3)
+	mov	%rax, w1
+	mov	%rdx, w2
+	mov	8(up,n,8), %rax
+	add	$-1, n
+	mul	v1
+	add	%rax, w2
+	jmp	L(m23)
+L(m2p0):
+	mul	v0
+	xor	R32(w2), R32(w2)
+	mov	%rax, w0
+	mov	%rdx, w1
+	jmp	L(m20)
+L(m2p1):
+	mul	v0
+	xor	R32(w3), R32(w3)
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	add	$1, n
+	jmp	L(m2top)
+L(m2p2):
+	mul	v0
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	8(up,n,8), %rax
+	add	$-2, n
+	jmp	L(m22)
+
+
+	ALIGN(32)
+L(m2top):
+	add	%rax, w3
+	adc	%rdx, w0
+	mov	0(up,n,8), %rax
+	adc	$0, R32(w1)
+	mov	$0, R32(w2)
+	mul	v1
+	add	%rax, w0
+	mov	w3, 0(rp,n,8)
+	adc	%rdx, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	add	%rax, w0
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+L(m20):	mov	8(up,n,8), %rax
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	16(up,n,8), %rax
+	mov	$0, R32(w3)
+	mul	v0
+	add	%rax, w1
+	mov	16(up,n,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mul	v1
+	add	%rax, w2
+	mov	w0, 8(rp,n,8)
+L(m23):	adc	%rdx, w3
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	$0, R32(w0)
+	add	%rax, w2
+	adc	%rdx, w3
+	mov	w1, 16(rp,n,8)
+	mov	24(up,n,8), %rax
+	mov	$0, R32(w1)
+	adc	$0, R32(w0)
+L(m22):	mul	v1
+	add	%rax, w3
+	mov	w2, 24(rp,n,8)
+	adc	%rdx, w0
+	mov	32(up,n,8), %rax
+	mul	v0
+	add	$4, n
+	js	L(m2top)
+
+
+	add	%rax, w3
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mov	(up), %rax
+	mul	v1
+	mov	w3, (rp)
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(rp)
+	mov	w1, %rax
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/popham.asm b/mpn/x86_64/popham.asm
new file mode 100644
index 0000000..57ead59
--- /dev/null
+++ b/mpn/x86_64/popham.asm
@@ -0,0 +1,163 @@
+dnl  AMD64 mpn_popcount, mpn_hamdist -- population count and hamming distance.
+
+dnl  Copyright 2004, 2005, 2007, 2010-2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`config.m4')
+
+
+C		     popcount	      hamdist
+C		    cycles/limb	    cycles/limb
+C AMD K8,K9		 6		 7
+C AMD K10		 6		 7
+C Intel P4		12		14.3
+C Intel core2		 7		 8
+C Intel corei		 ?		 7.3
+C Intel atom		16.5		17.5
+C VIA nano		 8.75		10.4
+
+C TODO
+C  * Tune.  It should be possible to reach 5 c/l for popcount and 6 c/l for
+C    hamdist for K8/K9.
+
+
+ifdef(`OPERATION_popcount',`
+  define(`func',`mpn_popcount')
+  define(`up',		`%rdi')
+  define(`n',		`%rsi')
+  define(`h55555555',	`%r10')
+  define(`h33333333',	`%r11')
+  define(`h0f0f0f0f',	`%rcx')
+  define(`h01010101',	`%rdx')
+  define(`POP',		`$1')
+  define(`HAM',		`dnl')
+')
+ifdef(`OPERATION_hamdist',`
+  define(`func',`mpn_hamdist')
+  define(`up',		`%rdi')
+  define(`vp',		`%rsi')
+  define(`n',		`%rdx')
+  define(`h55555555',	`%r10')
+  define(`h33333333',	`%r11')
+  define(`h0f0f0f0f',	`%rcx')
+  define(`h01010101',	`%r12')
+  define(`POP',		`dnl')
+  define(`HAM',		`$1')
+')
+
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+ POP(`	FUNC_ENTRY(2)		')
+ HAM(`	FUNC_ENTRY(3)		')
+	push	%rbx
+	mov	$0x5555555555555555, h55555555
+	push	%rbp
+	mov	$0x3333333333333333, h33333333
+ HAM(`	push	%r12		')
+	lea	(up,n,8), up
+	mov	$0x0f0f0f0f0f0f0f0f, h0f0f0f0f
+ HAM(`	lea	(vp,n,8), vp	')
+	neg	n
+	mov	$0x0101010101010101, h01010101
+	xor	R32(%rax), R32(%rax)
+	test	$1, R8(n)
+	jz	L(top)
+
+	mov	(up,n,8), %r8
+ HAM(`	xor	(vp,n,8), %r8	')
+
+	mov	%r8, %r9
+	shr	%r8
+	and	h55555555, %r8
+	sub	%r8, %r9
+
+	mov	%r9, %r8
+	shr	$2, %r9
+	and	h33333333, %r8
+	and	h33333333, %r9
+	add	%r8, %r9		C 16 4-bit fields (0..4)
+
+	dec	n
+	jmp	L(mid)
+
+	ALIGN(16)
+L(top):	mov	(up,n,8), %r8
+	mov	8(up,n,8), %rbx
+ HAM(`	xor	(vp,n,8), %r8	')
+ HAM(`	xor	8(vp,n,8), %rbx	')
+
+	mov	%r8, %r9
+	mov	%rbx, %rbp
+	shr	%r8
+	shr	%rbx
+	and	h55555555, %r8
+	and	h55555555, %rbx
+	sub	%r8, %r9
+	sub	%rbx, %rbp
+
+	mov	%r9, %r8
+	mov	%rbp, %rbx
+	shr	$2, %r9
+	shr	$2, %rbp
+	and	h33333333, %r8
+	and	h33333333, %r9
+	and	h33333333, %rbx
+	and	h33333333, %rbp
+	add	%r8, %r9		C 16 4-bit fields (0..4)
+	add	%rbx, %rbp		C 16 4-bit fields (0..4)
+
+	add	%rbp, %r9		C 16 4-bit fields (0..8)
+L(mid):	mov	%r9, %r8
+	shr	$4, %r9
+	and	h0f0f0f0f, %r8
+	and	h0f0f0f0f, %r9
+	add	%r8, %r9		C 8 8-bit fields (0..16)
+
+	imul	h01010101, %r9		C sum the 8 fields in high 8 bits
+	shr	$56, %r9
+
+	add	%r9, %rax		C add to total
+	add	$2, n
+	jnc	L(top)
+
+L(end):
+ HAM(`	pop	%r12		')
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/rsh1aors_n.asm b/mpn/x86_64/rsh1aors_n.asm
new file mode 100644
index 0000000..6a7d04d
--- /dev/null
+++ b/mpn/x86_64/rsh1aors_n.asm
@@ -0,0 +1,189 @@
+dnl  AMD64 mpn_rsh1add_n -- rp[] = (up[] + vp[]) >> 1
+dnl  AMD64 mpn_rsh1sub_n -- rp[] = (up[] - vp[]) >> 1
+
+dnl  Copyright 2003, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.14	(mpn_add_n + mpn_rshift need 4.125)
+C AMD K10	 2.14	(mpn_add_n + mpn_rshift need 4.125)
+C Intel P4	12.75
+C Intel core2	 3.75
+C Intel NMH	 4.4
+C Intel SBR	 ?
+C Intel atom	 ?
+C VIA nano	 3.25
+
+C TODO
+C  * Rewrite to use indexed addressing, like addlsh1.asm and sublsh1.asm.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`vp', `%rdx')
+define(`n',`  %rcx')
+
+ifdef(`OPERATION_rsh1add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func_n,	      mpn_rsh1add_n)
+	define(func_nc,	      mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func_n,	      mpn_rsh1sub_n)
+	define(func_nc,	      mpn_rsh1sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1add_nc mpn_rsh1sub_n mpn_rsh1sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+
+	xor	R32(%rax), R32(%rax)
+	neg	%r8			C set C flag from parameter
+	mov	(up), %rbx
+	ADCSBB	(vp), %rbx
+	jmp	L(ent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	xor	R32(%rax), R32(%rax)
+	mov	(up), %rbx
+	ADDSUB	(vp), %rbx
+L(ent):
+	rcr	%rbx			C rotate, save acy
+	adc	R32(%rax), R32(%rax)	C return value
+
+	mov	R32(n), R32(%r11)
+	and	$3, R32(%r11)
+
+	cmp	$1, R32(%r11)
+	je	L(do)			C jump if n = 1 5 9 ...
+
+L(n1):	cmp	$2, R32(%r11)
+	jne	L(n2)			C jump unless n = 2 6 10 ...
+	add	%rbx, %rbx		C rotate carry limb, restore acy
+	mov	8(up), %r10
+	ADCSBB	8(vp), %r10
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	rcr	%r10
+	rcr	%rbx
+	mov	%rbx, -8(rp)
+	jmp	L(cj1)
+
+L(n2):	cmp	$3, R32(%r11)
+	jne	L(n3)			C jump unless n = 3 7 11 ...
+	add	%rbx, %rbx		C rotate carry limb, restore acy
+	mov	8(up), %r9
+	mov	16(up), %r10
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	rcr	%r10
+	rcr	%r9
+	rcr	%rbx
+	mov	%rbx, -16(rp)
+	jmp	L(cj2)
+
+L(n3):	dec	n			C come here for n = 4 8 12 ...
+	add	%rbx, %rbx		C rotate carry limb, restore acy
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	mov	24(up), %r10
+	ADCSBB	24(vp), %r10
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	rcr	%r10
+	rcr	%r9
+	rcr	%r8
+	rcr	%rbx
+	mov	%rbx, -24(rp)
+	mov	%r8, -16(rp)
+L(cj2):	mov	%r9, -8(rp)
+L(cj1):	mov	%r10, %rbx
+
+L(do):
+	shr	$2, n			C				4
+	je	L(end)			C				2
+	ALIGN(16)
+L(top):	add	%rbx, %rbx		C rotate carry limb, restore acy
+
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	mov	24(up), %r10
+	mov	32(up), %r11
+	ADCSBB	24(vp), %r10
+	ADCSBB	32(vp), %r11
+
+	lea	32(up), up
+	lea	32(vp), vp
+
+	rcr	%r11			C rotate, save acy
+	rcr	%r10
+	rcr	%r9
+	rcr	%r8
+
+	rcr	%rbx
+	mov	%rbx, (rp)
+	mov	%r8, 8(rp)
+	mov	%r9, 16(rp)
+	mov	%r10, 24(rp)
+	mov	%r11, %rbx
+
+	lea	32(rp), rp
+	dec	n
+	jne	L(top)
+
+L(end):	mov	%rbx, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/rshift.asm b/mpn/x86_64/rshift.asm
new file mode 100644
index 0000000..eb04e29
--- /dev/null
+++ b/mpn/x86_64/rshift.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 2003, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.375
+C AMD K10	 2.375
+C Intel P4	 8
+C Intel core2	 2.11
+C Intel corei	 ?
+C Intel atom	 5.75
+C VIA nano	 3.5
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_rshift)
+	FUNC_ENTRY(4)
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	(up), %rax
+	shl	R8(%rcx), %rax		C function return value
+	neg	R32(%rcx)		C put lsh count in cl
+
+	lea	1(n), R32(%r8)
+
+	lea	-8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	neg	n
+
+	and	$3, R32(%r8)
+	je	L(rlx)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, 8(rp,n,8)
+	inc	n
+	jmp	L(rll)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, 8(rp,n,8)
+	inc	n
+	neg	R32(%rcx)		C put lsh count in cl
+L(1x):
+	cmp	$-1, n
+	je	L(ast)
+	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	mov	16(up,n,8), %r11
+	shr	R8(%rcx), %r11
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	mov	24(up,n,8), %r9
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	shl	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, 8(rp,n,8)
+	mov	%r11, 16(rp,n,8)
+	add	$2, n
+
+L(rll):	neg	R32(%rcx)		C put lsh count in cl
+L(rlx):	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	mov	16(up,n,8), %r11
+	shr	R8(%rcx), %r11
+
+	add	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(16)
+L(top):
+	C finish stuff from lsh block
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	mov	-8(up,n,8), %r9
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	shl	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, -24(rp,n,8)
+	mov	%r11, -16(rp,n,8)
+	C start two new rsh
+	mov	(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	shl	R8(%rcx), %r8
+	shl	R8(%rcx), %r9
+
+	C finish stuff from rsh block
+	neg	R32(%rcx)		C put lsh count in cl
+	mov	-8(up,n,8), %r10
+	mov	0(up,n,8), %r11
+	shr	R8(%rcx), %r10
+	or	%r10, %r8
+	shr	R8(%rcx), %r11
+	or	%r11, %r9
+	mov	%r8, -8(rp,n,8)
+	mov	%r9, 0(rp,n,8)
+	C start two new lsh
+	mov	8(up,n,8), %r10
+	mov	16(up,n,8), %r11
+	shr	R8(%rcx), %r10
+	shr	R8(%rcx), %r11
+
+	add	$4, n
+	jae	L(top)			C				      2
+L(end):
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-8(up), %r8
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	(up), %r9
+	shl	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, -16(rp)
+	mov	%r11, -8(rp)
+
+	neg	R32(%rcx)		C put lsh count in cl
+L(ast):	mov	(up), %r10
+	shr	R8(%rcx), %r10
+	mov	%r10, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/sec_tabselect.asm b/mpn/x86_64/sec_tabselect.asm
new file mode 100644
index 0000000..d145630
--- /dev/null
+++ b/mpn/x86_64/sec_tabselect.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb          good for cpu
+C AMD K8,K9	 1.5			Y
+C AMD K10	 1.4
+C AMD bd1	 2.64
+C AMD bobcat	 2.15			Y
+C Intel P4	 4
+C Intel core2	 1.38
+C Intel NHM	 1.75
+C Intel SBR	 1.25
+C Intel atom	 2.5			Y
+C VIA nano	 1.75			Y
+
+C NOTES
+C  * This has not been tuned for any specific processor.  Its speed should not
+C    be too bad, though.
+C  * Using SSE2/AVX2 could result in many-fold speedup.
+C  * WORKS FOR n mod 4 = 0 ONLY!
+
+C mpn_sec_tabselect (mp_limb_t *rp, mp_limb_t *tp, mp_size_t n, mp_size_t nents, mp_size_t which)
+define(`rp',     `%rdi')
+define(`tp',     `%rsi')
+define(`n',      `%rdx')
+define(`nents',  `%rcx')
+define(`which',  `%r8')
+
+define(`i',      `%rbp')
+define(`j',      `%r9')
+
+C rax  rbx  rcx  rdx  rdi  rsi  rbp   r8   r9  r10  r11  r12  r13  r14  r15
+C          nents  n   rp   tab   i   which j    *    *    *    *    *    *
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sec_tabselect)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	n, j
+	add	$-4, j
+	js	L(outer_end)
+
+L(outer_top):
+	mov	nents, i
+	push	tp
+	xor	R32(%r12), R32(%r12)
+	xor	R32(%r13), R32(%r13)
+	xor	R32(%r14), R32(%r14)
+	xor	R32(%r15), R32(%r15)
+	mov	which, %rbx
+
+	ALIGN(16)
+L(top):	sub	$1, %rbx
+	sbb	%rax, %rax
+	mov	0(tp), %r10
+	mov	8(tp), %r11
+	and	%rax, %r10
+	and	%rax, %r11
+	or	%r10, %r12
+	or	%r11, %r13
+	mov	16(tp), %r10
+	mov	24(tp), %r11
+	and	%rax, %r10
+	and	%rax, %r11
+	or	%r10, %r14
+	or	%r11, %r15
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(top)
+
+	mov	%r12, 0(rp)
+	mov	%r13, 8(rp)
+	mov	%r14, 16(rp)
+	mov	%r15, 24(rp)
+	pop	tp
+	lea	32(tp), tp
+	lea	32(rp), rp
+	add	$-4, j
+	jns	L(outer_top)
+L(outer_end):
+
+	test	$2, R8(n)
+	jz	L(b0x)
+L(b1x):	mov	nents, i
+	push	tp
+	xor	R32(%r12), R32(%r12)
+	xor	R32(%r13), R32(%r13)
+	mov	which, %rbx
+	ALIGN(16)
+L(tp2):	sub	$1, %rbx
+	sbb	%rax, %rax
+	mov	0(tp), %r10
+	mov	8(tp), %r11
+	and	%rax, %r10
+	and	%rax, %r11
+	or	%r10, %r12
+	or	%r11, %r13
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp2)
+	mov	%r12, 0(rp)
+	mov	%r13, 8(rp)
+	pop	tp
+	lea	16(tp), tp
+	lea	16(rp), rp
+
+L(b0x):	test	$1, R8(n)
+	jz	L(b00)
+L(b01):	mov	nents, i
+	xor	R32(%r12), R32(%r12)
+	mov	which, %rbx
+	ALIGN(16)
+L(tp1):	sub	$1, %rbx
+	sbb	%rax, %rax
+	mov	0(tp), %r10
+	and	%rax, %r10
+	or	%r10, %r12
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp1)
+	mov	%r12, 0(rp)
+
+L(b00):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/sqr_diag_addlsh1.asm b/mpn/x86_64/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..3eb32c6
--- /dev/null
+++ b/mpn/x86_64/sqr_diag_addlsh1.asm
@@ -0,0 +1,116 @@
+dnl  AMD64 mpn_sqr_diag_addlsh1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.5
+C AMD K10	 2.5
+C AMD bull	 3.6
+C AMD pile	 3.6
+C AMD steam	 ?
+C AMD bobcat	 4
+C AMD jaguar	 ?
+C Intel P4	 11.5
+C Intel core	 4
+C Intel NHM	 3.6
+C Intel SBR	 3.15
+C Intel IBR	 3.0
+C Intel HWL	 2.6
+C Intel BWL	 ?
+C Intel atom	14
+C VIA nano	 3.5
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',     `%rdi')
+define(`tp',     `%rsi')
+define(`up_arg', `%rdx')
+define(`n',      `%rcx')
+
+define(`up',     `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	dec	n
+	shl	n
+
+	mov	(up_arg), %rax
+
+	lea	(rp,n,8), rp
+	lea	(tp,n,8), tp
+	lea	(up_arg,n,4), up
+	neg	n
+
+	mul	%rax
+	mov	%rax, (rp,n,8)
+
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(mid)
+
+	ALIGN(16)
+L(top):	add	%r10, %r8
+	adc	%rax, %r9
+	mov	%r8, -8(rp,n,8)
+	mov	%r9, (rp,n,8)
+L(mid):	mov	8(up,n,4), %rax
+	mov	(tp,n,8), %r8
+	mov	8(tp,n,8), %r9
+	adc	%r8, %r8
+	adc	%r9, %r9
+	lea	(%rdx,%rbx), %r10
+	setc	R8(%rbx)
+	mul	%rax
+	add	$2, n
+	js	L(top)
+
+L(end):	add	%r10, %r8
+	adc	%rax, %r9
+	mov	%r8, I(-8(rp),-8(rp,n,8))
+	mov	%r9, I((rp),(rp,n,8))
+	adc	%rbx, %rdx
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/sublsh1_n.asm b/mpn/x86_64/sublsh1_n.asm
new file mode 100644
index 0000000..86fd16d
--- /dev/null
+++ b/mpn/x86_64/sublsh1_n.asm
@@ -0,0 +1,160 @@
+dnl  AMD64 mpn_sublsh1_n -- rp[] = up[] - (vp[] << 1)
+
+dnl  Copyright 2003, 2005-2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.2
+C AMD K10	 2.2
+C Intel P4	12.75
+C Intel core2	 3.45
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 3.25
+
+C Sometimes speed degenerates, supposedly related to that some operand
+C alignments cause cache conflicts.
+
+C The speed is limited by decoding/issue bandwidth.  There are 26 instructions
+C in the loop, which corresponds to 26/3/4 = 2.167 c/l.
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n', `%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sublsh1_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(vp), %r8
+	mov	R32(n), R32(%rax)
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+	xor	R32(%rbp), R32(%rbp)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	sbb	R32(%rax), R32(%rax)	C save scy
+	mov	(up,n,8), %rbp
+	mov	8(up,n,8), %rbx
+	sub	%r8, %rbp
+	sbb	%r9, %rbx
+	mov	%rbp, (rp,n,8)
+	mov	%rbx, 8(rp,n,8)
+	mov	16(up,n,8), %rbp
+	sbb	%r10, %rbp
+	mov	%rbp, 16(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$3, n
+	jmp	L(ent)
+
+L(b10):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	sbb	R32(%rax), R32(%rax)	C save scy
+	mov	(up,n,8), %rbp
+	mov	8(up,n,8), %rbx
+	sub	%r8, %rbp
+	sbb	%r9, %rbx
+	mov	%rbp, (rp,n,8)
+	mov	%rbx, 8(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$2, n
+	jmp	L(ent)
+
+L(b01):	add	%r8, %r8
+	sbb	R32(%rax), R32(%rax)	C save scy
+	mov	(up,n,8), %rbp
+	sub	%r8, %rbp
+	mov	%rbp, (rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	inc	n
+L(ent):	jns	L(end)
+
+	ALIGN(16)
+L(top):	add	R32(%rax), R32(%rax)	C restore scy
+
+	mov	(vp,n,8), %r8
+L(b00):	adc	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	mov	24(vp,n,8), %r11
+	adc	%r11, %r11
+
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+
+	mov	(up,n,8), %rbp
+	mov	8(up,n,8), %rbx
+	sbb	%r8, %rbp
+	sbb	%r9, %rbx
+	mov	%rbp, (rp,n,8)
+	mov	%rbx, 8(rp,n,8)
+	mov	16(up,n,8), %rbp
+	mov	24(up,n,8), %rbx
+	sbb	%r10, %rbp
+	sbb	%r11, %rbx
+	mov	%rbp, 16(rp,n,8)
+	mov	%rbx, 24(rp,n,8)
+
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$4, n
+	js	L(top)
+
+L(end):	add	R32(%rbp), R32(%rax)
+	neg	R32(%rax)
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/mpn/x86_64/x86_64-defs.m4 b/mpn/x86_64/x86_64-defs.m4
new file mode 100644
index 0000000..4e08f2a
--- /dev/null
+++ b/mpn/x86_64/x86_64-defs.m4
@@ -0,0 +1,493 @@
+divert(-1)
+
+dnl  m4 macros for amd64 assembler.
+
+dnl  Copyright 1999-2005, 2008, 2009, 2011-2013, 2017 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Usage: CPUVEC_FUNCS_LIST
+dnl
+dnl  A list of the functions from gmp-impl.h x86 struct cpuvec_t, in the
+dnl  order they appear in that structure.
+
+define(CPUVEC_FUNCS_LIST,
+``add_n',
+`addlsh1_n',
+`addlsh2_n',
+`addmul_1',
+`addmul_2',
+`bdiv_dbm1c',
+`cnd_add_n',
+`cnd_sub_n',
+`com',
+`copyd',
+`copyi',
+`divexact_1',
+`divrem_1',
+`gcd_11',
+`lshift',
+`lshiftc',
+`mod_1',
+`mod_1_1p',
+`mod_1_1p_cps',
+`mod_1s_2p',
+`mod_1s_2p_cps',
+`mod_1s_4p',
+`mod_1s_4p_cps',
+`mod_34lsub1',
+`modexact_1c_odd',
+`mul_1',
+`mul_basecase',
+`mullo_basecase',
+`preinv_divrem_1',
+`preinv_mod_1',
+`redc_1',
+`redc_2',
+`rshift',
+`sqr_basecase',
+`sub_n',
+`sublsh1_n',
+`submul_1'')
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  In the amd64 code we use explicit TEXT and ALIGN() calls in the code,
+dnl  since different alignments are wanted in various circumstances.  So for
+dnl  instance,
+dnl
+dnl                  TEXT
+dnl                  ALIGN(16)
+dnl          PROLOGUE(mpn_add_n)
+dnl                  ...
+dnl          EPILOGUE()
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+`	GLOBL	$1
+	TYPE($1,`function')
+	COFF_TYPE($1)
+$1:
+')
+
+
+dnl  Usage: COFF_TYPE(GSYM_PREFIX`'foo)
+dnl
+dnl  Emit COFF style ".def ... .endef" type information for a function, when
+dnl  supported.  The argument should include any GSYM_PREFIX.
+dnl
+dnl  See autoconf macro GMP_ASM_COFF_TYPE for HAVE_COFF_TYPE.
+
+define(COFF_TYPE,
+m4_assert_numargs(1)
+m4_assert_defined(`HAVE_COFF_TYPE')
+`ifelse(HAVE_COFF_TYPE,yes,
+	`.def	$1
+	.scl	2
+	.type	32
+	.endef')')
+
+
+dnl  Usage: ASSERT([cond][,instructions])
+dnl
+dnl  If WANT_ASSERT is 1, output the given instructions and expect the given
+dnl  flags condition to then be satisfied.  For example,
+dnl
+dnl         ASSERT(ne, `cmpq %rax, %rbx')
+dnl
+dnl  The instructions can be omitted to just assert a flags condition with
+dnl  no extra calculation.  For example,
+dnl
+dnl         ASSERT(nc)
+dnl
+dnl  When `instructions' is not empty, a pushfq/popfq is added for
+dnl  convenience to preserve the flags, but the instructions themselves must
+dnl  preserve any registers that matter.
+dnl
+dnl  The condition can be omitted to just output the given instructions when
+dnl  assertion checking is wanted.  In this case the pushf/popf is omitted.
+dnl  For example,
+dnl
+dnl         ASSERT(, `movq %rax, VAR_KEEPVAL')
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+`ifelse(`$1',,
+`	$2',
+`ifelse(`$2',,,
+`	pushfq')
+	$2
+	`j$1'	L(ASSERT_ok`'ASSERT_counter)
+	ud2	C assertion failed
+L(ASSERT_ok`'ASSERT_counter):
+ifelse(`$2',,,`	popfq')
+define(`ASSERT_counter',incr(ASSERT_counter))')')')
+
+define(ASSERT_counter,1)
+
+dnl LEA - load effective address
+dnl
+dnl FIXME: We should never create a GOT entry and therefore use the simpler 2nd
+dnl variant always. We need to understand what happens for not-yet-hidden
+dnl symbols first.
+dnl
+define(`LEA',`dnl
+ifdef(`PIC',
+	`mov	$1@GOTPCREL(%rip), $2'
+,
+	`lea	$1(%rip), $2')
+')
+
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(2,3)
+`	ifelse($#,3,`$3',`RODATA')
+	ALIGN($2)
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	SIZE(`$1',.-`$1')')
+
+
+define(`R32',
+	`ifelse($1,`%rax',`%eax',
+		$1,`%rbx',`%ebx',
+		$1,`%rcx',`%ecx',
+		$1,`%rdx',`%edx',
+		$1,`%rsi',`%esi',
+		$1,`%rdi',`%edi',
+		$1,`%rbp',`%ebp',
+		$1,`%r8',`%r8d',
+		$1,`%r9',`%r9d',
+		$1,`%r10',`%r10d',
+		$1,`%r11',`%r11d',
+		$1,`%r12',`%r12d',
+		$1,`%r13',`%r13d',
+		$1,`%r14',`%r14d',
+		$1,`%r15',`%r15d')')
+define(`R8',
+	`ifelse($1,`%rax',`%al',
+		$1,`%rbx',`%bl',
+		$1,`%rcx',`%cl',
+		$1,`%rdx',`%dl',
+		$1,`%rsi',`%sil',
+		$1,`%rdi',`%dil',
+		$1,`%rbp',`%bpl',
+		$1,`%r8',`%r8b',
+		$1,`%r9',`%r9b',
+		$1,`%r10',`%r10b',
+		$1,`%r11',`%r11b',
+		$1,`%r12',`%r12b',
+		$1,`%r13',`%r13b',
+		$1,`%r14',`%r14b',
+		$1,`%r15',`%r15b')')
+
+
+dnl  Usage: CALL(funcname)
+dnl
+
+define(`CALL',`dnl
+ifdef(`PIC',
+	`call	GSYM_PREFIX`'$1@PLT'
+,
+	`call	GSYM_PREFIX`'$1'
+)')
+
+define(`TCALL',`dnl
+ifdef(`PIC',
+	`jmp	GSYM_PREFIX`'$1@PLT'
+,
+	`jmp	GSYM_PREFIX`'$1'
+)')
+
+
+define(`JUMPTABSECT', `.section	.data.rel.ro.local,"a",@progbits')
+
+
+dnl  Usage: JMPENT(targlabel,tablabel)
+
+define(`JMPENT',`dnl
+ifdef(`PIC',
+	`.long	$1-$2'dnl
+,
+	`.quad	$1'dnl
+)')
+
+
+dnl  These macros are defined just for DOS64, where they provide calling
+dnl  sequence glue code.
+
+define(`FUNC_ENTRY',`')
+define(`FUNC_EXIT',`')
+
+
+dnl  Target ABI macros.
+
+define(`IFDOS',   `')
+define(`IFSTD',   `$1')
+define(`IFELF',   `$1')
+
+
+dnl  Usage: PROTECT(symbol)
+dnl
+dnl  Used for private GMP symbols that should never be overridden by users.
+dnl  This can save reloc entries and improve shlib sharing as well as
+dnl  application startup times
+
+define(`PROTECT',  `.hidden $1')
+
+
+dnl  Usage: x86_lookup(target, key,value, key,value, ...)
+dnl
+dnl  Look for `target' among the `key' parameters.
+dnl
+dnl  x86_lookup expands to the corresponding `value', or generates an error
+dnl  if `target' isn't found.
+
+define(x86_lookup,
+m4_assert_numargs_range(1,999)
+`ifelse(eval($#<3),1,
+`m4_error(`unrecognised part of x86 instruction: $1
+')',
+`ifelse(`$1',`$2', `$3',
+`x86_lookup(`$1',shift(shift(shift($@))))')')')
+
+
+dnl  Usage: x86_opcode_regxmm(reg)
+dnl
+dnl  Validate the given xmm register, and return its number, 0 to 7.
+
+define(x86_opcode_regxmm,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_regxmm_list)')
+
+define(x86_opcode_regxmm_list,
+``%xmm0',0,
+`%xmm1',1,
+`%xmm2',2,
+`%xmm3',3,
+`%xmm4',4,
+`%xmm5',5,
+`%xmm6',6,
+`%xmm7',7,
+`%xmm8',8,
+`%xmm9',9,
+`%xmm10',10,
+`%xmm11',11,
+`%xmm12',12,
+`%xmm13',13,
+`%xmm14',14,
+`%xmm15',15')
+
+dnl  Usage: palignr($imm,%srcreg,%dstreg)
+dnl
+dnl  Emit a palignr instruction, using a .byte sequence, since obsolete but
+dnl  still distributed versions of gas don't know SSSE3 instructions.
+
+define(`palignr',
+m4_assert_numargs(3)
+`.byte	0x66,dnl
+ifelse(eval(x86_opcode_regxmm($3) >= 8 || x86_opcode_regxmm($2) >= 8),1,
+       `eval(0x40+x86_opcode_regxmm($3)/8*4+x86_opcode_regxmm($2)/8),')dnl
+0x0f,0x3a,0x0f,dnl
+eval(0xc0+x86_opcode_regxmm($3)%8*8+x86_opcode_regxmm($2)%8),dnl
+substr($1,1)')
+
+
+dnl  Usage
+dnl
+dnl    regnum(op)   raw operand index (so slightly misnamed)
+dnl    regnumh(op)  high bit of register operand nimber
+dnl    ix(op)       0 for reg operand, 1 for plain pointer operand.
+dnl
+
+define(`regnum',`x86_lookup(`$1',oplist)')
+define(`regnumh',`eval(regnum($1)/8 & 1)')
+define(`ix',`eval(regnum($1)/16)')
+define(`oplist',
+``%rax',   0, `%rcx',   1, `%rdx',   2,  `%rbx',   3,
+ `%rsp',   4, `%rbp',   5, `%rsi',   6,  `%rdi',   7,
+ `%r8',    8, `%r9',    9, `%r10',  10,  `%r11',  11,
+ `%r12',  12, `%r13',  13, `%r14',  14,  `%r15',  15,
+ `(%rax)',16, `(%rcx)',17, `(%rdx)',18,  `(%rbx)',19,
+ `(%rsp)',20, `(%rbp)',21, `(%rsi)',22,  `(%rdi)',23,
+ `(%r8)', 24, `(%r9)', 25, `(%r10)',26,  `(%r11)',27,
+ `(%r12)',28, `(%r13)',29, `(%r14)',30,  `(%r15)',31')
+
+dnl  Usage (by mulx, shlx, shrx)
+dnl
+dnl     reg1,reg2,reg3,opc1,opc2
+dnl
+dnl  or
+dnl
+dnl     (reg1),reg2,reg3,opc1,opc2
+dnl
+dnl  where reg1 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl  or
+dnl
+dnl     off,(reg1),reg2,reg3,opc1,opc2
+dnl
+dnl  where reg1 is any register but rsp,r12.
+dnl
+dnl  The exceptions are due to special coding needed for some registers; rsp
+dnl  and r12 need an extra byte 0x24 at the end while rbp and r13 lack the
+dnl  offset-less form.
+dnl
+dnl  Other addressing forms are not handled.  Invalid forms are not properly
+dnl  detected.  Offsets that don't fit one byte are not handled correctly.
+
+define(`c4_helper',`dnl
+.byte	0xc4`'dnl
+ifelse(`$#',5,`dnl
+,eval(0xe2^32*regnumh($1)^128*regnumh($3))`'dnl
+,eval(0x$4-8*regnum($2))`'dnl
+,0x$5`'dnl
+,eval(0xc0+(7 & regnum($1))+8*(7 & regnum($3))-0xc0*ix($1))`'dnl
+',`$#',6,`dnl
+,eval(0xe2^32*regnumh($2)^128*regnumh($4))`'dnl
+,eval(0x$5-8*regnum($3))`'dnl
+,0x$6`'dnl
+,eval(0x40+(7 & regnum($2))+8*(7 & regnum($4)))`'dnl
+,eval(($1 + 256) % 256)`'dnl
+')')
+
+
+dnl  Usage
+dnl
+dnl     mulx(reg1,reg2,reg3)
+dnl
+dnl  or
+dnl
+dnl     mulx((reg1),reg2,reg3)
+dnl
+dnl  where reg1 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl     mulx(off,(reg1),reg2,reg3)
+dnl
+dnl  where reg1 is any register but rsp,r12.
+
+define(`mulx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($1,$2,$3,fb,f6)',`dnl         format 1,2
+c4_helper($1,$2,$3,$4,fb,f6)'dnl	format 3
+)')
+
+
+dnl  Usage
+dnl
+dnl     shlx(reg1,reg2,reg3)
+dnl     shrx(reg1,reg2,reg3)
+dnl
+dnl  or
+dnl
+dnl     shlx(reg1,(reg2),reg3)
+dnl     shrx(reg1,(reg2),reg3)
+dnl
+dnl  where reg2 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl     shlx(reg1,off,(reg2),reg3)
+dnl     shrx(reg1,off,(reg2),reg3)
+dnl
+dnl  where reg2 is any register but rsp,r12.
+
+define(`shlx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($2,$1,$3,f9,f7)',`dnl         format 1,2
+c4_helper($1,$3,$2,$4,f9,f7)'dnl        format 3
+)')
+
+define(`shrx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($2,$1,$3,fb,f7)',`dnl         format 1,2
+c4_helper($1,$3,$2,$4,fb,f7)'dnl        format 3
+)')
+
+define(`sarx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($2,$1,$3,fa,f7)',`dnl         format 1,2
+c4_helper($1,$3,$2,$4,fa,f7)'dnl        format 3
+)')
+
+
+dnl  Usage
+dnl
+dnl     adcx(reg1,reg2)
+dnl     adox(reg1,reg2)
+dnl
+dnl  or
+dnl
+dnl     adcx((reg1),reg2)
+dnl     adox((reg1),reg2)
+dnl
+dnl  where reg1 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl     adcx(off,(reg1),reg2)
+dnl     adox(off,(reg1),reg2)
+dnl
+dnl  where reg1 is any register but rsp,r12.
+dnl
+dnl  The exceptions are due to special coding needed for some registers; rsp
+dnl  and r12 need an extra byte 0x24 at the end while rbp and r13 lack the
+dnl  offset-less form.
+dnl
+dnl  Other addressing forms are not handled.  Invalid forms are not properly
+dnl  detected.  Offsets that don't fit one byte are not handled correctly.
+
+define(`adx_helper',`dnl
+,eval(0x48+regnumh($1)+4*regnumh($2))`'dnl
+,0x0f`'dnl
+,0x38`'dnl
+,0xf6`'dnl
+')
+
+define(`adx',`dnl
+ifelse(`$#',2,`dnl
+adx_helper($1,$2)dnl
+,eval(0xc0+(7 & regnum($1))+8*(7 & regnum($2))-0xc0*ix($1))`'dnl
+',`$#',3,`dnl
+adx_helper($2,$3)dnl
+,eval(0x40+(7 & regnum($2))+8*(7 & regnum($3)))`'dnl
+,eval(($1 + 256) % 256)`'dnl
+')')
+
+define(`adcx',`dnl
+.byte	0x66`'dnl
+adx($@)')
+
+define(`adox',`dnl
+.byte	0xf3`'dnl
+adx($@)')
+
+divert`'dnl
diff --git a/mpq/abs.c b/mpq/abs.c
new file mode 100644
index 0000000..1f0bf13
--- /dev/null
+++ b/mpq/abs.c
@@ -0,0 +1,55 @@
+/* mpq_abs -- absolute value of a rational.
+
+Copyright 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpq_abs 1
+
+#include "gmp-impl.h"
+
+
+void
+mpq_abs (mpq_ptr dst, mpq_srcptr src)
+{
+  mp_size_t  num_abs_size = ABSIZ(NUM(src));
+
+  if (dst != src)
+    {
+      mp_size_t  den_size = SIZ(DEN(src));
+      mp_ptr dp;
+
+      dp = MPZ_NEWALLOC (NUM(dst), num_abs_size);
+      MPN_COPY (dp, PTR(NUM(src)), num_abs_size);
+
+      dp = MPZ_NEWALLOC (DEN(dst), den_size);
+      SIZ(DEN(dst)) = den_size;
+      MPN_COPY (dp, PTR(DEN(src)), den_size);
+    }
+
+  SIZ(NUM(dst)) = num_abs_size;
+}
diff --git a/mpq/aors.c b/mpq/aors.c
new file mode 100644
index 0000000..e86af94
--- /dev/null
+++ b/mpq/aors.c
@@ -0,0 +1,112 @@
+/* mpq_add, mpq_sub -- add or subtract rational numbers.
+
+Copyright 1991, 1994-1997, 2000, 2001, 2004, 2005 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+static void __gmpq_aors (REGPARM_3_1 (mpq_ptr, mpq_srcptr, mpq_srcptr, void (*) (mpz_ptr, mpz_srcptr, mpz_srcptr))) REGPARM_ATTR (1);
+#define mpq_aors(w,x,y,fun)  __gmpq_aors (REGPARM_3_1 (w, x, y, fun))
+
+REGPARM_ATTR (1) static void
+mpq_aors (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2,
+          void (*fun) (mpz_ptr, mpz_srcptr, mpz_srcptr))
+{
+  mpz_t gcd;
+  mpz_t tmp1, tmp2;
+  mp_size_t op1_num_size = ABSIZ(NUM(op1));
+  mp_size_t op1_den_size =   SIZ(DEN(op1));
+  mp_size_t op2_num_size = ABSIZ(NUM(op2));
+  mp_size_t op2_den_size =   SIZ(DEN(op2));
+  TMP_DECL;
+
+  TMP_MARK;
+  MPZ_TMP_INIT (gcd, MIN (op1_den_size, op2_den_size));
+  MPZ_TMP_INIT (tmp1, op1_num_size + op2_den_size);
+  MPZ_TMP_INIT (tmp2, op2_num_size + op1_den_size);
+
+  /* ROP might be identical to either operand, so don't store the
+     result there until we are finished with the input operands.  We
+     dare to overwrite the numerator of ROP when we are finished
+     with the numerators of OP1 and OP2.  */
+
+  mpz_gcd (gcd, DEN(op1), DEN(op2));
+  if (! MPZ_EQUAL_1_P (gcd))
+    {
+      mpz_t t;
+
+      MPZ_TMP_INIT (t, MAX (op1_num_size + op2_den_size,
+	     op2_num_size + op1_den_size) + 2 - SIZ(gcd));
+
+      mpz_divexact_gcd (t, DEN(op2), gcd);
+      mpz_divexact_gcd (tmp2, DEN(op1), gcd);
+
+      mpz_mul (tmp1, NUM(op1), t);
+      mpz_mul (t, NUM(op2), tmp2);
+
+      (*fun) (t, tmp1, t);
+
+      mpz_gcd (gcd, t, gcd);
+      if (MPZ_EQUAL_1_P (gcd))
+        {
+          mpz_set (NUM(rop), t);
+          mpz_mul (DEN(rop), DEN(op2), tmp2);
+        }
+      else
+        {
+          mpz_divexact_gcd (NUM(rop), t, gcd);
+          mpz_divexact_gcd (tmp1, DEN(op2), gcd);
+          mpz_mul (DEN(rop), tmp1, tmp2);
+        }
+    }
+  else
+    {
+      /* The common divisor is 1.  This is the case (for random input) with
+	 probability 6/(pi**2), which is about 60.8%.  */
+      mpz_mul (tmp1, NUM(op1), DEN(op2));
+      mpz_mul (tmp2, NUM(op2), DEN(op1));
+      (*fun) (NUM(rop), tmp1, tmp2);
+      mpz_mul (DEN(rop), DEN(op1), DEN(op2));
+    }
+  TMP_FREE;
+}
+
+
+void
+mpq_add (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpq_aors (rop, op1, op2, mpz_add);
+}
+
+void
+mpq_sub (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpq_aors (rop, op1, op2, mpz_sub);
+}
diff --git a/mpq/canonicalize.c b/mpq/canonicalize.c
new file mode 100644
index 0000000..7ac2331
--- /dev/null
+++ b/mpq/canonicalize.c
@@ -0,0 +1,61 @@
+/* mpq_canonicalize(op) -- Remove common factors of the denominator and
+   numerator in OP.
+
+Copyright 1991, 1994-1996, 2000, 2001, 2005, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_canonicalize (mpq_ptr op)
+{
+  mpz_t gcd;
+  TMP_DECL;
+
+  if (SIZ(DEN(op)) < 0)
+    {
+      SIZ(NUM(op)) = -SIZ(NUM(op));
+      SIZ(DEN(op)) = -SIZ(DEN(op));
+    }
+  else if (UNLIKELY (SIZ(DEN(op)) == 0))
+    DIVIDE_BY_ZERO;
+
+  TMP_MARK;
+
+  /* ??? Dunno if the 1+ is needed.  */
+  MPZ_TMP_INIT (gcd, 1 + MAX (ABSIZ(NUM(op)),
+			      SIZ(DEN(op))));
+
+  mpz_gcd (gcd, NUM(op), DEN(op));
+  if (! MPZ_EQUAL_1_P (gcd))
+    {
+      mpz_divexact_gcd (NUM(op), NUM(op), gcd);
+      mpz_divexact_gcd (DEN(op), DEN(op), gcd);
+    }
+  TMP_FREE;
+}
diff --git a/mpq/clear.c b/mpq/clear.c
new file mode 100644
index 0000000..60beb51
--- /dev/null
+++ b/mpq/clear.c
@@ -0,0 +1,41 @@
+/* mpq_clear -- free the space occupied by an mpq_t.
+
+Copyright 1991, 1994, 1995, 2000, 2001, 2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_clear (mpq_ptr x)
+{
+  if (ALLOC (NUM(x)))
+    __GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x)));
+  if (ALLOC (DEN(x)))
+    __GMP_FREE_FUNC_LIMBS (PTR(DEN(x)), ALLOC(DEN(x)));
+}
diff --git a/mpq/clears.c b/mpq/clears.c
new file mode 100644
index 0000000..68c6ad3
--- /dev/null
+++ b/mpq/clears.c
@@ -0,0 +1,52 @@
+/* mpq_clears() -- Clear multiple mpq_t variables.
+
+Copyright 2009, 2014, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpq_clears (mpq_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      if (ALLOC (NUM(x)))
+	__GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x)));
+      if (ALLOC (DEN(x)))
+	__GMP_FREE_FUNC_LIMBS (PTR(DEN(x)), ALLOC(DEN(x)));
+      x = va_arg (ap, mpq_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/mpq/cmp.c b/mpq/cmp.c
new file mode 100644
index 0000000..495e77e
--- /dev/null
+++ b/mpq/cmp.c
@@ -0,0 +1,169 @@
+/* mpq_cmp(u,v) -- Compare U, V.  Return positive, zero, or negative
+   based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1994, 1996, 2001, 2002, 2005, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static int
+mpq_cmp_numden (mpq_srcptr op1, mpz_srcptr num_op2, mpz_srcptr den_op2)
+{
+  mp_size_t num1_size = SIZ(NUM(op1));
+  mp_size_t den1_size = SIZ(DEN(op1));
+  mp_size_t num2_size = SIZ(num_op2);
+  mp_size_t den2_size = SIZ(den_op2);
+  int op2_is_int;
+  mp_limb_t d1h, d2h;
+  mp_size_t tmp1_size, tmp2_size;
+  mp_ptr tmp1_ptr, tmp2_ptr;
+  mp_size_t num1_sign;
+  int cc;
+  TMP_DECL;
+
+  /* need canonical signs to get right result */
+  ASSERT (den1_size > 0);
+  ASSERT (den2_size > 0);
+
+  if (num1_size == 0)
+    return -num2_size;
+  if (num2_size == 0)
+    return num1_size;
+  if ((num1_size ^ num2_size) < 0) /* I.e. are the signs different? */
+    return num1_size;
+
+  num1_sign = num1_size;
+  num1_size = ABS (num1_size);
+
+  /* THINK: Does storing d1h and d2h make sense? */
+  d1h = PTR(DEN(op1))[den1_size - 1];
+  d2h = PTR(den_op2)[den2_size - 1];
+  op2_is_int = (den2_size | d2h) == 1;
+  if ((unsigned) op2_is_int == (den1_size | d1h)) /* Both ops are integers */
+    /* return mpz_cmp (NUM (op1), num_op2); */
+    {
+      int cmp;
+
+      /* Cannot use num1_sign - num2_size, may overflow an "int" */
+      if (num1_sign != num2_size)
+	return (num1_sign > num2_size) ? 1 : -1;
+
+      cmp = mpn_cmp (PTR(NUM(op1)), PTR(num_op2), num1_size);
+      return (num1_sign > 0 ? cmp : -cmp);
+    }
+
+  num2_size = ABS (num2_size);
+
+  tmp1_size = num1_size + den2_size;
+  tmp2_size = num2_size + den1_size;
+
+  /* 1. Check to see if we can tell which operand is larger by just looking at
+     the number of limbs.  */
+
+  /* NUM1 x DEN2 is either TMP1_SIZE limbs or TMP1_SIZE-1 limbs.
+     Same for NUM1 x DEN1 with respect to TMP2_SIZE.  */
+  if (tmp1_size > tmp2_size + 1)
+    /* NUM1 x DEN2 is surely larger in magnitude than NUM2 x DEN1.  */
+    return num1_sign;
+  if (tmp2_size + op2_is_int > tmp1_size + 1)
+    /* NUM1 x DEN2 is surely smaller in magnitude than NUM2 x DEN1.  */
+    return -num1_sign;
+
+  /* 2. Same, but compare the number of significant bits.  */
+  {
+    int cnt1, cnt2;
+    mp_bitcnt_t bits1, bits2;
+
+    count_leading_zeros (cnt1, PTR(NUM(op1))[num1_size - 1]);
+    count_leading_zeros (cnt2, d2h);
+    bits1 = (mp_bitcnt_t) tmp1_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS;
+
+    count_leading_zeros (cnt1, PTR(num_op2)[num2_size - 1]);
+    count_leading_zeros (cnt2, d1h);
+    bits2 = (mp_bitcnt_t) tmp2_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS;
+
+    if (bits1 > bits2 + 1)
+      return num1_sign;
+    if (bits2 + op2_is_int > bits1 + 1)
+      return -num1_sign;
+  }
+
+  /* 3. Finally, cross multiply and compare.  */
+
+  TMP_MARK;
+  if (op2_is_int)
+    {
+      tmp2_ptr = TMP_ALLOC_LIMBS (tmp2_size);
+      tmp1_ptr = PTR(NUM(op1));
+      --tmp1_size;
+    }
+  else
+    {
+  TMP_ALLOC_LIMBS_2 (tmp1_ptr,tmp1_size, tmp2_ptr,tmp2_size);
+
+  if (num1_size >= den2_size)
+    tmp1_size -= 0 == mpn_mul (tmp1_ptr,
+			       PTR(NUM(op1)), num1_size,
+			       PTR(den_op2), den2_size);
+  else
+    tmp1_size -= 0 == mpn_mul (tmp1_ptr,
+			       PTR(den_op2), den2_size,
+			       PTR(NUM(op1)), num1_size);
+    }
+
+   if (num2_size >= den1_size)
+     tmp2_size -= 0 == mpn_mul (tmp2_ptr,
+				PTR(num_op2), num2_size,
+				PTR(DEN(op1)), den1_size);
+   else
+     tmp2_size -= 0 == mpn_mul (tmp2_ptr,
+				PTR(DEN(op1)), den1_size,
+				PTR(num_op2), num2_size);
+
+
+  cc = tmp1_size - tmp2_size != 0
+    ? tmp1_size - tmp2_size : mpn_cmp (tmp1_ptr, tmp2_ptr, tmp1_size);
+  TMP_FREE;
+  return num1_sign < 0 ? -cc : cc;
+}
+
+int
+mpq_cmp (mpq_srcptr op1, mpq_srcptr op2)
+{
+  return mpq_cmp_numden (op1, NUM(op2), DEN(op2));
+}
+
+int
+mpq_cmp_z (mpq_srcptr op1, mpz_srcptr op2)
+{
+  const static mp_limb_t one = 1;
+  const static mpz_t den = MPZ_ROINIT_N ((mp_limb_t *) &one, 1);
+
+  return mpq_cmp_numden (op1, op2, den);
+}
diff --git a/mpq/cmp_si.c b/mpq/cmp_si.c
new file mode 100644
index 0000000..faf472c
--- /dev/null
+++ b/mpq/cmp_si.c
@@ -0,0 +1,60 @@
+/* _mpq_cmp_si -- compare mpq and long/ulong fraction.
+
+Copyright 2001, 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Something like mpq_cmpabs_ui would be more useful for the neg/neg case,
+   and perhaps a version accepting a parameter to reverse the test, to make
+   it a tail call here.  */
+
+int
+_mpq_cmp_si (mpq_srcptr q, long n, unsigned long d)
+{
+  /* need canonical sign to get right result */
+  ASSERT (SIZ(DEN(q)) > 0);
+
+  if (n >= 0)
+    return _mpq_cmp_ui (q, n, d);
+  if (SIZ(NUM(q)) >= 0)
+    {
+      return 1;                                /* >=0 cmp <0 */
+    }
+  else
+    {
+      mpq_t  qabs;
+      SIZ(NUM(qabs)) = -SIZ(NUM(q));
+      PTR(NUM(qabs)) = PTR(NUM(q));
+      SIZ(DEN(qabs)) = SIZ(DEN(q));
+      PTR(DEN(qabs)) = PTR(DEN(q));
+
+      return - _mpq_cmp_ui (qabs, NEG_CAST (unsigned long, n), d);    /* <0 cmp <0 */
+    }
+}
diff --git a/mpq/cmp_ui.c b/mpq/cmp_ui.c
new file mode 100644
index 0000000..9d99a9a
--- /dev/null
+++ b/mpq/cmp_ui.c
@@ -0,0 +1,99 @@
+/* mpq_cmp_ui(u,vn,vd) -- Compare U with Vn/Vd.  Return positive, zero, or
+   negative based on if U > V, U == V, or U < V.  Vn and Vd may have
+   common factors.
+
+Copyright 1993, 1994, 1996, 2000-2003, 2005, 2014, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+_mpq_cmp_ui (mpq_srcptr op1, unsigned long int num2, unsigned long int den2)
+{
+  mp_size_t num1_size = SIZ(NUM(op1));
+  mp_size_t den1_size = SIZ(DEN(op1));
+  mp_size_t tmp1_size, tmp2_size;
+  mp_ptr tmp1_ptr, tmp2_ptr;
+  mp_limb_t cy_limb;
+  int cc;
+  TMP_DECL;
+
+#if GMP_NAIL_BITS != 0
+  if ((num2 | den2) > GMP_NUMB_MAX)
+    {
+      mpq_t op2;
+      mpq_init (op2);
+      mpz_set_ui (mpq_numref (op2), num2);
+      mpz_set_ui (mpq_denref (op2), den2);
+      cc = mpq_cmp (op1, op2);
+      mpq_clear (op2);
+      return cc;
+    }
+#endif
+
+  /* need canonical sign to get right result */
+  ASSERT (den1_size > 0);
+
+  if (UNLIKELY (den2 == 0))
+    DIVIDE_BY_ZERO;
+
+  if (num2 == 0)
+    return num1_size;
+  if (num1_size <= 0)
+    return -1;
+
+  /* NUM1 x DEN2 is either TMP1_SIZE limbs or TMP1_SIZE-1 limbs.
+     Same for NUM2 x DEN1 with respect to TMP2_SIZE.  */
+  /* If frac2 <= 1 (i.e. num2 <= den2), shortcut with a simpler
+     condition: num1 > den1. Here we only test sizes. */
+  if (num1_size > den1_size + (num2 > den2))
+    /* NUM1 x DEN2 is surely larger in magnitude than NUM2 x DEN1.  */
+    return num1_size;
+  if (den1_size > num1_size + (den2 > num2))
+    /* NUM1 x DEN2 is surely smaller in magnitude than NUM2 x DEN1.  */
+    return -num1_size;
+
+  TMP_MARK;
+  TMP_ALLOC_LIMBS_2 (tmp1_ptr, num1_size + 1, tmp2_ptr, den1_size + 1);
+
+  cy_limb = mpn_mul_1 (tmp1_ptr, PTR(NUM(op1)), num1_size,
+                       (mp_limb_t) den2);
+  tmp1_ptr[num1_size] = cy_limb;
+  tmp1_size = num1_size + (cy_limb != 0);
+
+  cy_limb = mpn_mul_1 (tmp2_ptr, PTR(DEN(op1)), den1_size,
+                       (mp_limb_t) num2);
+  tmp2_ptr[den1_size] = cy_limb;
+  tmp2_size = den1_size + (cy_limb != 0);
+
+  cc = tmp1_size - tmp2_size;
+  cc = cc != 0 ? cc : mpn_cmp (tmp1_ptr, tmp2_ptr, tmp1_size);
+  TMP_FREE;
+  return cc;
+}
diff --git a/mpq/div.c b/mpq/div.c
new file mode 100644
index 0000000..3bd9726
--- /dev/null
+++ b/mpq/div.c
@@ -0,0 +1,133 @@
+/* mpq_div -- divide two rational numbers.
+
+Copyright 1991, 1994-1996, 2000, 2001, 2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpq_div (mpq_ptr quot, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpz_t gcd1, gcd2;
+  mpz_t tmp1, tmp2;
+  mp_size_t op1_size;
+  mp_size_t op2_size;
+  mp_size_t alloc;
+  TMP_DECL;
+
+  op2_size = SIZ(NUM(op2));
+
+  if (UNLIKELY (op2_size == 0))
+    DIVIDE_BY_ZERO;
+
+  if (UNLIKELY (quot == op2))
+    {
+      if (UNLIKELY (op1 == op2))
+	{
+	  mpq_set_ui (quot, 1, 1);
+	  return;
+	}
+
+      /* We checked for op1 == op2: we are not in the x=x/x case.
+	 We compute x=y/x by computing x=inv(x)*y */
+      MPN_PTR_SWAP (PTR(NUM(quot)), ALLOC(NUM(quot)),
+		    PTR(DEN(quot)), ALLOC(DEN(quot)));
+      if (op2_size > 0)
+	{
+	  SIZ(NUM(quot)) = SIZ(DEN(quot));
+	  SIZ(DEN(quot)) = op2_size;
+	}
+      else
+	{
+	  SIZ(NUM(quot)) = - SIZ(DEN(quot));
+	  SIZ(DEN(quot)) = - op2_size;
+	}
+      mpq_mul (quot, quot, op1);
+      return;
+    }
+
+  op1_size = ABSIZ(NUM(op1));
+
+  if (op1_size == 0)
+    {
+      /* We special case this to simplify allocation logic; gcd(0,x) = x
+	 is a singular case for the allocations.  */
+      SIZ(NUM(quot)) = 0;
+      MPZ_NEWALLOC (DEN(quot), 1)[0] = 1;
+      SIZ(DEN(quot)) = 1;
+      return;
+    }
+
+  op2_size = ABS(op2_size);
+
+  TMP_MARK;
+
+  alloc = MIN (op1_size, op2_size);
+  MPZ_TMP_INIT (gcd1, alloc);
+
+  alloc = MAX (op1_size, op2_size);
+  MPZ_TMP_INIT (tmp1, alloc);
+
+  op2_size = SIZ(DEN(op2));
+  op1_size = SIZ(DEN(op1));
+
+  alloc = MIN (op1_size, op2_size);
+  MPZ_TMP_INIT (gcd2, alloc);
+
+  alloc = MAX (op1_size, op2_size);
+  MPZ_TMP_INIT (tmp2, alloc);
+
+  /* QUOT might be identical to OP1, so don't store the result there
+     until we are finished with the input operand.  We can overwrite
+     the numerator of QUOT when we are finished with the numerator of
+     OP1. */
+
+  mpz_gcd (gcd1, NUM(op1), NUM(op2));
+  mpz_gcd (gcd2, DEN(op2), DEN(op1));
+
+  mpz_divexact_gcd (tmp1, NUM(op1), gcd1);
+  mpz_divexact_gcd (tmp2, DEN(op2), gcd2);
+
+  mpz_mul (NUM(quot), tmp1, tmp2);
+
+  mpz_divexact_gcd (tmp1, NUM(op2), gcd1);
+  mpz_divexact_gcd (tmp2, DEN(op1), gcd2);
+
+  mpz_mul (DEN(quot), tmp1, tmp2);
+
+  /* Keep the denominator positive.  */
+  if (SIZ(DEN(quot)) < 0)
+    {
+      SIZ(DEN(quot)) = -SIZ(DEN(quot));
+      SIZ(NUM(quot)) = -SIZ(NUM(quot));
+    }
+
+  TMP_FREE;
+}
diff --git a/mpq/equal.c b/mpq/equal.c
new file mode 100644
index 0000000..9835e04
--- /dev/null
+++ b/mpq/equal.c
@@ -0,0 +1,68 @@
+/* mpq_equal(u,v) -- Compare U, V.  Return non-zero if they are equal, zero
+   if they are non-equal.
+
+Copyright 1996, 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpq_equal (mpq_srcptr op1, mpq_srcptr op2) __GMP_NOTHROW
+{
+  mp_size_t  num1_size, num2_size, den1_size, den2_size, i;
+  mp_srcptr  num1_ptr,  num2_ptr,  den1_ptr,  den2_ptr;
+
+  /* need fully canonical for correct results */
+  ASSERT_MPQ_CANONICAL (op1);
+  ASSERT_MPQ_CANONICAL (op2);
+
+  num1_size = SIZ(NUM(op1));
+  num2_size = SIZ(NUM(op2));
+  if (num1_size != num2_size)
+    return 0;
+
+  den1_size = SIZ(DEN(op1));
+  den2_size = SIZ(DEN(op2));
+  if (den1_size != den2_size)
+    return 0;
+
+  num1_ptr = PTR(NUM(op1));
+  num2_ptr = PTR(NUM(op2));
+  num1_size = ABS (num1_size);
+  for (i = 0; i < num1_size; i++)
+    if (num1_ptr[i] != num2_ptr[i])
+      return 0;
+
+  den1_ptr = PTR(DEN(op1));
+  den2_ptr = PTR(DEN(op2));
+  for (i = 0; i < den1_size; i++)
+    if (den1_ptr[i] != den2_ptr[i])
+      return 0;
+
+  return 1;
+}
diff --git a/mpq/get_d.c b/mpq/get_d.c
new file mode 100644
index 0000000..4d9779d
--- /dev/null
+++ b/mpq/get_d.c
@@ -0,0 +1,162 @@
+/* double mpq_get_d (mpq_t src) -- mpq to double, rounding towards zero.
+
+Copyright 1995, 1996, 2001-2005, 2018, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* All that's needed is to get the high 53 bits of the quotient num/den,
+   rounded towards zero.  More than 53 bits is fine, any excess is ignored
+   by mpn_get_d.
+
+   N_QLIMBS is how many quotient limbs we need to satisfy the mantissa of a
+   double, assuming the highest of those limbs is non-zero.  The target
+   qsize for mpn_tdiv_qr is then 1 more than this, since that function may
+   give a zero in the high limb (and non-zero in the second highest).
+
+   The use of 8*sizeof(double) in N_QLIMBS is an overestimate of the
+   mantissa bits, but it gets the same result as the true value (53 or 48 or
+   whatever) when rounded up to a multiple of GMP_NUMB_BITS, for non-nails.
+
+   Enhancements:
+
+   Use the true mantissa size in the N_QLIMBS formula, to save a divide step
+   in nails.
+
+   Examine the high limbs of num and den to see if the highest 1 bit of the
+   quotient will fall high enough that just N_QLIMBS-1 limbs is enough to
+   get the necessary bits, thereby saving a division step.
+
+   Bit shift either num or den to arrange for the above condition on the
+   high 1 bit of the quotient, to save a division step always.  A shift to
+   save a division step is definitely worthwhile with mpn_tdiv_qr, though we
+   may want to reassess this on big num/den when a quotient-only division
+   exists.
+
+   Maybe we could estimate the final exponent using nsize-dsize (and
+   possibly the high limbs of num and den), so as to detect overflow and
+   return infinity or zero quickly.  Overflow is never very helpful to an
+   application, and can therefore probably be regarded as abnormal, but we
+   may still like to optimize it if the conditions are easy.  (This would
+   only be for float formats we know, unknown formats are not important and
+   can be left to mpn_get_d.)
+
+   Future:
+
+   If/when mpn_tdiv_qr supports its qxn parameter we can use that instead of
+   padding n with zeros in temporary space.
+
+   Alternatives:
+
+   An alternative algorithm, that may be faster:
+   0. Let n be somewhat larger than the number of significant bits in a double.
+   1. Extract the most significant n bits of the denominator, and an equal
+      number of bits from the numerator.
+   2. Interpret the extracted numbers as integers, call them a and b
+      respectively, and develop n bits of the fractions ((a + 1) / b) and
+      (a / (b + 1)) using mpn_divrem.
+   3. If the computed values are identical UP TO THE POSITION WE CARE ABOUT,
+      we are done.  If they are different, repeat the algorithm from step 1,
+      but first let n = n * 2.
+   4. If we end up using all bits from the numerator and denominator, fall
+      back to a plain division.
+   5. Just to make life harder, The computation of a + 1 and b + 1 above
+      might give carry-out...  Needs special handling.  It might work to
+      subtract 1 in both cases instead.
+
+   Not certain if this approach would be faster than a quotient-only
+   division.  Presumably such optimizations are the sort of thing we would
+   like to have helping everywhere that uses a quotient-only division. */
+
+double
+mpq_get_d (mpq_srcptr src)
+{
+  double res;
+  mp_srcptr np, dp;
+  mp_ptr temp;
+  mp_size_t nsize = SIZ(NUM(src));
+  mp_size_t dsize = SIZ(DEN(src));
+  mp_size_t qsize, prospective_qsize, zeros;
+  mp_size_t sign_quotient = nsize;
+  long exp;
+#define N_QLIMBS (1 + (sizeof (double) + GMP_LIMB_BYTES-1) / GMP_LIMB_BYTES)
+  mp_limb_t qarr[N_QLIMBS + 1];
+  mp_ptr qp = qarr;
+  TMP_DECL;
+
+  ASSERT (dsize > 0);    /* canonical src */
+
+  /* mpn_get_d below requires a non-zero operand */
+  if (UNLIKELY (nsize == 0))
+    return 0.0;
+
+  TMP_MARK;
+  nsize = ABS (nsize);
+  dsize = ABS (dsize);
+  np = PTR(NUM(src));
+  dp = PTR(DEN(src));
+
+  prospective_qsize = nsize - dsize;       /* from using given n,d */
+  qsize = N_QLIMBS;                        /* desired qsize */
+
+  zeros = qsize - prospective_qsize;       /* padding n to get qsize */
+  exp = (long) -zeros * GMP_NUMB_BITS;     /* relative to low of qp */
+
+  /* zero extend n into temporary space, if necessary */
+  if (zeros > 0)
+    {
+      mp_size_t tsize;
+      tsize = nsize + zeros;               /* size for copy of n */
+
+      temp = TMP_ALLOC_LIMBS (tsize + 1);
+      MPN_FILL (temp, zeros, 0);
+      MPN_COPY (temp + zeros, np, nsize);
+      np = temp;
+      nsize = tsize;
+    }
+  else /* negative zeros means shorten n */
+    {
+      np -= zeros;
+      nsize += zeros;
+
+      temp = TMP_ALLOC_LIMBS (nsize + 1);
+    }
+
+  ASSERT (qsize == nsize - dsize);
+  mpn_div_q (qp, np, nsize, dp, dsize, temp);
+
+  /* strip possible zero high limb */
+  qsize += (qp[qsize] != 0);
+
+  res = mpn_get_d (qp, qsize, sign_quotient, exp);
+  TMP_FREE;
+  return res;
+}
diff --git a/mpq/get_den.c b/mpq/get_den.c
new file mode 100644
index 0000000..d4fd90b
--- /dev/null
+++ b/mpq/get_den.c
@@ -0,0 +1,42 @@
+/* mpq_get_den(den,rat_src) -- Set DEN to the denominator of RAT_SRC.
+
+Copyright 1991, 1994, 1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_get_den (mpz_ptr den, mpq_srcptr src)
+{
+  mp_size_t size = SIZ(DEN(src));
+  mp_ptr dp;
+
+  dp = MPZ_NEWALLOC (den, size);
+  SIZ(den) = size;
+  MPN_COPY (dp, PTR(DEN(src)), size);
+}
diff --git a/mpq/get_num.c b/mpq/get_num.c
new file mode 100644
index 0000000..079211c
--- /dev/null
+++ b/mpq/get_num.c
@@ -0,0 +1,44 @@
+ /* mpq_get_num(num,rat_src) -- Set NUM to the numerator of RAT_SRC.
+
+Copyright 1991, 1994, 1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_get_num (mpz_ptr num, mpq_srcptr src)
+{
+  mp_size_t size = SIZ(NUM(src));
+  mp_size_t abs_size = ABS (size);
+  mp_ptr dp;
+
+  dp = MPZ_NEWALLOC (num, abs_size);
+  SIZ(num) = size;
+
+  MPN_COPY (dp, PTR(NUM(src)), abs_size);
+}
diff --git a/mpq/get_str.c b/mpq/get_str.c
new file mode 100644
index 0000000..d0cfb58
--- /dev/null
+++ b/mpq/get_str.c
@@ -0,0 +1,80 @@
+/* mpq_get_str -- mpq to string conversion.
+
+Copyright 2001, 2002, 2006, 2011, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+char *
+mpq_get_str (char *str, int base, mpq_srcptr q)
+{
+  size_t  str_alloc, len;
+
+  if (base > 62 || base < -36)
+    return NULL;
+
+  str_alloc = 0;
+  if (str == NULL)
+    {
+      /* This is an overestimate since we don't bother checking how much of
+	 the high limbs of num and den are used.  +2 for rounding up the
+	 chars per bit of num and den.  +3 for sign, slash and '\0'.  */
+      if (ABS(base) < 2)
+	base = 10;
+      DIGITS_IN_BASE_PER_LIMB (str_alloc, ABSIZ(NUM(q)) + SIZ(DEN(q)), ABS(base));
+      str_alloc += 6;
+
+      str = __GMP_ALLOCATE_FUNC_TYPE (str_alloc, char);
+    }
+
+  mpz_get_str (str, base, mpq_numref(q));
+  len = strlen (str);
+  if (! MPZ_EQUAL_1_P (mpq_denref (q)))
+    {
+      str[len++] = '/';
+      mpz_get_str (str+len, base, mpq_denref(q));
+      len += strlen (str+len);
+    }
+
+  ASSERT (len == strlen(str));
+  ASSERT (str_alloc == 0 || len+1 <= str_alloc);
+  ASSERT (len+1 <= 3 + /* size recommended to applications */
+	  (ABS(base) < 2 ?
+	   mpz_sizeinbase (mpq_numref(q), 10) +
+	   mpz_sizeinbase (mpq_denref(q), 10)
+	   : mpz_sizeinbase (mpq_numref(q), ABS(base)) +
+	   mpz_sizeinbase (mpq_denref(q), ABS(base))));
+
+  if (str_alloc != 0)
+    __GMP_REALLOCATE_FUNC_MAYBE_TYPE (str, str_alloc, len+1, char);
+
+  return str;
+}
diff --git a/mpq/init.c b/mpq/init.c
new file mode 100644
index 0000000..5310066
--- /dev/null
+++ b/mpq/init.c
@@ -0,0 +1,45 @@
+/* mpq_init -- Make a new rational number with value 0/1.
+
+Copyright 1991, 1994, 1995, 2000-2002, 2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_init (mpq_ptr x)
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  ALLOC(NUM(x)) = 0;
+  PTR(NUM(x)) = (mp_ptr) &dummy_limb;
+  SIZ(NUM(x)) = 0;
+  ALLOC(DEN(x)) = 1;
+  PTR(DEN(x)) = __GMP_ALLOCATE_FUNC_LIMBS (1);
+  PTR(DEN(x))[0] = 1;
+  SIZ(DEN(x)) = 1;
+}
diff --git a/mpq/inits.c b/mpq/inits.c
new file mode 100644
index 0000000..fff4343
--- /dev/null
+++ b/mpq/inits.c
@@ -0,0 +1,49 @@
+/* mpq_inits() -- Initialize multiple mpq_t variables and set them to 0.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpq_inits (mpq_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      mpq_init (x);
+      x = va_arg (ap, mpq_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/mpq/inp_str.c b/mpq/inp_str.c
new file mode 100644
index 0000000..b7662bc
--- /dev/null
+++ b/mpq/inp_str.c
@@ -0,0 +1,75 @@
+/* mpq_inp_str -- read an mpq from a FILE.
+
+Copyright 2001, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+
+
+size_t
+mpq_inp_str (mpq_ptr q, FILE *fp, int base)
+{
+  size_t  nread;
+  int     c;
+
+  if (fp == NULL)
+    fp = stdin;
+
+  SIZ(DEN(q)) = 1;
+  MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+
+  nread = mpz_inp_str (mpq_numref(q), fp, base);
+  if (nread == 0)
+    return 0;
+
+  c = getc (fp);
+  nread++;
+
+  if (c == '/')
+    {
+      c = getc (fp);
+      nread++;
+
+      nread = mpz_inp_str_nowhite (mpq_denref(q), fp, base, c, nread);
+      if (nread == 0)
+	{
+	  SIZ(NUM(q)) = 0;
+	  SIZ(DEN(q)) = 1;
+	  PTR(DEN(q))[0] = 1;
+	}
+    }
+  else
+    {
+      ungetc (c, fp);
+      nread--;
+    }
+
+  return nread;
+}
diff --git a/mpq/inv.c b/mpq/inv.c
new file mode 100644
index 0000000..c395984
--- /dev/null
+++ b/mpq/inv.c
@@ -0,0 +1,70 @@
+/* mpq_inv(dest,src) -- invert a rational number, i.e. set DEST to SRC
+   with the numerator and denominator swapped.
+
+Copyright 1991, 1994, 1995, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_inv (mpq_ptr dest, mpq_srcptr src)
+{
+  mp_size_t num_size = SIZ(NUM(src));
+  mp_size_t den_size = SIZ(DEN(src));
+
+  if (num_size < 0)
+    {
+      num_size = -num_size;
+      den_size = -den_size;
+    }
+  else if (UNLIKELY (num_size == 0))
+    DIVIDE_BY_ZERO;
+
+  SIZ(DEN(dest)) = num_size;
+  SIZ(NUM(dest)) = den_size;
+
+  /* If dest == src we may just swap the numerator and denominator;
+     we ensured that the new denominator is positive.  */
+
+  if (dest == src)
+    {
+      MP_PTR_SWAP (PTR(NUM(dest)), PTR(DEN(dest)));
+      MP_SIZE_T_SWAP (ALLOC(NUM(dest)), ALLOC(DEN(dest)));
+    }
+  else
+    {
+      mp_ptr dp;
+
+      den_size = ABS (den_size);
+      dp = MPZ_NEWALLOC (NUM(dest), den_size);
+      MPN_COPY (dp, PTR(DEN(src)), den_size);
+
+      dp = MPZ_NEWALLOC (DEN(dest), num_size);
+      MPN_COPY (dp, PTR(NUM(src)), num_size);
+    }
+}
diff --git a/mpq/md_2exp.c b/mpq/md_2exp.c
new file mode 100644
index 0000000..b3378b3
--- /dev/null
+++ b/mpq/md_2exp.c
@@ -0,0 +1,110 @@
+/* mpq_mul_2exp, mpq_div_2exp - multiply or divide by 2^N */
+
+/*
+Copyright 2000, 2002, 2012, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The multiplier/divisor "n", representing 2^n, is applied by right shifting
+   "r" until it's odd (if it isn't already), and left shifting "l" for the
+   rest. */
+
+static void
+mord_2exp (mpz_ptr ldst, mpz_ptr rdst, mpz_srcptr lsrc, mpz_srcptr rsrc,
+           mp_bitcnt_t n)
+{
+  mp_size_t  rsrc_size = SIZ(rsrc);
+  mp_size_t  len = ABS (rsrc_size);
+  mp_ptr     rsrc_ptr = PTR(rsrc);
+  mp_ptr     p, rdst_ptr;
+  mp_limb_t  plow;
+
+  p = rsrc_ptr;
+  plow = *p;
+  while (n >= GMP_NUMB_BITS && plow == 0)
+    {
+      n -= GMP_NUMB_BITS;
+      p++;
+      plow = *p;
+    }
+
+  /* no realloc here if rsrc==rdst, so p and rsrc_ptr remain valid */
+  len -= (p - rsrc_ptr);
+  rdst_ptr = MPZ_REALLOC (rdst, len);
+
+  if ((plow & 1) || n == 0)
+    {
+      /* need INCR when src==dst */
+      if (p != rdst_ptr)
+        MPN_COPY_INCR (rdst_ptr, p, len);
+    }
+  else
+    {
+      unsigned long  shift;
+      if (plow == 0)
+        shift = n;
+      else
+        {
+          count_trailing_zeros (shift, plow);
+          shift = MIN (shift, n);
+        }
+      mpn_rshift (rdst_ptr, p, len, shift);
+      len -= (rdst_ptr[len-1] == 0);
+      n -= shift;
+    }
+  SIZ(rdst) = (rsrc_size >= 0) ? len : -len;
+
+  if (n)
+    mpz_mul_2exp (ldst, lsrc, n);
+  else if (ldst != lsrc)
+    mpz_set (ldst, lsrc);
+}
+
+
+void
+mpq_mul_2exp (mpq_ptr dst, mpq_srcptr src, mp_bitcnt_t n)
+{
+  mord_2exp (NUM(dst), DEN(dst), NUM(src), DEN(src), n);
+}
+
+void
+mpq_div_2exp (mpq_ptr dst, mpq_srcptr src, mp_bitcnt_t n)
+{
+  if (SIZ(NUM(src)) == 0)
+    {
+      SIZ(NUM(dst)) = 0;
+      SIZ(DEN(dst)) = 1;
+      MPZ_NEWALLOC (DEN(dst), 1)[0] = 1;
+      return;
+    }
+
+  mord_2exp (DEN(dst), NUM(dst), DEN(src), NUM(src), n);
+}
diff --git a/mpq/mul.c b/mpq/mul.c
new file mode 100644
index 0000000..270dafc
--- /dev/null
+++ b/mpq/mul.c
@@ -0,0 +1,102 @@
+/* mpq_mul -- multiply two rational numbers.
+
+Copyright 1991, 1994-1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpq_mul (mpq_ptr prod, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpz_t gcd1, gcd2;
+  mpz_t tmp1, tmp2;
+  mp_size_t op1_num_size;
+  mp_size_t op1_den_size;
+  mp_size_t op2_num_size;
+  mp_size_t op2_den_size;
+  mp_size_t alloc;
+  TMP_DECL;
+
+  if (op1 == op2)
+    {
+      /* No need for any GCDs when squaring. */
+      mpz_mul (mpq_numref (prod), mpq_numref (op1), mpq_numref (op1));
+      mpz_mul (mpq_denref (prod), mpq_denref (op1), mpq_denref (op1));
+      return;
+    }
+
+  op1_num_size = ABSIZ(NUM(op1));
+  op1_den_size =   SIZ(DEN(op1));
+  op2_num_size = ABSIZ(NUM(op2));
+  op2_den_size =   SIZ(DEN(op2));
+
+  if (op1_num_size == 0 || op2_num_size == 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;
+    }
+
+  TMP_MARK;
+
+  alloc = MIN (op1_num_size, op2_den_size);
+  MPZ_TMP_INIT (gcd1, alloc);
+
+  alloc = MIN (op2_num_size, op1_den_size);
+  MPZ_TMP_INIT (gcd2, alloc);
+
+  alloc = MAX (op1_num_size, op2_den_size);
+  MPZ_TMP_INIT (tmp1, alloc);
+
+  alloc = MAX (op2_num_size, op1_den_size);
+  MPZ_TMP_INIT (tmp2, alloc);
+
+  /* PROD might be identical to either operand, so don't store the result there
+     until we are finished with the input operands.  We can overwrite the
+     numerator of PROD when we are finished with the numerators of OP1 and
+     OP2.  */
+
+  mpz_gcd (gcd1, NUM(op1), DEN(op2));
+  mpz_gcd (gcd2, NUM(op2), DEN(op1));
+
+  mpz_divexact_gcd (tmp1, NUM(op1), gcd1);
+  mpz_divexact_gcd (tmp2, NUM(op2), gcd2);
+
+  mpz_mul (NUM(prod), tmp1, tmp2);
+
+  mpz_divexact_gcd (tmp1, DEN(op2), gcd1);
+  mpz_divexact_gcd (tmp2, DEN(op1), gcd2);
+
+  mpz_mul (DEN(prod), tmp1, tmp2);
+
+  TMP_FREE;
+}
diff --git a/mpq/neg.c b/mpq/neg.c
new file mode 100644
index 0000000..8fda41c
--- /dev/null
+++ b/mpq/neg.c
@@ -0,0 +1,57 @@
+/* mpq_neg -- negate a rational.
+
+Copyright 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpq_neg 1
+
+#include "gmp-impl.h"
+
+
+void
+mpq_neg (mpq_ptr dst, mpq_srcptr src)
+{
+  mp_size_t  num_size = SIZ(NUM(src));
+
+  if (src != dst)
+    {
+      mp_size_t  size;
+      mp_ptr dp;
+
+      size = ABS(num_size);
+      dp = MPZ_NEWALLOC (NUM(dst), size);
+      MPN_COPY (dp, PTR(NUM(src)), size);
+
+      size = SIZ(DEN(src));
+      dp = MPZ_NEWALLOC (DEN(dst), size);
+      SIZ(DEN(dst)) = size;
+      MPN_COPY (dp, PTR(DEN(src)), size);
+    }
+
+  SIZ(NUM(dst)) = -num_size;
+}
diff --git a/mpq/out_str.c b/mpq/out_str.c
new file mode 100644
index 0000000..5d2dd4e
--- /dev/null
+++ b/mpq/out_str.c
@@ -0,0 +1,53 @@
+/* mpq_out_str(stream,base,integer) */
+
+/*
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+size_t
+mpq_out_str (FILE *stream, int base, mpq_srcptr q)
+{
+  size_t  written;
+
+  if (stream == NULL)
+    stream = stdout;
+
+  written = mpz_out_str (stream, base, mpq_numref (q));
+
+  if (mpz_cmp_ui (mpq_denref (q), 1) != 0)
+    {
+      putc ('/', stream);
+      written += 1 + mpz_out_str (stream, base, mpq_denref (q));
+    }
+
+  return ferror (stream) ? 0 : written;
+}
diff --git a/mpq/set.c b/mpq/set.c
new file mode 100644
index 0000000..87c15e3
--- /dev/null
+++ b/mpq/set.c
@@ -0,0 +1,51 @@
+/* mpq_set(dest,src) -- Set DEST to SRC.
+
+Copyright 1991, 1994, 1995, 2001, 2012, 2015 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set (mpq_ptr dest, mpq_srcptr src)
+{
+  mp_size_t num_size, den_size;
+  mp_size_t abs_num_size;
+  mp_ptr dp;
+
+  num_size = SIZ(NUM(src));
+  SIZ(NUM(dest)) = num_size;
+  abs_num_size = ABS (num_size);
+  dp = MPZ_NEWALLOC (NUM(dest), abs_num_size);
+  MPN_COPY (dp, PTR(NUM(src)), abs_num_size);
+
+  den_size = SIZ(DEN(src));
+  SIZ(DEN(dest)) = den_size;
+  dp = MPZ_NEWALLOC (DEN(dest), den_size);
+  MPN_COPY (dp, PTR(DEN(src)), den_size);
+}
diff --git a/mpq/set_d.c b/mpq/set_d.c
new file mode 100644
index 0000000..3f3fab0
--- /dev/null
+++ b/mpq/set_d.c
@@ -0,0 +1,165 @@
+/* mpq_set_d(mpq_t q, double d) -- Set q to d without rounding.
+
+Copyright 2000, 2002, 2003, 2012, 2014, 2018 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if LIMBS_PER_DOUBLE > 4
+  choke me
+#endif
+
+void
+mpq_set_d (mpq_ptr dest, double d)
+{
+  int negative;
+  mp_exp_t exp;
+  mp_limb_t tp[LIMBS_PER_DOUBLE];
+  mp_ptr np, dp;
+  mp_size_t nn, dn;
+  int c;
+
+  DOUBLE_NAN_INF_ACTION (d,
+                         __gmp_invalid_operation (),
+                         __gmp_invalid_operation ());
+
+  negative = d < 0;
+  d = ABS (d);
+
+  exp = __gmp_extract_double (tp, d);
+
+  /* There are two main version of the conversion.  The `then' arm handles
+     numbers with a fractional part, while the `else' arm handles integers.  */
+#if LIMBS_PER_DOUBLE == 4
+  if (exp <= 1 || (exp == 2 && (tp[0] | tp[1]) != 0))
+#endif
+#if LIMBS_PER_DOUBLE == 3
+  if (exp <= 1 || (exp == 2 && tp[0] != 0))
+#endif
+#if LIMBS_PER_DOUBLE == 2
+  if (exp <= 1)
+#endif
+    {
+      if (d == 0.0)
+	{
+	  SIZ(NUM(dest)) = 0;
+	  SIZ(DEN(dest)) = 1;
+	  MPZ_NEWALLOC (DEN(dest), 1)[0] = 1;
+	  return;
+	}
+
+#if LIMBS_PER_DOUBLE == 4
+      np = MPZ_NEWALLOC (NUM(dest), 4);
+      if ((tp[0] | tp[1] | tp[2]) == 0)
+	np[0] = tp[3], nn = 1;
+      else if ((tp[0] | tp[1]) == 0)
+	np[1] = tp[3], np[0] = tp[2], nn = 2;
+      else if (tp[0] == 0)
+	np[2] = tp[3], np[1] = tp[2], np[0] = tp[1], nn = 3;
+      else
+	np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 4;
+#endif
+#if LIMBS_PER_DOUBLE == 3
+      np = MPZ_NEWALLOC (NUM(dest), 3);
+      if ((tp[0] | tp[1]) == 0)
+	np[0] = tp[2], nn = 1;
+      else if (tp[0] == 0)
+	np[1] = tp[2], np[0] = tp[1], nn = 2;
+      else
+	np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 3;
+#endif
+#if LIMBS_PER_DOUBLE == 2
+      np = MPZ_NEWALLOC (NUM(dest), 2);
+      if (tp[0] == 0)
+	np[0] = tp[1], nn = 1;
+      else
+	np[1] = tp[1], np[0] = tp[0], nn = 2;
+#endif
+      dn = nn + 1 - exp;
+      ASSERT (dn > 0); /* -exp >= -1; nn >= 1*/
+      dp = MPZ_NEWALLOC (DEN(dest), dn);
+      MPN_ZERO (dp, dn - 1);
+      dp[dn - 1] = 1;
+      count_trailing_zeros (c, np[0] | dp[0]);
+      if (c != 0)
+	{
+	  mpn_rshift (np, np, nn, c);
+	  nn -= np[nn - 1] == 0;
+	  --dn;
+	  dp[dn - 1] = CNST_LIMB(1) << (GMP_LIMB_BITS - c);
+	}
+      SIZ(DEN(dest)) = dn;
+    }
+  else
+    {
+      nn = exp;
+      np = MPZ_NEWALLOC (NUM(dest), nn);
+      switch (nn)
+        {
+	default:
+	  MPN_ZERO (np, nn - LIMBS_PER_DOUBLE);
+	  np += nn - LIMBS_PER_DOUBLE;
+	  /* fall through */
+#if LIMBS_PER_DOUBLE == 2
+	case 2:
+	  np[1] = tp[1], np[0] = tp[0];
+	  break;
+#endif
+#if LIMBS_PER_DOUBLE == 3
+	case 3:
+	  np[2] = tp[2], np[1] = tp[1], np[0] = tp[0];
+	  break;
+	case 2:
+	  np[1] = tp[2], np[0] = tp[1];
+	  break;
+#endif
+#if LIMBS_PER_DOUBLE == 4
+	case 4:
+	  np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0];
+	  break;
+	case 3:
+	  np[2] = tp[3], np[1] = tp[2], np[0] = tp[1];
+	  break;
+	case 2:
+	  np[1] = tp[3], np[0] = tp[2];
+	  break;
+#endif
+	}
+      MPZ_NEWALLOC (DEN(dest), 1)[0] = 1;
+      SIZ(DEN(dest)) = 1;
+    }
+  SIZ(NUM(dest)) = negative ? -nn : nn;
+}
diff --git a/mpq/set_den.c b/mpq/set_den.c
new file mode 100644
index 0000000..e249db7
--- /dev/null
+++ b/mpq/set_den.c
@@ -0,0 +1,45 @@
+/* mpq_set_den(dest,den) -- Set the denominator of DEST from DEN.
+
+Copyright 1991, 1994-1996, 2000, 2001, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_den (mpq_ptr dest, mpz_srcptr den)
+{
+  mp_size_t size = SIZ (den);
+  mp_size_t abs_size = ABS (size);
+  mp_ptr dp;
+
+  SIZ(DEN(dest)) = size;
+  dp = MPZ_NEWALLOC (DEN(dest), abs_size);
+
+  MPN_COPY (dp, PTR(den), abs_size);
+}
diff --git a/mpq/set_f.c b/mpq/set_f.c
new file mode 100644
index 0000000..581d4fc
--- /dev/null
+++ b/mpq/set_f.c
@@ -0,0 +1,106 @@
+/* mpq_set_f -- set an mpq from an mpf.
+
+Copyright 2000-2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpq_set_f (mpq_ptr q, mpf_srcptr f)
+{
+  mp_size_t  fexp = EXP(f);
+  mp_ptr     fptr = PTR(f);
+  mp_size_t  fsize = SIZ(f);
+  mp_size_t  abs_fsize = ABS(fsize);
+  mp_limb_t  flow;
+
+  if (fsize == 0)
+    {
+      /* set q=0 */
+      SIZ(NUM(q)) = 0;
+      SIZ(DEN(q)) = 1;
+      MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+      return;
+    }
+
+  /* strip low zero limbs from f */
+  flow = *fptr;
+  MPN_STRIP_LOW_ZEROS_NOT_ZERO (fptr, abs_fsize, flow);
+
+  if (fexp >= abs_fsize)
+    {
+      /* radix point is to the right of the limbs, no denominator */
+      mp_ptr  num_ptr;
+
+      num_ptr = MPZ_NEWALLOC (mpq_numref (q), fexp);
+      MPN_ZERO (num_ptr, fexp - abs_fsize);
+      MPN_COPY (num_ptr + fexp - abs_fsize, fptr, abs_fsize);
+
+      SIZ(NUM(q)) = fsize >= 0 ? fexp : -fexp;
+      SIZ(DEN(q)) = 1;
+      MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+    }
+  else
+    {
+      /* radix point is within or to the left of the limbs, use denominator */
+      mp_ptr     num_ptr, den_ptr;
+      mp_size_t  den_size;
+
+      den_size = abs_fsize - fexp;
+      num_ptr = MPZ_NEWALLOC (mpq_numref (q), abs_fsize);
+      den_ptr = MPZ_NEWALLOC (mpq_denref (q), den_size+1);
+
+      if (flow & 1)
+        {
+          /* no powers of two to strip from numerator */
+
+          MPN_COPY (num_ptr, fptr, abs_fsize);
+          MPN_ZERO (den_ptr, den_size);
+          den_ptr[den_size] = 1;
+        }
+      else
+        {
+          /* right shift numerator, adjust denominator accordingly */
+          int  shift;
+
+          den_size--;
+          count_trailing_zeros (shift, flow);
+
+          mpn_rshift (num_ptr, fptr, abs_fsize, shift);
+          abs_fsize -= (num_ptr[abs_fsize-1] == 0);
+
+          MPN_ZERO (den_ptr, den_size);
+          den_ptr[den_size] = GMP_LIMB_HIGHBIT >> (shift-1);
+        }
+
+      SIZ(NUM(q)) = fsize >= 0 ? abs_fsize : -abs_fsize;
+      SIZ(DEN(q)) = den_size + 1;
+    }
+}
diff --git a/mpq/set_num.c b/mpq/set_num.c
new file mode 100644
index 0000000..1a099a2
--- /dev/null
+++ b/mpq/set_num.c
@@ -0,0 +1,45 @@
+/* mpq_set_num(dest,num) -- Set the numerator of DEST from NUM.
+
+Copyright 1991, 1994, 1995, 2001, 2012, 2015 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_num (mpq_ptr dest, mpz_srcptr num)
+{
+  mp_size_t size = SIZ (num);
+  mp_size_t abs_size = ABS (size);
+  mp_ptr dp;
+
+  SIZ(NUM(dest)) = size;
+  dp = MPZ_NEWALLOC (NUM(dest), abs_size);
+
+  MPN_COPY (dp, PTR(num), abs_size);
+}
diff --git a/mpq/set_si.c b/mpq/set_si.c
new file mode 100644
index 0000000..3159899
--- /dev/null
+++ b/mpq/set_si.c
@@ -0,0 +1,60 @@
+/* mpq_set_si(dest,ulong_num,ulong_den) -- Set DEST to the rational number
+   ULONG_NUM/ULONG_DEN.
+
+Copyright 1991, 1994, 1995, 2001, 2003, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_si (mpq_ptr dest, signed long int num, unsigned long int den)
+{
+  if (GMP_NUMB_BITS < BITS_PER_ULONG)
+    {
+      if (num == 0)  /* Canonicalize 0/d to 0/1.  */
+        den = 1;
+      mpz_set_si (mpq_numref (dest), num);
+      mpz_set_ui (mpq_denref (dest), den);
+      return;
+    }
+
+  if (num == 0)
+    {
+      /* Canonicalize 0/d to 0/1.  */
+      den = 1;
+      SIZ(NUM(dest)) = 0;
+    }
+  else
+    {
+      MPZ_NEWALLOC (NUM(dest), 1)[0] = ABS_CAST (unsigned long, num);
+      SIZ(NUM(dest)) = num > 0 ? 1 : -1;
+    }
+
+  MPZ_NEWALLOC (DEN(dest), 1)[0] = den;
+  SIZ(DEN(dest)) = (den != 0);
+}
diff --git a/mpq/set_str.c b/mpq/set_str.c
new file mode 100644
index 0000000..664bb2d
--- /dev/null
+++ b/mpq/set_str.c
@@ -0,0 +1,68 @@
+/* mpq_set_str -- string to mpq conversion.
+
+Copyright 2001, 2002, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp-impl.h"
+
+
+/* FIXME: Would like an mpz_set_mem (or similar) accepting a pointer and
+   length so we wouldn't have to copy the numerator just to null-terminate
+   it.  */
+
+int
+mpq_set_str (mpq_ptr q, const char *str, int base)
+{
+  const char  *slash;
+  char        *num;
+  size_t      numlen;
+  int         ret;
+
+  slash = strchr (str, '/');
+  if (slash == NULL)
+    {
+      SIZ(DEN(q)) = 1;
+      MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+
+      return mpz_set_str (mpq_numref(q), str, base);
+    }
+
+  numlen = slash - str;
+  num = __GMP_ALLOCATE_FUNC_TYPE (numlen+1, char);
+  memcpy (num, str, numlen);
+  num[numlen] = '\0';
+  ret = mpz_set_str (mpq_numref(q), num, base);
+  __GMP_FREE_FUNC_TYPE (num, numlen+1, char);
+
+  if (ret != 0)
+    return ret;
+
+  return mpz_set_str (mpq_denref(q), slash+1, base);
+}
diff --git a/mpq/set_ui.c b/mpq/set_ui.c
new file mode 100644
index 0000000..b03d4e3
--- /dev/null
+++ b/mpq/set_ui.c
@@ -0,0 +1,60 @@
+/* mpq_set_ui(dest,ulong_num,ulong_den) -- Set DEST to the rational number
+   ULONG_NUM/ULONG_DEN.
+
+Copyright 1991, 1994, 1995, 2001-2003, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_ui (mpq_ptr dest, unsigned long int num, unsigned long int den)
+{
+  if (GMP_NUMB_BITS < BITS_PER_ULONG)
+    {
+      if (num == 0)  /* Canonicalize 0/d to 0/1.  */
+        den = 1;
+      mpz_set_ui (mpq_numref (dest), num);
+      mpz_set_ui (mpq_denref (dest), den);
+      return;
+    }
+
+  if (num == 0)
+    {
+      /* Canonicalize 0/d to 0/1.  */
+      den = 1;
+      SIZ(NUM(dest)) = 0;
+    }
+  else
+    {
+      MPZ_NEWALLOC (NUM(dest), 1)[0] = num;
+      SIZ(NUM(dest)) = 1;
+    }
+
+  MPZ_NEWALLOC (DEN(dest), 1)[0] = den;
+  SIZ(DEN(dest)) = (den != 0);
+}
diff --git a/mpq/set_z.c b/mpq/set_z.c
new file mode 100644
index 0000000..8309c93
--- /dev/null
+++ b/mpq/set_z.c
@@ -0,0 +1,48 @@
+/* mpq_set_z (dest,src) -- Set DEST to SRC.
+
+Copyright 1996, 2001, 2012, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_z (mpq_ptr dest, mpz_srcptr src)
+{
+  mp_size_t num_size;
+  mp_size_t abs_num_size;
+  mp_ptr dp;
+
+  num_size = SIZ (src);
+  SIZ(NUM(dest)) = num_size;
+  abs_num_size = ABS (num_size);
+  dp = MPZ_NEWALLOC (NUM(dest), abs_num_size);
+  MPN_COPY (dp, PTR(src), abs_num_size);
+
+  MPZ_NEWALLOC (DEN(dest), 1)[0] = 1;
+  SIZ(DEN(dest)) = 1;
+}
diff --git a/mpq/swap.c b/mpq/swap.c
new file mode 100644
index 0000000..e5152d4
--- /dev/null
+++ b/mpq/swap.c
@@ -0,0 +1,42 @@
+/* mpq_swap (U, V) -- Swap U and V.
+
+Copyright 1997, 1998, 2000, 2001, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_swap (mpq_ptr u, mpq_ptr v) __GMP_NOTHROW
+{
+  MP_SIZE_T_SWAP (ALLOC(NUM(u)), ALLOC(NUM(v)));
+  MP_SIZE_T_SWAP (ALLOC(DEN(u)), ALLOC(DEN(v)));
+  MP_SIZE_T_SWAP (SIZ(NUM(u)), SIZ(NUM(v)));
+  MP_SIZE_T_SWAP (SIZ(DEN(u)), SIZ(DEN(v)));
+  MP_PTR_SWAP (PTR(NUM(u)), PTR(NUM(v)));
+  MP_PTR_SWAP (PTR(DEN(u)), PTR(DEN(v)));
+}
diff --git a/mpz/2fac_ui.c b/mpz/2fac_ui.c
new file mode 100644
index 0000000..141a0a7
--- /dev/null
+++ b/mpz/2fac_ui.c
@@ -0,0 +1,100 @@
+/* mpz_2fac_ui(RESULT, N) -- Set RESULT to N!!.
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2012, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define FAC_2DSC_THRESHOLD ((FAC_DSC_THRESHOLD << 1) | (FAC_DSC_THRESHOLD & 1))
+#define FACTORS_PER_LIMB   (GMP_NUMB_BITS / (LOG2C(FAC_2DSC_THRESHOLD-1)+1))
+
+/* Computes n!!, the 2-multi-factorial of n. (aka double-factorial or semi-factorial)
+   WARNING: it assumes that n fits in a limb!
+ */
+void
+mpz_2fac_ui (mpz_ptr x, unsigned long n)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+
+  if ((n & 1) == 0) { /* n is even, n = 2k, (2k)!! = k! 2^k */
+    mp_limb_t count;
+
+    if ((n <= TABLE_LIMIT_2N_MINUS_POPC_2N) & (n != 0))
+      count = __gmp_fac2cnt_table[n / 2 - 1];
+    else
+      {
+	popc_limb (count, n);	/* popc(n) == popc(k) */
+	count = n - count;		/* n - popc(n) == k + k - popc(k) */
+      }
+    mpz_oddfac_1 (x, n >> 1, 0);
+    mpz_mul_2exp (x, x, count);
+  } else { /* n is odd */
+    if (n <= ODD_DOUBLEFACTORIAL_TABLE_LIMIT) {
+      MPZ_NEWALLOC (x, 1)[0] = __gmp_odd2fac_table[n >> 1];
+      SIZ (x) = 1;
+    } else if (BELOW_THRESHOLD (n, FAC_2DSC_THRESHOLD)) { /* odd basecase, */
+      mp_limb_t *factors, prod, max_prod;
+      mp_size_t j;
+      TMP_SDECL;
+
+      /* FIXME: we might alloc a fixed amount 1+FAC_2DSC_THRESHOLD/FACTORS_PER_LIMB */
+      TMP_SMARK;
+      factors = TMP_SALLOC_LIMBS (1 + n / (2 * FACTORS_PER_LIMB));
+
+      factors[0] = ODD_DOUBLEFACTORIAL_TABLE_MAX;
+      j = 1;
+      prod = n;
+
+      max_prod = GMP_NUMB_MAX / FAC_2DSC_THRESHOLD;
+      while ((n -= 2) > ODD_DOUBLEFACTORIAL_TABLE_LIMIT)
+	FACTOR_LIST_STORE (n, prod, max_prod, factors, j);
+
+      factors[j++] = prod;
+      mpz_prodlimbs (x, factors, j);
+
+      TMP_SFREE;
+    } else { /* for the asymptotically fast odd case, let oddfac do the job. */
+      mpz_oddfac_1 (x, n, 1);
+    }
+  }
+}
+
+#undef FACTORS_PER_LIMB
+#undef FACTOR_LIST_STORE
+#undef FAC_2DSC_THRESHOLD
diff --git a/mpz/abs.c b/mpz/abs.c
new file mode 100644
index 0000000..0cfbc49
--- /dev/null
+++ b/mpz/abs.c
@@ -0,0 +1,54 @@
+/* mpz_abs(dst, src) -- Assign the absolute value of SRC to DST.
+
+Copyright 1991, 1993-1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_abs 1
+
+#include "gmp-impl.h"
+
+void
+mpz_abs (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp;
+  mp_srcptr up;
+  mp_size_t size;
+
+  size = ABSIZ (u);
+
+  if (u != w)
+    {
+      wp = MPZ_NEWALLOC (w, size);
+
+      up = PTR (u);
+
+      MPN_COPY (wp, up, size);
+    }
+
+  SIZ (w) = size;
+}
diff --git a/mpz/add.c b/mpz/add.c
new file mode 100644
index 0000000..f1f0ae8
--- /dev/null
+++ b/mpz/add.c
@@ -0,0 +1,33 @@
+/* mpz_add -- add integers.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_add
+#include "aors.h"
diff --git a/mpz/add_ui.c b/mpz/add_ui.c
new file mode 100644
index 0000000..8fd15ad
--- /dev/null
+++ b/mpz/add_ui.c
@@ -0,0 +1,33 @@
+/* mpz_add_ui -- Add an mpz_t and an unsigned one-word integer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_add_ui
+#include "aors_ui.h"
diff --git a/mpz/and.c b/mpz/and.c
new file mode 100644
index 0000000..5d34547
--- /dev/null
+++ b/mpz/and.c
@@ -0,0 +1,222 @@
+/* mpz_and -- Logical and.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2003, 2005, 2012,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_and (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+{
+  mp_srcptr op1_ptr, op2_ptr;
+  mp_size_t op1_size, op2_size;
+  mp_ptr res_ptr;
+  mp_size_t res_size;
+  mp_size_t i;
+
+  op1_size = SIZ(op1);
+  op2_size = SIZ(op2);
+
+  if (op1_size < op2_size)
+    {
+      MPZ_SRCPTR_SWAP (op1, op2);
+      MP_SIZE_T_SWAP (op1_size, op2_size);
+    }
+
+  op1_ptr = PTR(op1);
+  op2_ptr = PTR(op2);
+
+  if (op2_size >= 0)
+    {
+      /* First loop finds the size of the result.  */
+      for (i = op2_size; --i >= 0;)
+	if ((op1_ptr[i] & op2_ptr[i]) != 0)
+	  {
+	    res_size = i + 1;
+	    /* Handle allocation, now then we know exactly how much space is
+	       needed for the result.  */
+	    /* Don't re-read op1_ptr and op2_ptr.  Since res_size <=
+	       MIN(op1_size, op2_size), res is not changed when op1
+	       is identical to res or op2 is identical to res.  */
+	    SIZ (res) = res_size;
+	    mpn_and_n (MPZ_NEWALLOC (res, res_size), op1_ptr, op2_ptr, res_size);
+	    return;
+	  }
+
+      SIZ (res) = 0;
+    }
+  else
+    {
+      TMP_DECL;
+
+      op2_size = -op2_size;
+      TMP_MARK;
+      if (op1_size < 0)
+	{
+	  mp_ptr opx, opy;
+
+	  /* Both operands are negative, so will be the result.
+	     -((-OP1) & (-OP2)) = -(~(OP1 - 1) & ~(OP2 - 1)) =
+	     = ~(~(OP1 - 1) & ~(OP2 - 1)) + 1 =
+	     = ((OP1 - 1) | (OP2 - 1)) + 1      */
+
+	  /* It might seem as we could end up with an (invalid) result with
+	     a leading zero-limb here when one of the operands is of the
+	     type 1,,0,,..,,.0.  But some analysis shows that we surely
+	     would get carry into the zero-limb in this situation...  */
+
+	  op1_size = -op1_size;
+
+	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
+	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
+	  op1_ptr = opx;
+
+	  mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
+	  op2_ptr = opy;
+
+	  res_ptr = MPZ_NEWALLOC (res, 1 + op2_size);
+	  /* Don't re-read OP1_PTR and OP2_PTR.  They point to temporary
+	     space--never to the space PTR(res) used to point to before
+	     reallocation.  */
+
+	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+		    op2_size - op1_size);
+	  mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op1_size);
+	  TMP_FREE;
+	  res_size = op2_size;
+
+	  res_ptr[res_size] = 0;
+	  MPN_INCR_U (res_ptr, res_size + 1, (mp_limb_t) 1);
+	  res_size += res_ptr[res_size];
+
+	  SIZ(res) = -res_size;
+	}
+      else
+	{
+#if ANDNEW
+	  mp_size_t op2_lim;
+	  mp_size_t count;
+
+	  /* OP2 must be negated as with infinite precision.
+
+	     Scan from the low end for a non-zero limb.  The first non-zero
+	     limb is simply negated (two's complement).  Any subsequent
+	     limbs are one's complemented.  Of course, we don't need to
+	     handle more limbs than there are limbs in the other, positive
+	     operand as the result for those limbs is going to become zero
+	     anyway.  */
+
+	  /* Scan for the least significant non-zero OP2 limb, and zero the
+	     result meanwhile for those limb positions.  (We will surely
+	     find a non-zero limb, so we can write the loop with one
+	     termination condition only.)  */
+	  for (i = 0; op2_ptr[i] == 0; i++)
+	    res_ptr[i] = 0;
+	  op2_lim = i;
+
+	  if (op1_size <= op2_size)
+	    {
+	      /* The ones-extended OP2 is >= than the zero-extended OP1.
+		 RES_SIZE <= OP1_SIZE.  Find the exact size.  */
+	      for (i = op1_size - 1; i > op2_lim; i--)
+		if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
+		  break;
+	      res_size = i + 1;
+	      for (i = res_size - 1; i > op2_lim; i--)
+		res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+	      res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
+	      /* Yes, this *can* happen!  */
+	      MPN_NORMALIZE (res_ptr, res_size);
+	    }
+	  else
+	    {
+	      /* The ones-extended OP2 is < than the zero-extended OP1.
+		 RES_SIZE == OP1_SIZE, since OP1 is normalized.  */
+	      res_size = op1_size;
+	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
+	      for (i = op2_size - 1; i > op2_lim; i--)
+		res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+	      res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
+	    }
+#else
+
+	  /* OP1 is positive and zero-extended,
+	     OP2 is negative and ones-extended.
+	     The result will be positive.
+	     OP1 & -OP2 = OP1 & ~(OP2 - 1).  */
+
+	  mp_ptr opx;
+
+	  opx = TMP_ALLOC_LIMBS (op2_size);
+	  mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+	  op2_ptr = opx;
+
+	  if (op1_size > op2_size)
+	    {
+	      /* The result has the same size as OP1, since OP1 is normalized
+		 and longer than the ones-extended OP2.  */
+	      res_size = op1_size;
+
+	      /* Handle allocation, now then we know exactly how much space is
+		 needed for the result.  */
+	      res_ptr = MPZ_NEWALLOC (res, res_size);
+	      /* Don't re-read OP1_PTR or OP2_PTR.  Since res_size = op1_size,
+		 op1 is not changed if it is identical to res.
+		 OP2_PTR points to temporary space.  */
+
+	      mpn_andn_n (res_ptr, op1_ptr, op2_ptr, op2_size);
+	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, res_size - op2_size);
+	    }
+	  else
+	    {
+	      /* Find out the exact result size.  Ignore the high limbs of OP2,
+		 OP1 is zero-extended and would make the result zero.  */
+	      res_size = 0;
+	      for (i = op1_size; --i >= 0;)
+		if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
+		  {
+		    res_size = i + 1;
+		    /* Handle allocation, now then we know exactly how much
+		       space is needed for the result.  */
+		    /* Don't re-read OP1_PTR.  Since res_size <= op1_size,
+		       op1 is not changed if it is identical to res.  Don't
+		       re-read OP2_PTR.  It points to temporary space--never
+		       to the space PTR(res) used to point to before
+		       reallocation.  */
+		    mpn_andn_n (MPZ_NEWALLOC (res, res_size), op1_ptr, op2_ptr, res_size);
+
+		    break;
+		  }
+	    }
+#endif
+	  SIZ(res) = res_size;
+	  TMP_FREE;
+	}
+    }
+}
diff --git a/mpz/aors.h b/mpz/aors.h
new file mode 100644
index 0000000..782a5fe
--- /dev/null
+++ b/mpz/aors.h
@@ -0,0 +1,129 @@
+/* mpz_add, mpz_sub -- add or subtract integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2011, 2012, 2020 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_add
+#define FUNCTION     mpz_add
+#define VARIATION
+#endif
+#ifdef OPERATION_sub
+#define FUNCTION     mpz_sub
+#define VARIATION    -
+#endif
+
+#ifndef FUNCTION
+Error, need OPERATION_add or OPERATION_sub
+#endif
+
+
+void
+FUNCTION (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr wp;
+  mp_size_t usize, vsize, wsize;
+  mp_size_t abs_usize;
+  mp_size_t abs_vsize;
+
+  usize = SIZ(u);
+  vsize = VARIATION SIZ(v);
+  abs_usize = ABS (usize);
+  abs_vsize = ABS (vsize);
+
+  if (abs_usize < abs_vsize)
+    {
+      /* Swap U and V. */
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (usize, vsize);
+      MP_SIZE_T_SWAP (abs_usize, abs_vsize);
+    }
+
+  /* True: ABS_USIZE >= ABS_VSIZE.  */
+
+  /* If not space for w (and possible carry), increase space.  */
+  wsize = abs_usize + 1;
+  wp = MPZ_REALLOC (w, wsize);
+
+  /* These must be after realloc (u or v may be the same as w).  */
+  up = PTR(u);
+  vp = PTR(v);
+
+  if ((usize ^ vsize) < 0)
+    {
+      /* U and V have different sign.  Need to compare them to determine
+	 which operand to subtract from which.  */
+
+      /* This test is right since ABS_USIZE >= ABS_VSIZE.  */
+      if (abs_usize != abs_vsize)
+	{
+	  mpn_sub (wp, up, abs_usize, vp, abs_vsize);
+	  wsize = abs_usize;
+	  MPN_NORMALIZE_NOT_ZERO (wp, wsize);
+	  if (usize < 0)
+	    wsize = -wsize;
+	}
+      else
+	{
+	  int cmp = mpn_cmp (up, vp, abs_usize);
+	  if (cmp < 0)
+	    {
+	      mpn_sub_n (wp, vp, up, abs_usize);
+	      wsize = abs_usize;
+	      MPN_NORMALIZE_NOT_ZERO (wp, wsize);
+	      if (usize >= 0)
+		wsize = -wsize;
+	    }
+	  else if (cmp > 0)
+	    {
+	      mpn_sub_n (wp, up, vp, abs_usize);
+	      wsize = abs_usize;
+	      MPN_NORMALIZE_NOT_ZERO (wp, wsize);
+	      if (usize < 0)
+		wsize = -wsize;
+	    }
+	  else
+	    wsize = 0;
+	}
+    }
+  else
+    {
+      /* U and V have same sign.  Add them.  */
+      mp_limb_t cy_limb = mpn_add (wp, up, abs_usize, vp, abs_vsize);
+      wp[abs_usize] = cy_limb;
+      wsize = abs_usize + cy_limb;
+      if (usize < 0)
+	wsize = -wsize;
+    }
+
+  SIZ(w) = wsize;
+}
diff --git a/mpz/aors_ui.h b/mpz/aors_ui.h
new file mode 100644
index 0000000..cbc467b
--- /dev/null
+++ b/mpz/aors_ui.h
@@ -0,0 +1,125 @@
+/* mpz_add_ui, mpz_sub_ui -- Add or subtract an mpz_t and an unsigned
+   one-word integer.
+
+Copyright 1991, 1993, 1994, 1996, 1999-2002, 2004, 2012, 2013, 2015,
+2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_add_ui
+#define FUNCTION          mpz_add_ui
+#define FUNCTION2         mpz_add
+#define VARIATION_CMP     >=
+#define VARIATION_NEG
+#define VARIATION_UNNEG   -
+#endif
+
+#ifdef OPERATION_sub_ui
+#define FUNCTION          mpz_sub_ui
+#define FUNCTION2         mpz_sub
+#define VARIATION_CMP     <
+#define VARIATION_NEG     -
+#define VARIATION_UNNEG
+#endif
+
+#ifndef FUNCTION
+Error, need OPERATION_add_ui or OPERATION_sub_ui
+#endif
+
+
+void
+FUNCTION (mpz_ptr w, mpz_srcptr u, unsigned long int vval)
+{
+  mp_srcptr up;
+  mp_ptr wp;
+  mp_size_t usize, wsize;
+  mp_size_t abs_usize;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (vval > GMP_NUMB_MAX)
+    {
+      mpz_t v;
+      mp_limb_t vl[2];
+      PTR(v) = vl;
+      vl[0] = vval & GMP_NUMB_MASK;
+      vl[1] = vval >> GMP_NUMB_BITS;
+      SIZ(v) = 2;
+      FUNCTION2 (w, u, v);
+      return;
+    }
+#endif
+
+  usize = SIZ (u);
+  if (usize == 0)
+    {
+      MPZ_NEWALLOC (w, 1)[0] = vval;
+      SIZ (w) = VARIATION_NEG (vval != 0);
+      return;
+    }
+
+  abs_usize = ABS (usize);
+
+  if (usize VARIATION_CMP 0)
+    {
+      mp_limb_t cy;
+
+      /* If not space for W (and possible carry), increase space.  */
+      wp = MPZ_REALLOC (w, abs_usize + 1);
+      /* These must be after realloc (U may be the same as W).  */
+      up = PTR (u);
+
+      cy = mpn_add_1 (wp, up, abs_usize, (mp_limb_t) vval);
+      wp[abs_usize] = cy;
+      wsize = VARIATION_NEG (abs_usize + cy);
+    }
+  else
+    {
+      /* If not space for W, increase space.  */
+      wp = MPZ_REALLOC (w, abs_usize);
+      /* These must be after realloc (U may be the same as W).  */
+      up = PTR (u);
+
+      /* The signs are different.  Need exact comparison to determine
+	 which operand to subtract from which.  */
+      if (abs_usize == 1 && up[0] < vval)
+	{
+	  wp[0] = vval - up[0];
+	  wsize = VARIATION_NEG 1;
+	}
+      else
+	{
+	  mpn_sub_1 (wp, up, abs_usize, (mp_limb_t) vval);
+	  /* Size can decrease with at most one limb.  */
+	  wsize = VARIATION_UNNEG (abs_usize - (wp[abs_usize - 1] == 0));
+	}
+    }
+
+  SIZ (w) = wsize;
+}
diff --git a/mpz/aorsmul.c b/mpz/aorsmul.c
new file mode 100644
index 0000000..ba766f6
--- /dev/null
+++ b/mpz/aorsmul.c
@@ -0,0 +1,179 @@
+/* mpz_addmul, mpz_submul -- add or subtract multiple.
+
+Copyright 2001, 2004, 2005, 2012, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* expecting x and y both with non-zero high limbs */
+#define mpn_cmp_twosizes_lt(xp,xsize, yp,ysize)                 \
+  ((xsize) < (ysize)                                            \
+   || ((xsize) == (ysize) && mpn_cmp (xp, yp, xsize) < 0))
+
+
+/* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
+
+   The signs of w, x and y are fully accounted for by each flipping "sub".
+
+   The sign of w is retained for the result, unless the absolute value
+   submul underflows, in which case it flips.  */
+
+static void __gmpz_aorsmul (REGPARM_3_1 (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)) REGPARM_ATTR (1);
+#define mpz_aorsmul(w,x,y,sub)  __gmpz_aorsmul (REGPARM_3_1 (w, x, y, sub))
+
+REGPARM_ATTR (1) static void
+mpz_aorsmul (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)
+{
+  mp_size_t  xsize, ysize, tsize, wsize, wsize_signed;
+  mp_ptr     wp, tp;
+  mp_limb_t  c;
+  TMP_DECL;
+
+  /* w unaffected if x==0 or y==0 */
+  xsize = SIZ(x);
+  ysize = SIZ(y);
+  if (xsize == 0 || ysize == 0)
+    return;
+
+  /* make x the bigger of the two */
+  if (ABS(ysize) > ABS(xsize))
+    {
+      MPZ_SRCPTR_SWAP (x, y);
+      MP_SIZE_T_SWAP (xsize, ysize);
+    }
+
+  sub ^= ysize;
+  ysize = ABS(ysize);
+
+  /* use mpn_addmul_1/mpn_submul_1 if possible */
+  if (ysize == 1)
+    {
+      mpz_aorsmul_1 (w, x, PTR(y)[0], sub);
+      return;
+    }
+
+  sub ^= xsize;
+  xsize = ABS(xsize);
+
+  wsize_signed = SIZ(w);
+  sub ^= wsize_signed;
+  wsize = ABS(wsize_signed);
+
+  tsize = xsize + ysize;
+  wp = MPZ_REALLOC (w, MAX (wsize, tsize) + 1);
+
+  if (wsize_signed == 0)
+    {
+      mp_limb_t  high;
+      /* Nothing to add to, just set w=x*y.  No w==x or w==y overlap here,
+	 since we know x,y!=0 but w==0.  */
+      if (x == y)
+	{
+	  mpn_sqr (wp, PTR(x),xsize);
+	  high = wp[tsize-1];
+	}
+      else
+	high = mpn_mul (wp, PTR(x),xsize, PTR(y),ysize);
+      tsize -= (high == 0);
+      SIZ(w) = (sub >= 0 ? tsize : -tsize);
+      return;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (tsize);
+
+  if (x == y)
+    {
+      mpn_sqr (tp, PTR(x),xsize);
+      tsize -= (tp[tsize-1] == 0);
+    }
+  else
+    {
+      mp_limb_t high;
+      high = mpn_mul (tp, PTR(x),xsize, PTR(y),ysize);
+      tsize -= (high == 0);
+    }
+  ASSERT (tp[tsize-1] != 0);
+  if (sub >= 0)
+    {
+      mp_srcptr up    = wp;
+      mp_size_t usize = wsize;
+
+      if (usize < tsize)
+	{
+	  up	= tp;
+	  usize = tsize;
+	  tp	= wp;
+	  tsize = wsize;
+
+	  wsize = usize;
+	}
+
+      c = mpn_add (wp, up,usize, tp,tsize);
+      wp[wsize] = c;
+      wsize += (c != 0);
+    }
+  else
+    {
+      mp_srcptr up    = wp;
+      mp_size_t usize = wsize;
+
+      if (mpn_cmp_twosizes_lt (up,usize, tp,tsize))
+	{
+	  up	= tp;
+	  usize = tsize;
+	  tp	= wp;
+	  tsize = wsize;
+
+	  wsize = usize;
+	  wsize_signed = -wsize_signed;
+	}
+
+      ASSERT_NOCARRY (mpn_sub (wp, up,usize, tp,tsize));
+      wsize = usize;
+      MPN_NORMALIZE (wp, wsize);
+    }
+
+  SIZ(w) = (wsize_signed >= 0 ? wsize : -wsize);
+
+  TMP_FREE;
+}
+
+
+void
+mpz_addmul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mpz_aorsmul (w, u, v, (mp_size_t) 0);
+}
+
+void
+mpz_submul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mpz_aorsmul (w, u, v, (mp_size_t) -1);
+}
diff --git a/mpz/aorsmul_i.c b/mpz/aorsmul_i.c
new file mode 100644
index 0000000..317be3e
--- /dev/null
+++ b/mpz/aorsmul_i.c
@@ -0,0 +1,254 @@
+/* mpz_addmul_ui, mpz_submul_ui - add or subtract small multiple.
+
+   THE mpz_aorsmul_1 FUNCTION IN THIS FILE IS FOR INTERNAL USE ONLY AND IS
+   ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
+   COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2004, 2005, 2012, 2021, 2022 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if HAVE_NATIVE_mpn_mul_1c
+#define MPN_MUL_1C(cout, dst, src, size, n, cin)        \
+  do {                                                  \
+    (cout) = mpn_mul_1c (dst, src, size, n, cin);       \
+  } while (0)
+#else
+#define MPN_MUL_1C(cout, dst, src, size, n, cin)        \
+  do {                                                  \
+    mp_limb_t __cy;                                     \
+    __cy = mpn_mul_1 (dst, src, size, n);               \
+    (cout) = __cy + mpn_add_1 (dst, dst, size, cin);    \
+  } while (0)
+#endif
+
+
+/* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
+
+   All that's needed to account for negative w or x is to flip "sub".
+
+   The final w will retain its sign, unless an underflow occurs in a submul
+   of absolute values, in which case it's flipped.
+
+   If x has more limbs than w, then mpn_submul_1 followed by mpn_com is
+   used.  The alternative would be mpn_mul_1 into temporary space followed
+   by mpn_sub_n.  Avoiding temporary space seem good, and submul+com stands
+   a chance of being faster since it involves only one set of carry
+   propagations, not two.  Note that doing an addmul_1 with a
+   twos-complement negative y doesn't work, because it effectively adds an
+   extra x * 2^GMP_LIMB_BITS.  */
+
+REGPARM_ATTR(1) void
+mpz_aorsmul_1 (mpz_ptr w, mpz_srcptr x, mp_limb_t y, mp_size_t sub)
+{
+  mp_size_t  xsize, wsize, wsize_signed, new_wsize, min_size, dsize;
+  mp_srcptr  xp;
+  mp_ptr     wp;
+  mp_limb_t  cy;
+
+  /* w unaffected if x==0 or y==0 */
+  xsize = SIZ (x);
+  if (xsize == 0 || y == 0)
+    return;
+
+  sub ^= xsize;
+  xsize = ABS (xsize);
+
+  wsize_signed = SIZ (w);
+  if (wsize_signed == 0)
+    {
+      /* nothing to add to, just set x*y, "sub" gives the sign */
+      wp = MPZ_NEWALLOC (w, xsize+1);
+      cy = mpn_mul_1 (wp, PTR(x), xsize, y);
+      wp[xsize] = cy;
+      xsize += (cy != 0);
+      SIZ (w) = (sub >= 0 ? xsize : -xsize);
+      return;
+    }
+
+  sub ^= wsize_signed;
+  wsize = ABS (wsize_signed);
+
+  new_wsize = MAX (wsize, xsize);
+  wp = MPZ_REALLOC (w, new_wsize+1);
+  xp = PTR (x);
+  min_size = MIN (wsize, xsize);
+
+  if (sub >= 0)
+    {
+      /* addmul of absolute values */
+
+      cy = mpn_addmul_1 (wp, xp, min_size, y);
+      wp += min_size;
+      xp += min_size;
+
+      dsize = xsize - wsize;
+#if HAVE_NATIVE_mpn_mul_1c
+      if (dsize > 0)
+	cy = mpn_mul_1c (wp, xp, dsize, y, cy);
+      else if (dsize < 0)
+	{
+	  dsize = -dsize;
+	  cy = mpn_add_1 (wp, wp, dsize, cy);
+	}
+#else
+      if (dsize != 0)
+	{
+	  mp_limb_t  cy2;
+	  if (dsize > 0)
+	    cy2 = mpn_mul_1 (wp, xp, dsize, y);
+	  else
+	    {
+	      dsize = -dsize;
+	      cy2 = 0;
+	    }
+	  cy = cy2 + mpn_add_1 (wp, wp, dsize, cy);
+	}
+#endif
+
+      wp[dsize] = cy;
+      new_wsize += (cy != 0);
+    }
+  else
+    {
+      /* submul of absolute values */
+
+      cy = mpn_submul_1 (wp, xp, min_size, y);
+      if (wsize >= xsize)
+	{
+	  /* if w bigger than x, then propagate borrow through it */
+	  if (wsize != xsize)
+	    cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy);
+
+	  if (cy != 0)
+	    {
+	      /* Borrow out of w, take twos complement negative to get
+		 absolute value, flip sign of w.  */
+	      cy -= mpn_neg (wp, wp, new_wsize);
+	      wp[new_wsize] = cy;
+	      new_wsize += (cy != 0);
+	      wsize_signed = -wsize_signed;
+	    }
+	}
+      else /* wsize < xsize */
+	{
+	  /* x bigger than w, so want x*y-w.  Submul has given w-x*y, so
+	     take twos complement and use an mpn_mul_1 for the rest.  */
+
+	  mp_limb_t  cy2;
+
+	  /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */
+	  cy -= mpn_neg (wp, wp, wsize);
+
+	  /* If cy-1 == -1 then hold that -1 for latter.  mpn_submul_1 never
+	     returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */
+	  cy2 = (cy == MP_LIMB_T_MAX);
+	  cy += cy2;
+	  MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy);
+	  wp[new_wsize] = cy;
+	  new_wsize += (cy != 0);
+
+	  /* Apply any -1 from above.  The value at wp+wsize is non-zero
+	     because y!=0 and the high limb of x will be non-zero.  */
+	  if (cy2)
+	    MPN_DECR_U (wp+wsize, new_wsize-wsize, CNST_LIMB(1));
+
+	  wsize_signed = -wsize_signed;
+	}
+
+      /* submul can produce high zero limbs due to cancellation, both when w
+	 has more limbs or x has more  */
+      MPN_NORMALIZE (wp, new_wsize);
+    }
+
+  SIZ (w) = (wsize_signed >= 0 ? new_wsize : -new_wsize);
+
+  ASSERT (new_wsize == 0 || PTR(w)[new_wsize-1] != 0);
+}
+
+
+void
+mpz_addmul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (UNLIKELY (y > GMP_NUMB_MAX))
+    {
+      mpz_t t;
+      mp_ptr tp;
+      mp_size_t xn;
+      TMP_DECL;
+      TMP_MARK;
+      xn = SIZ (x);
+      if (xn == 0) return;
+      MPZ_TMP_INIT (t, ABS (xn) + 1);
+      tp = PTR (t);
+      tp[0] = 0;
+      MPN_COPY (tp + 1, PTR(x), ABS (xn));
+      SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) 0);
+      PTR(t) = tp + 1;
+      SIZ(t) = xn;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) 0);
+      TMP_FREE;
+      return;
+    }
+#endif
+  mpz_aorsmul_1 (w, x, (mp_limb_t) y, (mp_size_t) 0);
+}
+
+void
+mpz_submul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (y > GMP_NUMB_MAX)
+    {
+      mpz_t t;
+      mp_ptr tp;
+      mp_size_t xn;
+      TMP_DECL;
+      TMP_MARK;
+      xn = SIZ (x);
+      if (xn == 0) return;
+      MPZ_TMP_INIT (t, ABS (xn) + 1);
+      tp = PTR (t);
+      tp[0] = 0;
+      MPN_COPY (tp + 1, PTR(x), ABS (xn));
+      SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) -1);
+      PTR(t) = tp + 1;
+      SIZ(t) = xn;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
+      TMP_FREE;
+      return;
+    }
+#endif
+  mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
+}
diff --git a/mpz/array_init.c b/mpz/array_init.c
new file mode 100644
index 0000000..df97f34
--- /dev/null
+++ b/mpz/array_init.c
@@ -0,0 +1,49 @@
+/* mpz_array_init (array, array_size, size_per_elem) --
+
+Copyright 1991, 1993-1995, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_array_init (mpz_ptr arr, mp_size_t arr_size, mp_size_t nbits)
+{
+  mp_ptr p;
+  mp_size_t i;
+  mp_size_t nlimbs;
+
+  nlimbs = nbits / GMP_NUMB_BITS + 1;
+  p = __GMP_ALLOCATE_FUNC_LIMBS (arr_size * nlimbs);
+
+  for (i = 0; i < arr_size; i++)
+    {
+      ALLOC (&arr[i]) = nlimbs + 1; /* Yes, lie a little... */
+      SIZ (&arr[i]) = 0;
+      PTR (&arr[i]) = p + i * nlimbs;
+    }
+}
diff --git a/mpz/bin_ui.c b/mpz/bin_ui.c
new file mode 100644
index 0000000..04cd340
--- /dev/null
+++ b/mpz/bin_ui.c
@@ -0,0 +1,459 @@
+/* mpz_bin_ui(RESULT, N, K) -- Set RESULT to N over K.
+
+Copyright 1998-2002, 2012, 2013, 2015, 2017-2018, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* How many special cases? Minimum is 2: 0 and 1;
+ * also 3 {0,1,2} and 5 {0,1,2,3,4} are implemented.
+ */
+#define APARTAJ_KALKULOJ 2
+
+/* Whether to use (1) or not (0) the function mpz_bin_uiui whenever
+ * the operands fit.
+ */
+#define UZU_BIN_UIUI 0
+
+/* Whether to use a shortcut to precompute the product of four
+ * elements (1), or precompute only the product of a couple (0).
+ *
+ * In both cases the precomputed product is then updated with some
+ * linear operations to obtain the product of the next four (1)
+ * [or two (0)] operands.
+ */
+#define KVAROPE 1
+
+static void
+posmpz_init (mpz_ptr r)
+{
+  mp_ptr rp;
+  ASSERT (SIZ (r) > 0);
+  rp = SIZ (r) + MPZ_REALLOC (r, SIZ (r) + 2);
+  *rp = 0;
+  *++rp = 0;
+}
+
+/* Equivalent to mpz_add_ui (r, r, in), but faster when
+   0 < SIZ (r) < ALLOC (r) and limbs above SIZ (r) contain 0. */
+static void
+posmpz_inc_ui (mpz_ptr r, unsigned long in)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  mpz_add_ui (r, r, in);
+#else
+  ASSERT (SIZ (r) > 0);
+  MPN_INCR_U (PTR (r), SIZ (r) + 1, in);
+  SIZ (r) += PTR (r)[SIZ (r)];
+#endif
+}
+
+/* Equivalent to mpz_sub_ui (r, r, in), but faster when
+   0 < SIZ (r) and we know in advance that the result is positive. */
+static void
+posmpz_dec_ui (mpz_ptr r, unsigned long in)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  mpz_sub_ui (r, r, in);
+#else
+  ASSERT (mpz_cmp_ui (r, in) >= 0);
+  MPN_DECR_U (PTR (r), SIZ (r), in);
+  SIZ (r) -= (PTR (r)[SIZ (r)-1] == 0);
+#endif
+}
+
+/* Equivalent to mpz_tdiv_q_2exp (r, r, 1), but faster when
+   0 < SIZ (r) and we know in advance that the result is positive. */
+static void
+posmpz_rsh1 (mpz_ptr r)
+{
+  mp_ptr rp;
+  mp_size_t rn;
+
+  rn = SIZ (r);
+  rp = PTR (r);
+  ASSERT (rn > 0);
+  mpn_rshift (rp, rp, rn, 1);
+  SIZ (r) -= rp[rn - 1] == 0;
+}
+
+/* Computes r = n(n+(2*k-1))/2
+   It uses a sqare instead of a product, computing
+   r = ((n+k-1)^2 + n - (k-1)^2)/2
+   As a side effect, sets t = n+k-1
+ */
+static void
+mpz_hmul_nbnpk (mpz_ptr r, mpz_srcptr n, unsigned long int k, mpz_ptr t)
+{
+  ASSERT (k > 0 && SIZ(n) > 0);
+  --k;
+  mpz_add_ui (t, n, k);
+  mpz_mul (r, t, t);
+  mpz_add (r, r, n);
+  posmpz_rsh1 (r);
+  if (LIKELY (k <= (1UL << (BITS_PER_ULONG / 2))))
+    posmpz_dec_ui (r, (k + (k & 1))*(k >> 1));
+  else
+    {
+      mpz_t tmp;
+      mpz_init_set_ui (tmp, (k + (k & 1)));
+      mpz_mul_ui (tmp, tmp, k >> 1);
+      mpz_sub (r, r, tmp);
+      mpz_clear (tmp);
+    }
+}
+
+#if KVAROPE
+static void
+rek_raising_fac4 (mpz_ptr r, mpz_ptr p, mpz_ptr P, unsigned long int k, unsigned long int lk, mpz_ptr t)
+{
+  if (k - lk < 5)
+    {
+      do {
+	posmpz_inc_ui (p, 4*k+2);
+	mpz_addmul_ui (P, p, 4*k);
+	posmpz_dec_ui (P, k);
+	mpz_mul (r, r, P);
+      } while (--k > lk);
+    }
+  else
+    {
+      mpz_t lt;
+      unsigned long int m;
+
+      ALLOC (lt) = 0;
+      SIZ (lt) = 0;
+      if (t == NULL)
+	t = lt;
+      m = ((k + lk) >> 1) + 1;
+      rek_raising_fac4 (r, p, P, k, m, t);
+
+      posmpz_inc_ui (p, 4*m+2);
+      mpz_addmul_ui (P, p, 4*m);
+      posmpz_dec_ui (P, m);
+      mpz_set (t, P);
+      rek_raising_fac4 (t, p, P, m - 1, lk, NULL);
+
+      mpz_mul (r, r, t);
+      mpz_clear (lt);
+    }
+}
+
+/* Computes (n+1)(n+2)...(n+k)/2^(k/2 +k/4) using the helper function
+   rek_raising_fac4, and exploiting an idea inspired by a piece of
+   code that Fredrik Johansson wrote and by a comment by Niels Möller.
+
+   Assume k = 4i then compute:
+     p  = (n+1)(n+4i)/2 - i
+	  (n+1+1)(n+4i)/2 = p + i + (n+4i)/2
+	  (n+1+1)(n+4i-1)/2 = p + i + ((n+4i)-(n+1+1))/2 = p + i + (n-n+4i-2)/2 = p + 3i-1
+     P  = (p + i)*(p+3i-1)/2 = (n+1)(n+2)(n+4i-1)(n+4i)/8
+     n' = n + 2
+     i' = i - 1
+	  (n'-1)(n')(n'+4i'+1)(n'+4i'+2)/8 = P
+	  (n'-1)(n'+4i'+2)/2 - i' - 1 = p
+	  (n'-1+2)(n'+4i'+2)/2 - i' - 1 = p + (n'+4i'+2)
+	  (n'-1+2)(n'+4i'+2-2)/2 - i' - 1 = p + (n'+4i'+2) - (n'-1+2) =  p + 4i' + 1
+	  (n'-1+2)(n'+4i'+2-2)/2 - i' = p + 4i' + 2
+     p' = p + 4i' + 2 = (n'+1)(n'+4i')/2 - i'
+	  p' - 4i' - 2 = p
+	  (p' - 4i' - 2 + i)*(p' - 4i' - 2+3i-1)/2 = P
+	  (p' - 4i' - 2 + i' + 1)*(p' - 4i' - 2 + 3i' + 3 - 1)/2 = P
+	  (p' - 3i' - 1)*(p' - i')/2 = P
+	  (p' - 3i' - 1 + 4i' + 1)*(p' - i' + 4i' - 1)/2 = P + (4i' + 1)*(p' - i')/2 + (p' - 3i' - 1 + 4i' + 1)*(4i' - 1)/2
+	  (p' + i')*(p' + 3i' - 1)/2 = P + (4i')*(p' + p')/2 + (p' - i' - (p' + i'))/2
+	  (p' + i')*(p' + 3i' - 1)/2 = P + 4i'p' + (p' - i' - p' - i')/2
+	  (p' + i')*(p' + 3i' - 1)/2 = P + 4i'p' - i'
+     P' = P + 4i'p' - i'
+
+   And compute the product P * P' * P" ...
+ */
+
+static void
+mpz_raising_fac4 (mpz_ptr r, mpz_ptr n, unsigned long int k, mpz_ptr t, mpz_ptr p)
+{
+  ASSERT ((k >= APARTAJ_KALKULOJ) && (APARTAJ_KALKULOJ > 0));
+  posmpz_init (n);
+  posmpz_inc_ui (n, 1);
+  SIZ (r) = 0;
+  if (k & 1)
+    {
+      mpz_set (r, n);
+      posmpz_inc_ui (n, 1);
+    }
+  k >>= 1;
+  if (APARTAJ_KALKULOJ < 2 && k == 0)
+    return;
+
+  mpz_hmul_nbnpk (p, n, k, t);
+  posmpz_init (p);
+
+  if (k & 1)
+    {
+      if (SIZ (r))
+	mpz_mul (r, r, p);
+      else
+	mpz_set (r, p);
+      posmpz_inc_ui (p, k - 1);
+    }
+  k >>= 1;
+  if (APARTAJ_KALKULOJ < 4 && k == 0)
+    return;
+
+  mpz_hmul_nbnpk (t, p, k, n);
+  if (SIZ (r))
+    mpz_mul (r, r, t);
+  else
+    mpz_set (r, t);
+
+  if (APARTAJ_KALKULOJ > 8 || k > 1)
+    {
+      posmpz_dec_ui (p, k);
+      rek_raising_fac4 (r, p, t, k - 1, 0, n);
+    }
+}
+
+#else /* KVAROPE */
+
+static void
+rek_raising_fac (mpz_ptr r, mpz_ptr n, unsigned long int k, unsigned long int lk, mpz_ptr t1, mpz_ptr t2)
+{
+  /* Should the threshold depend on SIZ (n) ? */
+  if (k - lk < 10)
+    {
+      do {
+	posmpz_inc_ui (n, k);
+	mpz_mul (r, r, n);
+	--k;
+      } while (k > lk);
+    }
+  else
+    {
+      mpz_t t3;
+      unsigned long int m;
+
+      m = ((k + lk) >> 1) + 1;
+      rek_raising_fac (r, n, k, m, t1, t2);
+
+      posmpz_inc_ui (n, m);
+      if (t1 == NULL)
+	{
+	  mpz_init_set (t3, n);
+	  t1 = t3;
+	}
+      else
+	{
+	  ALLOC (t3) = 0;
+	  mpz_set (t1, n);
+	}
+      rek_raising_fac (t1, n, m - 1, lk, t2, NULL);
+
+      mpz_mul (r, r, t1);
+      mpz_clear (t3);
+    }
+}
+
+/* Computes (n+1)(n+2)...(n+k)/2^(k/2) using the helper function
+   rek_raising_fac, and exploiting an idea inspired by a piece of
+   code that Fredrik Johansson wrote.
+
+   Force an even k = 2i then compute:
+     p  = (n+1)(n+2i)/2
+     i' = i - 1
+     p == (n+1)(n+2i'+2)/2
+     p' = p + i' == (n+2)(n+2i'+1)/2
+     n' = n + 1
+     p'== (n'+1)(n'+2i')/2 == (n+1 +1)(n+2i -1)/2
+
+   And compute the product p * p' * p" ...
+*/
+
+static void
+mpz_raising_fac (mpz_ptr r, mpz_ptr n, unsigned long int k, mpz_ptr t, mpz_ptr p)
+{
+  unsigned long int hk;
+  ASSERT ((k >= APARTAJ_KALKULOJ) && (APARTAJ_KALKULOJ > 1));
+  mpz_add_ui (n, n, 1);
+  hk = k >> 1;
+  mpz_hmul_nbnpk (p, n, hk, t);
+
+  if ((k & 1) != 0)
+    {
+      mpz_add_ui (t, t, hk + 1);
+      mpz_mul (r, t, p);
+    }
+  else
+    {
+      mpz_set (r, p);
+    }
+
+  if ((APARTAJ_KALKULOJ > 3) || (hk > 1))
+    {
+      posmpz_init (p);
+      rek_raising_fac (r, p, hk - 1, 0, t, n);
+    }
+}
+#endif /* KVAROPE */
+
+/* This is a poor implementation.  Look at bin_uiui.c for improvement ideas.
+   In fact consider calling mpz_bin_uiui() when the arguments fit, leaving
+   the code here only for big n.
+
+   The identity bin(n,k) = (-1)^k * bin(-n+k-1,k) can be found in Knuth vol
+   1 section 1.2.6 part G. */
+
+void
+mpz_bin_ui (mpz_ptr r, mpz_srcptr n, unsigned long int k)
+{
+  mpz_t      ni;
+  mp_size_t  negate;
+
+  if (SIZ (n) < 0)
+    {
+      /* bin(n,k) = (-1)^k * bin(-n+k-1,k), and set ni = -n+k-1 - k = -n-1 */
+      mpz_init (ni);
+      mpz_add_ui (ni, n, 1L);
+      mpz_neg (ni, ni);
+      negate = (k & 1);   /* (-1)^k */
+    }
+  else
+    {
+      /* bin(n,k) == 0 if k>n
+	 (no test for this under the n<0 case, since -n+k-1 >= k there) */
+      if (mpz_cmp_ui (n, k) < 0)
+	{
+	  SIZ (r) = 0;
+	  return;
+	}
+
+      /* set ni = n-k */
+      mpz_init (ni);
+      mpz_sub_ui (ni, n, k);
+      negate = 0;
+    }
+
+  /* Now wanting bin(ni+k,k), with ni positive, and "negate" is the sign (0
+     for positive, 1 for negative). */
+
+  /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller.  In this case it's
+     whether ni+k-k < k meaning ni<k, and if so change to denominator ni+k-k
+     = ni, and new ni of ni+k-ni = k.  */
+  if (mpz_cmp_ui (ni, k) < 0)
+    {
+      unsigned long  tmp;
+      tmp = k;
+      k = mpz_get_ui (ni);
+      mpz_set_ui (ni, tmp);
+    }
+
+  if (k < APARTAJ_KALKULOJ)
+    {
+      if (k == 0)
+	{
+	  SIZ (r) = 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	}
+#if APARTAJ_KALKULOJ > 2
+      else if (k > 1)
+	{
+	  mpz_add_ui (ni, ni, 1 + (APARTAJ_KALKULOJ > 2 && k > 2));
+	  mpz_mul (r, ni, ni); /* r = (n + (k>2))^2 */
+	  if (APARTAJ_KALKULOJ == 2 || k == 2)
+	    {
+	      mpz_add (r, r, ni); /* n^2+n= n(n+1) */
+	      posmpz_rsh1 (r);
+	    }
+#if APARTAJ_KALKULOJ > 3
+#if APARTAJ_KALKULOJ != 5
+#error Not implemented! 3 < APARTAJ_KALKULOJ != 5
+#endif
+	  else /* k > 2 */
+	    { /* k = 3, 4 */
+	      mpz_sub_ui (r, r, 1); /* (n+1)^2-1 */
+	      if (k == 3)
+		{
+		  mpz_mul (r, r, ni); /* ((n+1)^2-1)(n+1) = n(n+1)(n+2) */
+		  /* mpz_divexact_ui (r, r, 6); /\* 6=3<<1; div_by3 ? *\/ */
+		}
+	      else /* k = 4 */
+		{
+		  mpz_add (ni, ni, r); /* (n+1)^2+n */
+		  mpz_mul (r, ni, ni); /* ((n+1)^2+n)^2 */
+		  /* We should subtract one: ((n+1)^2+n)^2-1 = n(n+1)(n+2)(n+3). */
+		  /* PTR (r) [0] ^= 1; would suffice, but it is not even needed, */
+		  /* because the next division will shift away this bit anyway.  */
+		  /* mpz_divexact_ui (r, r, 24); /\* 24=3<<3; div_by3 ? *\/ */
+		}
+	      mpn_pi1_bdiv_q_1 (PTR(r), PTR(r), SIZ(r), 3, GMP_NUMB_MASK/3*2+1, 1 | (k>>1));
+	      SIZ(r) -= PTR(r) [SIZ(r) - 1] == 0;
+	    }
+#endif
+	}
+#endif
+      else
+	{ /* k = 1 */
+	  mpz_add_ui (r, ni, 1);
+	}
+    }
+#if UZU_BIN_UIUI
+  else if (mpz_cmp_ui (ni, ULONG_MAX - k) <= 0)
+    {
+      mpz_bin_uiui (r, mpz_get_ui (ni) + k, k);
+    }
+#endif
+  else
+    {
+      mp_limb_t count;
+      mpz_t num, den;
+
+      mpz_init (num);
+      mpz_init (den);
+
+#if KVAROPE
+      mpz_raising_fac4 (num, ni, k, den, r);
+      popc_limb (count, k);
+      ASSERT (k - (k >> 1) - (k >> 2) - count >= 0);
+      mpz_tdiv_q_2exp (num, num, k - (k >> 1) - (k >> 2) - count);
+#else
+      mpz_raising_fac (num, ni, k, den, r);
+      popc_limb (count, k);
+      ASSERT (k - (k >> 1) - count >= 0);
+      mpz_tdiv_q_2exp (num, num, k - (k >> 1) - count);
+#endif
+
+      mpz_oddfac_1(den, k, 0);
+
+      mpz_divexact(r, num, den);
+      mpz_clear (num);
+      mpz_clear (den);
+    }
+  mpz_clear (ni);
+
+  SIZ(r) = (SIZ(r) ^ -negate) + negate;
+}
diff --git a/mpz/bin_uiui.c b/mpz/bin_uiui.c
new file mode 100644
index 0000000..542d485
--- /dev/null
+++ b/mpz/bin_uiui.c
@@ -0,0 +1,707 @@
+/* mpz_bin_uiui - compute n over k.
+
+Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+Copyright 2010-2012, 2015-2018, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef BIN_GOETGHELUCK_THRESHOLD
+#define BIN_GOETGHELUCK_THRESHOLD  512
+#endif
+#ifndef BIN_UIUI_ENABLE_SMALLDC
+#define BIN_UIUI_ENABLE_SMALLDC    1
+#endif
+#ifndef BIN_UIUI_RECURSIVE_SMALLDC
+#define BIN_UIUI_RECURSIVE_SMALLDC (GMP_NUMB_BITS > 32)
+#endif
+
+/* Algorithm:
+
+   Accumulate chunks of factors first limb-by-limb (using one of mul0-mul8)
+   which are then accumulated into mpn numbers.  The first inner loop
+   accumulates divisor factors, the 2nd inner loop accumulates exactly the same
+   number of dividend factors.  We avoid accumulating more for the divisor,
+   even with its smaller factors, since we else cannot guarantee divisibility.
+
+   Since we know each division will yield an integer, we compute the quotient
+   using Hensel norm: If the quotient is limited by 2^t, we compute A / B mod
+   2^t.
+
+   Improvements:
+
+   (1) An obvious improvement to this code would be to compute mod 2^t
+   everywhere.  Unfortunately, we cannot determine t beforehand, unless we
+   invoke some approximation, such as Stirling's formula.  Of course, we don't
+   need t to be tight.  However, it is not clear that this would help much,
+   our numbers are kept reasonably small already.
+
+   (2) Compute nmax/kmax semi-accurately, without scalar division or a loop.
+   Extracting the 3 msb, then doing a table lookup using cnt*8+msb as index,
+   would make it both reasonably accurate and fast.  (We could use a table
+   stored into a limb, perhaps.)  The table should take the removed factors of
+   2 into account (those done on-the-fly in mulN).
+
+   (3) The first time in the loop we compute the odd part of a
+   factorial in kp, we might use oddfac_1 for this task.
+ */
+
+/* This threshold determines how large divisor to accumulate before we call
+   bdiv.  Perhaps we should never call bdiv, and accumulate all we are told,
+   since we are just basecase code anyway?  Presumably, this depends on the
+   relative speed of the asymptotically fast code and this code.  */
+#define SOME_THRESHOLD 20
+
+/* Multiply-into-limb functions.  These remove factors of 2 on-the-fly.  FIXME:
+   All versions of MAXFACS don't take this 2 removal into account now, meaning
+   that then, shifting just adds some overhead.  (We remove factors from the
+   completed limb anyway.)  */
+
+static mp_limb_t
+mul1 (mp_limb_t m)
+{
+  return m;
+}
+
+static mp_limb_t
+mul2 (mp_limb_t m)
+{
+  /* We need to shift before multiplying, to avoid an overflow. */
+  mp_limb_t m01 = (m | 1) * ((m + 1) >> 1);
+  return m01;
+}
+
+static mp_limb_t
+mul3 (mp_limb_t m)
+{
+  mp_limb_t m01 = (m + 0) * (m + 1) >> 1;
+  mp_limb_t m2 = (m + 2);
+  return m01 * m2;
+}
+
+static mp_limb_t
+mul4 (mp_limb_t m)
+{
+  mp_limb_t m03 = (m + 0) * (m + 3) >> 1;
+  return m03 * (m03 + 1); /* mul2 (m03) ? */
+}
+
+static mp_limb_t
+mul5 (mp_limb_t m)
+{
+  mp_limb_t m03 = (m + 0) * (m + 3) >> 1;
+  mp_limb_t m034 = m03 * (m + 4);
+  return (m03 + 1) * m034;
+}
+
+static mp_limb_t
+mul6 (mp_limb_t m)
+{
+  mp_limb_t m05 = (m + 0) * (m + 5);
+  mp_limb_t m1234 = (m05 + 5) * (m05 + 5) >> 3;
+  return m1234 * (m05 >> 1);
+}
+
+static mp_limb_t
+mul7 (mp_limb_t m)
+{
+  mp_limb_t m05 = (m + 0) * (m + 5);
+  mp_limb_t m1234 = (m05 + 5) * (m05 + 5) >> 3;
+  mp_limb_t m056 = m05 * (m + 6) >> 1;
+  return m1234 * m056;
+}
+
+static mp_limb_t
+mul8 (mp_limb_t m)
+{
+  mp_limb_t m07 = (m + 0) * (m + 7);
+  mp_limb_t m0257 = m07 * (m07 + 10) >> 3;
+  mp_limb_t m1346 = m07 + 9 + m0257;
+  return m0257 * m1346;
+}
+
+/*
+static mp_limb_t
+mul9 (mp_limb_t m)
+{
+  return (m + 8) * mul8 (m) ;
+}
+
+static mp_limb_t
+mul10 (mp_limb_t m)
+{
+  mp_limb_t m09 = (m + 0) * (m + 9);
+  mp_limb_t m18 = (m09 >> 1) + 4;
+  mp_limb_t m0369 = m09 * (m09 + 18) >> 3;
+  mp_limb_t m2457 = m09 * 2 + 35 + m0369;
+  return ((m0369 * m2457) >> 1) * m18;
+}
+*/
+
+typedef mp_limb_t (* mulfunc_t) (mp_limb_t);
+
+static const mulfunc_t mulfunc[] = {mul1,mul2,mul3,mul4,mul5,mul6,mul7,mul8 /* ,mul9,mul10 */};
+#define M (numberof(mulfunc))
+
+/* Number of factors-of-2 removed by the corresponding mulN function.  */
+static const unsigned char tcnttab[] = {0, 1, 1, 2, 2, 4, 4, 6 /*,6,8*/};
+
+#if 1
+/* This variant is inaccurate but share the code with other functions.  */
+#define MAXFACS(max,l)							\
+  do {									\
+    (max) = log_n_max (l);						\
+  } while (0)
+#else
+
+/* This variant is exact(?) but uses a loop.  It takes the 2 removal
+ of mulN into account.  */
+static const unsigned long ftab[] =
+#if GMP_NUMB_BITS == 64
+  /* 1 to 8 factors per iteration */
+  {CNST_LIMB(0xffffffffffffffff),CNST_LIMB(0x16a09e667),0x32cbfc,0x16a08,0x24c0,0xa11,0x345,0x1ab /*,0xe9,0x8e */};
+#endif
+#if GMP_NUMB_BITS == 32
+  /* 1 to 7 factors per iteration */
+  {0xffffffff,0x16a09,0x7ff,0x168,0x6f,0x3d,0x20 /* ,0x17 */};
+#endif
+
+#define MAXFACS(max,l)							\
+  do {									\
+    int __i;								\
+    for (__i = numberof (ftab) - 1; l > ftab[__i]; __i--)		\
+      ;									\
+    (max) = __i + 1;							\
+  } while (0)
+#endif
+
+/* Entry i contains (i!/2^t)^(-1) where t is chosen such that the parenthesis
+   is an odd integer. */
+static const mp_limb_t facinv[] = { ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE };
+
+static void
+mpz_bdiv_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  unsigned nmax, kmax, nmaxnow, numfac;
+  mp_ptr np, kp;
+  mp_size_t nn, kn, alloc;
+  mp_limb_t i, j, t, iii, jjj, cy, dinv;
+  int cnt;
+  mp_size_t maxn;
+  TMP_DECL;
+
+  ASSERT (k > ODD_FACTORIAL_TABLE_LIMIT);
+  TMP_MARK;
+
+  maxn = 1 + n / GMP_NUMB_BITS;    /* absolutely largest result size (limbs) */
+
+  /* FIXME: This allocation might be insufficient, but is usually way too
+     large.  */
+  alloc = SOME_THRESHOLD - 1 + MAX (3 * maxn / 2, SOME_THRESHOLD);
+  alloc = MIN (alloc, (mp_size_t) k) + 1;
+  TMP_ALLOC_LIMBS_2 (np, alloc, kp, SOME_THRESHOLD + 1);
+
+  MAXFACS (nmax, n);
+  ASSERT (nmax <= M);
+  MAXFACS (kmax, k);
+  ASSERT (kmax <= M);
+  ASSERT (k >= M);
+
+  i = n - k + 1;
+
+  np[0] = 1; nn = 1;
+
+  numfac = 1;
+  j = ODD_FACTORIAL_TABLE_LIMIT + 1;
+  jjj = ODD_FACTORIAL_TABLE_MAX;
+  ASSERT (__gmp_oddfac_table[ODD_FACTORIAL_TABLE_LIMIT] == ODD_FACTORIAL_TABLE_MAX);
+
+  while (1)
+    {
+      kp[0] = jjj;				/* store new factors */
+      kn = 1;
+      t = k - j + 1;
+      kmax = MIN (kmax, t);
+
+      while (kmax != 0 && kn < SOME_THRESHOLD)
+	{
+	  jjj = mulfunc[kmax - 1] (j);
+	  j += kmax;				/* number of factors used */
+	  count_trailing_zeros (cnt, jjj);	/* count low zeros */
+	  jjj >>= cnt;				/* remove remaining low zeros */
+	  cy = mpn_mul_1 (kp, kp, kn, jjj);	/* accumulate new factors */
+	  kp[kn] = cy;
+	  kn += cy != 0;
+	  t = k - j + 1;
+	  kmax = MIN (kmax, t);
+	}
+      numfac = j - numfac;
+
+      while (numfac != 0)
+	{
+	  nmaxnow = MIN (nmax, numfac);
+	  iii = mulfunc[nmaxnow - 1] (i);
+	  i += nmaxnow;				/* number of factors used */
+	  count_trailing_zeros (cnt, iii);	/* count low zeros */
+	  iii >>= cnt;				/* remove remaining low zeros */
+	  cy = mpn_mul_1 (np, np, nn, iii);	/* accumulate new factors */
+	  np[nn] = cy;
+	  nn += cy != 0;
+	  numfac -= nmaxnow;
+	}
+
+      ASSERT (nn < alloc);
+
+      binvert_limb (dinv, kp[0]);
+      nn += (np[nn - 1] >= kp[kn - 1]);
+      nn -= kn;
+      mpn_sbpi1_bdiv_q (np, np, nn, kp, MIN(kn,nn), -dinv);
+      mpn_neg (np, np, nn);
+
+      if (kmax == 0)
+	break;
+      numfac = j;
+
+      jjj = mulfunc[kmax - 1] (j);
+      j += kmax;				/* number of factors used */
+      count_trailing_zeros (cnt, jjj);		/* count low zeros */
+      jjj >>= cnt;				/* remove remaining low zeros */
+    }
+
+  /* Put back the right number of factors of 2.  */
+  popc_limb (cnt, n - k);
+  popc_limb (j, k);
+  cnt += j;
+  popc_limb (j, n);
+  cnt -= j;
+  if (cnt != 0)
+    {
+      ASSERT (cnt < GMP_NUMB_BITS); /* can happen, but not for intended use */
+      cy = mpn_lshift (np, np, nn, cnt);
+      np[nn] = cy;
+      nn += cy != 0;
+    }
+
+  nn -= np[nn - 1] == 0;	/* normalisation */
+
+  kp = MPZ_NEWALLOC (r, nn);
+  SIZ(r) = nn;
+  MPN_COPY (kp, np, nn);
+  TMP_FREE;
+}
+
+static void
+mpz_smallk_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  unsigned nmax, numfac;
+  mp_ptr rp;
+  mp_size_t rn, alloc;
+  mp_limb_t i, iii, cy;
+  unsigned i2cnt, cnt;
+
+  MAXFACS (nmax, n);
+  nmax = MIN (nmax, M);
+
+  i = n - k + 1;
+
+  i2cnt = __gmp_fac2cnt_table[k / 2 - 1];		/* low zeros count */
+  if (nmax >= k)
+    {
+      MPZ_NEWALLOC (r, 1) [0] = mulfunc[k - 1] (i) * facinv[k - 2] >>
+	(i2cnt - tcnttab[k - 1]);
+      SIZ(r) = 1;
+      return;
+    }
+
+  count_leading_zeros (cnt, (mp_limb_t) n);
+  cnt = GMP_LIMB_BITS - cnt;
+  alloc = cnt * k / GMP_NUMB_BITS + 3;	/* FIXME: ensure rounding is enough. */
+  rp = MPZ_NEWALLOC (r, alloc);
+
+  rp[0] = mulfunc[nmax - 1] (i);
+  rn = 1;
+  i += nmax;				/* number of factors used */
+  i2cnt -= tcnttab[nmax - 1];		/* low zeros count */
+  numfac = k - nmax;
+  do
+    {
+      nmax = MIN (nmax, numfac);
+      iii = mulfunc[nmax - 1] (i);
+      i += nmax;			/* number of factors used */
+      i2cnt -= tcnttab[nmax - 1];	/* update low zeros count */
+      cy = mpn_mul_1 (rp, rp, rn, iii);	/* accumulate new factors */
+      rp[rn] = cy;
+      rn += cy != 0;
+      numfac -= nmax;
+    } while (numfac != 0);
+
+  ASSERT (rn < alloc);
+
+  mpn_pi1_bdiv_q_1 (rp, rp, rn, __gmp_oddfac_table[k], facinv[k - 2], i2cnt);
+  /* A two-fold, branch-free normalisation is possible :*/
+  /* rn -= rp[rn - 1] == 0; */
+  /* rn -= rp[rn - 1] == 0; */
+  MPN_NORMALIZE_NOT_ZERO (rp, rn);
+
+  SIZ(r) = rn;
+}
+
+/* Algorithm:
+
+   Plain and simply multiply things together.
+
+   We tabulate factorials (k!/2^t)^(-1) mod B (where t is chosen such
+   that k!/2^t is odd).
+
+*/
+
+static mp_limb_t
+bc_bin_uiui (unsigned int n, unsigned int k)
+{
+  return ((__gmp_oddfac_table[n] * facinv[k - 2] * facinv[n - k - 2])
+    << (__gmp_fac2cnt_table[n / 2 - 1] - __gmp_fac2cnt_table[k / 2 - 1] - __gmp_fac2cnt_table[(n-k) / 2 - 1]))
+    & GMP_NUMB_MASK;
+}
+
+/* Algorithm:
+
+   Recursively exploit the relation
+   bin(n,k) = bin(n,k>>1)*bin(n-k>>1,k-k>>1)/bin(k,k>>1) .
+
+   Values for binomial(k,k>>1) that fit in a limb are precomputed
+   (with inverses).
+*/
+
+/* bin2kk[i - ODD_CENTRAL_BINOMIAL_OFFSET] =
+   binomial(i*2,i)/2^t (where t is chosen so that it is odd). */
+static const mp_limb_t bin2kk[] = { ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE };
+
+/* bin2kkinv[i] = bin2kk[i]^-1 mod B */
+static const mp_limb_t bin2kkinv[] = { ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE };
+
+/* bin2kk[i] = binomial((i+MIN_S)*2,i+MIN_S)/2^t. This table contains the t values. */
+static const unsigned char fac2bin[] = { CENTRAL_BINOMIAL_2FAC_TABLE };
+
+static void
+mpz_smallkdc_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  mp_ptr rp;
+  mp_size_t rn;
+  unsigned long int hk;
+
+  hk = k >> 1;
+
+  if ((! BIN_UIUI_RECURSIVE_SMALLDC) || hk <= ODD_FACTORIAL_TABLE_LIMIT)
+    mpz_smallk_bin_uiui (r, n, hk);
+  else
+    mpz_smallkdc_bin_uiui (r, n, hk);
+  k -= hk;
+  n -= hk;
+  if (n <= ODD_FACTORIAL_EXTTABLE_LIMIT) {
+    mp_limb_t cy;
+    rn = SIZ (r);
+    rp = MPZ_REALLOC (r, rn + 1);
+    cy = mpn_mul_1 (rp, rp, rn, bc_bin_uiui (n, k));
+    rp [rn] = cy;
+    rn += cy != 0;
+  } else {
+    mp_limb_t buffer[ODD_CENTRAL_BINOMIAL_TABLE_LIMIT + 3];
+    mpz_t t;
+
+    ALLOC (t) = ODD_CENTRAL_BINOMIAL_TABLE_LIMIT + 3;
+    PTR (t) = buffer;
+    if ((! BIN_UIUI_RECURSIVE_SMALLDC) || k <= ODD_FACTORIAL_TABLE_LIMIT)
+      mpz_smallk_bin_uiui (t, n, k);
+    else
+      mpz_smallkdc_bin_uiui (t, n, k);
+    mpz_mul (r, r, t);
+    rp = PTR (r);
+    rn = SIZ (r);
+  }
+
+  mpn_pi1_bdiv_q_1 (rp, rp, rn, bin2kk[k - ODD_CENTRAL_BINOMIAL_OFFSET],
+		    bin2kkinv[k - ODD_CENTRAL_BINOMIAL_OFFSET],
+		    fac2bin[k - ODD_CENTRAL_BINOMIAL_OFFSET] - (k != hk));
+  /* A two-fold, branch-free normalisation is possible :*/
+  /* rn -= rp[rn - 1] == 0; */
+  /* rn -= rp[rn - 1] == 0; */
+  MPN_NORMALIZE_NOT_ZERO (rp, rn);
+
+  SIZ(r) = rn;
+}
+
+/* mpz_goetgheluck_bin_uiui(RESULT, N, K) -- Set RESULT to binomial(N,K).
+ *
+ * Contributed to the GNU project by Marco Bodrato.
+ *
+ * Implementation of the algorithm by P. Goetgheluck, "Computing
+ * Binomial Coefficients", The American Mathematical Monthly, Vol. 94,
+ * No. 4 (April 1987), pp. 360-365.
+ *
+ * Acknowledgment: Peter Luschny did spot the slowness of the previous
+ * code and suggested the reference.
+ */
+
+/* TODO: Remove duplicated constants / macros / static functions...
+ */
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I)			\
+  if ((PR) > (MAX_PR)) {					\
+    (VEC)[(I)++] = (PR);					\
+    (PR) = 1;							\
+  }
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if ((*__sieve & __mask) == 0)				\
+	{							\
+	  mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, *__sieve, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __sieve = (sieve) + __i / GMP_LIMB_BITS;			\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __sieve += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+#if WANT_ASSERT
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+
+/*********************************************************/
+/* Section binomial: fast binomial implementation        */
+/*********************************************************/
+
+#define COUNT_A_PRIME(P, N, K, PR, MAX_PR, VEC, I)	\
+  do {							\
+    mp_limb_t __a, __b, __prime, __ma,__mb;		\
+    __prime = (P);					\
+    __a = (N); __b = (K); __mb = 0;			\
+    FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I);		\
+    do {						\
+      __mb += __b % __prime; __b /= __prime;		\
+      __ma = __a % __prime; __a /= __prime;		\
+      if (__ma < __mb) {				\
+        __mb = 1; (PR) *= __prime;			\
+      } else  __mb = 0;					\
+    } while (__a >= __prime);				\
+  } while (0)
+
+#define SH_COUNT_A_PRIME(P, N, K, PR, MAX_PR, VEC, I)	\
+  do {							\
+    mp_limb_t __prime;					\
+    __prime = (P);					\
+    if (((N) % __prime) < ((K) % __prime)) {		\
+      FACTOR_LIST_STORE (__prime, PR, MAX_PR, VEC, I);	\
+    }							\
+  } while (0)
+
+/* Returns an approximation of the sqare root of x.
+ * It gives:
+ *   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
+ * or
+ *   x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
+ */
+static mp_limb_t
+limb_apprsqrt (mp_limb_t x)
+{
+  int s;
+
+  ASSERT (x > 2);
+  count_leading_zeros (s, x);
+  s = (GMP_LIMB_BITS - s) >> 1;
+  return ((CNST_LIMB(1) << (s - 1)) + (x >> 1 >> s));
+}
+
+static void
+mpz_goetgheluck_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  mp_limb_t *sieve, *factors, count;
+  mp_limb_t prod, max_prod;
+  mp_size_t j;
+  TMP_DECL;
+
+  ASSERT (BIN_GOETGHELUCK_THRESHOLD >= 13);
+  ASSERT (n >= 25);
+
+  TMP_MARK;
+  sieve = TMP_ALLOC_LIMBS (primesieve_size (n));
+
+  count = gmp_primesieve (sieve, n) + 1;
+  factors = TMP_ALLOC_LIMBS (count / log_n_max (n) + 1);
+
+  max_prod = GMP_NUMB_MAX / n;
+
+  /* Handle primes = 2, 3 separately. */
+  popc_limb (count, n - k);
+  popc_limb (j, k);
+  count += j;
+  popc_limb (j, n);
+  count -= j;
+  prod = CNST_LIMB(1) << count;
+
+  j = 0;
+  COUNT_A_PRIME (3, n, k, prod, max_prod, factors, j);
+
+  /* Accumulate prime factors from 5 to n/2 */
+    {
+      mp_limb_t s;
+
+      s = limb_apprsqrt(n);
+      s = n_to_bit (s);
+      ASSERT (bit_to_n (s+1) * bit_to_n (s+1) > n);
+      ASSERT (s <= n_to_bit (n >> 1));
+      LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (5), s, 0,sieve);
+      COUNT_A_PRIME (prime, n, k, prod, max_prod, factors, j);
+      LOOP_ON_SIEVE_STOP;
+
+      ASSERT (max_prod <= GMP_NUMB_MAX / 2);
+      max_prod <<= 1;
+
+      LOOP_ON_SIEVE_CONTINUE (prime, n_to_bit (n >> 1));
+      SH_COUNT_A_PRIME (prime, n, k, prod, max_prod, factors, j);
+      LOOP_ON_SIEVE_END;
+
+      max_prod >>= 1;
+    }
+
+  /* Store primes from (n-k)+1 to n */
+  ASSERT (n_to_bit (n - k) < n_to_bit (n));
+
+  LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (n - k) + 1, n_to_bit (n), 0,sieve);
+  FACTOR_LIST_STORE (prime, prod, max_prod, factors, j);
+  LOOP_ON_SIEVE_END;
+
+  if (LIKELY (j != 0))
+    {
+      factors[j++] = prod;
+      mpz_prodlimbs (r, factors, j);
+    }
+  else
+    {
+      MPZ_NEWALLOC (r, 1)[0] = prod;
+      SIZ (r) = 1;
+    }
+  TMP_FREE;
+}
+
+#undef COUNT_A_PRIME
+#undef SH_COUNT_A_PRIME
+#undef LOOP_ON_SIEVE_END
+#undef LOOP_ON_SIEVE_STOP
+#undef LOOP_ON_SIEVE_BEGIN
+#undef LOOP_ON_SIEVE_CONTINUE
+
+/*********************************************************/
+/* End of implementation of Goetgheluck's algorithm      */
+/*********************************************************/
+
+void
+mpz_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  if (UNLIKELY (n < k)) {
+    SIZ (r) = 0;
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  } else if (UNLIKELY (n > GMP_NUMB_MAX)) {
+    mpz_t tmp;
+
+    mpz_init_set_ui (tmp, n);
+    mpz_bin_ui (r, tmp, k);
+    mpz_clear (tmp);
+#endif
+  } else {
+    ASSERT (n <= GMP_NUMB_MAX);
+    /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller. */
+    k = MIN (k, n - k);
+    if (k < 2) {
+      MPZ_NEWALLOC (r, 1)[0] = k ? n : 1; /* 1 + ((-k) & (n-1)); */
+      SIZ(r) = 1;
+    } else if (n <= ODD_FACTORIAL_EXTTABLE_LIMIT) { /* k >= 2, n >= 4 */
+      MPZ_NEWALLOC (r, 1)[0] = bc_bin_uiui (n, k);
+      SIZ(r) = 1;
+    } else if (k <= ODD_FACTORIAL_TABLE_LIMIT)
+      mpz_smallk_bin_uiui (r, n, k);
+    else if (BIN_UIUI_ENABLE_SMALLDC &&
+	     k <= (BIN_UIUI_RECURSIVE_SMALLDC ? ODD_CENTRAL_BINOMIAL_TABLE_LIMIT : ODD_FACTORIAL_TABLE_LIMIT)* 2)
+      mpz_smallkdc_bin_uiui (r, n, k);
+    else if (ABOVE_THRESHOLD (k, BIN_GOETGHELUCK_THRESHOLD) &&
+	     k > (n >> 4)) /* k > ODD_FACTORIAL_TABLE_LIMIT */
+      mpz_goetgheluck_bin_uiui (r, n, k);
+    else
+      mpz_bdiv_bin_uiui (r, n, k);
+  }
+}
diff --git a/mpz/cdiv_q.c b/mpz/cdiv_q.c
new file mode 100644
index 0000000..f19eb74
--- /dev/null
+++ b/mpz/cdiv_q.c
@@ -0,0 +1,52 @@
+/* mpz_cdiv_q -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_cdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t dividend_size = SIZ (dividend);
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t rem;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  MPZ_TMP_INIT (rem, ABS (divisor_size));
+
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if ((divisor_size ^ dividend_size) >= 0 && SIZ (rem) != 0)
+    mpz_add_ui (quot, quot, 1L);
+
+  TMP_FREE;
+}
diff --git a/mpz/cdiv_q_ui.c b/mpz/cdiv_q_ui.c
new file mode 100644
index 0000000..269d9a3
--- /dev/null
+++ b/mpz/cdiv_q_ui.c
@@ -0,0 +1,102 @@
+/* mpz_cdiv_q_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994, 1996, 1999, 2001, 2002, 2004, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  rl = np[0];
+	  qn = 1;		/* a white lie, fixed below */
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+
+      if (rl != 0 && ns >= 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/mpz/cdiv_qr.c b/mpz/cdiv_qr.c
new file mode 100644
index 0000000..bc9b892
--- /dev/null
+++ b/mpz/cdiv_qr.c
@@ -0,0 +1,64 @@
+/* mpz_cdiv_qr -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_cdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mp_size_t xsize;
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the quotient and
+     remainder have been preliminary calculated.  We have to copy it to
+     temporary space if it's the same variable as either QUOT or REM.  */
+  if (quot == divisor || rem == divisor)
+    {
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  xsize = SIZ (dividend) ^ divisor_size;;
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if (xsize >= 0 && SIZ (rem) != 0)
+    {
+      mpz_add_ui (quot, quot, 1L);
+      mpz_sub (rem, rem, divisor);
+    }
+
+  TMP_FREE;
+}
diff --git a/mpz/cdiv_qr_ui.c b/mpz/cdiv_qr_ui.c
new file mode 100644
index 0000000..0c11fb6
--- /dev/null
+++ b/mpz/cdiv_qr_ui.c
@@ -0,0 +1,118 @@
+/* mpz_cdiv_qr_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994-1996, 1999, 2001, 2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp;
+      mp_size_t rn;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  qn = 1;		/* a white lie, fixed below */
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns >= 0)
+	    {
+	      mpn_incr_u (qp, (mp_limb_t) 1);
+	      rl = divisor - rl;
+	    }
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = -(rl != 0);
+	}
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/mpz/cdiv_r.c b/mpz/cdiv_r.c
new file mode 100644
index 0000000..83c624a
--- /dev/null
+++ b/mpz/cdiv_r.c
@@ -0,0 +1,60 @@
+/* mpz_cdiv_r -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.
+
+Copyright 1994-1996, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_cdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the remainder has been
+     preliminary calculated.  We have to copy it to temporary space if it's
+     the same variable as REM.  */
+  if (rem == divisor)
+    {
+
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  mpz_tdiv_r (rem, dividend, divisor);
+
+  if ((divisor_size ^ SIZ (dividend)) >= 0 && SIZ (rem) != 0)
+    mpz_sub (rem, rem, divisor);
+
+  TMP_FREE;
+}
diff --git a/mpz/cdiv_r_ui.c b/mpz/cdiv_r_ui.c
new file mode 100644
index 0000000..84d51db
--- /dev/null
+++ b/mpz/cdiv_r_ui.c
@@ -0,0 +1,109 @@
+/* mpz_cdiv_r_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp, qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns >= 0)
+	    rl = divisor - rl;
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = -1;
+	}
+    }
+
+  return rl;
+}
diff --git a/mpz/cdiv_ui.c b/mpz/cdiv_ui.c
new file mode 100644
index 0000000..e1a1c49
--- /dev/null
+++ b/mpz/cdiv_ui.c
@@ -0,0 +1,102 @@
+/* mpz_cdiv_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+      mp_ptr qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	;
+      else
+	{
+	  if (ns >= 0)
+	    rl = divisor - rl;
+	}
+    }
+
+  return rl;
+}
diff --git a/mpz/cfdiv_q_2exp.c b/mpz/cfdiv_q_2exp.c
new file mode 100644
index 0000000..413ea36
--- /dev/null
+++ b/mpz/cfdiv_q_2exp.c
@@ -0,0 +1,111 @@
+/* mpz_cdiv_q_2exp, mpz_fdiv_q_2exp -- quotient from mpz divided by 2^n.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 1999, 2001, 2002, 2004, 2012,
+2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* dir==1 for ceil, dir==-1 for floor */
+
+static void __gmpz_cfdiv_q_2exp (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int)) REGPARM_ATTR (1);
+#define cfdiv_q_2exp(w,u,cnt,dir)  __gmpz_cfdiv_q_2exp (REGPARM_3_1 (w,u,cnt,dir))
+
+REGPARM_ATTR (1) static void
+cfdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir)
+{
+  mp_size_t  wsize, usize, abs_usize, limb_cnt, i;
+  mp_srcptr  up;
+  mp_ptr     wp;
+  mp_limb_t  round, rmask;
+
+  usize = SIZ (u);
+  abs_usize = ABS (usize);
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  wsize = abs_usize - limb_cnt;
+  if (wsize <= 0)
+    {
+      /* u < 2**cnt, so result 1, 0 or -1 according to rounding */
+      MPZ_NEWALLOC (w, 1)[0] = 1;
+      SIZ(w) = (usize == 0 || (usize ^ dir) < 0 ? 0 : dir);
+      return;
+    }
+
+  /* +1 limb to allow for mpn_add_1 below */
+  wp = MPZ_REALLOC (w, wsize+1);
+
+  /* Check for rounding if direction matches u sign.
+     Set round if we're skipping non-zero limbs.  */
+  up = PTR(u);
+  round = 0;
+  rmask = ((usize ^ dir) >= 0 ? MP_LIMB_T_MAX : 0);
+  if (rmask != 0)
+    for (i = 0; i < limb_cnt && round == 0; i++)
+      round = up[i];
+
+  cnt %= GMP_NUMB_BITS;
+  if (cnt != 0)
+    {
+      round |= rmask & mpn_rshift (wp, up + limb_cnt, wsize, cnt);
+      wsize -= (wp[wsize - 1] == 0);
+    }
+  else
+    MPN_COPY_INCR (wp, up + limb_cnt, wsize);
+
+  if (round != 0)
+    {
+      if (wsize != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_add_1 (wp, wp, wsize, CNST_LIMB(1));
+	  wp[wsize] = cy;
+	  wsize += cy;
+	}
+      else
+	{
+	  /* We shifted something to zero.  */
+	  wp[0] = 1;
+	  wsize = 1;
+	}
+    }
+  SIZ(w) = (usize >= 0 ? wsize : -wsize);
+}
+
+
+void
+mpz_cdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_q_2exp (w, u, cnt, 1);
+}
+
+void
+mpz_fdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_q_2exp (w, u, cnt, -1);
+}
diff --git a/mpz/cfdiv_r_2exp.c b/mpz/cfdiv_r_2exp.c
new file mode 100644
index 0000000..fedb97d
--- /dev/null
+++ b/mpz/cfdiv_r_2exp.c
@@ -0,0 +1,159 @@
+/* mpz_cdiv_r_2exp, mpz_fdiv_r_2exp -- remainder from mpz divided by 2^n.
+
+Copyright 2001, 2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Bit mask of "n" least significant bits of a limb. */
+#define LOW_MASK(n)   ((CNST_LIMB(1) << (n)) - 1)
+
+
+/* dir==1 for ceil, dir==-1 for floor */
+
+static void __gmpz_cfdiv_r_2exp (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int)) REGPARM_ATTR (1);
+#define cfdiv_r_2exp(w,u,cnt,dir)  __gmpz_cfdiv_r_2exp (REGPARM_3_1 (w, u, cnt, dir))
+
+REGPARM_ATTR (1) static void
+cfdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir)
+{
+  mp_size_t  usize, abs_usize, limb_cnt, i;
+  mp_srcptr  up;
+  mp_ptr     wp;
+  mp_limb_t  high;
+
+  usize = SIZ(u);
+  if (usize == 0)
+    {
+      SIZ(w) = 0;
+      return;
+    }
+
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  cnt %= GMP_NUMB_BITS;
+  abs_usize = ABS (usize);
+
+  /* MPZ_REALLOC(w) below is only when w!=u, so we can fetch PTR(u) here
+     nice and early */
+  up = PTR(u);
+
+  if ((usize ^ dir) < 0)
+    {
+      /* Round towards zero, means just truncate */
+
+      if (w == u)
+	{
+	  /* if already smaller than limb_cnt then do nothing */
+	  if (abs_usize <= limb_cnt)
+	    return;
+	  wp = (mp_ptr) up;
+	}
+      else
+	{
+	  i = MIN (abs_usize, limb_cnt+1);
+	  wp = MPZ_NEWALLOC (w, i);
+	  MPN_COPY (wp, up, i);
+
+	  /* if smaller than limb_cnt then only the copy is needed */
+	  if (abs_usize <= limb_cnt)
+	    {
+	      SIZ(w) = usize;
+	      return;
+	    }
+	}
+    }
+  else
+    {
+      /* Round away from zero, means twos complement if non-zero */
+
+      /* if u!=0 and smaller than divisor, then must negate */
+      if (abs_usize <= limb_cnt)
+	goto negate;
+
+      /* if non-zero low limb, then must negate */
+      for (i = 0; i < limb_cnt; i++)
+	if (up[i] != 0)
+	  goto negate;
+
+      /* if non-zero partial limb, then must negate */
+      if ((up[limb_cnt] & LOW_MASK (cnt)) != 0)
+	goto negate;
+
+      /* otherwise low bits of u are zero, so that's the result */
+      SIZ(w) = 0;
+      return;
+
+    negate:
+      /* twos complement negation to get 2**cnt-u */
+
+      wp = MPZ_REALLOC (w, limb_cnt+1);
+      up = PTR(u);
+
+      /* Ones complement */
+      i = MIN (abs_usize, limb_cnt+1);
+      ASSERT_CARRY (mpn_neg (wp, up, i));
+      for ( ; i <= limb_cnt; i++)
+	wp[i] = GMP_NUMB_MAX;
+
+      usize = -usize;
+    }
+
+  /* Mask the high limb */
+  high = wp[limb_cnt];
+  high &= LOW_MASK (cnt);
+  wp[limb_cnt] = high;
+
+  /* Strip any consequent high zeros */
+  while (high == 0)
+    {
+      limb_cnt--;
+      if (limb_cnt < 0)
+	{
+	  SIZ(w) = 0;
+	  return;
+	}
+      high = wp[limb_cnt];
+    }
+
+  limb_cnt++;
+  SIZ(w) = (usize >= 0 ? limb_cnt : -limb_cnt);
+}
+
+
+void
+mpz_cdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_r_2exp (w, u, cnt, 1);
+}
+
+void
+mpz_fdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_r_2exp (w, u, cnt, -1);
+}
diff --git a/mpz/clear.c b/mpz/clear.c
new file mode 100644
index 0000000..f8c38a2
--- /dev/null
+++ b/mpz/clear.c
@@ -0,0 +1,40 @@
+/* mpz_clear -- de-allocate the space occupied by the dynamic digit space of
+   an integer.
+
+Copyright 1991, 1993-1995, 2000, 2001, 2012, 2014, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_clear (mpz_ptr x)
+{
+  if (ALLOC (x))
+    __GMP_FREE_FUNC_LIMBS (PTR (x), ALLOC(x));
+}
diff --git a/mpz/clears.c b/mpz/clears.c
new file mode 100644
index 0000000..7ac257a
--- /dev/null
+++ b/mpz/clears.c
@@ -0,0 +1,50 @@
+/* mpz_clears() -- Clear multiple mpz_t variables.
+
+Copyright 2009, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpz_clears (mpz_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      if (ALLOC (x))
+	__GMP_FREE_FUNC_LIMBS (PTR (x), ALLOC (x));
+      x = va_arg (ap, mpz_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/mpz/clrbit.c b/mpz/clrbit.c
new file mode 100644
index 0000000..8b3c854
--- /dev/null
+++ b/mpz/clrbit.c
@@ -0,0 +1,115 @@
+/* mpz_clrbit -- clear a specified bit.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_clrbit (mpz_ptr d, mp_bitcnt_t bit_idx)
+{
+  mp_size_t dsize = SIZ (d);
+  mp_ptr dp = PTR (d);
+  mp_size_t limb_idx;
+  mp_limb_t mask;
+
+  limb_idx = bit_idx / GMP_NUMB_BITS;
+  mask = CNST_LIMB(1) << (bit_idx % GMP_NUMB_BITS);
+  if (dsize >= 0)
+    {
+      if (limb_idx < dsize)
+	{
+	  mp_limb_t  dlimb;
+	  dlimb = dp[limb_idx] & ~mask;
+	  dp[limb_idx] = dlimb;
+
+	  if (UNLIKELY ((dlimb == 0) + limb_idx == dsize)) /* dsize == limb_idx + 1 */
+	    {
+	      /* high limb became zero, must normalize */
+	      MPN_NORMALIZE (dp, limb_idx);
+	      SIZ (d) = limb_idx;
+	    }
+	}
+      else
+	;
+    }
+  else
+    {
+      /* Simulate two's complement arithmetic, i.e. simulate
+	 1. Set OP = ~(OP - 1) [with infinitely many leading ones].
+	 2. clear the bit.
+	 3. Set OP = ~OP + 1.  */
+
+      dsize = -dsize;
+
+      if (limb_idx < dsize)
+	{
+	  mp_size_t zero_bound;
+
+	  /* No index upper bound on this loop, we're sure there's a non-zero limb
+	     sooner or later.  */
+	  zero_bound = 0;
+	  while (dp[zero_bound] == 0)
+	    zero_bound++;
+
+	  if (limb_idx > zero_bound)
+	    {
+	      dp[limb_idx] |= mask;
+	    }
+	  else if (limb_idx == zero_bound)
+	    {
+	      mp_limb_t  dlimb;
+	      dlimb = (((dp[limb_idx] - 1) | mask) + 1) & GMP_NUMB_MASK;
+	      dp[limb_idx] = dlimb;
+
+	      if (dlimb == 0)
+		{
+		  /* Increment at limb_idx + 1.  Extend the number with a zero limb
+		     for simplicity.  */
+		  dp = MPZ_REALLOC (d, dsize + 1);
+		  dp[dsize] = 0;
+		  MPN_INCR_U (dp + limb_idx + 1, dsize - limb_idx, 1);
+		  dsize += dp[dsize];
+
+		  SIZ (d) = -dsize;
+		}
+	    }
+	  else
+	    ;
+	}
+      else
+	{
+	  /* Ugh.  The bit should be cleared outside of the end of the
+	     number.  We have to increase the size of the number.  */
+	  dp = MPZ_REALLOC (d, limb_idx + 1);
+	  SIZ (d) = -(limb_idx + 1);
+	  MPN_ZERO (dp + dsize, limb_idx - dsize);
+	  dp[limb_idx] = mask;
+	}
+    }
+}
diff --git a/mpz/cmp.c b/mpz/cmp.c
new file mode 100644
index 0000000..ba4c023
--- /dev/null
+++ b/mpz/cmp.c
@@ -0,0 +1,53 @@
+/* mpz_cmp(u,v) -- Compare U, V.  Return positive, zero, or negative
+   based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2002, 2011, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_cmp (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mp_size_t  usize, vsize, asize;
+  mp_srcptr  up, vp;
+  int        cmp;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+  /* Cannot use usize - vsize, may overflow an "int" */
+  if (usize != vsize)
+    return (usize > vsize) ? 1 : -1;
+
+  asize = ABS (usize);
+  up = PTR(u);
+  vp = PTR(v);
+  MPN_CMP (cmp, up, vp, asize);
+  return (usize >= 0 ? cmp : -cmp);
+}
diff --git a/mpz/cmp_d.c b/mpz/cmp_d.c
new file mode 100644
index 0000000..b5b5e8b
--- /dev/null
+++ b/mpz/cmp_d.c
@@ -0,0 +1,144 @@
+/* mpz_cmp_d -- compare absolute values of mpz and double.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+
+#define RETURN_CMP(zl, dl)                      \
+  do {                                          \
+    zlimb = (zl);                               \
+    dlimb = (dl);                               \
+    if (zlimb != dlimb)                         \
+      return (zlimb >= dlimb ? ret : -ret);     \
+  } while (0)
+
+#define RETURN_NONZERO(ptr, size, val)          \
+  do {                                          \
+    mp_size_t __i;                              \
+    for (__i = (size)-1; __i >= 0; __i--)       \
+      if ((ptr)[__i] != 0)                      \
+        return val;                             \
+    return 0;                                   \
+  } while (0)
+
+
+int
+mpz_cmp_d (mpz_srcptr z, double d)
+{
+  mp_limb_t  darray[LIMBS_PER_DOUBLE], zlimb, dlimb;
+  mp_srcptr  zp;
+  mp_size_t  zsize;
+  int        dexp, ret;
+
+  /* d=NaN is an invalid operation, there's no sensible return value.
+     d=Inf or -Inf is always bigger than z.  */
+  DOUBLE_NAN_INF_ACTION (d, __gmp_invalid_operation (), goto z_zero);
+
+  /* 1. Either operand zero. */
+  zsize = SIZ(z);
+  if (d == 0.0)
+    return zsize;
+  if (zsize == 0)
+    {
+    z_zero:
+      return (d < 0.0 ? 1 : -1);
+    }
+
+  /* 2. Opposite signs. */
+  if (zsize >= 0)
+    {
+      if (d < 0.0)
+	return 1;    /* >=0 cmp <0 */
+      ret = 1;
+    }
+  else
+    {
+      if (d >= 0.0)
+	return -1;   /* <0 cmp >=0 */
+      ret = -1;
+      d = -d;
+      zsize = -zsize;
+    }
+
+  /* 3. Small d, knowing abs(z) >= 1. */
+  if (d < 1.0)
+    return ret;
+
+  dexp = __gmp_extract_double (darray, d);
+  ASSERT (dexp >= 1);
+
+  /* 4. Check for different high limb positions. */
+  if (zsize != dexp)
+    return (zsize >= dexp ? ret : -ret);
+
+  /* 5. Limb data. */
+  zp = PTR(z);
+
+#if LIMBS_PER_DOUBLE == 2
+  RETURN_CMP (zp[zsize-1], darray[1]);
+  if (zsize == 1)
+    return (darray[0] != 0 ? -ret : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[0]);
+  RETURN_NONZERO (zp, zsize-2, ret);
+#endif
+
+#if LIMBS_PER_DOUBLE == 3
+  RETURN_CMP (zp[zsize-1], darray[2]);
+  if (zsize == 1)
+    return ((darray[0] | darray[1]) != 0 ? -ret : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[1]);
+  if (zsize == 2)
+    return (darray[0] != 0 ? -ret : 0);
+
+  RETURN_CMP (zp[zsize-3], darray[0]);
+  RETURN_NONZERO (zp, zsize-3, ret);
+#endif
+
+#if LIMBS_PER_DOUBLE >= 4
+  {
+    int i;
+    for (i = 1; i <= LIMBS_PER_DOUBLE; i++)
+      {
+	RETURN_CMP (zp[zsize-i], darray[LIMBS_PER_DOUBLE-i]);
+	if (i >= zsize)
+	  RETURN_NONZERO (darray, LIMBS_PER_DOUBLE-i, -ret);
+      }
+    RETURN_NONZERO (zp, zsize-LIMBS_PER_DOUBLE, ret);
+  }
+#endif
+}
diff --git a/mpz/cmp_si.c b/mpz/cmp_si.c
new file mode 100644
index 0000000..23296c8
--- /dev/null
+++ b/mpz/cmp_si.c
@@ -0,0 +1,69 @@
+/* mpz_cmp_si(u,v) -- Compare an integer U with a single-word int V.
+   Return positive, zero, or negative based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1993-1996, 2000-2002, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+_mpz_cmp_si (mpz_srcptr u, signed long int v_digit) __GMP_NOTHROW
+{
+#if GMP_NAIL_BITS != 0
+  /* FIXME.  This isn't very pretty.  */
+  mpz_t tmp;
+  mp_limb_t tt[2];
+  PTR(tmp) = tt;
+  ALLOC(tmp) = 2;
+  mpz_set_si (tmp, v_digit);
+  return mpz_cmp (u, tmp);
+#else
+
+  mp_size_t vsize, usize;
+
+  usize = SIZ (u);
+  vsize = (v_digit > 0) - (v_digit < 0);
+
+  if ((usize == 0) | (usize != vsize))
+    return usize - vsize;
+  else {
+    mp_limb_t u_digit, absv_digit;
+
+    u_digit = PTR (u)[0];
+    absv_digit = ABS_CAST (unsigned long, v_digit);
+
+    if (u_digit == absv_digit)
+      return 0;
+
+    if (u_digit > absv_digit)
+      return usize;
+    else
+      return -usize;
+  }
+#endif
+}
diff --git a/mpz/cmp_ui.c b/mpz/cmp_ui.c
new file mode 100644
index 0000000..4b40ab7
--- /dev/null
+++ b/mpz/cmp_ui.c
@@ -0,0 +1,77 @@
+/* mpz_cmp_ui.c -- Compare an mpz_t a with an mp_limb_t b.  Return positive,
+  zero, or negative based on if a > b, a == b, or a < b.
+
+Copyright 1991, 1993-1996, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+_mpz_cmp_ui (mpz_srcptr u, unsigned long int v_digit) __GMP_NOTHROW
+{
+  mp_ptr up;
+  mp_size_t un;
+  mp_limb_t ul;
+
+  up = PTR(u);
+  un = SIZ(u);
+
+  if (un == 0)
+    return -(v_digit != 0);
+
+  if (un == 1)
+    {
+      ul = up[0];
+      if (ul > v_digit)
+	return 1;
+      if (ul < v_digit)
+	return -1;
+      return 0;
+    }
+
+#if GMP_NAIL_BITS != 0
+  if (v_digit > GMP_NUMB_MAX)
+    {
+      if (un == 2)
+	{
+	  ul = up[0] + (up[1] << GMP_NUMB_BITS);
+
+	  if ((up[1] >> GMP_NAIL_BITS) != 0)
+	    return 1;
+
+	  if (ul > v_digit)
+	    return 1;
+	  if (ul < v_digit)
+	    return -1;
+	  return 0;
+	}
+    }
+#endif
+
+  return un > 0 ? 1 : -1;
+}
diff --git a/mpz/cmpabs.c b/mpz/cmpabs.c
new file mode 100644
index 0000000..7e9f160
--- /dev/null
+++ b/mpz/cmpabs.c
@@ -0,0 +1,53 @@
+/* mpz_cmpabs(u,v) -- Compare U, V.  Return positive, zero, or negative
+   based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpz_cmpabs (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mp_size_t  usize, vsize;
+  mp_srcptr  up, vp;
+  int        cmp;
+
+  usize = ABSIZ (u);
+  vsize = ABSIZ (v);
+  /* Cannot use usize - vsize, may overflow an "int" */
+  if (usize != vsize)
+    return (usize > vsize) ? 1 : -1;
+
+  up = PTR(u);
+  vp = PTR(v);
+  MPN_CMP (cmp, up, vp, usize);
+  return cmp;
+}
diff --git a/mpz/cmpabs_d.c b/mpz/cmpabs_d.c
new file mode 100644
index 0000000..d2431cc
--- /dev/null
+++ b/mpz/cmpabs_d.c
@@ -0,0 +1,129 @@
+/* mpz_cmpabs_d -- compare absolute values of mpz and double.
+
+Copyright 2001-2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+
+#define RETURN_CMP(zl, dl)              \
+  do {                                  \
+    zlimb = (zl);                       \
+    dlimb = (dl);                       \
+    if (zlimb != dlimb)                 \
+      return (zlimb >= dlimb ? 1 : -1); \
+  } while (0)
+
+#define RETURN_NONZERO(ptr, size, val)          \
+  do {                                          \
+    mp_size_t __i;                              \
+    for (__i = (size)-1; __i >= 0; __i--)       \
+      if ((ptr)[__i] != 0)                      \
+        return val;                             \
+    return 0;                                   \
+  } while (0)
+
+
+int
+mpz_cmpabs_d (mpz_srcptr z, double d)
+{
+  mp_limb_t  darray[LIMBS_PER_DOUBLE], zlimb, dlimb;
+  mp_srcptr  zp;
+  mp_size_t  zsize;
+  int        dexp;
+
+  /* d=NaN is an invalid operation, there's no sensible return value.
+     d=Inf or -Inf is always bigger than z.  */
+  DOUBLE_NAN_INF_ACTION (d, __gmp_invalid_operation (), return -1);
+
+  /* 1. Check for either operand zero. */
+  zsize = SIZ(z);
+  if (d == 0.0)
+    return (zsize != 0);
+  if (zsize == 0)
+    return -1; /* d != 0 */
+
+  /* 2. Ignore signs. */
+  zsize = ABS(zsize);
+  d = ABS(d);
+
+  /* 3. Small d, knowing abs(z) >= 1. */
+  if (d < 1.0)
+    return 1;
+
+  dexp = __gmp_extract_double (darray, d);
+  ASSERT (dexp >= 1);
+
+  /* 4. Check for different high limb positions. */
+  if (zsize != dexp)
+    return (zsize >= dexp ? 1 : -1);
+
+  /* 5. Limb data. */
+  zp = PTR(z);
+
+#if LIMBS_PER_DOUBLE == 2
+  RETURN_CMP (zp[zsize-1], darray[1]);
+  if (zsize == 1)
+    return (darray[0] != 0 ? -1 : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[0]);
+  RETURN_NONZERO (zp, zsize-2, 1);
+#endif
+
+#if LIMBS_PER_DOUBLE == 3
+  RETURN_CMP (zp[zsize-1], darray[2]);
+  if (zsize == 1)
+    return ((darray[0] | darray[1]) != 0 ? -1 : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[1]);
+  if (zsize == 2)
+    return (darray[0] != 0 ? -1 : 0);
+
+  RETURN_CMP (zp[zsize-3], darray[0]);
+  RETURN_NONZERO (zp, zsize-3, 1);
+#endif
+
+#if LIMBS_PER_DOUBLE >= 4
+  {
+    int i;
+    for (i = 1; i <= LIMBS_PER_DOUBLE; i++)
+      {
+	RETURN_CMP (zp[zsize-i], darray[LIMBS_PER_DOUBLE-i]);
+	if (i >= zsize)
+	  RETURN_NONZERO (darray, LIMBS_PER_DOUBLE-i, -1);
+      }
+    RETURN_NONZERO (zp, zsize-LIMBS_PER_DOUBLE, 1);
+  }
+#endif
+}
diff --git a/mpz/cmpabs_ui.c b/mpz/cmpabs_ui.c
new file mode 100644
index 0000000..6deffb3
--- /dev/null
+++ b/mpz/cmpabs_ui.c
@@ -0,0 +1,76 @@
+/* mpz_cmpabs_ui.c -- Compare an mpz_t a with an mp_limb_t b.  Return positive,
+  zero, or negative based on if a > b, a == b, or a < b.
+
+Copyright 1991, 1993-1995, 1997, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_cmpabs_ui (mpz_srcptr u, unsigned long int v_digit) __GMP_NOTHROW
+{
+  mp_ptr up;
+  mp_size_t un;
+  mp_limb_t ul;
+
+  up = PTR(u);
+  un = SIZ(u);
+
+  if (un == 0)
+    return -(v_digit != 0);
+
+  un = ABS (un);
+
+  if (un == 1)
+    {
+      ul = up[0];
+      if (ul > v_digit)
+	return 1;
+      if (ul < v_digit)
+	return -1;
+      return 0;
+    }
+
+#if GMP_NAIL_BITS != 0
+  if (v_digit > GMP_NUMB_MAX)
+    {
+      if (un == 2)
+	{
+	  ul = up[0] + (up[1] << GMP_NUMB_BITS);
+
+	  if (ul > v_digit)
+	    return 1;
+	  if (ul < v_digit)
+	    return -1;
+	  return 0;
+	}
+    }
+#endif
+
+  return 1;
+}
diff --git a/mpz/com.c b/mpz/com.c
new file mode 100644
index 0000000..c5d22b0
--- /dev/null
+++ b/mpz/com.c
@@ -0,0 +1,87 @@
+/* mpz_com(mpz_ptr dst, mpz_ptr src) -- Assign the bit-complemented value of
+   SRC to DST.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2003, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_com (mpz_ptr dst, mpz_srcptr src)
+{
+  mp_size_t size = SIZ (src);
+  mp_srcptr src_ptr;
+  mp_ptr dst_ptr;
+
+  if (size >= 0)
+    {
+      /* As with infinite precision: one's complement, two's complement.
+	 But this can be simplified using the identity -x = ~x + 1.
+	 So we're going to compute (~~x) + 1 = x + 1!  */
+
+      if (UNLIKELY (size == 0))
+	{
+	  /* special case, as mpn_add_1 wants size!=0 */
+	  MPZ_NEWALLOC (dst, 1)[0] = 1;
+	  SIZ (dst) = -1;
+	}
+      else
+	{
+	  mp_limb_t cy;
+
+	  dst_ptr = MPZ_REALLOC (dst, size + 1);
+
+	  src_ptr = PTR (src);
+
+	  cy = mpn_add_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
+	  dst_ptr[size] = cy;
+	  size += cy;
+
+	  /* Store a negative size, to indicate ones-extension.  */
+	  SIZ (dst) = -size;
+      }
+    }
+  else
+    {
+      /* As with infinite precision: two's complement, then one's complement.
+	 But that can be simplified using the identity -x = ~(x - 1).
+	 So we're going to compute ~~(x - 1) = x - 1!  */
+      size = -size;
+
+      dst_ptr = MPZ_REALLOC (dst, size);
+
+      src_ptr = PTR (src);
+
+      mpn_sub_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
+      size -= dst_ptr[size - 1] == 0;
+
+      /* Store a positive size, to indicate zero-extension.  */
+      SIZ (dst) = size;
+    }
+}
diff --git a/mpz/combit.c b/mpz/combit.c
new file mode 100644
index 0000000..0a29875
--- /dev/null
+++ b/mpz/combit.c
@@ -0,0 +1,103 @@
+/* mpz_combit -- complement a specified bit.
+
+Copyright 2002, 2003, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_combit (mpz_ptr d, mp_bitcnt_t bit_index)
+{
+  mp_size_t dsize = SIZ(d);
+  mp_ptr dp = PTR(d);
+
+  mp_size_t limb_index = bit_index / GMP_NUMB_BITS;
+  mp_limb_t bit = (CNST_LIMB (1) << (bit_index % GMP_NUMB_BITS));
+
+  /* Check for the most common case: Positive input, no realloc or
+     normalization needed. */
+  if (limb_index + 1 < dsize)
+    dp[limb_index] ^= bit;
+
+  /* Check for the hairy case. d < 0, and we have all zero bits to the
+     right of the bit to toggle. */
+  else if (limb_index < -dsize
+	   && (limb_index == 0 || mpn_zero_p (dp, limb_index))
+	   && (dp[limb_index] & (bit - 1)) == 0)
+    {
+      ASSERT (dsize < 0);
+      dsize = -dsize;
+
+      if (dp[limb_index] & bit)
+	{
+	  /* We toggle the least significant one bit. Corresponds to
+	     an add, with potential carry propagation, on the absolute
+	     value. */
+	  dp = MPZ_REALLOC (d, 1 + dsize);
+	  dp[dsize] = 0;
+	  MPN_INCR_U (dp + limb_index, 1 + dsize - limb_index, bit);
+	  SIZ(d) = - dsize - dp[dsize];
+	}
+      else
+	{
+	  /* We toggle a zero bit, subtract from the absolute value. */
+	  MPN_DECR_U (dp + limb_index, dsize - limb_index, bit);
+	  /* The absolute value shrinked by at most one bit. */
+	  dsize -= dp[dsize - 1] == 0;
+	  ASSERT (dsize > 0 && dp[dsize - 1] != 0);
+	  SIZ (d) = -dsize;
+	}
+    }
+  else
+    {
+      /* Simple case: Toggle the bit in the absolute value. */
+      dsize = ABS(dsize);
+      if (limb_index < dsize)
+	{
+	  mp_limb_t	 dlimb;
+	  dlimb = dp[limb_index] ^ bit;
+	  dp[limb_index] = dlimb;
+
+	  /* Can happen only when limb_index = dsize - 1. Avoid SIZ(d)
+	     bookkeeping in the common case. */
+	  if (UNLIKELY ((dlimb == 0) + limb_index == dsize)) /* dsize == limb_index + 1 */
+	    {
+	      /* high limb became zero, must normalize */
+	      MPN_NORMALIZE (dp, limb_index);
+	      SIZ (d) = SIZ (d) >= 0 ? limb_index : -limb_index;
+	    }
+	}
+      else
+	{
+	  dp = MPZ_REALLOC (d, limb_index + 1);
+	  MPN_ZERO(dp + dsize, limb_index - dsize);
+	  dp[limb_index++] = bit;
+	  SIZ(d) = SIZ(d) >= 0 ? limb_index : -limb_index;
+	}
+    }
+}
diff --git a/mpz/cong.c b/mpz/cong.c
new file mode 100644
index 0000000..5d2d835
--- /dev/null
+++ b/mpz/cong.c
@@ -0,0 +1,182 @@
+/* mpz_congruent_p -- test congruence of two mpz's.
+
+Copyright 2001, 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* For big divisors this code is only very slightly better than the user
+   doing a combination of mpz_sub and mpz_tdiv_r, but it's quite convenient,
+   and perhaps in the future can be improved, in similar ways to
+   mpn_divisible_p perhaps.
+
+   The csize==1 / dsize==1 special case makes mpz_congruent_p as good as
+   mpz_congruent_ui_p on relevant operands, though such a combination
+   probably doesn't occur often.
+
+   Alternatives:
+
+   If c<d then it'd work to just form a%d and compare a and c (either as
+   a==c or a+c==d depending on the signs), but the saving from avoiding the
+   abs(a-c) calculation would be small compared to the division.
+
+   Similarly if both a<d and c<d then it would work to just compare a and c
+   (a==c or a+c==d), but this isn't considered a particularly important case
+   and so isn't done for the moment.
+
+   Low zero limbs on d could be stripped and the corresponding limbs of a
+   and c tested and skipped, but doing so would introduce a borrow when a
+   and c differ in sign and have non-zero skipped limbs.  It doesn't seem
+   worth the complications to do this, since low zero limbs on d should
+   occur only rarely.  */
+
+int
+mpz_congruent_p (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d)
+{
+  mp_size_t  asize, csize, dsize, sign;
+  mp_srcptr  ap, cp, dp;
+  mp_ptr     xp;
+  mp_limb_t  alow, clow, dlow, dmask, r;
+  int        result;
+  TMP_DECL;
+
+  dsize = SIZ(d);
+  if (UNLIKELY (dsize == 0))
+    return (mpz_cmp (a, c) == 0);
+
+  dsize = ABS(dsize);
+  dp = PTR(d);
+
+  if (ABSIZ(a) < ABSIZ(c))
+    MPZ_SRCPTR_SWAP (a, c);
+
+  asize = SIZ(a);
+  csize = SIZ(c);
+  sign = (asize ^ csize);
+
+  asize = ABS(asize);
+  ap = PTR(a);
+
+  if (csize == 0)
+    return mpn_divisible_p (ap, asize, dp, dsize);
+
+  csize = ABS(csize);
+  cp = PTR(c);
+
+  alow = ap[0];
+  clow = cp[0];
+  dlow = dp[0];
+
+  /* Check a==c mod low zero bits of dlow.  This might catch a few cases of
+     a!=c quickly, and it helps the csize==1 special cases below.  */
+  dmask = LOW_ZEROS_MASK (dlow) & GMP_NUMB_MASK;
+  alow = (sign >= 0 ? alow : -alow);
+  if (((alow-clow) & dmask) != 0)
+    return 0;
+
+  if (csize == 1)
+    {
+      if (dsize == 1)
+	{
+	cong_1:
+	  if (sign < 0)
+	    NEG_MOD (clow, clow, dlow);
+
+	  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
+	    {
+	      r = mpn_mod_1 (ap, asize, dlow);
+	      if (clow < dlow)
+		return r == clow;
+	      else
+		return r == (clow % dlow);
+	    }
+
+	  if ((dlow & 1) == 0)
+	    {
+	      /* Strip low zero bits to get odd d required by modexact.  If
+		 d==e*2^n then a==c mod d if and only if both a==c mod e and
+		 a==c mod 2^n, the latter having been done above.  */
+	      unsigned	twos;
+	      count_trailing_zeros (twos, dlow);
+	      dlow >>= twos;
+	    }
+
+	  r = mpn_modexact_1c_odd (ap, asize, dlow, clow);
+	  return r == 0 || r == dlow;
+	}
+
+      /* dlow==0 is avoided since we don't want to bother handling extra low
+	 zero bits if dsecond is even (would involve borrow if a,c differ in
+	 sign and alow,clow!=0).  */
+      if (dsize == 2 && dlow != 0)
+	{
+	  mp_limb_t  dsecond = dp[1];
+
+	  if (dsecond <= dmask)
+	    {
+	      unsigned	 twos;
+	      count_trailing_zeros (twos, dlow);
+	      dlow = (dlow >> twos) | (dsecond << (GMP_NUMB_BITS-twos));
+	      ASSERT_LIMB (dlow);
+
+	      /* dlow will be odd here, so the test for it even under cong_1
+		 is unnecessary, but the rest of that code is wanted. */
+	      goto cong_1;
+	    }
+	}
+    }
+
+  TMP_MARK;
+  xp = TMP_ALLOC_LIMBS (asize+1);
+
+  /* calculate abs(a-c) */
+  if (sign >= 0)
+    {
+      /* same signs, subtract */
+      if (asize > csize || mpn_cmp (ap, cp, asize) >= 0)
+	ASSERT_NOCARRY (mpn_sub (xp, ap, asize, cp, csize));
+      else
+	ASSERT_NOCARRY (mpn_sub_n (xp, cp, ap, asize));
+      MPN_NORMALIZE (xp, asize);
+    }
+  else
+    {
+      /* different signs, add */
+      mp_limb_t  carry;
+      carry = mpn_add (xp, ap, asize, cp, csize);
+      xp[asize] = carry;
+      asize += (carry != 0);
+    }
+
+  result = mpn_divisible_p (xp, asize, dp, dsize);
+
+  TMP_FREE;
+  return result;
+}
diff --git a/mpz/cong_2exp.c b/mpz/cong_2exp.c
new file mode 100644
index 0000000..9de9645
--- /dev/null
+++ b/mpz/cong_2exp.c
@@ -0,0 +1,149 @@
+/* mpz_congruent_2exp_p -- test congruence of mpz mod 2^n.
+
+Copyright 2001, 2002, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpz_congruent_2exp_p (mpz_srcptr a, mpz_srcptr c, mp_bitcnt_t d) __GMP_NOTHROW
+{
+  mp_size_t      i, dlimbs;
+  unsigned       dbits;
+  mp_ptr         ap, cp;
+  mp_limb_t      dmask, alimb, climb, sum;
+  mp_size_t      as, cs, asize, csize;
+
+  as = SIZ(a);
+  asize = ABS(as);
+
+  cs = SIZ(c);
+  csize = ABS(cs);
+
+  if (asize < csize)
+    {
+      MPZ_SRCPTR_SWAP (a, c);
+      MP_SIZE_T_SWAP (asize, csize);
+    }
+
+  dlimbs = d / GMP_NUMB_BITS;
+  dbits = d % GMP_NUMB_BITS;
+  dmask = (CNST_LIMB(1) << dbits) - 1;
+
+  ap = PTR(a);
+  cp = PTR(c);
+
+  if (csize == 0)
+    goto a_zeros;
+
+  if ((cs ^ as) >= 0)
+    {
+      /* same signs, direct comparison */
+
+      /* a==c for limbs in common */
+      if (mpn_cmp (ap, cp, MIN (csize, dlimbs)) != 0)
+	return 0;
+
+      /* if that's all of dlimbs, then a==c for remaining bits */
+      if (csize > dlimbs)
+	return ((ap[dlimbs]-cp[dlimbs]) & dmask) == 0;
+
+    a_zeros:
+      /* a remains, need all zero bits */
+
+      /* if d covers all of a and c, then must be exactly equal */
+      if (asize <= dlimbs)
+	return asize == csize;
+
+      /* whole limbs zero */
+      for (i = csize; i < dlimbs; i++)
+	if (ap[i] != 0)
+	  return 0;
+
+      /* partial limb zero */
+      return (ap[dlimbs] & dmask) == 0;
+    }
+  else
+    {
+      /* different signs, negated comparison */
+
+      /* common low zero limbs, stopping at first non-zeros, which must
+	 match twos complement */
+      i = 0;
+      do
+	{
+	  ASSERT (i < csize);  /* always have a non-zero limb on c */
+	  alimb = ap[i];
+	  climb = cp[i];
+	  sum = (alimb + climb) & GMP_NUMB_MASK;
+
+	  if (i >= dlimbs)
+	    return (sum & dmask) == 0;
+	  ++i;
+
+	  /* require both zero, or first non-zeros as twos-complements */
+	  if (sum != 0)
+	    return 0;
+	} while (alimb == 0);
+
+      /* further limbs matching as ones-complement */
+      for (; i < csize; ++i)
+	{
+	  alimb = ap[i];
+	  climb = cp[i];
+	  sum = alimb ^ climb ^ GMP_NUMB_MASK;
+
+	  if (i >= dlimbs)
+	    return (sum & dmask) == 0;
+
+	  if (sum != 0)
+	    return 0;
+	}
+
+      /* no more c, so require all 1 bits in a */
+
+      if (asize < dlimbs)
+	return 0;   /* not enough a */
+
+      /* whole limbs */
+      for ( ; i < dlimbs; i++)
+	if (ap[i] != GMP_NUMB_MAX)
+	  return 0;
+
+      /* if only whole limbs, no further fetches from a */
+      if (dbits == 0)
+	return 1;
+
+      /* need enough a */
+      if (asize == dlimbs)
+	return 0;
+
+      return ((ap[dlimbs]+1) & dmask) == 0;
+    }
+}
diff --git a/mpz/cong_ui.c b/mpz/cong_ui.c
new file mode 100644
index 0000000..6f86c23
--- /dev/null
+++ b/mpz/cong_ui.c
@@ -0,0 +1,115 @@
+/* mpz_congruent_ui_p -- test congruence of mpz and ulong.
+
+Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* There's some explicit checks for c<d since it seems reasonably likely an
+   application might use that in a test.
+
+   Hopefully the compiler can generate something good for r==(c%d), though
+   if modexact is being used exclusively then that's not reached.  */
+
+int
+mpz_congruent_ui_p (mpz_srcptr a, unsigned long cu, unsigned long du)
+{
+  mp_srcptr  ap;
+  mp_size_t  asize;
+  mp_limb_t  c, d, r;
+
+  if (UNLIKELY (du == 0))
+    return (mpz_cmp_ui (a, cu) == 0);
+
+  asize = SIZ(a);
+  if (asize == 0)
+    {
+      if (cu < du)
+	return cu == 0;
+      else
+	return (cu % du) == 0;
+    }
+
+  /* For nails don't try to be clever if c or d is bigger than a limb, just
+     fake up some mpz_t's and go to the main mpz_congruent_p.  */
+  if (du > GMP_NUMB_MAX || cu > GMP_NUMB_MAX)
+    {
+      mp_limb_t  climbs[2], dlimbs[2];
+      mpz_t      cz, dz;
+
+      ALLOC(cz) = 2;
+      PTR(cz) = climbs;
+      ALLOC(dz) = 2;
+      PTR(dz) = dlimbs;
+
+      mpz_set_ui (cz, cu);
+      mpz_set_ui (dz, du);
+      return mpz_congruent_p (a, cz, dz);
+    }
+
+  /* NEG_MOD works on limbs, so convert ulong to limb */
+  c = cu;
+  d = du;
+
+  if (asize < 0)
+    {
+      asize = -asize;
+      NEG_MOD (c, c, d);
+    }
+
+  ap = PTR (a);
+
+  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
+    {
+      r = mpn_mod_1 (ap, asize, d);
+      if (c < d)
+	return r == c;
+      else
+	return r == (c % d);
+    }
+
+  if ((d & 1) == 0)
+    {
+      /* Strip low zero bits to get odd d required by modexact.  If
+	 d==e*2^n then a==c mod d if and only if both a==c mod 2^n
+	 and a==c mod e.  */
+
+      unsigned	twos;
+
+      if ((ap[0]-c) & LOW_ZEROS_MASK (d))
+	return 0;
+
+      count_trailing_zeros (twos, d);
+      d >>= twos;
+    }
+
+  r = mpn_modexact_1c_odd (ap, asize, d, c);
+  return r == 0 || r == d;
+}
diff --git a/mpz/dive_ui.c b/mpz/dive_ui.c
new file mode 100644
index 0000000..c859b96
--- /dev/null
+++ b/mpz/dive_ui.c
@@ -0,0 +1,68 @@
+/* mpz_divexact_ui -- exact division mpz by ulong.
+
+Copyright 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_divexact_ui (mpz_ptr dst, mpz_srcptr src, unsigned long divisor)
+{
+  mp_size_t  size, abs_size;
+  mp_ptr     dst_ptr;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  /* For nails don't try to be clever if d is bigger than a limb, just fake
+     up an mpz_t and go to the main mpz_divexact.  */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t  dlimbs[2];
+      mpz_t      dz;
+      ALLOC(dz) = 2;
+      PTR(dz) = dlimbs;
+      mpz_set_ui (dz, divisor);
+      mpz_divexact (dst, src, dz);
+      return;
+    }
+
+  size = SIZ(src);
+  if (size == 0)
+    {
+      SIZ(dst) = 0;
+      return;
+    }
+  abs_size = ABS (size);
+
+  dst_ptr = MPZ_REALLOC (dst, abs_size);
+
+  MPN_DIVREM_OR_DIVEXACT_1 (dst_ptr, PTR(src), abs_size, (mp_limb_t) divisor);
+  abs_size -= (dst_ptr[abs_size-1] == 0);
+  SIZ(dst) = (size >= 0 ? abs_size : -abs_size);
+}
diff --git a/mpz/divegcd.c b/mpz/divegcd.c
new file mode 100644
index 0000000..dc236c3
--- /dev/null
+++ b/mpz/divegcd.c
@@ -0,0 +1,156 @@
+/* mpz_divexact_gcd -- exact division optimized for GCDs.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2005, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Set q to a/d, expecting d to be from a GCD and therefore usually small.
+
+   The distribution of GCDs of random numbers can be found in Knuth volume 2
+   section 4.5.2 theorem D.
+
+            GCD     chance
+             1       60.8%
+            2^k      20.2%     (1<=k<32)
+           3*2^k      9.0%     (1<=k<32)
+           other     10.1%
+
+   Only the low limb is examined for optimizations, since GCDs bigger than
+   2^32 (or 2^64) will occur very infrequently.
+
+   Future: This could change to an mpn_divexact_gcd, possibly partly
+   inlined, if/when the relevant mpq functions change to an mpn based
+   implementation.  */
+
+
+#if GMP_NUMB_BITS % 2 == 0
+static void
+mpz_divexact_by3 (mpz_ptr q, mpz_srcptr a)
+{
+  mp_size_t  size = SIZ(a);
+  mp_size_t  abs_size = ABS(size);
+  mp_ptr     qp;
+
+  qp = MPZ_REALLOC (q, abs_size);
+
+  mpn_bdiv_dbm1 (qp, PTR(a), abs_size, GMP_NUMB_MASK / 3);
+
+  abs_size -= (qp[abs_size-1] == 0);
+  SIZ(q) = (size>0 ? abs_size : -abs_size);
+}
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+static void
+mpz_divexact_by5 (mpz_ptr q, mpz_srcptr a)
+{
+  mp_size_t  size = SIZ(a);
+  mp_size_t  abs_size = ABS(size);
+  mp_ptr     qp;
+
+  qp = MPZ_REALLOC (q, abs_size);
+
+  mpn_bdiv_dbm1 (qp, PTR(a), abs_size, GMP_NUMB_MASK / 5);
+
+  abs_size -= (qp[abs_size-1] == 0);
+  SIZ(q) = (size>0 ? abs_size : -abs_size);
+}
+#endif
+
+static void
+mpz_divexact_limb (mpz_ptr q, mpz_srcptr a, mp_limb_t d)
+{
+  mp_size_t  size = SIZ(a);
+  mp_size_t  abs_size = ABS(size);
+  mp_ptr     qp;
+
+  qp = MPZ_REALLOC (q, abs_size);
+
+  MPN_DIVREM_OR_DIVEXACT_1 (qp, PTR(a), abs_size, d);
+
+  abs_size -= (qp[abs_size-1] == 0);
+  SIZ(q) = (size > 0 ? abs_size : -abs_size);
+}
+
+void
+mpz_divexact_gcd (mpz_ptr q, mpz_srcptr a, mpz_srcptr d)
+{
+  ASSERT (mpz_sgn (d) > 0);
+
+  if (SIZ(a) == 0)
+    {
+      SIZ(q) = 0;
+      return;
+    }
+
+  if (SIZ(d) == 1)
+    {
+      mp_limb_t  dl = PTR(d)[0];
+      int        twos;
+
+      if ((dl & 1) == 0)
+	{
+	  count_trailing_zeros (twos, dl);
+	  dl >>= twos;
+	  mpz_tdiv_q_2exp (q, a, twos);
+	  a = q;
+	}
+
+      if (dl == 1)
+	{
+	  if (q != a)
+	    mpz_set (q, a);
+	  return;
+	}
+#if GMP_NUMB_BITS % 2 == 0
+      if (dl == 3)
+	{
+	  mpz_divexact_by3 (q, a);
+	  return;
+	}
+#endif
+#if GMP_NUMB_BITS % 4 == 0
+      if (dl == 5)
+	{
+	  mpz_divexact_by5 (q, a);
+	  return;
+	}
+#endif
+
+      mpz_divexact_limb (q, a, dl);
+      return;
+    }
+
+  mpz_divexact (q, a, d);
+}
diff --git a/mpz/divexact.c b/mpz/divexact.c
new file mode 100644
index 0000000..8336819
--- /dev/null
+++ b/mpz/divexact.c
@@ -0,0 +1,89 @@
+/* mpz_divexact -- finds quotient when known that quot * den == num && den != 0.
+
+Contributed to the GNU project by Niels Möller.
+
+Copyright 1991, 1993-1998, 2000-2002, 2005-2007, 2009, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+void
+mpz_divexact (mpz_ptr quot, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_ptr qp;
+  mp_size_t qn;
+  mp_srcptr np, dp;
+  mp_size_t nn, dn;
+  TMP_DECL;
+
+#if WANT_ASSERT
+  {
+    mpz_t  rem;
+    mpz_init (rem);
+    mpz_tdiv_r (rem, num, den);
+    ASSERT (SIZ(rem) == 0);
+    mpz_clear (rem);
+  }
+#endif
+
+  nn = ABSIZ (num);
+  dn = ABSIZ (den);
+
+  if (nn < dn)
+    {
+      /* This special case avoids segfaults below when the function is
+	 incorrectly called with |N| < |D|, N != 0.  It also handles the
+	 well-defined case N = 0.  */
+      SIZ(quot) = 0;
+      return;
+    }
+
+  qn = nn - dn + 1;
+
+  TMP_MARK;
+
+  if (quot == num || quot == den)
+    qp = TMP_ALLOC_LIMBS (qn);
+  else
+    qp = MPZ_NEWALLOC (quot, qn);
+
+  np = PTR(num);
+  dp = PTR(den);
+
+  mpn_divexact (qp, np, nn, dp, dn);
+  MPN_NORMALIZE (qp, qn);
+
+  if (qp != PTR(quot))
+    MPN_COPY (MPZ_NEWALLOC (quot, qn), qp, qn);
+
+  SIZ(quot) = (SIZ(num) ^ SIZ(den)) >= 0 ? qn : -qn;
+
+  TMP_FREE;
+}
diff --git a/mpz/divis.c b/mpz/divis.c
new file mode 100644
index 0000000..35429a7
--- /dev/null
+++ b/mpz/divis.c
@@ -0,0 +1,43 @@
+/* mpz_divisible_p -- mpz by mpz divisibility test
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_divisible_p (mpz_srcptr a, mpz_srcptr d)
+{
+  mp_size_t dsize = SIZ(d);
+  mp_size_t asize = SIZ(a);
+
+  if (UNLIKELY (dsize == 0))
+    return (asize == 0);
+
+  return mpn_divisible_p (PTR(a), ABS(asize), PTR(d), ABS(dsize));
+}
diff --git a/mpz/divis_2exp.c b/mpz/divis_2exp.c
new file mode 100644
index 0000000..4ecb0c0
--- /dev/null
+++ b/mpz/divis_2exp.c
@@ -0,0 +1,60 @@
+/* mpz_divisible_2exp_p -- mpz by 2^n divisibility test
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpz_divisible_2exp_p (mpz_srcptr a, mp_bitcnt_t d) __GMP_NOTHROW
+{
+  mp_size_t      i, dlimbs;
+  unsigned       dbits;
+  mp_ptr         ap;
+  mp_limb_t      dmask;
+  mp_size_t      asize;
+
+  asize = ABSIZ(a);
+  dlimbs = d / GMP_NUMB_BITS;
+
+  /* if d covers the whole of a, then only a==0 is divisible */
+  if (asize <= dlimbs)
+    return asize == 0;
+
+  /* whole limbs must be zero */
+  ap = PTR(a);
+  for (i = 0; i < dlimbs; i++)
+    if (ap[i] != 0)
+      return 0;
+
+  /* left over bits must be zero */
+  dbits = d % GMP_NUMB_BITS;
+  dmask = (CNST_LIMB(1) << dbits) - 1;
+  return (ap[dlimbs] & dmask) == 0;
+}
diff --git a/mpz/divis_ui.c b/mpz/divis_ui.c
new file mode 100644
index 0000000..b24c7dc
--- /dev/null
+++ b/mpz/divis_ui.c
@@ -0,0 +1,80 @@
+/* mpz_divisible_ui_p -- mpz by ulong divisibility test.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_divisible_ui_p (mpz_srcptr a, unsigned long d)
+{
+  mp_size_t  asize;
+  mp_ptr     ap;
+  unsigned   twos;
+
+  asize = SIZ(a);
+  if (UNLIKELY (d == 0))
+    return (asize == 0);
+
+  if (asize == 0)  /* 0 divisible by any d */
+    return 1;
+
+  /* For nails don't try to be clever if d is bigger than a limb, just fake
+     up an mpz_t and go to the main mpz_divisible_p.  */
+  if (d > GMP_NUMB_MAX)
+    {
+      mp_limb_t  dlimbs[2];
+      mpz_t      dz;
+      ALLOC(dz) = 2;
+      PTR(dz) = dlimbs;
+      mpz_set_ui (dz, d);
+      return mpz_divisible_p (a, dz);
+    }
+
+  ap = PTR(a);
+  asize = ABS(asize);  /* ignore sign of a */
+
+  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
+    return mpn_mod_1 (ap, asize, (mp_limb_t) d) == 0;
+
+  if (! (d & 1))
+    {
+      /* Strip low zero bits to get odd d required by modexact.  If d==e*2^n
+	 and a is divisible by 2^n and by e, then it's divisible by d. */
+
+      if ((ap[0] & LOW_ZEROS_MASK (d)) != 0)
+	return 0;
+
+      count_trailing_zeros (twos, (mp_limb_t) d);
+      d >>= twos;
+    }
+
+  return mpn_modexact_1_odd (ap, asize, (mp_limb_t) d) == 0;
+}
diff --git a/mpz/dump.c b/mpz/dump.c
new file mode 100644
index 0000000..6135ddd
--- /dev/null
+++ b/mpz/dump.c
@@ -0,0 +1,48 @@
+/* mpz_dump - Dump an integer to stdout.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS NOT SAFE TO
+   CALL THIS FUNCTION DIRECTLY.  IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+   FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h> /* for strlen */
+#include "gmp-impl.h"
+
+void
+mpz_dump (mpz_srcptr u)
+{
+  char *str;
+
+  str = mpz_get_str (0, 10, u);
+  printf ("%s\n", str);
+  (*__gmp_free_func) (str, strlen (str) + 1);
+}
diff --git a/mpz/export.c b/mpz/export.c
new file mode 100644
index 0000000..2dacd69
--- /dev/null
+++ b/mpz/export.c
@@ -0,0 +1,189 @@
+/* mpz_export -- create word data from mpz.
+
+Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define HOST_ENDIAN     1
+#endif
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HOST_ENDIAN     (-1)
+#endif
+#ifndef HOST_ENDIAN
+static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
+#define HOST_ENDIAN     (* (signed char *) &endian_test)
+#endif
+
+void *
+mpz_export (void *data, size_t *countp, int order,
+	    size_t size, int endian, size_t nail, mpz_srcptr z)
+{
+  mp_size_t      zsize;
+  mp_srcptr      zp;
+  size_t         count, dummy;
+  unsigned long  numb;
+  unsigned       align;
+
+  ASSERT (order == 1 || order == -1);
+  ASSERT (endian == 1 || endian == 0 || endian == -1);
+  ASSERT (nail <= 8*size);
+  ASSERT (nail <  8*size || SIZ(z) == 0); /* nail < 8*size+(SIZ(z)==0) */
+
+  if (countp == NULL)
+    countp = &dummy;
+
+  zsize = SIZ(z);
+  if (zsize == 0)
+    {
+      *countp = 0;
+      return data;
+    }
+
+  zsize = ABS (zsize);
+  zp = PTR(z);
+  numb = 8*size - nail;
+  MPN_SIZEINBASE_2EXP (count, zp, zsize, numb);
+  *countp = count;
+
+  if (data == NULL)
+    data = (*__gmp_allocate_func) (count*size);
+
+  if (endian == 0)
+    endian = HOST_ENDIAN;
+
+  align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
+
+  if (nail == GMP_NAIL_BITS)
+    {
+      if (size == sizeof (mp_limb_t) && align == 0)
+	{
+	  if (order == -1 && endian == HOST_ENDIAN)
+	    {
+	      MPN_COPY ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+	  if (order == 1 && endian == HOST_ENDIAN)
+	    {
+	      MPN_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+
+	  if (order == -1 && endian == -HOST_ENDIAN)
+	    {
+	      MPN_BSWAP ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+	  if (order == 1 && endian == -HOST_ENDIAN)
+	    {
+	      MPN_BSWAP_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+	}
+    }
+
+  {
+    mp_limb_t      limb, wbitsmask;
+    size_t         i, numb;
+    mp_size_t      j, wbytes, woffset;
+    unsigned char  *dp;
+    int            lbits, wbits;
+    mp_srcptr      zend;
+
+    numb = size * 8 - nail;
+
+    /* whole bytes per word */
+    wbytes = numb / 8;
+
+    /* possible partial byte */
+    wbits = numb % 8;
+    wbitsmask = (CNST_LIMB(1) << wbits) - 1;
+
+    /* offset to get to the next word */
+    woffset = (endian >= 0 ? size : - (mp_size_t) size)
+      + (order < 0 ? size : - (mp_size_t) size);
+
+    /* least significant byte */
+    dp = (unsigned char *) data
+      + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
+
+#define EXTRACT(N, MASK)                                \
+    do {                                                \
+      if (lbits >= (N))                                 \
+        {                                               \
+          *dp = limb MASK;                              \
+          limb >>= (N);                                 \
+          lbits -= (N);                                 \
+        }                                               \
+      else                                              \
+        {                                               \
+          mp_limb_t  newlimb;                           \
+          newlimb = (zp == zend ? 0 : *zp++);           \
+          *dp = (limb | (newlimb << lbits)) MASK;       \
+          limb = newlimb >> ((N)-lbits);                \
+          lbits += GMP_NUMB_BITS - (N);                 \
+        }                                               \
+    } while (0)
+
+    zend = zp + zsize;
+    lbits = 0;
+    limb = 0;
+    for (i = 0; i < count; i++)
+      {
+	for (j = 0; j < wbytes; j++)
+	  {
+	    EXTRACT (8, + 0);
+	    dp -= endian;
+	  }
+	if (wbits != 0)
+	  {
+	    EXTRACT (wbits, & wbitsmask);
+	    dp -= endian;
+	    j++;
+	  }
+	for ( ; j < size; j++)
+	  {
+	    *dp = '\0';
+	    dp -= endian;
+	  }
+	dp += woffset;
+      }
+
+    ASSERT (zp == PTR(z) + ABSIZ(z));
+
+    /* low byte of word after most significant */
+    ASSERT (dp == (unsigned char *) data
+	    + (order < 0 ? count*size : - (mp_size_t) size)
+	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
+  }
+  return data;
+}
diff --git a/mpz/fac_ui.c b/mpz/fac_ui.c
new file mode 100644
index 0000000..a7998b3
--- /dev/null
+++ b/mpz/fac_ui.c
@@ -0,0 +1,122 @@
+/* mpz_fac_ui(RESULT, N) -- Set RESULT to N!.
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 1991, 1993-1995, 2000-2003, 2011, 2012, 2015, 2021 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#if TUNE_PROGRAM_BUILD
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_DSC_THRESHOLD_LIMIT-1)+1))
+#else
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_ODD_THRESHOLD)+1))
+#endif
+
+/* Computes n!, the factorial of n.
+   WARNING: it assumes that n fits in a limb!
+ */
+void
+mpz_fac_ui (mpz_ptr x, unsigned long n)
+{
+  static const mp_limb_t table[] = { ONE_LIMB_FACTORIAL_TABLE };
+
+  ASSERT (n <= GMP_NUMB_MAX);
+
+  if (n < numberof (table))
+    {
+      MPZ_NEWALLOC (x, 1)[0] = table[n];
+      SIZ (x) = 1;
+    }
+  else if (BELOW_THRESHOLD (n, FAC_ODD_THRESHOLD))
+    {
+      mp_limb_t prod, max_prod;
+      mp_size_t j;
+      mp_ptr    factors;
+      mp_limb_t fac, diff = n - numberof (table);
+      TMP_SDECL;
+
+      TMP_SMARK;
+      factors = TMP_SALLOC_LIMBS (2 + diff / FACTORS_PER_LIMB);
+
+      factors[0] = table[numberof (table)-1];
+      j = 1;
+      if ((diff & 1) == 0)
+	{
+	  prod = n;
+	  /* if (diff != 0) */
+	    fac = --n * numberof (table);
+	}
+      else
+	{
+	  prod = n * numberof (table);
+	  fac = prod + --diff;
+	}
+
+#if TUNE_PROGRAM_BUILD
+      max_prod = GMP_NUMB_MAX / (FAC_DSC_THRESHOLD_LIMIT * FAC_DSC_THRESHOLD_LIMIT);
+#else
+      max_prod = GMP_NUMB_MAX /
+	(((FAC_ODD_THRESHOLD + numberof (table) + 1) / 2) *
+	 ((FAC_ODD_THRESHOLD + numberof (table)) / 2));
+#endif
+      for (;diff != 0; fac += (diff -= 2))
+	FACTOR_LIST_STORE (fac, prod, max_prod, factors, j);
+
+      factors[j++] = prod;
+      mpz_prodlimbs (x, factors, j);
+
+      TMP_SFREE;
+    }
+  else
+    {
+      mp_limb_t count;
+      mpz_oddfac_1 (x, n, 0);
+      if (n <= TABLE_LIMIT_2N_MINUS_POPC_2N)
+	count = __gmp_fac2cnt_table[n / 2 - 1];
+      else
+	{
+	  popc_limb (count, n);
+	  count = n - count;
+	}
+      mpz_mul_2exp (x, x, count);
+    }
+}
+
+#undef FACTORS_PER_LIMB
+#undef FACTOR_LIST_STORE
diff --git a/mpz/fdiv_q.c b/mpz/fdiv_q.c
new file mode 100644
index 0000000..f17023e
--- /dev/null
+++ b/mpz/fdiv_q.c
@@ -0,0 +1,52 @@
+/* mpz_fdiv_q -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_fdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t dividend_size = SIZ (dividend);
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t rem;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  MPZ_TMP_INIT (rem, ABS (divisor_size));
+
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if ((divisor_size ^ dividend_size) < 0 && SIZ (rem) != 0)
+    mpz_sub_ui (quot, quot, 1L);
+
+  TMP_FREE;
+}
diff --git a/mpz/fdiv_q_ui.c b/mpz/fdiv_q_ui.c
new file mode 100644
index 0000000..539f951
--- /dev/null
+++ b/mpz/fdiv_q_ui.c
@@ -0,0 +1,100 @@
+/* mpz_fdiv_q_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 1999, 2001, 2002, 2004, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  rl = np[0];
+	  qn = 1;		/* a white lie, fixed below */
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+
+      if (rl != 0 && ns < 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/mpz/fdiv_qr.c b/mpz/fdiv_qr.c
new file mode 100644
index 0000000..a0a6166
--- /dev/null
+++ b/mpz/fdiv_qr.c
@@ -0,0 +1,64 @@
+/* mpz_fdiv_qr -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_fdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mp_size_t xsize;
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the quotient and
+     remainder have been preliminary calculated.  We have to copy it to
+     temporary space if it's the same variable as either QUOT or REM.  */
+  if (quot == divisor || rem == divisor)
+    {
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  xsize = SIZ (dividend) ^ divisor_size;;
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if (xsize < 0 && SIZ (rem) != 0)
+    {
+      mpz_sub_ui (quot, quot, 1L);
+      mpz_add (rem, rem, divisor);
+    }
+
+  TMP_FREE;
+}
diff --git a/mpz/fdiv_qr_ui.c b/mpz/fdiv_qr_ui.c
new file mode 100644
index 0000000..984ca1c
--- /dev/null
+++ b/mpz/fdiv_qr_ui.c
@@ -0,0 +1,116 @@
+/* mpz_fdiv_qr_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 1999, 2001, 2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp;
+      mp_size_t rn;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  qn = 1;		/* a white lie, fixed below */
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns < 0)
+	    {
+	      mpn_incr_u (qp, (mp_limb_t) 1);
+	      rl = divisor - rl;
+	    }
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = rl != 0;
+	}
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/mpz/fdiv_r.c b/mpz/fdiv_r.c
new file mode 100644
index 0000000..c7a3c8e
--- /dev/null
+++ b/mpz/fdiv_r.c
@@ -0,0 +1,59 @@
+/* mpz_fdiv_r -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_fdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the remainder has been
+     preliminary calculated.  We have to copy it to temporary space if it's
+     the same variable as REM.  */
+  if (rem == divisor)
+    {
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  mpz_tdiv_r (rem, dividend, divisor);
+
+  if ((divisor_size ^ SIZ (dividend)) < 0 && SIZ (rem) != 0)
+    mpz_add (rem, rem, divisor);
+
+  TMP_FREE;
+}
diff --git a/mpz/fdiv_r_ui.c b/mpz/fdiv_r_ui.c
new file mode 100644
index 0000000..f2df8a8
--- /dev/null
+++ b/mpz/fdiv_r_ui.c
@@ -0,0 +1,107 @@
+/* mpz_fdiv_r_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp, qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns < 0)
+	    rl = divisor - rl;
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = 1;
+	}
+    }
+
+  return rl;
+}
diff --git a/mpz/fdiv_ui.c b/mpz/fdiv_ui.c
new file mode 100644
index 0000000..f0aacdb
--- /dev/null
+++ b/mpz/fdiv_ui.c
@@ -0,0 +1,100 @@
+/* mpz_fdiv_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+      mp_ptr qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	;
+      else
+	{
+	  if (ns < 0)
+	    rl = divisor - rl;
+	}
+    }
+
+  return rl;
+}
diff --git a/mpz/fib2_ui.c b/mpz/fib2_ui.c
new file mode 100644
index 0000000..ea26227
--- /dev/null
+++ b/mpz/fib2_ui.c
@@ -0,0 +1,58 @@
+/* mpz_fib2_ui -- calculate Fibonacci numbers.
+
+Copyright 2001, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+void
+mpz_fib2_ui (mpz_ptr fn, mpz_ptr fnsub1, unsigned long n)
+{
+  mp_ptr     fp, f1p;
+  mp_size_t  size;
+
+  if (n <= FIB_TABLE_LIMIT)
+    {
+      MPZ_NEWALLOC (fn, 1)[0] = FIB_TABLE (n);
+      SIZ(fn) = (n != 0);      /* F[0]==0, others are !=0 */
+      MPZ_NEWALLOC (fnsub1, 1)[0] = FIB_TABLE ((int) n - 1);
+      SIZ(fnsub1) = (n != 1);  /* F[1-1]==0, others are !=0 */
+      return;
+    }
+
+  size = MPN_FIB2_SIZE (n);
+  fp =  MPZ_NEWALLOC (fn,     size);
+  f1p = MPZ_NEWALLOC (fnsub1, size);
+
+  size = mpn_fib2_ui (fp, f1p, n);
+
+  SIZ(fn)     = size;
+  SIZ(fnsub1) = size - (f1p[size-1] == 0);
+}
diff --git a/mpz/fib_ui.c b/mpz/fib_ui.c
new file mode 100644
index 0000000..a65f3c9
--- /dev/null
+++ b/mpz/fib_ui.c
@@ -0,0 +1,158 @@
+/* mpz_fib_ui -- calculate Fibonacci numbers.
+
+Copyright 2000-2002, 2005, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* change to "#define TRACE(x) x" to get some traces */
+#define TRACE(x)
+
+
+/* In the F[2k+1] below for k odd, the -2 won't give a borrow from the low
+   limb because the result F[2k+1] is an F[4m+3] and such numbers are always
+   == 1, 2 or 5 mod 8, whereas an underflow would leave 6 or 7.  (This is
+   the same as in mpn_fib2_ui.)
+
+   In the F[2k+1] for k even, the +2 won't give a carry out of the low limb
+   in normal circumstances.  This is an F[4m+1] and we claim that F[3*2^b+1]
+   == 1 mod 2^b is the first F[4m+1] congruent to 0 or 1 mod 2^b, and hence
+   if n < 2^GMP_NUMB_BITS then F[n] cannot have a low limb of 0 or 1.  No
+   proof for this claim, but it's been verified up to b==32 and has such a
+   nice pattern it must be true :-).  Of interest is that F[3*2^b] == 0 mod
+   2^(b+1) seems to hold too.
+
+   When n >= 2^GMP_NUMB_BITS, which can arise in a nails build, then the low
+   limb of F[4m+1] can certainly be 1, and an mpn_add_1 must be used.  */
+
+void
+mpz_fib_ui (mpz_ptr fn, unsigned long n)
+{
+  mp_ptr         fp, xp, yp;
+  mp_size_t      size, xalloc;
+  unsigned long  n2;
+  mp_limb_t      c;
+  TMP_DECL;
+
+  if (n <= FIB_TABLE_LIMIT)
+    {
+      MPZ_NEWALLOC (fn, 1)[0] = FIB_TABLE (n);
+      SIZ(fn) = (n != 0);      /* F[0]==0, others are !=0 */
+      return;
+    }
+
+  n2 = n/2;
+  xalloc = MPN_FIB2_SIZE (n2) + 1;
+  fp = MPZ_NEWALLOC (fn, 2 * xalloc);
+
+  TMP_MARK;
+  TMP_ALLOC_LIMBS_2 (xp,xalloc, yp,xalloc);
+  size = mpn_fib2_ui (xp, yp, n2);
+
+  TRACE (printf ("mpz_fib_ui last step n=%lu size=%ld bit=%lu\n",
+		 n >> 1, size, n&1);
+	 mpn_trace ("xp", xp, size);
+	 mpn_trace ("yp", yp, size));
+
+  if (n & 1)
+    {
+      /* F[2k+1] = (2F[k]+F[k-1])*(2F[k]-F[k-1]) + 2*(-1)^k  */
+      mp_size_t  xsize, ysize;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      xp[size] = mpn_lshift (xp, xp, size, 1);
+      yp[size] = 0;
+      ASSERT_NOCARRY (mpn_add_n_sub_n (xp, yp, xp, yp, size+1));
+      xsize = size + (xp[size] != 0);
+      ASSERT (yp[size] <= 1);
+      ysize = size + yp[size];
+#else
+      mp_limb_t  c2;
+
+      c2 = mpn_lshift (fp, xp, size, 1);
+      c = c2 + mpn_add_n (xp, fp, yp, size);
+      xp[size] = c;
+      xsize = size + (c != 0);
+      c2 -= mpn_sub_n (yp, fp, yp, size);
+      yp[size] = c2;
+      ASSERT (c2 <= 1);
+      ysize = size + c2;
+#endif
+
+      size = xsize + ysize;
+      c = mpn_mul (fp, xp, xsize, yp, ysize);
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+      /* no overflow, see comments above */
+      ASSERT (n & 2 ? fp[0] >= 2 : fp[0] <= GMP_NUMB_MAX-2);
+      fp[0] += (n & 2 ? -CNST_LIMB(2) : CNST_LIMB(2));
+#else
+      if (n & 2)
+	{
+	  ASSERT (fp[0] >= 2);
+	  fp[0] -= 2;
+	}
+      else
+	{
+	  ASSERT (c != GMP_NUMB_MAX); /* because it's the high of a mul */
+	  c += mpn_add_1 (fp, fp, size-1, CNST_LIMB(2));
+	  fp[size-1] = c;
+	}
+#endif
+    }
+  else
+    {
+      /* F[2k] = F[k]*(F[k]+2F[k-1]) */
+
+      mp_size_t  xsize, ysize;
+#if HAVE_NATIVE_mpn_addlsh1_n
+      c = mpn_addlsh1_n (yp, xp, yp, size);
+#else
+      c = mpn_lshift (yp, yp, size, 1);
+      c += mpn_add_n (yp, yp, xp, size);
+#endif
+      yp[size] = c;
+      xsize = size;
+      ysize = size + (c != 0);
+      size += ysize;
+      c = mpn_mul (fp, yp, ysize, xp, xsize);
+    }
+
+  /* one or two high zeros */
+  size -= (c == 0);
+  size -= (fp[size-1] == 0);
+  SIZ(fn) = size;
+
+  TRACE (printf ("done special, size=%ld\n", size);
+	 mpn_trace ("fp ", fp, size));
+
+  TMP_FREE;
+}
diff --git a/mpz/fits_s.h b/mpz/fits_s.h
new file mode 100644
index 0000000..9fd6a0b
--- /dev/null
+++ b/mpz/fits_s.h
@@ -0,0 +1,60 @@
+/* int mpz_fits_X_p (mpz_t z) -- test whether z fits signed type X.
+
+Copyright 1997, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+FUNCTION (mpz_srcptr z) __GMP_NOTHROW
+{
+  mp_size_t n = SIZ(z);
+  mp_ptr p = PTR(z);
+  mp_limb_t limb = p[0];
+
+  if (n == 0)
+    return 1;
+  if (n == 1)
+    return limb <= MAXIMUM;
+  if (n == -1)
+    return limb <= NEG_CAST (mp_limb_t, MINIMUM);
+#if GMP_NAIL_BITS != 0
+  {
+    if ((p[1] >> GMP_NAIL_BITS) == 0)
+      {
+	limb += p[1] << GMP_NUMB_BITS;
+	if (n == 2)
+	  return limb <= MAXIMUM;
+	if (n == -2)
+	  return limb <= NEG_CAST (mp_limb_t, MINIMUM);
+      }
+  }
+#endif
+  return 0;
+}
diff --git a/mpz/fits_sint.c b/mpz/fits_sint.c
new file mode 100644
index 0000000..d548c45
--- /dev/null
+++ b/mpz/fits_sint.c
@@ -0,0 +1,36 @@
+/* int mpz_fits_sint_p (mpz_t z) -- test whether z fits an int.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpz_fits_sint_p
+#define MAXIMUM   INT_MAX
+#define MINIMUM   INT_MIN
+
+#include "fits_s.h"
diff --git a/mpz/fits_slong.c b/mpz/fits_slong.c
new file mode 100644
index 0000000..9306a00
--- /dev/null
+++ b/mpz/fits_slong.c
@@ -0,0 +1,36 @@
+/* int mpz_fits_slong_p (mpz_t z) -- test whether z fits a long.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpz_fits_slong_p
+#define MAXIMUM   LONG_MAX
+#define MINIMUM   LONG_MIN
+
+#include "fits_s.h"
diff --git a/mpz/fits_sshort.c b/mpz/fits_sshort.c
new file mode 100644
index 0000000..431d6b0
--- /dev/null
+++ b/mpz/fits_sshort.c
@@ -0,0 +1,36 @@
+/* int mpz_fits_sshort_p (mpz_t z) -- test whether z fits a short.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpz_fits_sshort_p
+#define MAXIMUM   SHRT_MAX
+#define MINIMUM   SHRT_MIN
+
+#include "fits_s.h"
diff --git a/mpz/fits_uint.c b/mpz/fits_uint.c
new file mode 100644
index 0000000..6becc8b
--- /dev/null
+++ b/mpz/fits_uint.c
@@ -0,0 +1,33 @@
+/* mpz_fits_uint_p -- test whether z fits an unsigned int.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_fits_uint_p 1
+
+#include "gmp-impl.h"
diff --git a/mpz/fits_ulong.c b/mpz/fits_ulong.c
new file mode 100644
index 0000000..c70886b
--- /dev/null
+++ b/mpz/fits_ulong.c
@@ -0,0 +1,33 @@
+/* mpz_fits_ulong_p -- test whether z fits an unsigned long.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_fits_ulong_p 1
+
+#include "gmp-impl.h"
diff --git a/mpz/fits_ushort.c b/mpz/fits_ushort.c
new file mode 100644
index 0000000..16873d6
--- /dev/null
+++ b/mpz/fits_ushort.c
@@ -0,0 +1,33 @@
+/* mpz_fits_ushort_p -- test whether z fits an unsigned short.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_fits_ushort_p 1
+
+#include "gmp-impl.h"
diff --git a/mpz/gcd.c b/mpz/gcd.c
new file mode 100644
index 0000000..9557155
--- /dev/null
+++ b/mpz/gcd.c
@@ -0,0 +1,164 @@
+/* mpz/gcd.c:   Calculate the greatest common divisor of two integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2010, 2015, 2016
+Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpz_gcd (mpz_ptr g, mpz_srcptr u, mpz_srcptr v)
+{
+  unsigned long int g_zero_bits, u_zero_bits, v_zero_bits;
+  mp_size_t g_zero_limbs, u_zero_limbs, v_zero_limbs;
+  mp_ptr tp;
+  mp_ptr up;
+  mp_size_t usize;
+  mp_ptr vp;
+  mp_size_t vsize;
+  mp_size_t gsize;
+  TMP_DECL;
+
+  up = PTR(u);
+  usize = ABSIZ (u);
+  vp = PTR(v);
+  vsize = ABSIZ (v);
+  /* GCD(0, V) == V.  */
+  if (usize == 0)
+    {
+      SIZ (g) = vsize;
+      if (g == v)
+	return;
+      tp = MPZ_NEWALLOC (g, vsize);
+      MPN_COPY (tp, vp, vsize);
+      return;
+    }
+
+  /* GCD(U, 0) == U.  */
+  if (vsize == 0)
+    {
+      SIZ (g) = usize;
+      if (g == u)
+	return;
+      tp = MPZ_NEWALLOC (g, usize);
+      MPN_COPY (tp, up, usize);
+      return;
+    }
+
+  if (usize == 1)
+    {
+      SIZ (g) = 1;
+      MPZ_NEWALLOC (g, 1)[0] = mpn_gcd_1 (vp, vsize, up[0]);
+      return;
+    }
+
+  if (vsize == 1)
+    {
+      SIZ(g) = 1;
+      MPZ_NEWALLOC (g, 1)[0] = mpn_gcd_1 (up, usize, vp[0]);
+      return;
+    }
+
+  TMP_MARK;
+
+  /*  Eliminate low zero bits from U and V and move to temporary storage.  */
+  tp = up;
+  while (*tp == 0)
+    tp++;
+  u_zero_limbs = tp - up;
+  usize -= u_zero_limbs;
+  count_trailing_zeros (u_zero_bits, *tp);
+  up = TMP_ALLOC_LIMBS (usize);
+  if (u_zero_bits != 0)
+    {
+      mpn_rshift (up, tp, usize, u_zero_bits);
+      usize -= up[usize - 1] == 0;
+    }
+  else
+    MPN_COPY (up, tp, usize);
+
+  tp = vp;
+  while (*tp == 0)
+    tp++;
+  v_zero_limbs = tp - vp;
+  vsize -= v_zero_limbs;
+  count_trailing_zeros (v_zero_bits, *tp);
+  vp = TMP_ALLOC_LIMBS (vsize);
+  if (v_zero_bits != 0)
+    {
+      mpn_rshift (vp, tp, vsize, v_zero_bits);
+      vsize -= vp[vsize - 1] == 0;
+    }
+  else
+    MPN_COPY (vp, tp, vsize);
+
+  if (u_zero_limbs > v_zero_limbs)
+    {
+      g_zero_limbs = v_zero_limbs;
+      g_zero_bits = v_zero_bits;
+    }
+  else
+    {
+      g_zero_limbs = u_zero_limbs;
+      if (u_zero_limbs < v_zero_limbs)
+	g_zero_bits = u_zero_bits;
+      else  /*  Equal.  */
+	g_zero_bits = MIN (u_zero_bits, v_zero_bits);
+    }
+
+  /*  Call mpn_gcd.  The 2nd argument must not have more bits than the 1st.  */
+  vsize = (usize < vsize || (usize == vsize && up[usize-1] < vp[vsize-1]))
+    ? mpn_gcd (vp, vp, vsize, up, usize)
+    : mpn_gcd (vp, up, usize, vp, vsize);
+
+  /*  Here G <-- V << (g_zero_limbs*GMP_LIMB_BITS + g_zero_bits).  */
+  gsize = vsize + g_zero_limbs;
+  if (g_zero_bits != 0)
+    {
+      mp_limb_t cy_limb;
+      gsize += (vp[vsize - 1] >> (GMP_NUMB_BITS - g_zero_bits)) != 0;
+      tp = MPZ_NEWALLOC (g, gsize);
+      MPN_ZERO (tp, g_zero_limbs);
+
+      tp = tp + g_zero_limbs;
+      cy_limb = mpn_lshift (tp, vp, vsize, g_zero_bits);
+      if (cy_limb != 0)
+	tp[vsize] = cy_limb;
+    }
+  else
+    {
+      tp = MPZ_NEWALLOC (g, gsize);
+      MPN_ZERO (tp, g_zero_limbs);
+      MPN_COPY (tp + g_zero_limbs, vp, vsize);
+    }
+
+  SIZ (g) = gsize;
+  TMP_FREE;
+}
diff --git a/mpz/gcd_ui.c b/mpz/gcd_ui.c
new file mode 100644
index 0000000..64aa46d
--- /dev/null
+++ b/mpz/gcd_ui.c
@@ -0,0 +1,92 @@
+/* mpz_gcd_ui -- Calculate the greatest common divisor of two integers.
+
+Copyright 1994, 1996, 1999-2004, 2015, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_gcd_ui (mpz_ptr w, mpz_srcptr u, unsigned long int v)
+{
+  mp_size_t un;
+  mp_limb_t res;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpz_t vz, lw;
+      mp_limb_t vlimbs[2], wlimbs[2];
+
+      if (w == NULL)
+	{
+	  PTR(lw) = wlimbs;
+	  ALLOC(lw) = 2;
+	  SIZ(lw) = 0;
+	  w = lw;
+	}
+      vlimbs[0] = v & GMP_NUMB_MASK;
+      vlimbs[1] = v >> GMP_NUMB_BITS;
+      PTR(vz) = vlimbs;
+      SIZ(vz) = 2;
+      mpz_gcd (w, u, vz);
+      /* because v!=0 we will have w<=v hence fitting a ulong */
+      ASSERT (mpz_fits_ulong_p (w));
+      return mpz_get_ui (w);
+    }
+#endif
+
+  un = ABSIZ(u);
+
+  if (un == 0)
+    res = v;
+  else if (v == 0)
+    {
+      if (w != NULL)
+	{
+	  if (u != w)
+	    {
+	      MPZ_NEWALLOC (w, un);
+	      MPN_COPY (PTR(w), PTR(u), un);
+	    }
+	  SIZ(w) = un;
+	}
+      /* Return u if it fits a ulong, otherwise 0. */
+      res = PTR(u)[0];
+      return (un == 1 && res <= ULONG_MAX ? res : 0);
+    }
+  else
+    res = mpn_gcd_1 (PTR(u), un, (mp_limb_t) v);
+
+  if (w != NULL)
+    {
+      MPZ_NEWALLOC (w, 1)[0] = res;
+      SIZ(w) = res != 0;
+    }
+  return res;
+}
diff --git a/mpz/gcdext.c b/mpz/gcdext.c
new file mode 100644
index 0000000..b1f73c2
--- /dev/null
+++ b/mpz/gcdext.c
@@ -0,0 +1,135 @@
+/* mpz_gcdext(g, s, t, a, b) -- Set G to gcd(a, b), and S and T such that
+   g = as + bt.
+
+Copyright 1991, 1993-1997, 2000, 2001, 2005, 2011, 2012, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+void
+mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b)
+{
+  mp_size_t asize, bsize;
+  mp_ptr tmp_ap, tmp_bp;
+  mp_size_t gsize, ssize, tmp_ssize;
+  mp_ptr gp, tmp_gp, tmp_sp;
+  TMP_DECL;
+
+  /* mpn_gcdext requires that Usize >= Vsize.  Therefore, we often
+     have to swap U and V.  The computed cofactor will be the
+     "smallest" one, which is faster to produce.  The wanted one will
+     be computed here; this is needed anyway when both are requested.  */
+
+  asize = ABSIZ (a);
+  bsize = ABSIZ (b);
+
+  ASSERT (s != NULL);
+
+  if (asize < bsize)
+    {
+      MPZ_SRCPTR_SWAP (a, b);
+      MP_SIZE_T_SWAP (asize, bsize);
+      MPZ_PTR_SWAP (s, t);
+    }
+
+  if (bsize == 0)
+    {
+      /* g = |a|, s = sgn(a), t = 0. */
+      ssize = SIZ (a) >= 0 ? (asize != 0) : -1;
+
+      if (g != NULL)
+	{
+	  /* If g == a, then ALLOC(g) == ALLOC(a) >= asize, i.e.
+	     the next MPZ_NEWALLOC returns the old PTR(a) .*/
+	  gp = MPZ_NEWALLOC (g, asize);
+	  MPN_COPY (gp, PTR (a), asize);
+	  SIZ (g) = asize;
+	}
+      if (t != NULL)
+	SIZ (t) = 0;
+      if (s != NULL)
+	{
+	  SIZ (s) = ssize;
+	  MPZ_NEWALLOC (s, 1)[0] = 1;
+	}
+      return;
+    }
+
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (tmp_gp, bsize, tmp_sp, asize + bsize + bsize + 1);
+  tmp_bp = tmp_sp + bsize + 1;
+  tmp_ap = tmp_bp + bsize;
+  MPN_COPY (tmp_ap, PTR (a), asize);
+  MPN_COPY (tmp_bp, PTR (b), bsize);
+
+  gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, tmp_ap, asize, tmp_bp, bsize);
+
+  ssize = ABS (tmp_ssize);
+  tmp_ssize = SIZ (a) >= 0 ? tmp_ssize : -tmp_ssize;
+
+  if (t != NULL)
+    {
+      mpz_t x;
+      mpz_t gtmp, stmp;
+
+      PTR (gtmp) = tmp_gp;
+      SIZ (gtmp) = gsize;
+
+      PTR (stmp) = tmp_sp;
+      SIZ (stmp) = tmp_ssize;
+
+      ASSERT (ssize <= bsize); /* ssize*2 + asize + 1 <= asize + bsize*2 + 1 */
+      PTR (x) = tmp_sp + ssize;
+      ALLOC (x) = ssize + asize + 1;
+
+      mpz_mul (x, stmp, a);
+      mpz_sub (x, gtmp, x);
+      mpz_divexact (t, x, b);
+    }
+
+  if (s != NULL)
+    {
+      mp_ptr sp;
+
+      sp = MPZ_NEWALLOC (s, ssize);
+      MPN_COPY (sp, tmp_sp, ssize);
+      SIZ (s) = tmp_ssize;
+    }
+
+  if (g != NULL)
+    {
+      gp = MPZ_NEWALLOC (g, gsize);
+      MPN_COPY (gp, tmp_gp, gsize);
+      SIZ (g) = gsize;
+    }
+
+  TMP_FREE;
+}
diff --git a/mpz/get_d.c b/mpz/get_d.c
new file mode 100644
index 0000000..61d4e36
--- /dev/null
+++ b/mpz/get_d.c
@@ -0,0 +1,43 @@
+/* double mpz_get_d (mpz_t src) -- Return the double approximation to SRC.
+
+Copyright 1996, 1997, 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+double
+mpz_get_d (mpz_srcptr z)
+{
+  mp_size_t size;
+
+  size = SIZ (z);
+  if (UNLIKELY (size == 0))
+    return 0.0;
+
+  return mpn_get_d (PTR (z), ABS (size), size, 0L);
+}
diff --git a/mpz/get_d_2exp.c b/mpz/get_d_2exp.c
new file mode 100644
index 0000000..beb364a
--- /dev/null
+++ b/mpz/get_d_2exp.c
@@ -0,0 +1,53 @@
+/* double mpz_get_d_2exp (signed long int *exp, mpz_t src).
+
+Copyright 2001, 2003, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+double
+mpz_get_d_2exp (signed long int *exp2, mpz_srcptr src)
+{
+  mp_size_t size, abs_size;
+  mp_srcptr ptr;
+  long exp;
+
+  size = SIZ(src);
+  if (UNLIKELY (size == 0))
+    {
+      *exp2 = 0;
+      return 0.0;
+    }
+
+  ptr = PTR(src);
+  abs_size = ABS(size);
+  MPN_SIZEINBASE_2EXP(exp, ptr, abs_size, 1);
+  *exp2 = exp;
+  return mpn_get_d (ptr, abs_size, size, -exp);
+}
diff --git a/mpz/get_si.c b/mpz/get_si.c
new file mode 100644
index 0000000..c65be2e
--- /dev/null
+++ b/mpz/get_si.c
@@ -0,0 +1,52 @@
+/* mpz_get_si(integer) -- Return the least significant digit from INTEGER.
+
+Copyright 1991, 1993-1995, 2000-2002, 2006, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+signed long int
+mpz_get_si (mpz_srcptr z) __GMP_NOTHROW
+{
+  mp_ptr zp = PTR (z);
+  mp_size_t size = SIZ (z);
+  mp_limb_t zl = zp[0];
+
+#if GMP_NAIL_BITS != 0
+  if (ULONG_MAX > GMP_NUMB_MAX && ABS (size) >= 2)
+    zl |= zp[1] << GMP_NUMB_BITS;
+#endif
+
+  if (size > 0)
+    return zl & LONG_MAX;
+  else if (size < 0)
+    /* This expression is necessary to properly handle 0x80000000 */
+    return -1 - (long) ((zl - 1) & LONG_MAX);
+  else
+    return 0;
+}
diff --git a/mpz/get_str.c b/mpz/get_str.c
new file mode 100644
index 0000000..c00a9a3
--- /dev/null
+++ b/mpz/get_str.c
@@ -0,0 +1,115 @@
+/* mpz_get_str (string, base, mp_src) -- Convert the multiple precision
+   number MP_SRC to a string STRING of base BASE.  If STRING is NULL
+   allocate space for the result.  In any case, return a pointer to the
+   result.  If STRING is not NULL, the caller must ensure enough space is
+   available to store the result.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2012, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <string.h> /* for strlen */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+char *
+mpz_get_str (char *res_str, int base, mpz_srcptr x)
+{
+  mp_ptr xp;
+  mp_size_t x_size = SIZ (x);
+  char *return_str;
+  size_t str_size;
+  size_t alloc_size = 0;
+  const char *num_to_text;
+  int i;
+  TMP_DECL;
+
+  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (UNLIKELY (base > 62))
+	return NULL;
+    }
+  else if (base > -2)
+    {
+      base = 10;
+    }
+  else
+    {
+      base = -base;
+      if (UNLIKELY (base > 36))
+	return NULL;
+    }
+
+  /* allocate string for the user if necessary */
+  if (res_str == NULL)
+    {
+      /* digits, null terminator, possible minus sign */
+      MPN_SIZEINBASE (alloc_size, PTR(x), ABS(x_size), base);
+      alloc_size += 1 + (x_size<0);
+      res_str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
+    }
+  return_str = res_str;
+
+  if (x_size < 0)
+    {
+      *res_str++ = '-';
+      x_size = -x_size;
+    }
+
+  /* mpn_get_str clobbers its input on non power-of-2 bases */
+  TMP_MARK;
+  xp = PTR (x);
+  if (! POW2_P (base))
+    {
+      xp = TMP_ALLOC_LIMBS (x_size | 1);  /* |1 in case x_size==0 */
+      MPN_COPY (xp, PTR (x), x_size);
+    }
+
+  str_size = mpn_get_str ((unsigned char *) res_str, base, xp, x_size);
+  ASSERT (alloc_size == 0 || str_size <= alloc_size - (SIZ(x) < 0));
+
+  /* Convert result to printable chars.  */
+  for (i = 0; i < str_size; i++)
+    res_str[i] = num_to_text[(int) res_str[i]];
+  res_str[str_size] = 0;
+
+  TMP_FREE;
+
+  /* if allocated then resize down to the actual space required */
+  if (alloc_size != 0)
+    {
+      size_t  actual_size = str_size + 1 + (res_str - return_str);
+      ASSERT (actual_size == strlen (return_str) + 1);
+      __GMP_REALLOCATE_FUNC_MAYBE_TYPE (return_str, alloc_size, actual_size,
+					char);
+    }
+  return return_str;
+}
diff --git a/mpz/get_ui.c b/mpz/get_ui.c
new file mode 100644
index 0000000..2d7ea4e
--- /dev/null
+++ b/mpz/get_ui.c
@@ -0,0 +1,33 @@
+/* mpz_get_ui(integer) -- Return the least significant digit from INTEGER.
+
+Copyright 1991, 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_get_ui 1
+
+#include "gmp-impl.h"
diff --git a/mpz/getlimbn.c b/mpz/getlimbn.c
new file mode 100644
index 0000000..d34d764
--- /dev/null
+++ b/mpz/getlimbn.c
@@ -0,0 +1,33 @@
+/* mpz_getlimbn(integer,n) -- Return the N:th limb from INTEGER.
+
+Copyright 1993-1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_getlimbn 1
+
+#include "gmp-impl.h"
diff --git a/mpz/hamdist.c b/mpz/hamdist.c
new file mode 100644
index 0000000..1dfb7b8
--- /dev/null
+++ b/mpz/hamdist.c
@@ -0,0 +1,174 @@
+/* mpz_hamdist -- calculate hamming distance.
+
+Copyright 1994, 1996, 2001, 2002, 2009-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+mp_bitcnt_t
+mpz_hamdist (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mp_srcptr      up, vp;
+  mp_size_t      usize, vsize;
+  mp_bitcnt_t    count;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+
+  up = PTR(u);
+  vp = PTR(v);
+
+  if (usize >= 0)
+    {
+      if (vsize < 0)
+	return ~ (mp_bitcnt_t) 0;
+
+      /* positive/positive */
+
+      if (usize < vsize)
+	MPN_SRCPTR_SWAP (up,usize, vp,vsize);
+
+      count = 0;
+      if (vsize != 0)
+	count = mpn_hamdist (up, vp, vsize);
+
+      usize -= vsize;
+      if (usize != 0)
+	count += mpn_popcount (up + vsize, usize);
+
+      return count;
+    }
+  else
+    {
+      mp_limb_t  ulimb, vlimb;
+      mp_size_t  old_vsize, step;
+
+      if (vsize >= 0)
+	return ~ (mp_bitcnt_t) 0;
+
+      /* negative/negative */
+
+      usize = -usize;
+      vsize = -vsize;
+
+      /* skip common low zeros */
+      for (;;)
+	{
+	  ASSERT (usize > 0);
+	  ASSERT (vsize > 0);
+
+	  usize--;
+	  vsize--;
+
+	  ulimb = *up++;
+	  vlimb = *vp++;
+
+	  if (ulimb != 0)
+	    break;
+
+	  if (vlimb != 0)
+	    {
+	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
+	      ulimb = vlimb;
+	      vlimb = 0;
+	      break;
+	    }
+	}
+
+      /* twos complement first non-zero limbs (ulimb is non-zero, but vlimb
+	 might be zero) */
+      ulimb = -ulimb;
+      vlimb = -vlimb;
+      popc_limb (count, (ulimb ^ vlimb) & GMP_NUMB_MASK);
+
+      if (vlimb == 0)
+	{
+	  mp_bitcnt_t  twoscount;
+
+	  /* first non-zero of v */
+	  old_vsize = vsize;
+	  do
+	    {
+	      ASSERT (vsize > 0);
+	      vsize--;
+	      vlimb = *vp++;
+	    }
+	  while (vlimb == 0);
+
+	  /* part of u corresponding to skipped v zeros */
+	  step = old_vsize - vsize - 1;
+	  count += step * GMP_NUMB_BITS;
+	  step = MIN (step, usize);
+	  if (step != 0)
+	    {
+	      count -= mpn_popcount (up, step);
+	      usize -= step;
+	      up += step;
+	    }
+
+	  /* First non-zero vlimb as twos complement, xor with ones
+	     complement ulimb.  Note -v^(~0^u) == (v-1)^u. */
+	  vlimb--;
+	  if (usize != 0)
+	    {
+	      usize--;
+	      vlimb ^= *up++;
+	    }
+	  popc_limb (twoscount, vlimb);
+	  count += twoscount;
+	}
+
+      /* Overlapping part of u and v, if any.  Ones complement both, so just
+	 plain hamdist. */
+      step = MIN (usize, vsize);
+      if (step != 0)
+	{
+	  count += mpn_hamdist (up, vp, step);
+	  usize -= step;
+	  vsize -= step;
+	  up += step;
+	  vp += step;
+	}
+
+      /* Remaining high part of u or v, if any, ones complement but xor
+	 against all ones in the other, so plain popcount. */
+      if (usize != 0)
+	{
+	remaining:
+	  count += mpn_popcount (up, usize);
+	}
+      else if (vsize != 0)
+	{
+	  up = vp;
+	  usize = vsize;
+	  goto remaining;
+	}
+      return count;
+    }
+}
diff --git a/mpz/import.c b/mpz/import.c
new file mode 100644
index 0000000..9ff0670
--- /dev/null
+++ b/mpz/import.c
@@ -0,0 +1,166 @@
+/* mpz_import -- set mpz from word data.
+
+Copyright 2002, 2012, 2021, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define HOST_ENDIAN     1
+#endif
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HOST_ENDIAN     (-1)
+#endif
+#ifndef HOST_ENDIAN
+static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
+#define HOST_ENDIAN     (* (signed char *) &endian_test)
+#endif
+
+
+void
+mpz_import (mpz_ptr z, size_t count, int order,
+	    size_t size, int endian, size_t nail, const void *data)
+{
+  mp_size_t  zsize;
+  mp_ptr     zp;
+
+  ASSERT (order == 1 || order == -1);
+  ASSERT (endian == 1 || endian == 0 || endian == -1);
+  ASSERT (nail <= 8*size);
+
+  zsize = BITS_TO_LIMBS (count * (8*size - nail));
+  zp = MPZ_NEWALLOC (z, zsize);
+
+  if (endian == 0)
+    endian = HOST_ENDIAN;
+
+  /* Can't use these special cases with nails currently, since they don't
+     mask out the nail bits in the input data.  */
+  if (nail == 0 && GMP_NAIL_BITS == 0
+      && size == sizeof (mp_limb_t)
+      && (((char *) data - (char *) NULL) % sizeof (mp_limb_t)) == 0 /* align */)
+    {
+      if (order == -1)
+	{
+	  if (endian == HOST_ENDIAN)
+	    MPN_COPY (zp, (mp_srcptr) data, (mp_size_t) count);
+	  else /* if (endian == - HOST_ENDIAN) */
+	    MPN_BSWAP (zp, (mp_srcptr) data, (mp_size_t) count);
+	}
+      else /* if (order == 1) */
+	{
+	  if (endian == HOST_ENDIAN)
+	    MPN_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
+	  else /* if (endian == - HOST_ENDIAN) */
+	    MPN_BSWAP_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
+	}
+    }
+  else
+  {
+    mp_limb_t      limb, byte, wbitsmask;
+    size_t         i, j, numb, wbytes;
+    mp_size_t      woffset;
+    unsigned char  *dp;
+    int            lbits, wbits;
+
+    numb = size * 8 - nail;
+
+    /* whole bytes to process */
+    wbytes = numb / 8;
+
+    /* partial byte to process */
+    wbits = numb % 8;
+    wbitsmask = (CNST_LIMB(1) << wbits) - 1;
+
+    /* offset to get to the next word after processing wbytes and wbits */
+    woffset = (numb + 7) / 8;
+    woffset = (endian >= 0 ? woffset : -woffset)
+      + (order < 0 ? size : - (mp_size_t) size);
+
+    /* least significant byte */
+    dp = (unsigned char *) data
+      + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
+
+#define ACCUMULATE(N)                                   \
+    do {                                                \
+      ASSERT (lbits < GMP_NUMB_BITS);                   \
+      ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1);     \
+                                                        \
+      limb |= (mp_limb_t) byte << lbits;                \
+      lbits += (N);                                     \
+      if (lbits >= GMP_NUMB_BITS)                       \
+        {                                               \
+          *zp++ = limb & GMP_NUMB_MASK;                 \
+          lbits -= GMP_NUMB_BITS;                       \
+          ASSERT (lbits < (N));                         \
+          limb = byte >> ((N) - lbits);                 \
+        }                                               \
+    } while (0)
+
+    limb = 0;
+    lbits = 0;
+    for (i = 0; i < count; i++)
+      {
+	for (j = 0; j < wbytes; j++)
+	  {
+	    byte = *dp;
+	    dp -= endian;
+	    ACCUMULATE (8);
+	  }
+	if (wbits != 0)
+	  {
+	    byte = *dp & wbitsmask;
+	    dp -= endian;
+	    ACCUMULATE (wbits);
+	  }
+	dp += woffset;
+      }
+
+    if (lbits != 0)
+      {
+	ASSERT (lbits <= GMP_NUMB_BITS);
+	ASSERT_LIMB (limb);
+	*zp++ = limb;
+      }
+
+    ASSERT (zp == PTR(z) + zsize);
+
+    /* low byte of word after most significant */
+    ASSERT (dp == (unsigned char *) data
+	    + (order < 0 ? count*size : - (mp_size_t) size)
+	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
+
+  }
+
+  zp = PTR(z);
+  MPN_NORMALIZE (zp, zsize);
+  SIZ(z) = zsize;
+}
diff --git a/mpz/init.c b/mpz/init.c
new file mode 100644
index 0000000..b85a2da
--- /dev/null
+++ b/mpz/init.c
@@ -0,0 +1,41 @@
+/* mpz_init() -- Make a new multiple precision number with value 0.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init (mpz_ptr x) __GMP_NOTHROW
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  ALLOC (x) = 0;
+  PTR (x) = (mp_ptr) &dummy_limb;
+  SIZ (x) = 0;
+}
diff --git a/mpz/init2.c b/mpz/init2.c
new file mode 100644
index 0000000..cdb46bf
--- /dev/null
+++ b/mpz/init2.c
@@ -0,0 +1,50 @@
+/* mpz_init2 -- initialize mpz, with requested size in bits.
+
+Copyright 2001, 2002, 2008, 2021, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init2 (mpz_ptr x, mp_bitcnt_t bits)
+{
+  mp_size_t  new_alloc;
+
+  bits -= (bits != 0);		/* Round down, except if 0 */
+  new_alloc = 1 + bits / GMP_NUMB_BITS;
+
+  if (sizeof (unsigned long) > sizeof (int)) /* param vs _mp_size field */
+    {
+      if (UNLIKELY (new_alloc > INT_MAX))
+	MPZ_OVERFLOW;
+    }
+
+  PTR(x) = __GMP_ALLOCATE_FUNC_LIMBS (new_alloc);
+  ALLOC(x) = new_alloc;
+  SIZ(x) = 0;
+}
diff --git a/mpz/inits.c b/mpz/inits.c
new file mode 100644
index 0000000..1660744
--- /dev/null
+++ b/mpz/inits.c
@@ -0,0 +1,53 @@
+/* mpz_inits() -- Initialize multiple mpz_t variables and set them to 0.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpz_inits (mpz_ptr x, ...) __GMP_NOTHROW
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      ALLOC (x) = 0;
+      PTR (x) = (mp_ptr) &dummy_limb;
+      SIZ (x) = 0;
+
+      x = va_arg (ap, mpz_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/mpz/inp_raw.c b/mpz/inp_raw.c
new file mode 100644
index 0000000..746d926
--- /dev/null
+++ b/mpz/inp_raw.c
@@ -0,0 +1,172 @@
+/* mpz_inp_raw -- read an mpz_t in raw format.
+
+Copyright 2001, 2002, 2005, 2012, 2016, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* NTOH_LIMB_FETCH fetches a limb which is in network byte order (ie. big
+   endian) and produces a normal host byte order result. */
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define NTOH_LIMB_FETCH(limb, src)  do { (limb) = *(src); } while (0)
+#endif
+
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define NTOH_LIMB_FETCH(limb, src)  BSWAP_LIMB_FETCH (limb, src)
+#endif
+
+#ifndef NTOH_LIMB_FETCH
+#define NTOH_LIMB_FETCH(limb, src)                              \
+  do {                                                          \
+    const unsigned char  *__p = (const unsigned char *) (src);  \
+    mp_limb_t  __limb;                                          \
+    int        __i;                                             \
+    __limb = 0;                                                 \
+    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)               \
+      __limb = (__limb << 8) | __p[__i];                        \
+    (limb) = __limb;                                            \
+  } while (0)
+#endif
+
+
+/* Enhancement: The byte swap loop ought to be safe to vectorize on Cray
+   etc, but someone who knows what they're doing needs to check it.  */
+
+size_t
+mpz_inp_raw (mpz_ptr x, FILE *fp)
+{
+  unsigned char  csize_bytes[4];
+  mp_size_t      csize, abs_xsize, i;
+  size_t         size;
+  size_t         abs_csize;
+  char           *cp;
+  mp_ptr         xp, sp, ep;
+  mp_limb_t      slimb, elimb;
+
+  if (fp == 0)
+    fp = stdin;
+
+  /* 4 bytes for size */
+  if (UNLIKELY (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1))
+    return 0;
+
+  size = (((size_t) csize_bytes[0] << 24) + ((size_t) csize_bytes[1] << 16) +
+	  ((size_t) csize_bytes[2] << 8)  + ((size_t) csize_bytes[3]));
+
+  if (size < 0x80000000u)
+    csize = size;
+  else
+    csize = size - 0x80000000u - 0x80000000u;
+
+  abs_csize = ABS (csize);
+
+  if (UNLIKELY (abs_csize > ~(mp_bitcnt_t) 0 / 8))
+    return 0; /* Bit size overflows */
+
+  /* round up to a multiple of limbs */
+  abs_xsize = BITS_TO_LIMBS ((mp_bitcnt_t) abs_csize * 8);
+
+  if (abs_xsize != 0)
+    {
+      xp = MPZ_NEWALLOC (x, abs_xsize);
+
+      /* Get limb boundaries right in the read, for the benefit of the
+	 non-nails case.  */
+      xp[0] = 0;
+      cp = (char *) (xp + abs_xsize) - abs_csize;
+      if (UNLIKELY (fread (cp, abs_csize, 1, fp) != 1))
+	return 0;
+
+      if (GMP_NAIL_BITS == 0)
+	{
+	  /* Reverse limbs to least significant first, and byte swap.  If
+	     abs_xsize is odd then on the last iteration elimb and slimb are
+	     the same.  It doesn't seem extra code to handle that case
+	     separately, to save an NTOH.  */
+	  sp = xp;
+	  ep = xp + abs_xsize-1;
+	  for (i = 0; i < (abs_xsize+1)/2; i++)
+	    {
+	      NTOH_LIMB_FETCH (elimb, ep);
+	      NTOH_LIMB_FETCH (slimb, sp);
+	      *sp++ = elimb;
+	      *ep-- = slimb;
+	    }
+	}
+      else
+	{
+	  /* It ought to be possible to do the transformation in-place, but
+	     for now it's easier to use an extra temporary area.  */
+	  mp_limb_t  byte, limb;
+	  int	     bits;
+	  mp_size_t  tpos;
+	  mp_ptr     tp;
+	  TMP_DECL;
+
+	  TMP_MARK;
+	  tp = TMP_ALLOC_LIMBS (abs_xsize);
+	  limb = 0;
+	  bits = 0;
+	  tpos = 0;
+	  for (i = abs_csize-1; i >= 0; i--)
+	    {
+	      byte = (unsigned char) cp[i];
+	      limb |= (byte << bits);
+	      bits += 8;
+	      if (bits >= GMP_NUMB_BITS)
+		{
+		  ASSERT (tpos < abs_xsize);
+		  tp[tpos++] = limb & GMP_NUMB_MASK;
+		  bits -= GMP_NUMB_BITS;
+		  ASSERT (bits < 8);
+		  limb = byte >> (8 - bits);
+		}
+	    }
+	  if (bits != 0)
+	    {
+	      ASSERT (tpos < abs_xsize);
+	      tp[tpos++] = limb;
+	    }
+	  ASSERT (tpos == abs_xsize);
+
+	  MPN_COPY (xp, tp, abs_xsize);
+	  TMP_FREE;
+	}
+
+      /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
+	 limbs resulting from this.  Should be a non-zero value here, but
+	 for safety don't assume that. */
+      MPN_NORMALIZE (xp, abs_xsize);
+    }
+
+  SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
+  return abs_csize + 4;
+}
diff --git a/mpz/inp_str.c b/mpz/inp_str.c
new file mode 100644
index 0000000..0756055
--- /dev/null
+++ b/mpz/inp_str.c
@@ -0,0 +1,173 @@
+/* mpz_inp_str(dest_integer, stream, base) -- Input a number in base
+   BASE from stdio stream STREAM and store the result in DEST_INTEGER.
+
+   OF THE FUNCTIONS IN THIS FILE, ONLY mpz_inp_str IS FOR EXTERNAL USE, THE
+   REST ARE INTERNALS AND ARE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE
+   CHANGES OR DISAPPEAR COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2000-2003, 2011-2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define digit_value_tab __gmp_digit_value_tab
+
+size_t
+mpz_inp_str (mpz_ptr x, FILE *stream, int base)
+{
+  int c;
+  size_t nread;
+
+  if (stream == 0)
+    stream = stdin;
+
+  nread = 0;
+
+  /* Skip whitespace.  */
+  do
+    {
+      c = getc (stream);
+      nread++;
+    }
+  while (isspace (c));
+
+  return mpz_inp_str_nowhite (x, stream, base, c, nread);
+}
+
+/* shared by mpq_inp_str */
+size_t
+mpz_inp_str_nowhite (mpz_ptr x, FILE *stream, int base, int c, size_t nread)
+{
+  char *str;
+  size_t alloc_size, str_size;
+  int negative;
+  mp_size_t xsize;
+  const unsigned char *digit_value;
+
+  ASSERT_ALWAYS (EOF == -1);	/* FIXME: handle this by adding explicit */
+				/* comparisons of c and EOF before each  */
+				/* read of digit_value[].  */
+
+  digit_value = digit_value_tab;
+  if (base > 36)
+    {
+      /* For bases > 36, use the collating sequence
+	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
+      digit_value += 208;
+      if (UNLIKELY (base > 62))
+	return 0;		/* too large base */
+    }
+
+  negative = 0;
+  if (c == '-')
+    {
+      negative = 1;
+      c = getc (stream);
+      nread++;
+    }
+
+  if (c == EOF || digit_value[c] >= (base == 0 ? 10 : base))
+    return 0;			/* error if no digits */
+
+  /* If BASE is 0, try to find out the base by looking at the initial
+     characters.  */
+  if (base == 0)
+    {
+      base = 10;
+      if (c == '0')
+	{
+	  base = 8;
+	  c = getc (stream);
+	  nread++;
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      c = getc (stream);
+	      nread++;
+	    }
+	  else if (c == 'b' || c == 'B')
+	    {
+	      base = 2;
+	      c = getc (stream);
+	      nread++;
+	    }
+	}
+    }
+
+  /* Skip leading zeros.  */
+  while (c == '0')
+    {
+      c = getc (stream);
+      nread++;
+    }
+
+  alloc_size = 100;
+  str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
+  str_size = 0;
+
+  while (c != EOF)
+    {
+      int dig;
+      dig = digit_value[c];
+      if (dig >= base)
+	break;
+      if (str_size >= alloc_size)
+	{
+	  size_t old_alloc_size = alloc_size;
+	  alloc_size = alloc_size * 3 / 2;
+	  str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
+	}
+      str[str_size++] = dig;
+      c = getc (stream);
+    }
+  nread += str_size;
+
+  ungetc (c, stream);
+  nread--;
+
+  /* Make sure the string is not empty, mpn_set_str would fail.  */
+  if (str_size == 0)
+    {
+      SIZ (x) = 0;
+    }
+  else
+    {
+      LIMBS_PER_DIGIT_IN_BASE (xsize, str_size, base);
+      MPZ_NEWALLOC (x, xsize);
+
+      /* Convert the byte array in base BASE to our bignum format.  */
+      xsize = mpn_set_str (PTR (x), (unsigned char *) str, str_size, base);
+      SIZ (x) = negative ? -xsize : xsize;
+    }
+  (*__gmp_free_func) (str, alloc_size);
+  return nread;
+}
diff --git a/mpz/invert.c b/mpz/invert.c
new file mode 100644
index 0000000..5532d13
--- /dev/null
+++ b/mpz/invert.c
@@ -0,0 +1,72 @@
+/* mpz_invert (inv, x, n).  Find multiplicative inverse of X in Z(N).
+   If X has an inverse, return non-zero and store inverse in INVERSE,
+   otherwise, return 0 and put garbage in INVERSE.
+
+Copyright 1996-2001, 2005, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_invert (mpz_ptr inverse, mpz_srcptr x, mpz_srcptr n)
+{
+  mpz_t gcd, tmp;
+  mp_size_t xsize, nsize, size;
+  TMP_DECL;
+
+  xsize = ABSIZ (x);
+  nsize = ABSIZ (n);
+
+  size = MAX (xsize, nsize) + 1;
+  TMP_MARK;
+
+  MPZ_TMP_INIT (gcd, size);
+  MPZ_TMP_INIT (tmp, size);
+  mpz_gcdext (gcd, tmp, (mpz_ptr) 0, x, n);
+
+  /* If no inverse existed, return with an indication of that.  */
+  if (!MPZ_EQUAL_1_P (gcd))
+    {
+      TMP_FREE;
+      return 0;
+    }
+
+  /* Make sure we return a positive inverse.  */
+  if (SIZ (tmp) < 0)
+    {
+      if (SIZ (n) < 0)
+	mpz_sub (inverse, tmp, n);
+      else
+	mpz_add (inverse, tmp, n);
+    }
+  else
+    mpz_set (inverse, tmp);
+
+  TMP_FREE;
+  return 1;
+}
diff --git a/mpz/ior.c b/mpz/ior.c
new file mode 100644
index 0000000..32f3042
--- /dev/null
+++ b/mpz/ior.c
@@ -0,0 +1,184 @@
+/* mpz_ior -- Logical inclusive or.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012, 2013,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+{
+  mp_srcptr op1_ptr, op2_ptr;
+  mp_size_t op1_size, op2_size;
+  mp_ptr res_ptr;
+  mp_size_t res_size;
+  mp_size_t i;
+
+  op1_size = SIZ(op1);
+  op2_size = SIZ(op2);
+
+  if (op1_size < op2_size)
+    {
+      MPZ_SRCPTR_SWAP (op1, op2);
+      MP_SIZE_T_SWAP (op1_size, op2_size);
+    }
+
+  op1_ptr = PTR(op1);
+  res_ptr = PTR(res);
+
+  if (op2_size >= 0)
+    {
+      if (res_ptr != op1_ptr)
+	{
+	  res_ptr = MPZ_REALLOC (res, op1_size);
+	  /* No overlapping possible: op1_ptr = PTR(op1); */
+	  MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+		    op1_size - op2_size);
+	}
+      if (LIKELY (op2_size != 0))
+	mpn_ior_n (res_ptr, op1_ptr, PTR(op2), op2_size);
+
+      SIZ(res) = op1_size;
+    }
+  else
+    {
+      mp_ptr opx;
+      TMP_DECL;
+
+      TMP_MARK;
+      if (op1_size < 0)
+	{
+	  mp_ptr opy;
+
+	  /* Both operands are negative, so will be the result.
+	     -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
+	     = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
+	     = ((OP1 - 1) & (OP2 - 1)) + 1      */
+
+	  res_size = -op1_size;
+
+	  /* Possible optimization: Decrease mpn_sub precision,
+	     as we won't use the entire res of both.  */
+	  TMP_ALLOC_LIMBS_2 (opx, res_size, opy, res_size);
+	  mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
+	  op1_ptr = opx;
+
+	  mpn_sub_1 (opy, PTR(op2), res_size, (mp_limb_t) 1);
+	  op2_ptr = opy;
+
+	  /* First loop finds the size of the result.  */
+	  for (i = res_size; --i >= 0;)
+	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
+	      break;
+	  res_size = i + 1;
+
+	  res_ptr = MPZ_NEWALLOC (res, res_size + 1);
+
+	  if (res_size != 0)
+	    {
+	      /* Second loop computes the real result.  */
+	      mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
+
+	      res_ptr[res_size] = 0;
+	      MPN_INCR_U (res_ptr, res_size + 1, 1);
+	      res_size += res_ptr[res_size];
+	    }
+	  else
+	    {
+	      res_ptr[0] = 1;
+	      res_size = 1;
+	    }
+
+	  SIZ(res) = -res_size;
+	}
+      else
+	{
+	  mp_limb_t cy;
+	  mp_size_t count;
+
+	  /* Operand 2 negative, so will be the result.
+	     -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
+	     = ~(OP1 | ~(OP2 - 1)) + 1 =
+	     = (~OP1 & (OP2 - 1)) + 1      */
+
+	  op2_size = -op2_size;
+
+	  res_ptr = MPZ_REALLOC (res, op2_size);
+	  op1_ptr = PTR(op1);
+
+	  opx = TMP_ALLOC_LIMBS (op2_size);
+	  mpn_sub_1 (opx, PTR(op2), op2_size, (mp_limb_t) 1);
+	  op2_ptr = opx;
+	  op2_size -= op2_ptr[op2_size - 1] == 0;
+
+	  if (op1_size >= op2_size)
+	    {
+	      /* We can just ignore the part of OP1 that stretches above OP2,
+		 because the result limbs are zero there.  */
+
+	      /* First loop finds the size of the result.  */
+	      for (i = op2_size; --i >= 0;)
+		if ((~op1_ptr[i] & op2_ptr[i]) != 0)
+		  break;
+	      res_size = i + 1;
+	      count = res_size;
+	    }
+	  else
+	    {
+	      res_size = op2_size;
+
+	      /* Copy the part of OP2 that stretches above OP1, to RES.  */
+	      MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
+	      count = op1_size;
+	    }
+
+	  if (res_size != 0)
+	    {
+	      /* Second loop computes the real result.  */
+	      if (LIKELY (count != 0))
+		mpn_andn_n (res_ptr, op2_ptr, op1_ptr, count);
+
+	      cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
+	      if (cy)
+		{
+		  res_ptr[res_size] = cy;
+		  ++res_size;
+		}
+	    }
+	  else
+	    {
+	      res_ptr[0] = 1;
+	      res_size = 1;
+	    }
+
+	  SIZ(res) = -res_size;
+	}
+      TMP_FREE;
+    }
+}
diff --git a/mpz/iset.c b/mpz/iset.c
new file mode 100644
index 0000000..252cada
--- /dev/null
+++ b/mpz/iset.c
@@ -0,0 +1,52 @@
+/* mpz_init_set (src_integer) -- Make a new multiple precision number with
+   a value copied from SRC_INTEGER.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp, up;
+  mp_size_t usize, size;
+
+  usize = SIZ (u);
+  size = ABS (usize);
+
+  ALLOC (w) = MAX (size, 1);
+  wp = __GMP_ALLOCATE_FUNC_LIMBS (ALLOC (w));
+
+  PTR (w) = wp;
+  up = PTR (u);
+
+  MPN_COPY (wp, up, size);
+  SIZ (w) = usize;
+}
diff --git a/mpz/iset_d.c b/mpz/iset_d.c
new file mode 100644
index 0000000..5d04a6f
--- /dev/null
+++ b/mpz/iset_d.c
@@ -0,0 +1,43 @@
+/* mpz_init_set_d(integer, val) -- Initialize and assign INTEGER with a double
+   value VAL.
+
+Copyright 1996, 2000, 2001, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set_d (mpz_ptr dest, double val)
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+
+  ALLOC (dest) = 0;
+  SIZ (dest) = 0;
+  PTR (dest) = (mp_ptr) &dummy_limb;
+  mpz_set_d (dest, val);
+}
diff --git a/mpz/iset_si.c b/mpz/iset_si.c
new file mode 100644
index 0000000..7179cb0
--- /dev/null
+++ b/mpz/iset_si.c
@@ -0,0 +1,58 @@
+/* mpz_init_set_si(dest,val) -- Make a new multiple precision in DEST and
+   assign VAL to the new number.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set_si (mpz_ptr dest, signed long int val)
+{
+  mp_size_t size;
+  mp_limb_t vl;
+
+  ALLOC (dest) = 1;
+  PTR (dest) = __GMP_ALLOCATE_FUNC_LIMBS (1);
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  PTR (dest)[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if GMP_NAIL_BITS != 0
+  if (vl > GMP_NUMB_MAX)
+    {
+      MPZ_REALLOC (dest, 2);
+      PTR (dest)[1] = vl >> GMP_NUMB_BITS;
+      size = 2;
+    }
+#endif
+
+  SIZ (dest) = val >= 0 ? size : -size;
+}
diff --git a/mpz/iset_str.c b/mpz/iset_str.c
new file mode 100644
index 0000000..2df12f9
--- /dev/null
+++ b/mpz/iset_str.c
@@ -0,0 +1,47 @@
+/* mpz_init_set_str(string, base) -- Convert the \0-terminated string STRING in
+   base BASE to a multiple precision integer.  Allow white space in the string.
+   If BASE == 0 determine the base in the C standard way, i.e.  0xhh...h means
+   base 16, 0oo...o means base 8, otherwise assume base 10.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_init_set_str (mpz_ptr x, const char *str, int base)
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  ALLOC (x) = 0;
+  PTR (x) = (mp_ptr) &dummy_limb;
+
+  /* if str has no digits mpz_set_str leaves x->_mp_size unset */
+  SIZ (x) = 0;
+
+  return mpz_set_str (x, str, base);
+}
diff --git a/mpz/iset_ui.c b/mpz/iset_ui.c
new file mode 100644
index 0000000..22a8e15
--- /dev/null
+++ b/mpz/iset_ui.c
@@ -0,0 +1,58 @@
+/* mpz_init_set_ui(dest,val) -- Make a new multiple precision in DEST and
+   assign VAL to the new number.
+
+Copyright 1991, 1993-1995, 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set_ui (mpz_ptr dest, unsigned long int val)
+{
+  mp_size_t size;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (val > GMP_NUMB_MAX)
+    {
+      ALLOC (dest) = 2;
+      PTR (dest) = __GMP_ALLOCATE_FUNC_LIMBS (2);
+      PTR (dest)[1] = val >> GMP_NUMB_BITS;
+      size = 2;
+    }
+  else
+#endif
+    {
+      ALLOC (dest) = 1;
+      PTR (dest) = __GMP_ALLOCATE_FUNC_LIMBS (1);
+
+      size = val != 0;
+    }
+  PTR (dest)[0] = val & GMP_NUMB_MASK;
+
+  SIZ (dest) = size;
+}
diff --git a/mpz/jacobi.c b/mpz/jacobi.c
new file mode 100644
index 0000000..cd556d7
--- /dev/null
+++ b/mpz/jacobi.c
@@ -0,0 +1,210 @@
+/* mpz_jacobi, mpz_legendre, mpz_kronecker -- mpz/mpz Jacobi symbols.
+
+Copyright 2000-2002, 2005, 2010-2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This code does triple duty as mpz_jacobi, mpz_legendre and
+   mpz_kronecker. For ABI compatibility, the link symbol is
+   __gmpz_jacobi, not __gmpz_kronecker, even though the latter would
+   be more logical.
+
+   mpz_jacobi could assume b is odd, but the improvements from that seem
+   small compared to other operations, and anything significant should be
+   checked at run-time since we'd like odd b to go fast in mpz_kronecker
+   too.
+
+   mpz_legendre could assume b is an odd prime, but knowing this doesn't
+   present any obvious benefits.  Result 0 wouldn't arise (unless "a" is a
+   multiple of b), but the checking for that takes little time compared to
+   other operations.
+
+   Enhancements:
+
+   mpn_bdiv_qr should be used instead of mpn_tdiv_qr.
+
+*/
+
+int
+mpz_jacobi (mpz_srcptr a, mpz_srcptr b)
+{
+  mp_srcptr  asrcp, bsrcp;
+  mp_size_t  asize, bsize;
+  mp_limb_t  alow, blow;
+  mp_ptr     ap, bp;
+  unsigned   btwos;
+  int        result_bit1;
+  int        res;
+  TMP_DECL;
+
+  asize = SIZ(a);
+  asrcp = PTR(a);
+  alow = asrcp[0];
+
+  bsize = SIZ(b);
+  bsrcp = PTR(b);
+  blow = bsrcp[0];
+
+  /* The MPN jacobi functions require positive a and b, and b odd. So
+     we must to handle the cases of a or b zero, then signs, and then
+     the case of even b.
+  */
+
+  if (bsize == 0)
+    /* (a/0) = [ a = 1 or a = -1 ] */
+    return JACOBI_LS0 (alow, asize);
+
+  if (asize == 0)
+    /* (0/b) = [ b = 1 or b = - 1 ] */
+    return JACOBI_0LS (blow, bsize);
+
+  if ( (((alow | blow) & 1) == 0))
+    /* Common factor of 2 ==> (a/b) = 0 */
+    return 0;
+
+  if (bsize < 0)
+    {
+      /* (a/-1) = -1 if a < 0, +1 if a >= 0 */
+      result_bit1 = (asize < 0) << 1;
+      bsize = -bsize;
+    }
+  else
+    result_bit1 = 0;
+
+  JACOBI_STRIP_LOW_ZEROS (result_bit1, alow, bsrcp, bsize, blow);
+
+  count_trailing_zeros (btwos, blow);
+  blow >>= btwos;
+
+  if (bsize > 1 && btwos > 0)
+    {
+      mp_limb_t b1 = bsrcp[1];
+      blow |= b1 << (GMP_NUMB_BITS - btwos);
+      if (bsize == 2 && (b1 >> btwos) == 0)
+	bsize = 1;
+    }
+
+  if (asize < 0)
+    {
+      /* (-1/b) = -1 iff b = 3 (mod 4) */
+      result_bit1 ^= JACOBI_N1B_BIT1(blow);
+      asize = -asize;
+    }
+
+  JACOBI_STRIP_LOW_ZEROS (result_bit1, blow, asrcp, asize, alow);
+
+  /* Ensure asize >= bsize. Take advantage of the generalized
+     reciprocity law (a/b*2^n) = (b*2^n / a) * RECIP(a,b) */
+
+  if (asize < bsize)
+    {
+      MPN_SRCPTR_SWAP (asrcp, asize, bsrcp, bsize);
+      MP_LIMB_T_SWAP (alow, blow);
+
+      /* NOTE: The value of alow (old blow) is a bit subtle. For this code
+	 path, we get alow as the low, always odd, limb of shifted A. Which is
+	 what we need for the reciprocity update below.
+
+	 However, all other uses of alow assumes that it is *not*
+	 shifted. Luckily, alow matters only when either
+
+	 + btwos > 0, in which case A is always odd
+
+	 + asize == bsize == 1, in which case this code path is never
+	   taken. */
+
+      count_trailing_zeros (btwos, blow);
+      blow >>= btwos;
+
+      if (bsize > 1 && btwos > 0)
+	{
+	  mp_limb_t b1 = bsrcp[1];
+	  blow |= b1 << (GMP_NUMB_BITS - btwos);
+	  if (bsize == 2 && (b1 >> btwos) == 0)
+	    bsize = 1;
+	}
+
+      result_bit1 ^= JACOBI_RECIP_UU_BIT1 (alow, blow);
+    }
+
+  if (bsize == 1)
+    {
+      result_bit1 ^= JACOBI_TWOS_U_BIT1(btwos, alow);
+
+      if (blow == 1)
+	return JACOBI_BIT1_TO_PN (result_bit1);
+
+      if (asize > 1)
+	JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, alow, asrcp, asize, blow);
+
+      return mpn_jacobi_base (alow, blow, result_bit1);
+    }
+
+  /* Allocation strategy: For A, we allocate a working copy only for A % B, but
+     when A is much larger than B, we have to allocate space for the large
+     quotient. We use the same area, pointed to by bp, for both the quotient
+     A/B and the working copy of B. */
+
+  TMP_MARK;
+
+  if (asize >= 2*bsize)
+    TMP_ALLOC_LIMBS_2 (ap, bsize, bp, asize - bsize + 1);
+  else
+    TMP_ALLOC_LIMBS_2 (ap, bsize, bp, bsize);
+
+  /* In the case of even B, we conceptually shift out the powers of two first,
+     and then divide A mod B. Hence, when taking those powers of two into
+     account, we must use alow *before* the division. Doing the actual division
+     first is ok, because the point is to remove multiples of B from A, and
+     multiples of 2^k B are good enough. */
+  if (asize > bsize)
+    mpn_tdiv_qr (bp, ap, 0, asrcp, asize, bsrcp, bsize);
+  else
+    MPN_COPY (ap, asrcp, bsize);
+
+  if (btwos > 0)
+    {
+      result_bit1 ^= JACOBI_TWOS_U_BIT1(btwos, alow);
+
+      ASSERT_NOCARRY (mpn_rshift (bp, bsrcp, bsize, btwos));
+      bsize -= (ap[bsize-1] | bp[bsize-1]) == 0;
+    }
+  else
+    MPN_COPY (bp, bsrcp, bsize);
+
+  ASSERT (blow == bp[0]);
+  res = mpn_jacobi_n (ap, bp, bsize,
+		      mpn_jacobi_init (ap[0], blow, (result_bit1>>1) & 1));
+
+  TMP_FREE;
+  return res;
+}
diff --git a/mpz/kronsz.c b/mpz/kronsz.c
new file mode 100644
index 0000000..92cc971
--- /dev/null
+++ b/mpz/kronsz.c
@@ -0,0 +1,137 @@
+/* mpz_si_kronecker -- long+mpz Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_si_kronecker (long a, mpz_srcptr b)
+{
+  mp_srcptr  b_ptr;
+  mp_limb_t  b_low;
+  mp_size_t  b_size;
+  mp_size_t  b_abs_size;
+  mp_limb_t  a_limb, b_rem;
+  unsigned   twos;
+  int        result_bit1;
+
+#if GMP_NUMB_BITS < BITS_PER_ULONG
+  if (a > GMP_NUMB_MAX || a < -GMP_NUMB_MAX)
+    {
+      mp_limb_t  alimbs[2];
+      mpz_t      az;
+      ALLOC(az) = numberof (alimbs);
+      PTR(az) = alimbs;
+      mpz_set_si (az, a);
+      return mpz_kronecker (az, b);
+    }
+#endif
+
+  b_size = SIZ (b);
+  if (b_size == 0)
+    return JACOBI_S0 (a);  /* (a/0) */
+
+  /* account for the effect of the sign of b, then ignore it */
+  result_bit1 = JACOBI_BSGN_SS_BIT1 (a, b_size);
+
+  b_ptr = PTR(b);
+  b_low = b_ptr[0];
+  b_abs_size = ABS (b_size);
+
+  if ((b_low & 1) != 0)
+    {
+      /* b odd */
+
+      result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a, b_low);
+      a_limb = ABS_CAST(mp_limb_t, a);
+
+      if ((a_limb & 1) == 0)
+	{
+	  /* (0/b)=1 for b=+/-1, 0 otherwise */
+	  if (a_limb == 0)
+	    return (b_abs_size == 1 && b_low == 1);
+
+	  /* a even, b odd */
+	  count_trailing_zeros (twos, a_limb);
+	  a_limb >>= twos;
+	  /* (a*2^n/b) = (a/b) * twos(n,a) */
+	  result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b_low);
+	}
+    }
+  else
+    {
+      /* (even/even)=0, and (0/b)=0 for b!=+/-1 */
+      if ((a & 1) == 0)
+	return 0;
+
+      /* a odd, b even
+
+	 Establish shifted b_low with valid bit1 for ASGN and RECIP below.
+	 Zero limbs stripped are accounted for, but zero bits on b_low are
+	 not because they remain in {b_ptr,b_abs_size} for the
+	 JACOBI_MOD_OR_MODEXACT_1_ODD. */
+
+      JACOBI_STRIP_LOW_ZEROS (result_bit1, a, b_ptr, b_abs_size, b_low);
+      if ((b_low & 1) == 0)
+	{
+	  if (UNLIKELY (b_low == GMP_NUMB_HIGHBIT))
+	    {
+	      /* need b_ptr[1] to get bit1 in b_low */
+	      if (b_abs_size == 1)
+		{
+		  /* (a/0x80000000) = (a/2)^(BPML-1) */
+		  if ((GMP_NUMB_BITS % 2) == 0)
+		    result_bit1 ^= JACOBI_TWO_U_BIT1 (a);
+		  return JACOBI_BIT1_TO_PN (result_bit1);
+		}
+
+	      /* b_abs_size > 1 */
+	      b_low = b_ptr[1] << 1;
+	    }
+	  else
+	    {
+	      count_trailing_zeros (twos, b_low);
+	      b_low >>= twos;
+	    }
+	}
+
+      result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a, b_low);
+      a_limb = (unsigned long) ABS(a);
+    }
+
+  if (a_limb == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (1/b)=1 */
+
+  /* (a/b*2^n) = (b*2^n mod a / a) * recip(a,b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, b_rem, b_ptr, b_abs_size, a_limb);
+  result_bit1 ^= JACOBI_RECIP_UU_BIT1 (a_limb, b_low);
+  return mpn_jacobi_base (b_rem, a_limb, result_bit1);
+}
diff --git a/mpz/kronuz.c b/mpz/kronuz.c
new file mode 100644
index 0000000..ba5c6dd
--- /dev/null
+++ b/mpz/kronuz.c
@@ -0,0 +1,129 @@
+/* mpz_ui_kronecker -- ulong+mpz Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_ui_kronecker (unsigned long a, mpz_srcptr b)
+{
+  mp_srcptr  b_ptr;
+  mp_limb_t  b_low;
+  int        b_abs_size;
+  mp_limb_t  b_rem;
+  int        twos;
+  int        result_bit1;
+
+  /* (a/-1)=1 when a>=0, so the sign of b is ignored */
+  b_abs_size = ABSIZ (b);
+
+  if (b_abs_size == 0)
+    return JACOBI_U0 (a);  /* (a/0) */
+
+  if (a > GMP_NUMB_MAX)
+    {
+      mp_limb_t  alimbs[2];
+      mpz_t      az;
+      ALLOC(az) = numberof (alimbs);
+      PTR(az) = alimbs;
+      mpz_set_ui (az, a);
+      return mpz_kronecker (az, b);
+    }
+
+  b_ptr = PTR(b);
+  b_low = b_ptr[0];
+  result_bit1 = 0;
+
+  if (! (b_low & 1))
+    {
+      /* (0/b)=0 for b!=+/-1; and (even/even)=0 */
+      if (! (a & 1))
+	return 0;
+
+      /* a odd, b even
+
+	 Establish shifted b_low with valid bit1 for the RECIP below.  Zero
+	 limbs stripped are accounted for, but zero bits on b_low are not
+	 because they remain in {b_ptr,b_abs_size} for
+	 JACOBI_MOD_OR_MODEXACT_1_ODD. */
+
+      JACOBI_STRIP_LOW_ZEROS (result_bit1, a, b_ptr, b_abs_size, b_low);
+      if (! (b_low & 1))
+	{
+	  if (UNLIKELY (b_low == GMP_NUMB_HIGHBIT))
+	    {
+	      /* need b_ptr[1] to get bit1 in b_low */
+	      if (b_abs_size == 1)
+		{
+		  /* (a/0x80...00) == (a/2)^(NUMB-1) */
+		  if ((GMP_NUMB_BITS % 2) == 0)
+		    {
+		      /* JACOBI_STRIP_LOW_ZEROS does nothing to result_bit1
+			 when GMP_NUMB_BITS is even, so it's still 0. */
+		      ASSERT (result_bit1 == 0);
+		      result_bit1 = JACOBI_TWO_U_BIT1 (a);
+		    }
+		  return JACOBI_BIT1_TO_PN (result_bit1);
+		}
+
+	      /* b_abs_size > 1 */
+	      b_low = b_ptr[1] << 1;
+	    }
+	  else
+	    {
+	      count_trailing_zeros (twos, b_low);
+	      b_low >>= twos;
+	    }
+	}
+    }
+  else
+    {
+      if (a == 0)        /* (0/b)=1 for b=+/-1, 0 otherwise */
+	return (b_abs_size == 1 && b_low == 1);
+
+      if (! (a & 1))
+	{
+	  /* a even, b odd */
+	  count_trailing_zeros (twos, a);
+	  a >>= twos;
+	  /* (a*2^n/b) = (a/b) * (2/a)^n */
+	  result_bit1 = JACOBI_TWOS_U_BIT1 (twos, b_low);
+	}
+    }
+
+  if (a == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (1/b)=1 */
+
+  /* (a/b*2^n) = (b*2^n mod a / a) * RECIP(a,b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, b_rem, b_ptr, b_abs_size, a);
+  result_bit1 ^= JACOBI_RECIP_UU_BIT1 (a, b_low);
+  return mpn_jacobi_base (b_rem, (mp_limb_t) a, result_bit1);
+}
diff --git a/mpz/kronzs.c b/mpz/kronzs.c
new file mode 100644
index 0000000..1f63f15
--- /dev/null
+++ b/mpz/kronzs.c
@@ -0,0 +1,92 @@
+/* mpz_kronecker_si -- mpz+long Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* After the absolute value of b is established it's treated as an unsigned
+   long, because 0x80..00 doesn't fit in a signed long. */
+
+int
+mpz_kronecker_si (mpz_srcptr a, long b)
+{
+  mp_srcptr  a_ptr;
+  mp_size_t  a_size;
+  mp_limb_t  a_rem, b_limb;
+  int        result_bit1;
+
+  a_size = SIZ(a);
+  if (a_size == 0)
+    return JACOBI_0S (b);
+
+#if GMP_NUMB_BITS < BITS_PER_ULONG
+  if (b > GMP_NUMB_MAX || b < -GMP_NUMB_MAX)
+    {
+      mp_limb_t  blimbs[2];
+      mpz_t      bz;
+      ALLOC(bz) = numberof (blimbs);
+      PTR(bz) = blimbs;
+      mpz_set_si (bz, b);
+      return mpz_kronecker (a, bz);
+    }
+#endif
+
+  result_bit1 = JACOBI_BSGN_SS_BIT1 (a_size, b);
+  b_limb = ABS_CAST (unsigned long, b);
+  a_ptr = PTR(a);
+
+  if ((b_limb & 1) == 0)
+    {
+      mp_limb_t  a_low = a_ptr[0];
+      int        twos;
+
+      if (b_limb == 0)
+	return JACOBI_LS0 (a_low, a_size);   /* (a/0) */
+
+      if (! (a_low & 1))
+	return 0;  /* (even/even)=0 */
+
+      /* (a/2)=(2/a) for a odd */
+      count_trailing_zeros (twos, b_limb);
+      b_limb >>= twos;
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, a_low);
+    }
+
+  if (b_limb == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (a/1)=1 for any a */
+
+  result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a_size, b_limb);
+  a_size = ABS(a_size);
+
+  /* (a/b) = (a mod b / b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, a_rem, a_ptr, a_size, b_limb);
+  return mpn_jacobi_base (a_rem, b_limb, result_bit1);
+}
diff --git a/mpz/kronzu.c b/mpz/kronzu.c
new file mode 100644
index 0000000..b4fbf79
--- /dev/null
+++ b/mpz/kronzu.c
@@ -0,0 +1,88 @@
+/* mpz_kronecker_ui -- mpz+ulong Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_kronecker_ui (mpz_srcptr a, unsigned long b)
+{
+  mp_srcptr  a_ptr;
+  mp_size_t  a_size;
+  mp_limb_t  a_rem;
+  int        result_bit1;
+
+  a_size = SIZ(a);
+  if (a_size == 0)
+    return JACOBI_0U (b);
+
+  if (b > GMP_NUMB_MAX)
+    {
+      mp_limb_t  blimbs[2];
+      mpz_t      bz;
+      ALLOC(bz) = numberof (blimbs);
+      PTR(bz) = blimbs;
+      mpz_set_ui (bz, b);
+      return mpz_kronecker (a, bz);
+    }
+
+  a_ptr = PTR(a);
+  if ((b & 1) != 0)
+    {
+      result_bit1 = JACOBI_ASGN_SU_BIT1 (a_size, b);
+    }
+  else
+    {
+      mp_limb_t  a_low = a_ptr[0];
+      int        twos;
+
+      if (b == 0)
+	return JACOBI_LS0 (a_low, a_size);   /* (a/0) */
+
+      if (! (a_low & 1))
+	return 0;  /* (even/even)=0 */
+
+      /* (a/2)=(2/a) for a odd */
+      count_trailing_zeros (twos, b);
+      b >>= twos;
+      result_bit1 = (JACOBI_TWOS_U_BIT1 (twos, a_low)
+		     ^ JACOBI_ASGN_SU_BIT1 (a_size, b));
+    }
+
+  if (b == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (a/1)=1 for any a */
+
+  a_size = ABS(a_size);
+
+  /* (a/b) = (a mod b / b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, a_rem, a_ptr, a_size, b);
+  return mpn_jacobi_base (a_rem, (mp_limb_t) b, result_bit1);
+}
diff --git a/mpz/lcm.c b/mpz/lcm.c
new file mode 100644
index 0000000..2807ef7
--- /dev/null
+++ b/mpz/lcm.c
@@ -0,0 +1,87 @@
+/* mpz_lcm -- mpz/mpz least common multiple.
+
+Copyright 1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_lcm (mpz_ptr r, mpz_srcptr u, mpz_srcptr v)
+{
+  mpz_t g;
+  mp_size_t usize, vsize;
+  TMP_DECL;
+
+  usize = SIZ (u);
+  vsize = SIZ (v);
+  if (usize == 0 || vsize == 0)
+    {
+      SIZ (r) = 0;
+      return;
+    }
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  if (vsize == 1 || usize == 1)
+    {
+      mp_limb_t  vl, gl, c;
+      mp_srcptr  up;
+      mp_ptr     rp;
+
+      if (usize == 1)
+	{
+	  usize = vsize;
+	  MPZ_SRCPTR_SWAP (u, v);
+	}
+
+      MPZ_REALLOC (r, usize+1);
+
+      up = PTR(u);
+      vl = PTR(v)[0];
+      gl = mpn_gcd_1 (up, usize, vl);
+      vl /= gl;
+
+      rp = PTR(r);
+      c = mpn_mul_1 (rp, up, usize, vl);
+      rp[usize] = c;
+      usize += (c != 0);
+      SIZ(r) = usize;
+      return;
+    }
+
+  TMP_MARK;
+  MPZ_TMP_INIT (g, usize); /* v != 0 implies |gcd(u,v)| <= |u| */
+
+  mpz_gcd (g, u, v);
+  mpz_divexact (g, u, g);
+  mpz_mul (r, g, v);
+
+  SIZ (r) = ABS (SIZ (r));	/* result always positive */
+
+  TMP_FREE;
+}
diff --git a/mpz/lcm_ui.c b/mpz/lcm_ui.c
new file mode 100644
index 0000000..1f199b7
--- /dev/null
+++ b/mpz/lcm_ui.c
@@ -0,0 +1,78 @@
+/* mpz_lcm_ui -- least common multiple of mpz and ulong.
+
+Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpz_lcm_ui (mpz_ptr r, mpz_srcptr u, unsigned long v)
+{
+  mp_size_t      usize;
+  mp_srcptr      up;
+  mp_ptr         rp;
+  unsigned long  g;
+  mp_limb_t      c;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpz_t vz;
+      mp_limb_t vlimbs[2];
+      vlimbs[0] = v & GMP_NUMB_MASK;
+      vlimbs[1] = v >> GMP_NUMB_BITS;
+      PTR(vz) = vlimbs;
+      SIZ(vz) = 2;
+      mpz_lcm (r, u, vz);
+      return;
+    }
+#endif
+
+  /* result zero if either operand zero */
+  usize = SIZ(u);
+  if (usize == 0 || v == 0)
+    {
+      SIZ(r) = 0;
+      return;
+    }
+  usize = ABS(usize);
+
+  MPZ_REALLOC (r, usize+1);
+
+  up = PTR(u);
+  g = (unsigned long) mpn_gcd_1 (up, usize, (mp_limb_t) v);
+  v /= g;
+
+  rp = PTR(r);
+  c = mpn_mul_1 (rp, up, usize, (mp_limb_t) v);
+  rp[usize] = c;
+  usize += (c != 0);
+  SIZ(r) = usize;
+}
diff --git a/mpz/limbs_finish.c b/mpz/limbs_finish.c
new file mode 100644
index 0000000..a02839d
--- /dev/null
+++ b/mpz/limbs_finish.c
@@ -0,0 +1,39 @@
+/* mpz_finish_limbs -- Update mpz after writing to the limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_limbs_finish (mpz_ptr x, mp_size_t xs)
+{
+  mp_size_t xn = ABS(xs);
+  MPN_NORMALIZE (PTR (x), xn);
+  SIZ (x) = xs < 0 ? -xn : xn;
+}
diff --git a/mpz/limbs_modify.c b/mpz/limbs_modify.c
new file mode 100644
index 0000000..a778b6e
--- /dev/null
+++ b/mpz/limbs_modify.c
@@ -0,0 +1,38 @@
+/* mpz_limbs_modify -- Read-and-modify access to the mpn-style limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_ptr
+mpz_limbs_modify (mpz_ptr x, mp_size_t n)
+{
+  ASSERT (n > 0);
+  return MPZ_REALLOC (x, n);
+}
diff --git a/mpz/limbs_read.c b/mpz/limbs_read.c
new file mode 100644
index 0000000..705f0c1
--- /dev/null
+++ b/mpz/limbs_read.c
@@ -0,0 +1,37 @@
+/* mpz_limbs_read -- Read access to the mpn-style limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_srcptr
+mpz_limbs_read (mpz_srcptr x)
+{
+  return PTR(x);
+}
diff --git a/mpz/limbs_write.c b/mpz/limbs_write.c
new file mode 100644
index 0000000..b116ad0
--- /dev/null
+++ b/mpz/limbs_write.c
@@ -0,0 +1,38 @@
+/* mpz_limbs_write -- Write access to the mpn-style limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_ptr
+mpz_limbs_write (mpz_ptr x, mp_size_t n)
+{
+  ASSERT (n > 0);
+  return MPZ_NEWALLOC (x, n);
+}
diff --git a/mpz/lucmod.c b/mpz/lucmod.c
new file mode 100644
index 0000000..0dad48c
--- /dev/null
+++ b/mpz/lucmod.c
@@ -0,0 +1,127 @@
+/* mpz_lucas_mod -- Helper function for the strong Lucas
+   primality test.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2018 Free Software Foundation, Inc.
+
+Contributed by Marco Bodrato.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes V_{k+1}, Q^{k+1} (mod n) for the Lucas' sequence	*/
+/* with P=1, Q=Q; k = n>>b0.	*/
+/* Requires n > 4; b0 > 0; -2*Q must not overflow a long.	*/
+/* If U_{k+1}==0 (mod n) or V_{k+1}==0 (mod n), it returns 1,	*/
+/* otherwise it returns 0 and sets V=V_{k+1} and Qk=Q^{k+1}.	*/
+/* V will never grow beyond SIZ(n), Qk not beyond 2*SIZ(n).	*/
+int
+mpz_lucas_mod (mpz_ptr V, mpz_ptr Qk, long Q,
+	       mp_bitcnt_t b0, mpz_srcptr n, mpz_ptr T1, mpz_ptr T2)
+{
+  mp_bitcnt_t bs;
+  int res;
+
+  ASSERT (b0 > 0);
+  ASSERT (SIZ (n) > 1 || SIZ (n) > 0 && PTR (n) [0] > 4);
+
+  mpz_set_ui (V, 1); /* U1 = 1 */
+  bs = mpz_sizeinbase (n, 2) - 2;
+  if (UNLIKELY (bs < b0))
+    {
+      /* n = 2^b0 - 1, should we use Lucas-Lehmer instead? */
+      ASSERT (bs == b0 - 2);
+      mpz_set_si (Qk, Q);
+      return 0;
+    }
+  mpz_set_ui (Qk, 1); /* U2 = 1 */
+
+  do
+    {
+      /* We use the iteration suggested in "Elementary Number Theory"	*/
+      /* by Peter Hackman (November 1, 2009), section "L.XVII Scalar	*/
+      /* Formulas", from http://hackmat.se/kurser/TATM54/booktot.pdf	*/
+      /* U_{2k} = 2*U_{k+1}*U_k - P*U_k^2	*/
+      /* U_{2k+1} = U_{k+1}^2  - Q*U_k^2	*/
+      /* U_{2k+2} = P*U_{k+1}^2 - 2*Q*U_{k+1}*U_k	*/
+      /* We note that U_{2k+2} = P*U_{2k+1} - Q*U_{2k}	*/
+      /* The formulas are specialized for P=1, and only squares:	*/
+      /* U_{2k}   = U_{k+1}^2 - |U_{k+1} - U_k|^2	*/
+      /* U_{2k+1} = U_{k+1}^2 - Q*U_k^2		*/
+      /* U_{2k+2} = U_{2k+1}  - Q*U_{2k}	*/
+      mpz_mul (T1, Qk, Qk);	/* U_{k+1}^2		*/
+      mpz_sub (Qk, V, Qk);	/* |U_{k+1} - U_k|	*/
+      mpz_mul (T2, Qk, Qk);	/* |U_{k+1} - U_k|^2	*/
+      mpz_mul (Qk, V, V);	/* U_k^2		*/
+      mpz_sub (T2, T1, T2);	/* U_{k+1}^2 - (U_{k+1} - U_k)^2	*/
+      if (Q > 0)		/* U_{k+1}^2 - Q U_k^2 = U_{2k+1}	*/
+	mpz_submul_ui (T1, Qk, Q);
+      else
+	mpz_addmul_ui (T1, Qk, NEG_CAST (unsigned long, Q));
+
+      /* A step k->k+1 is performed if the bit in $n$ is 1	*/
+      if (mpz_tstbit (n, bs))
+	{
+	  /* U_{2k+2} = U_{2k+1} - Q*U_{2k}	*/
+	  mpz_mul_si (T2, T2, Q);
+	  mpz_sub (T2, T1, T2);
+	  mpz_swap (T1, T2);
+	}
+      mpz_tdiv_r (Qk, T1, n);
+      mpz_tdiv_r (V, T2, n);
+    } while (--bs >= b0);
+
+  res = SIZ (Qk) == 0;
+  if (!res) {
+    mpz_mul_si (T1, V, -2*Q);
+    mpz_add (T1, Qk, T1);	/* V_k = U_k - 2Q*U_{k-1} */
+    mpz_tdiv_r (V, T1, n);
+    res = SIZ (V) == 0;
+    if (!res && b0 > 1) {
+      /* V_k and Q^k will be needed for further check, compute them.	*/
+      /* FIXME: Here we compute V_k^2 and store V_k, but the former	*/
+      /* will be recomputed by the calling function, shoul we store	*/
+      /* that instead?							*/
+      mpz_mul (T2, T1, T1);	/* V_k^2 */
+      mpz_mul (T1, Qk, Qk);	/* P^2 U_k^2 = U_k^2 */
+      mpz_sub (T2, T2, T1);
+      ASSERT (SIZ (T2) == 0 || PTR (T2) [0] % 4 == 0);
+      mpz_tdiv_q_2exp (T2, T2, 2);	/* (V_k^2 - P^2 U_k^2) / 4 */
+      if (Q > 0)		/* (V_k^2 - (P^2 -4Q) U_k^2) / 4 = Q^k */
+	mpz_addmul_ui (T2, T1, Q);
+      else
+	mpz_submul_ui (T2, T1, NEG_CAST (unsigned long, Q));
+      mpz_tdiv_r (Qk, T2, n);
+    }
+  }
+
+  return res;
+}
diff --git a/mpz/lucnum2_ui.c b/mpz/lucnum2_ui.c
new file mode 100644
index 0000000..3cc3d7b
--- /dev/null
+++ b/mpz/lucnum2_ui.c
@@ -0,0 +1,94 @@
+/* mpz_lucnum2_ui -- calculate Lucas numbers.
+
+Copyright 2001, 2003, 2005, 2012, 2015, 2016, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+void
+mpz_lucnum2_ui (mpz_ptr ln, mpz_ptr lnsub1, unsigned long n)
+{
+  mp_ptr     lp, l1p, f1p;
+  mp_size_t  size;
+  mp_limb_t  c;
+  TMP_DECL;
+
+  ASSERT (ln != lnsub1);
+
+  /* handle small n quickly, and hide the special case for L[-1]=-1 */
+  if (n <= FIB_TABLE_LUCNUM_LIMIT)
+    {
+      mp_limb_t  f  = FIB_TABLE (n);
+      mp_limb_t  f1 = FIB_TABLE ((int) n - 1);
+
+      /* L[n] = F[n] + 2F[n-1] */
+      MPZ_NEWALLOC (ln, 1)[0] = f + 2*f1;
+      SIZ(ln) = 1;
+
+      /* L[n-1] = 2F[n] - F[n-1], but allow for L[-1]=-1 */
+      MPZ_NEWALLOC (lnsub1, 1)[0] = (n == 0 ? 1 : 2*f - f1);
+      SIZ(lnsub1) = (n == 0 ? -1 : 1);
+
+      return;
+    }
+
+  TMP_MARK;
+  size = MPN_FIB2_SIZE (n);
+  f1p = TMP_ALLOC_LIMBS (size);
+
+  lp  = MPZ_NEWALLOC (ln,     size+1);
+  l1p = MPZ_NEWALLOC (lnsub1, size+1);
+
+  size = mpn_fib2_ui (l1p, f1p, n);
+
+  /* L[n] = F[n] + 2F[n-1] */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  c = mpn_addlsh1_n (lp, l1p, f1p, size);
+#else
+  c = mpn_lshift (lp, f1p, size, 1);
+  c += mpn_add_n (lp, lp, l1p, size);
+#endif
+  lp[size] = c;
+  SIZ(ln) = size + (c != 0);
+
+  /* L[n-1] = 2F[n] - F[n-1] */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  c = mpn_rsblsh1_n (l1p, f1p, l1p, size);
+#else
+  c = mpn_lshift (l1p, l1p, size, 1);
+  c -= mpn_sub_n (l1p, l1p, f1p, size);
+#endif
+  ASSERT ((mp_limb_signed_t) c >= 0);
+  l1p[size] = c;
+  SIZ(lnsub1) = size + (c != 0);
+
+  TMP_FREE;
+}
diff --git a/mpz/lucnum_ui.c b/mpz/lucnum_ui.c
new file mode 100644
index 0000000..4213bb7
--- /dev/null
+++ b/mpz/lucnum_ui.c
@@ -0,0 +1,208 @@
+/* mpz_lucnum_ui -- calculate Lucas number.
+
+Copyright 2001, 2003, 2005, 2011, 2012, 2015, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* Notes:
+
+   For the +4 in L[2k+1] when k is even, all L[4m+3] == 4, 5 or 7 mod 8, so
+   there can't be an overflow applying +4 to just the low limb (since that
+   would leave 0, 1, 2 or 3 mod 8).
+
+   For the -4 in L[2k+1] when k is even, it seems (no proof) that
+   L[3*2^(b-2)-3] == -4 mod 2^b, so for instance with a 32-bit limb
+   L[0xBFFFFFFD] == 0xFFFFFFFC mod 2^32, and this implies a borrow from the
+   low limb.  Obviously L[0xBFFFFFFD] is a huge number, but it's at least
+   conceivable to calculate it, so it probably should be handled.
+
+   For the -2 in L[2k] with k even, it seems (no proof) L[2^(b-1)] == -1 mod
+   2^b, so for instance in 32-bits L[0x80000000] has a low limb of
+   0xFFFFFFFF so there would have been a borrow.  Again L[0x80000000] is
+   obviously huge, but probably should be made to work.  */
+
+void
+mpz_lucnum_ui (mpz_ptr ln, unsigned long n)
+{
+  mp_size_t  lalloc, xalloc, lsize, xsize;
+  mp_ptr     lp, xp;
+  mp_limb_t  c;
+  int        zeros;
+  TMP_DECL;
+
+  TRACE (printf ("mpn_lucnum_ui n=%lu\n", n));
+
+  if (n <= FIB_TABLE_LUCNUM_LIMIT)
+    {
+      /* L[n] = F[n] + 2F[n-1] */
+      MPZ_NEWALLOC (ln, 1)[0] = FIB_TABLE(n) + 2 * FIB_TABLE ((int) n - 1);
+      SIZ(ln) = 1;
+      return;
+    }
+
+  /* +1 since L[n]=F[n]+2F[n-1] might be 1 limb bigger than F[n], further +1
+     since square or mul used below might need an extra limb over the true
+     size */
+  lalloc = MPN_FIB2_SIZE (n) + 2;
+  lp = MPZ_NEWALLOC (ln, lalloc);
+
+  TMP_MARK;
+  xalloc = lalloc;
+  xp = TMP_ALLOC_LIMBS (xalloc);
+
+  /* Strip trailing zeros from n, until either an odd number is reached
+     where the L[2k+1] formula can be used, or until n fits within the
+     FIB_TABLE data.  The table is preferred of course.  */
+  zeros = 0;
+  for (;;)
+    {
+      if (n & 1)
+	{
+	  /* L[2k+1] = 5*F[k-1]*(2*F[k]+F[k-1]) - 4*(-1)^k */
+
+	  mp_size_t  yalloc, ysize;
+	  mp_ptr     yp;
+
+	  TRACE (printf ("  initial odd n=%lu\n", n));
+
+	  yalloc = MPN_FIB2_SIZE (n/2);
+	  yp = TMP_ALLOC_LIMBS (yalloc);
+	  ASSERT (xalloc >= yalloc);
+
+	  xsize = mpn_fib2_ui (xp, yp, n/2);
+
+	  /* possible high zero on F[k-1] */
+	  ysize = xsize;
+	  ysize -= (yp[ysize-1] == 0);
+	  ASSERT (yp[ysize-1] != 0);
+
+	  /* xp = 2*F[k] + F[k-1] */
+#if HAVE_NATIVE_mpn_addlsh1_n
+	  c = mpn_addlsh1_n (xp, yp, xp, xsize);
+#else
+	  c = mpn_lshift (xp, xp, xsize, 1);
+	  c += mpn_add_n (xp, xp, yp, xsize);
+#endif
+	  ASSERT (xalloc >= xsize+1);
+	  xp[xsize] = c;
+	  xsize += (c != 0);
+	  ASSERT (xp[xsize-1] != 0);
+
+	  ASSERT (lalloc >= xsize + ysize);
+	  c = mpn_mul (lp, xp, xsize, yp, ysize);
+	  lsize = xsize + ysize;
+	  lsize -= (c == 0);
+
+	  /* lp = 5*lp */
+#if HAVE_NATIVE_mpn_addlsh2_n
+	  c = mpn_addlsh2_n (lp, lp, lp, lsize);
+#else
+	  /* FIXME: Is this faster than mpn_mul_1 ? */
+	  c = mpn_lshift (xp, lp, lsize, 2);
+	  c += mpn_add_n (lp, lp, xp, lsize);
+#endif
+	  ASSERT (lalloc >= lsize+1);
+	  lp[lsize] = c;
+	  lsize += (c != 0);
+
+	  /* lp = lp - 4*(-1)^k */
+	  if (n & 2)
+	    {
+	      /* no overflow, see comments above */
+	      ASSERT (lp[0] <= MP_LIMB_T_MAX-4);
+	      lp[0] += 4;
+	    }
+	  else
+	    {
+	      /* won't go negative */
+	      MPN_DECR_U (lp, lsize, CNST_LIMB(4));
+	    }
+
+	  TRACE (mpn_trace ("  l",lp, lsize));
+	  break;
+	}
+
+      MP_PTR_SWAP (xp, lp); /* balance the swaps wanted in the L[2k] below */
+      zeros++;
+      n /= 2;
+
+      if (n <= FIB_TABLE_LUCNUM_LIMIT)
+	{
+	  /* L[n] = F[n] + 2F[n-1] */
+	  lp[0] = FIB_TABLE (n) + 2 * FIB_TABLE ((int) n - 1);
+	  lsize = 1;
+
+	  TRACE (printf ("  initial small n=%lu\n", n);
+		 mpn_trace ("  l",lp, lsize));
+	  break;
+	}
+    }
+
+  for ( ; zeros != 0; zeros--)
+    {
+      /* L[2k] = L[k]^2 + 2*(-1)^k */
+
+      TRACE (printf ("  zeros=%d\n", zeros));
+
+      ASSERT (xalloc >= 2*lsize);
+      mpn_sqr (xp, lp, lsize);
+      lsize *= 2;
+      lsize -= (xp[lsize-1] == 0);
+
+      /* First time around the loop k==n determines (-1)^k, after that k is
+	 always even and we set n=0 to indicate that.  */
+      if (n & 1)
+	{
+	  /* L[n]^2 == 0 or 1 mod 4, like all squares, so +2 gives no carry */
+	  ASSERT (xp[0] <= MP_LIMB_T_MAX-2);
+	  xp[0] += 2;
+	  n = 0;
+	}
+      else
+	{
+	  /* won't go negative */
+	  MPN_DECR_U (xp, lsize, CNST_LIMB(2));
+	}
+
+      MP_PTR_SWAP (xp, lp);
+      ASSERT (lp[lsize-1] != 0);
+    }
+
+  /* should end up in the right spot after all the xp/lp swaps */
+  ASSERT (lp == PTR(ln));
+  SIZ(ln) = lsize;
+
+  TMP_FREE;
+}
diff --git a/mpz/mfac_uiui.c b/mpz/mfac_uiui.c
new file mode 100644
index 0000000..8595a9b
--- /dev/null
+++ b/mpz/mfac_uiui.c
@@ -0,0 +1,140 @@
+/* mpz_mfac_uiui(RESULT, N, M) -- Set RESULT to N!^(M) = N(N-M)(N-2M)...
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2012, 2013, 2015, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+/*********************************************************/
+/* Section oder factorials:                              */
+/*********************************************************/
+
+/* mpz_mfac_uiui (x, n, m) computes x = n!^(m) = n*(n-m)*(n-2m)*...   */
+
+void
+mpz_mfac_uiui (mpz_ptr x, unsigned long n, unsigned long m)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+  ASSERT (m != 0);
+
+  if ((n < 3) | (n - 3 < m - 1)) { /* (n < 3 || n - 1 <= m || m == 0) */
+    MPZ_NEWALLOC (x, 1)[0] = n + (n == 0);
+    SIZ (x) = 1;
+  } else { /* 0 < m < n - 1 < GMP_NUMB_MAX */
+    mp_limb_t g, sn;
+    mpz_t     t;
+
+    sn = n;
+    g = mpn_gcd_1 (&sn, 1, m);
+    if (g > 1) { n/=g; m/=g; }
+
+    if (m <= 2) { /* fac or 2fac */
+      if (m == 1) {
+	if (g > 2) {
+	  mpz_init (t);
+	  mpz_fac_ui (t, n);
+	  sn = n;
+	} else {
+	  if (g == 2)
+	    mpz_2fac_ui (x, n << 1);
+	  else
+	    mpz_fac_ui (x, n);
+	  return;
+	}
+      } else { /* m == 2 */
+	if (g > 1) {
+	  mpz_init (t);
+	  mpz_2fac_ui (t, n);
+	  sn = n / 2 + 1;
+	} else {
+	  mpz_2fac_ui (x, n);
+	  return;
+	}
+      }
+    } else { /* m >= 3, gcd(n,m) = 1 */
+      mp_limb_t *factors;
+      mp_limb_t prod, max_prod;
+      mp_size_t j;
+      TMP_DECL;
+
+      sn = n / m + 1;
+
+      j = 0;
+      prod = n;
+      n -= m;
+      max_prod = GMP_NUMB_MAX / n;
+
+      if (g > 1)
+	factors = MPZ_NEWALLOC (x, sn / log_n_max (n) + 2);
+      else {
+	TMP_MARK;
+	factors = TMP_ALLOC_LIMBS (sn / log_n_max (n) + 2);
+      }
+
+      for (; n > m; n -= m)
+	FACTOR_LIST_STORE (n, prod, max_prod, factors, j);
+
+      factors[j++] = n;
+      factors[j++] = prod;
+
+      if (g > 1) {
+	mpz_init (t);
+	mpz_prodlimbs (t, factors, j);
+      } else {
+	mpz_prodlimbs (x, factors, j);
+	TMP_FREE;
+	return;
+      }
+    }
+
+    {
+      mpz_t p;
+
+      mpz_init (p);
+      mpz_ui_pow_ui (p, g, sn); /* g^sn */
+      mpz_mul (x, p, t);
+      mpz_clear (p);
+      mpz_clear (t);
+    }
+  }
+}
diff --git a/mpz/millerrabin.c b/mpz/millerrabin.c
new file mode 100644
index 0000000..98c4d6a
--- /dev/null
+++ b/mpz/millerrabin.c
@@ -0,0 +1,216 @@
+/* mpz_millerrabin(n,reps) -- An implementation of the probabilistic primality
+   test found in Knuth's Seminumerical Algorithms book.  If the function
+   mpz_millerrabin() returns 0 then n is not prime.  If it returns 1, then n is
+   'probably' prime.  The probability of a false positive is (1/4)**reps, where
+   reps is the number of internal passes of the probabilistic algorithm.  Knuth
+   indicates that 25 passes are reasonable.
+
+   With the current implementation, the first 24 MR-tests are substituted by a
+   Baillie-PSW probable prime test.
+
+   This implementation of the Baillie-PSW test was checked up to 2463*10^12,
+   for smaller values no MR-test is performed, regardless of reps, and
+   2 ("surely prime") is returned if the number was not proved composite.
+
+   If GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS is defined as non-zero,
+   the code assumes that the Baillie-PSW test was checked up to 2^64.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 1991, 1993, 1994, 1996-2002, 2005, 2014, 2018-2022 Free
+Software Foundation, Inc.
+
+Contributed by John Amanatides.
+Changed to "BPSW, then Miller Rabin if required" by Marco Bodrato.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifndef GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS
+#define GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS 0
+#endif
+
+static int millerrabin (mpz_srcptr,
+			mpz_ptr, mpz_ptr,
+			mpz_srcptr, unsigned long int);
+
+int
+mpz_millerrabin (mpz_srcptr n, int reps)
+{
+  mpz_t nm, x, y, q;
+  mp_bitcnt_t k;
+  int is_prime;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (SIZ (n) > 0);
+  MPZ_TMP_INIT (nm, SIZ (n) + 1);
+  mpz_tdiv_q_2exp (nm, n, 1);
+
+  MPZ_TMP_INIT (x, SIZ (n) + 1);
+  MPZ_TMP_INIT (y, 2 * SIZ (n)); /* mpz_powm_ui needs excessive memory!!! */
+  MPZ_TMP_INIT (q, SIZ (n));
+
+  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
+  k = mpn_scan1 (PTR (nm), 0);
+  mpz_tdiv_q_2exp (q, nm, k);
+  ++k;
+
+  /* BPSW test */
+  mpz_set_ui (x, 2);
+  is_prime = millerrabin (n, x, y, q, k) && mpz_stronglucas (n, x, y);
+
+  if (is_prime)
+    {
+      if (
+#if GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS
+	  /* Consider numbers up to 2^64 that pass the BPSW test as primes. */
+#if GMP_NUMB_BITS <= 64
+	  SIZ (n) <= 64 / GMP_NUMB_BITS
+#else
+	  0
+#endif
+#if 64 % GMP_NUMB_BITS != 0
+	  || SIZ (n) - 64 / GMP_NUMB_BITS == (PTR (n) [64 / GMP_NUMB_BITS] < CNST_LIMB(1) << 64 % GMP_NUMB_BITS)
+#endif
+#else
+	  /* Consider numbers up to 35*2^46 that pass the BPSW test as primes.
+	     This implementation was tested up to 2463*10^12 > 2^51+2^47+2^46 */
+	  /* 2^5 < 35 = 0b100011 < 2^6 */
+#define GMP_BPSW_LIMB_CONST CNST_LIMB(35)
+#define GMP_BPSW_BITS_CONST (LOG2C(35) - 1)
+#define GMP_BPSW_BITS_LIMIT (46 + GMP_BPSW_BITS_CONST)
+
+#define GMP_BPSW_LIMBS_LIMIT (GMP_BPSW_BITS_LIMIT / GMP_NUMB_BITS)
+#define GMP_BPSW_BITS_MOD (GMP_BPSW_BITS_LIMIT % GMP_NUMB_BITS)
+
+#if GMP_NUMB_BITS <=  GMP_BPSW_BITS_LIMIT
+	  SIZ (n) <= GMP_BPSW_LIMBS_LIMIT
+#else
+	  0
+#endif
+#if GMP_BPSW_BITS_MOD >=  GMP_BPSW_BITS_CONST
+	  || SIZ (n) - GMP_BPSW_LIMBS_LIMIT == (PTR (n) [GMP_BPSW_LIMBS_LIMIT] < GMP_BPSW_LIMB_CONST << (GMP_BPSW_BITS_MOD - GMP_BPSW_BITS_CONST))
+#else
+#if GMP_BPSW_BITS_MOD != 0
+	  || SIZ (n) - GMP_BPSW_LIMBS_LIMIT == (PTR (n) [GMP_BPSW_LIMBS_LIMIT] < GMP_BPSW_LIMB_CONST >> (GMP_BPSW_BITS_CONST -  GMP_BPSW_BITS_MOD))
+#else
+#if GMP_NUMB_BITS > GMP_BPSW_BITS_CONST
+	  || SIZ (nm) - GMP_BPSW_LIMBS_LIMIT + 1 == (PTR (nm) [GMP_BPSW_LIMBS_LIMIT - 1] < GMP_BPSW_LIMB_CONST << (GMP_NUMB_BITS - 1 - GMP_BPSW_BITS_CONST))
+#endif
+#endif
+#endif
+
+#undef GMP_BPSW_BITS_LIMIT
+#undef GMP_BPSW_LIMB_CONST
+#undef GMP_BPSW_BITS_CONST
+#undef GMP_BPSW_LIMBS_LIMIT
+#undef GMP_BPSW_BITS_MOD
+
+#endif
+	  )
+	is_prime = 2;
+      else
+	{
+	  reps -= 24;
+	  if (reps > 0)
+	    {
+	      gmp_randstate_t rstate;
+	      /* (n-5)/2 */
+	      mpz_sub_ui (nm, nm, 2L);
+	      ASSERT (mpz_cmp_ui (nm, 1L) >= 0);
+
+	      gmp_randinit_default (rstate);
+
+	      do
+		{
+		  /* 3 to (n-1)/2 inclusive, don't want 1, 0 or 2 */
+		  mpz_urandomm (x, rstate, nm);
+		  mpz_add_ui (x, x, 3L);
+
+		  is_prime = millerrabin (n, x, y, q, k);
+		} while (--reps > 0 && is_prime);
+
+	      gmp_randclear (rstate);
+	    }
+	}
+    }
+  TMP_FREE;
+  return is_prime;
+}
+
+static int
+mod_eq_m1 (mpz_srcptr x, mpz_srcptr m)
+{
+  mp_size_t ms;
+  mp_srcptr mp, xp;
+
+  ms = SIZ (m);
+  if (SIZ (x) != ms)
+    return 0;
+  ASSERT (ms > 0);
+
+  mp = PTR (m);
+  xp = PTR (x);
+  ASSERT ((mp[0] - 1) == (mp[0] ^ 1)); /* n is odd */
+
+  if ((*xp ^ CNST_LIMB(1) ^ *mp) != CNST_LIMB(0)) /* xp[0] != mp[0] - 1 */
+    return 0;
+  else
+    {
+      int cmp;
+
+      --ms;
+      ++xp;
+      ++mp;
+
+      MPN_CMP (cmp, xp, mp, ms);
+
+      return cmp == 0;
+    }
+}
+
+static int
+millerrabin (mpz_srcptr n, mpz_ptr x, mpz_ptr y,
+	     mpz_srcptr q, mp_bitcnt_t k)
+{
+  mpz_powm (y, x, q, n);
+
+  if (mpz_cmp_ui (y, 1L) == 0 || mod_eq_m1 (y, n))
+    return 1;
+
+  for (mp_bitcnt_t i = 1; i < k; ++i)
+    {
+      mpz_powm_ui (y, y, 2L, n);
+      if (mod_eq_m1 (y, n))
+	return 1;
+    }
+  return 0;
+}
diff --git a/mpz/mod.c b/mpz/mod.c
new file mode 100644
index 0000000..ab5cdb1
--- /dev/null
+++ b/mpz/mod.c
@@ -0,0 +1,67 @@
+/* mpz_mod -- The mathematical mod function.
+
+Copyright 1991, 1993-1996, 2001, 2002, 2005, 2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_mod (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t rn, bn;
+  mpz_t temp_divisor;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  bn = ABSIZ(divisor);
+
+  /* We need the original value of the divisor after the remainder has been
+     preliminary calculated.  We have to copy it to temporary space if it's
+     the same variable as REM.  */
+  if (rem == divisor)
+    {
+      PTR(temp_divisor) = TMP_ALLOC_LIMBS (bn);
+      MPN_COPY (PTR(temp_divisor), PTR(divisor), bn);
+    }
+  else
+    {
+      PTR(temp_divisor) = PTR(divisor);
+    }
+  SIZ(temp_divisor) = bn;
+  divisor = temp_divisor;
+
+  mpz_tdiv_r (rem, dividend, divisor);
+
+  rn = SIZ (rem);
+  if (rn < 0)
+    mpz_add (rem, rem, divisor);
+
+  TMP_FREE;
+}
diff --git a/mpz/mul.c b/mpz/mul.c
new file mode 100644
index 0000000..a70df9f
--- /dev/null
+++ b/mpz/mul.c
@@ -0,0 +1,159 @@
+/* mpz_mul -- Multiply two integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2009, 2011, 2012,
+2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+void
+mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mp_size_t usize;
+  mp_size_t vsize;
+  mp_size_t wsize;
+  mp_size_t sign_product;
+  mp_ptr up, vp;
+  mp_ptr wp;
+  mp_ptr free_me;
+  size_t free_me_size;
+  mp_limb_t cy_limb;
+  TMP_DECL;
+
+  usize = SIZ (u);
+  vsize = SIZ (v);
+  sign_product = usize ^ vsize;
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  if (usize < vsize)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (usize, vsize);
+    }
+
+  if (vsize == 0)
+    {
+      SIZ (w) = 0;
+      return;
+    }
+
+#if HAVE_NATIVE_mpn_mul_2
+  if (vsize <= 2)
+    {
+      wp = MPZ_REALLOC (w, usize+vsize);
+      if (vsize == 1)
+	cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]);
+      else
+	{
+	  cy_limb = mpn_mul_2 (wp, PTR (u), usize, PTR (v));
+	  usize++;
+	}
+      wp[usize] = cy_limb;
+      usize += (cy_limb != 0);
+      SIZ (w) = (sign_product >= 0 ? usize : -usize);
+      return;
+    }
+#else
+  if (vsize == 1)
+    {
+      wp = MPZ_REALLOC (w, usize+1);
+      cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]);
+      wp[usize] = cy_limb;
+      usize += (cy_limb != 0);
+      SIZ (w) = (sign_product >= 0 ? usize : -usize);
+      return;
+    }
+#endif
+
+  TMP_MARK;
+  free_me = NULL;
+  up = PTR (u);
+  vp = PTR (v);
+  wp = PTR (w);
+
+  /* Ensure W has space enough to store the result.  */
+  wsize = usize + vsize;
+  if (ALLOC (w) < wsize)
+    {
+      if (ALLOC (w) != 0)
+	{
+	  if (wp == up || wp == vp)
+	    {
+	      free_me = wp;
+	      free_me_size = ALLOC (w);
+	    }
+	  else
+	    (*__gmp_free_func) (wp, (size_t) ALLOC (w) * GMP_LIMB_BYTES);
+	}
+
+      ALLOC (w) = wsize;
+      wp = __GMP_ALLOCATE_FUNC_LIMBS (wsize);
+      PTR (w) = wp;
+    }
+  else
+    {
+      /* Make U and V not overlap with W.  */
+      if (wp == up)
+	{
+	  /* W and U are identical.  Allocate temporary space for U.  */
+	  up = TMP_ALLOC_LIMBS (usize);
+	  /* Is V identical too?  Keep it identical with U.  */
+	  if (wp == vp)
+	    vp = up;
+	  /* Copy to the temporary space.  */
+	  MPN_COPY (up, wp, usize);
+	}
+      else if (wp == vp)
+	{
+	  /* W and V are identical.  Allocate temporary space for V.  */
+	  vp = TMP_ALLOC_LIMBS (vsize);
+	  /* Copy to the temporary space.  */
+	  MPN_COPY (vp, wp, vsize);
+	}
+    }
+
+  if (up == vp)
+    {
+      mpn_sqr (wp, up, usize);
+      cy_limb = wp[wsize - 1];
+    }
+  else
+    {
+      cy_limb = mpn_mul (wp, up, usize, vp, vsize);
+    }
+
+  wsize -= cy_limb == 0;
+
+  SIZ (w) = sign_product < 0 ? -wsize : wsize;
+  if (free_me != NULL)
+    (*__gmp_free_func) (free_me, free_me_size * GMP_LIMB_BYTES);
+  TMP_FREE;
+}
diff --git a/mpz/mul_2exp.c b/mpz/mul_2exp.c
new file mode 100644
index 0000000..6144d0d
--- /dev/null
+++ b/mpz/mul_2exp.c
@@ -0,0 +1,72 @@
+/* mpz_mul_2exp -- Multiply a bignum by 2**CNT
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2002, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_mul_2exp (mpz_ptr r, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  mp_size_t un, rn;
+  mp_size_t limb_cnt;
+  mp_ptr rp;
+  mp_srcptr up;
+  mp_limb_t rlimb;
+
+  un = ABSIZ (u);
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  rn = un + limb_cnt;
+
+  if (un == 0)
+    rn = 0;
+  else
+    {
+      rp = MPZ_REALLOC (r, rn + 1);
+      up = PTR(u);
+
+      cnt %= GMP_NUMB_BITS;
+      if (cnt != 0)
+	{
+	  rlimb = mpn_lshift (rp + limb_cnt, up, un, cnt);
+	  rp[rn] = rlimb;
+	  rn += (rlimb != 0);
+	}
+      else
+	{
+	  MPN_COPY_DECR (rp + limb_cnt, up, un);
+	}
+
+      /* Zero all whole limbs at low end.  Do it here and not before calling
+	 mpn_lshift, not to lose for U == R.  */
+      MPN_ZERO (rp, limb_cnt);
+    }
+
+  SIZ(r) = SIZ(u) >= 0 ? rn : -rn;
+}
diff --git a/mpz/mul_i.h b/mpz/mul_i.h
new file mode 100644
index 0000000..65c9c2f
--- /dev/null
+++ b/mpz/mul_i.h
@@ -0,0 +1,106 @@
+/* mpz_mul_ui/si (product, multiplier, small_multiplicand) -- Set PRODUCT to
+   MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2008, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_mul_si
+#define FUNCTION               mpz_mul_si
+#define MULTIPLICAND_UNSIGNED
+#define MULTIPLICAND_ABS(x)    ABS_CAST(unsigned long, (x))
+#endif
+
+#ifdef OPERATION_mul_ui
+#define FUNCTION               mpz_mul_ui
+#define MULTIPLICAND_UNSIGNED  unsigned
+#define MULTIPLICAND_ABS(x)    x
+#endif
+
+#ifndef FUNCTION
+Error, error, unrecognised OPERATION
+#endif
+
+
+void
+FUNCTION (mpz_ptr prod, mpz_srcptr mult,
+          MULTIPLICAND_UNSIGNED long int small_mult)
+{
+  mp_size_t size;
+  mp_size_t sign_product;
+  mp_limb_t sml;
+  mp_limb_t cy;
+  mp_ptr pp;
+
+  sign_product = SIZ(mult);
+  if (sign_product == 0 || small_mult == 0)
+    {
+      SIZ(prod) = 0;
+      return;
+    }
+
+  size = ABS (sign_product);
+
+  sml = MULTIPLICAND_ABS (small_mult);
+
+  if (sml <= GMP_NUMB_MAX)
+    {
+      pp = MPZ_REALLOC (prod, size + 1);
+      cy = mpn_mul_1 (pp, PTR(mult), size, sml);
+      pp[size] = cy;
+      size += cy != 0;
+    }
+#if GMP_NAIL_BITS != 0
+  else
+    {
+      /* Operand too large for the current nails size.  Use temporary for
+	 intermediate products, to allow prod and mult being identical.  */
+      mp_ptr tp;
+      TMP_DECL;
+      TMP_MARK;
+
+      tp = TMP_ALLOC_LIMBS (size + 2);
+
+      /* Use, maybe, mpn_mul_2? */
+      cy = mpn_mul_1 (tp, PTR(mult), size, sml & GMP_NUMB_MASK);
+      tp[size] = cy;
+      cy = mpn_addmul_1 (tp + 1, PTR(mult), size, sml >> GMP_NUMB_BITS);
+      tp[size + 1] = cy;
+      size += 2;
+      MPN_NORMALIZE_NOT_ZERO (tp, size); /* too general, need to trim one or two limb */
+      pp = MPZ_NEWALLOC (prod, size);
+      MPN_COPY (pp, tp, size);
+      TMP_FREE;
+    }
+#endif
+
+  SIZ(prod) = ((sign_product < 0) ^ (small_mult < 0)) ? -size : size;
+}
diff --git a/mpz/mul_si.c b/mpz/mul_si.c
new file mode 100644
index 0000000..9f29f60
--- /dev/null
+++ b/mpz/mul_si.c
@@ -0,0 +1,34 @@
+/* mpz_mul_si (product, multiplier, small_multiplicand) -- Set PRODUCT to
+   MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_mul_si
+#include "mul_i.h"
diff --git a/mpz/mul_ui.c b/mpz/mul_ui.c
new file mode 100644
index 0000000..d398c4f
--- /dev/null
+++ b/mpz/mul_ui.c
@@ -0,0 +1,34 @@
+/* mpz_mul_ui (product, multiplier, small_multiplicand) -- Set PRODUCT to
+   MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_mul_ui
+#include "mul_i.h"
diff --git a/mpz/n_pow_ui.c b/mpz/n_pow_ui.c
new file mode 100644
index 0000000..cf293f5
--- /dev/null
+++ b/mpz/n_pow_ui.c
@@ -0,0 +1,532 @@
+/* mpz_n_pow_ui -- mpn raised to ulong.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* Use this to test the mul_2 code on a CPU without a native version of that
+   routine.  */
+#if 0
+#define mpn_mul_2  refmpn_mul_2
+#define HAVE_NATIVE_mpn_mul_2  1
+#endif
+
+
+/* mpz_pow_ui and mpz_ui_pow_ui want to share almost all of this code.
+   ui_pow_ui doesn't need the mpn_mul based powering loop or the tests on
+   bsize==2 or >2, but separating that isn't easy because there's shared
+   code both before and after (the size calculations and the powers of 2
+   handling).
+
+   Alternatives:
+
+   It would work to just use the mpn_mul powering loop for 1 and 2 limb
+   bases, but the current separate loop allows mul_1 and mul_2 to be done
+   in-place, which might help cache locality a bit.  If mpn_mul was relaxed
+   to allow source==dest when vn==1 or 2 then some pointer twiddling might
+   let us get the same effect in one loop.
+
+   The initial powering for bsize==1 into blimb or blimb:blimb_low doesn't
+   form the biggest possible power of b that fits, only the biggest power of
+   2 power, ie. b^(2^n).  It'd be possible to choose a bigger power, perhaps
+   using mp_bases[b].big_base for small b, and thereby get better value
+   from mpn_mul_1 or mpn_mul_2 in the bignum powering.  It's felt that doing
+   so would be more complicated than it's worth, and could well end up being
+   a slowdown for small e.  For big e on the other hand the algorithm is
+   dominated by mpn_sqr so there wouldn't much of a saving.  The current
+   code can be viewed as simply doing the first few steps of the powering in
+   a single or double limb where possible.
+
+   If r==b, and blow_twos==0, and r must be realloc'ed, then the temporary
+   copy made of b is unnecessary.  We could just use the old alloc'ed block
+   and free it at the end.  But arranging this seems like a lot more trouble
+   than it's worth.  */
+
+
+/* floor(sqrt(GMP_NUMB_MAX)), ie. the biggest value that can be squared in
+   a limb without overflowing.
+   FIXME: This formula is an underestimate when GMP_NUMB_BITS is odd. */
+
+#define GMP_NUMB_HALFMAX  (((mp_limb_t) 1 << GMP_NUMB_BITS/2) - 1)
+
+
+/* The following are for convenience, they update the size and check the
+   alloc.  */
+
+#define MPN_SQR(dst, alloc, src, size)          \
+  do {                                          \
+    ASSERT (2*(size) <= (alloc));               \
+    mpn_sqr (dst, src, size);                   \
+    (size) *= 2;                                \
+    (size) -= ((dst)[(size)-1] == 0);           \
+  } while (0)
+
+#define MPN_MUL(dst, alloc, src, size, src2, size2)     \
+  do {                                                  \
+    mp_limb_t  cy;                                      \
+    ASSERT ((size) + (size2) <= (alloc));               \
+    cy = mpn_mul (dst, src, size, src2, size2);         \
+    (size) += (size2) - (cy == 0);                      \
+  } while (0)
+
+#define MPN_MUL_2(ptr, size, alloc, mult)       \
+  do {                                          \
+    mp_limb_t  cy;                              \
+    ASSERT ((size)+2 <= (alloc));               \
+    cy = mpn_mul_2 (ptr, ptr, size, mult);      \
+    (size)++;                                   \
+    (ptr)[(size)] = cy;                         \
+    (size) += (cy != 0);                        \
+  } while (0)
+
+#define MPN_MUL_1(ptr, size, alloc, limb)       \
+  do {                                          \
+    mp_limb_t  cy;                              \
+    ASSERT ((size)+1 <= (alloc));               \
+    cy = mpn_mul_1 (ptr, ptr, size, limb);      \
+    (ptr)[size] = cy;                           \
+    (size) += (cy != 0);                        \
+  } while (0)
+
+#define MPN_LSHIFT(ptr, size, alloc, shift)     \
+  do {                                          \
+    mp_limb_t  cy;                              \
+    ASSERT ((size)+1 <= (alloc));               \
+    cy = mpn_lshift (ptr, ptr, size, shift);    \
+    (ptr)[size] = cy;                           \
+    (size) += (cy != 0);                        \
+  } while (0)
+
+#define MPN_RSHIFT_OR_COPY(dst, src, size, shift)       \
+  do {                                                  \
+    if ((shift) == 0)                                   \
+      MPN_COPY (dst, src, size);                        \
+    else                                                \
+      {                                                 \
+        mpn_rshift (dst, src, size, shift);             \
+        (size) -= ((dst)[(size)-1] == 0);               \
+      }                                                 \
+  } while (0)
+
+
+/* ralloc and talloc are only wanted for ASSERTs, after the initial space
+   allocations.  Avoid writing values to them in a normal build, to ensure
+   the compiler lets them go dead.  gcc already figures this out itself
+   actually.  */
+
+#define SWAP_RP_TP                                      \
+  do {                                                  \
+    MP_PTR_SWAP (rp, tp);                               \
+    ASSERT_CODE (MP_SIZE_T_SWAP (ralloc, talloc));      \
+  } while (0)
+
+
+void
+mpz_n_pow_ui (mpz_ptr r, mp_srcptr bp, mp_size_t bsize, unsigned long int e)
+{
+  mp_ptr         rp;
+  mp_size_t      rtwos_limbs, ralloc, rsize;
+  int            rneg, i, cnt, btwos, r_bp_overlap;
+  mp_limb_t      blimb, rl;
+  mp_bitcnt_t    rtwos_bits;
+#if HAVE_NATIVE_mpn_mul_2
+  mp_limb_t      blimb_low, rl_high;
+#else
+  mp_limb_t      b_twolimbs[2];
+#endif
+  TMP_DECL;
+
+  TRACE (printf ("mpz_n_pow_ui rp=0x%lX bp=0x%lX bsize=%ld e=%lu (0x%lX)\n",
+		 PTR(r), bp, bsize, e, e);
+	 mpn_trace ("b", bp, bsize));
+
+  ASSERT (bsize == 0 || bp[ABS(bsize)-1] != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE2_P (PTR(r), ALLOC(r), bp, ABS(bsize)));
+
+  /* b^0 == 1, including 0^0 == 1 */
+  if (e == 0)
+    {
+      MPZ_NEWALLOC (r, 1)[0] = 1;
+      SIZ(r) = 1;
+      return;
+    }
+
+  /* 0^e == 0 apart from 0^0 above */
+  if (bsize == 0)
+    {
+      SIZ(r) = 0;
+      return;
+    }
+
+  /* Sign of the final result. */
+  rneg = (bsize < 0 && (e & 1) != 0);
+  bsize = ABS (bsize);
+  TRACE (printf ("rneg %d\n", rneg));
+
+  r_bp_overlap = (PTR(r) == bp);
+
+  /* Strip low zero limbs from b. */
+  rtwos_limbs = 0;
+  for (blimb = *bp; blimb == 0; blimb = *++bp)
+    {
+      rtwos_limbs += e;
+      bsize--; ASSERT (bsize >= 1);
+    }
+  TRACE (printf ("trailing zero rtwos_limbs=%ld\n", rtwos_limbs));
+
+  /* Strip low zero bits from b. */
+  count_trailing_zeros (btwos, blimb);
+  blimb >>= btwos;
+  rtwos_bits = e * btwos;
+  rtwos_limbs += rtwos_bits / GMP_NUMB_BITS;
+  rtwos_bits %= GMP_NUMB_BITS;
+  TRACE (printf ("trailing zero btwos=%d rtwos_limbs=%ld rtwos_bits=%lu\n",
+		 btwos, rtwos_limbs, rtwos_bits));
+
+  TMP_MARK;
+
+  rl = 1;
+#if HAVE_NATIVE_mpn_mul_2
+  rl_high = 0;
+#endif
+
+  if (bsize == 1)
+    {
+    bsize_1:
+      /* Power up as far as possible within blimb.  We start here with e!=0,
+	 but if e is small then we might reach e==0 and the whole b^e in rl.
+	 Notice this code works when blimb==1 too, reaching e==0.  */
+
+      while (blimb <= GMP_NUMB_HALFMAX)
+	{
+	  TRACE (printf ("small e=0x%lX blimb=0x%lX rl=0x%lX\n",
+			 e, blimb, rl));
+	  ASSERT (e != 0);
+	  if ((e & 1) != 0)
+	    rl *= blimb;
+	  e >>= 1;
+	  if (e == 0)
+	    goto got_rl;
+	  blimb *= blimb;
+	}
+
+#if HAVE_NATIVE_mpn_mul_2
+      TRACE (printf ("single power, e=0x%lX b=0x%lX rl=0x%lX\n",
+		     e, blimb, rl));
+
+      /* Can power b once more into blimb:blimb_low */
+      bsize = 2;
+      ASSERT (e != 0);
+      if ((e & 1) != 0)
+	{
+	  umul_ppmm (rl_high, rl, rl, blimb << GMP_NAIL_BITS);
+	  rl >>= GMP_NAIL_BITS;
+	}
+      e >>= 1;
+      umul_ppmm (blimb, blimb_low, blimb, blimb << GMP_NAIL_BITS);
+      blimb_low >>= GMP_NAIL_BITS;
+
+    got_rl:
+      TRACE (printf ("double power e=0x%lX blimb=0x%lX:0x%lX rl=0x%lX:%lX\n",
+		     e, blimb, blimb_low, rl_high, rl));
+
+      /* Combine left-over rtwos_bits into rl_high:rl to be handled by the
+	 final mul_1 or mul_2 rather than a separate lshift.
+	 - rl_high:rl mustn't be 1 (since then there's no final mul)
+	 - rl_high mustn't overflow
+	 - rl_high mustn't change to non-zero, since mul_1+lshift is
+	 probably faster than mul_2 (FIXME: is this true?)  */
+
+      if (rtwos_bits != 0
+	  && ! (rl_high == 0 && rl == 1)
+	  && (rl_high >> (GMP_NUMB_BITS-rtwos_bits)) == 0)
+	{
+	  mp_limb_t  new_rl_high = (rl_high << rtwos_bits)
+	    | (rl >> (GMP_NUMB_BITS-rtwos_bits));
+	  if (! (rl_high == 0 && new_rl_high != 0))
+	    {
+	      rl_high = new_rl_high;
+	      rl <<= rtwos_bits;
+	      rtwos_bits = 0;
+	      TRACE (printf ("merged rtwos_bits, rl=0x%lX:%lX\n",
+			     rl_high, rl));
+	    }
+	}
+#else
+    got_rl:
+      TRACE (printf ("small power e=0x%lX blimb=0x%lX rl=0x%lX\n",
+		     e, blimb, rl));
+
+      /* Combine left-over rtwos_bits into rl to be handled by the final
+	 mul_1 rather than a separate lshift.
+	 - rl mustn't be 1 (since then there's no final mul)
+	 - rl mustn't overflow	*/
+
+      if (rtwos_bits != 0
+	  && rl != 1
+	  && (rl >> (GMP_NUMB_BITS-rtwos_bits)) == 0)
+	{
+	  rl <<= rtwos_bits;
+	  rtwos_bits = 0;
+	  TRACE (printf ("merged rtwos_bits, rl=0x%lX\n", rl));
+	}
+#endif
+    }
+  else if (bsize == 2)
+    {
+      mp_limb_t  bsecond = bp[1];
+      if (btwos != 0)
+	blimb |= (bsecond << (GMP_NUMB_BITS - btwos)) & GMP_NUMB_MASK;
+      bsecond >>= btwos;
+      if (bsecond == 0)
+	{
+	  /* Two limbs became one after rshift. */
+	  bsize = 1;
+	  goto bsize_1;
+	}
+
+      TRACE (printf ("bsize==2 using b=0x%lX:%lX", bsecond, blimb));
+#if HAVE_NATIVE_mpn_mul_2
+      blimb_low = blimb;
+#else
+      bp = b_twolimbs;
+      b_twolimbs[0] = blimb;
+      b_twolimbs[1] = bsecond;
+#endif
+      blimb = bsecond;
+    }
+  else
+    {
+      if (r_bp_overlap || btwos != 0)
+	{
+	  mp_ptr tp = TMP_ALLOC_LIMBS (bsize);
+	  MPN_RSHIFT_OR_COPY (tp, bp, bsize, btwos);
+	  bp = tp;
+	  TRACE (printf ("rshift or copy bp,bsize, new bsize=%ld\n", bsize));
+	}
+#if HAVE_NATIVE_mpn_mul_2
+      /* in case 3 limbs rshift to 2 and hence use the mul_2 loop below */
+      blimb_low = bp[0];
+#endif
+      blimb = bp[bsize-1];
+
+      TRACE (printf ("big bsize=%ld  ", bsize);
+	     mpn_trace ("b", bp, bsize));
+    }
+
+  /* At this point blimb is the most significant limb of the base to use.
+
+     Each factor of b takes (bsize*BPML-cnt) bits and there's e of them; +1
+     limb to round up the division; +1 for multiplies all using an extra
+     limb over the true size; +2 for rl at the end; +1 for lshift at the
+     end.
+
+     The size calculation here is reasonably accurate.  The base is at least
+     half a limb, so in 32 bits the worst case is 2^16+1 treated as 17 bits
+     when it will power up as just over 16, an overestimate of 17/16 =
+     6.25%.  For a 64-bit limb it's half that.
+
+     If e==0 then blimb won't be anything useful (though it will be
+     non-zero), but that doesn't matter since we just end up with ralloc==5,
+     and that's fine for 2 limbs of rl and 1 of lshift.  */
+
+  ASSERT (blimb != 0);
+  count_leading_zeros (cnt, blimb);
+  ralloc = (bsize*GMP_NUMB_BITS - cnt + GMP_NAIL_BITS) * e / GMP_NUMB_BITS + 5;
+  TRACE (printf ("ralloc %ld, from bsize=%ld blimb=0x%lX cnt=%d\n",
+		 ralloc, bsize, blimb, cnt));
+  rp = MPZ_NEWALLOC (r, ralloc + rtwos_limbs);
+
+  /* Low zero limbs resulting from powers of 2. */
+  MPN_ZERO (rp, rtwos_limbs);
+  rp += rtwos_limbs;
+
+  if (e == 0)
+    {
+      /* Any e==0 other than via bsize==1 or bsize==2 is covered at the
+	 start. */
+      rp[0] = rl;
+      rsize = 1;
+#if HAVE_NATIVE_mpn_mul_2
+      rp[1] = rl_high;
+      rsize += (rl_high != 0);
+#endif
+      ASSERT (rp[rsize-1] != 0);
+    }
+  else
+    {
+      mp_ptr     tp;
+      mp_size_t  talloc;
+
+      /* In the mpn_mul_1 or mpn_mul_2 loops or in the mpn_mul loop when the
+	 low bit of e is zero, tp only has to hold the second last power
+	 step, which is half the size of the final result.  There's no need
+	 to round up the divide by 2, since ralloc includes a +2 for rl
+	 which not needed by tp.  In the mpn_mul loop when the low bit of e
+	 is 1, tp must hold nearly the full result, so just size it the same
+	 as rp.  */
+
+      talloc = ralloc;
+#if HAVE_NATIVE_mpn_mul_2
+      if (bsize <= 2 || (e & 1) == 0)
+	talloc /= 2;
+#else
+      if (bsize <= 1 || (e & 1) == 0)
+	talloc /= 2;
+#endif
+      TRACE (printf ("talloc %ld\n", talloc));
+      tp = TMP_ALLOC_LIMBS (talloc);
+
+      /* Go from high to low over the bits of e, starting with i pointing at
+	 the bit below the highest 1 (which will mean i==-1 if e==1).  */
+      count_leading_zeros (cnt, (mp_limb_t) e);
+      i = GMP_LIMB_BITS - cnt - 2;
+
+#if HAVE_NATIVE_mpn_mul_2
+      if (bsize <= 2)
+	{
+	  mp_limb_t  mult[2];
+
+	  /* Any bsize==1 will have been powered above to be two limbs. */
+	  ASSERT (bsize == 2);
+	  ASSERT (blimb != 0);
+
+	  /* Arrange the final result ends up in r, not in the temp space */
+	  if ((i & 1) == 0)
+	    SWAP_RP_TP;
+
+	  rp[0] = blimb_low;
+	  rp[1] = blimb;
+	  rsize = 2;
+
+	  mult[0] = blimb_low;
+	  mult[1] = blimb;
+
+	  for ( ; i >= 0; i--)
+	    {
+	      TRACE (printf ("mul_2 loop i=%d e=0x%lX, rsize=%ld ralloc=%ld talloc=%ld\n",
+			     i, e, rsize, ralloc, talloc);
+		     mpn_trace ("r", rp, rsize));
+
+	      MPN_SQR (tp, talloc, rp, rsize);
+	      SWAP_RP_TP;
+	      if ((e & (1L << i)) != 0)
+		MPN_MUL_2 (rp, rsize, ralloc, mult);
+	    }
+
+	  TRACE (mpn_trace ("mul_2 before rl, r", rp, rsize));
+	  if (rl_high != 0)
+	    {
+	      mult[0] = rl;
+	      mult[1] = rl_high;
+	      MPN_MUL_2 (rp, rsize, ralloc, mult);
+	    }
+	  else if (rl != 1)
+	    MPN_MUL_1 (rp, rsize, ralloc, rl);
+	}
+#else
+      if (bsize == 1)
+	{
+	  /* Arrange the final result ends up in r, not in the temp space */
+	  if ((i & 1) == 0)
+	    SWAP_RP_TP;
+
+	  rp[0] = blimb;
+	  rsize = 1;
+
+	  for ( ; i >= 0; i--)
+	    {
+	      TRACE (printf ("mul_1 loop i=%d e=0x%lX, rsize=%ld ralloc=%ld talloc=%ld\n",
+			     i, e, rsize, ralloc, talloc);
+		     mpn_trace ("r", rp, rsize));
+
+	      MPN_SQR (tp, talloc, rp, rsize);
+	      SWAP_RP_TP;
+	      if ((e & (1L << i)) != 0)
+		MPN_MUL_1 (rp, rsize, ralloc, blimb);
+	    }
+
+	  TRACE (mpn_trace ("mul_1 before rl, r", rp, rsize));
+	  if (rl != 1)
+	    MPN_MUL_1 (rp, rsize, ralloc, rl);
+	}
+#endif
+      else
+	{
+	  int  parity;
+
+	  /* Arrange the final result ends up in r, not in the temp space */
+	  ULONG_PARITY (parity, e);
+	  if (((parity ^ i) & 1) != 0)
+	    SWAP_RP_TP;
+
+	  MPN_COPY (rp, bp, bsize);
+	  rsize = bsize;
+
+	  for ( ; i >= 0; i--)
+	    {
+	      TRACE (printf ("mul loop i=%d e=0x%lX, rsize=%ld ralloc=%ld talloc=%ld\n",
+			     i, e, rsize, ralloc, talloc);
+		     mpn_trace ("r", rp, rsize));
+
+	      MPN_SQR (tp, talloc, rp, rsize);
+	      SWAP_RP_TP;
+	      if ((e & (1L << i)) != 0)
+		{
+		  MPN_MUL (tp, talloc, rp, rsize, bp, bsize);
+		  SWAP_RP_TP;
+		}
+	    }
+	}
+    }
+
+  ASSERT (rp == PTR(r) + rtwos_limbs);
+  TRACE (mpn_trace ("end loop r", rp, rsize));
+  TMP_FREE;
+
+  /* Apply any partial limb factors of 2. */
+  if (rtwos_bits != 0)
+    {
+      MPN_LSHIFT (rp, rsize, ralloc, (unsigned) rtwos_bits);
+      TRACE (mpn_trace ("lshift r", rp, rsize));
+    }
+
+  rsize += rtwos_limbs;
+  SIZ(r) = (rneg ? -rsize : rsize);
+}
diff --git a/mpz/neg.c b/mpz/neg.c
new file mode 100644
index 0000000..7f3fbcf
--- /dev/null
+++ b/mpz/neg.c
@@ -0,0 +1,56 @@
+/* mpz_neg(mpz_ptr dst, mpz_ptr src) -- Assign the negated value of SRC to DST.
+
+Copyright 1991, 1993-1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_neg 1
+
+#include "gmp-impl.h"
+
+void
+mpz_neg (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp;
+  mp_srcptr up;
+  mp_size_t usize, size;
+
+  usize = SIZ (u);
+
+  if (u != w)
+    {
+      size = ABS (usize);
+
+      wp = MPZ_NEWALLOC (w, size);
+
+      up = PTR (u);
+
+      MPN_COPY (wp, up, size);
+    }
+
+  SIZ (w) = -usize;
+}
diff --git a/mpz/nextprime.c b/mpz/nextprime.c
new file mode 100644
index 0000000..2fe2616
--- /dev/null
+++ b/mpz/nextprime.c
@@ -0,0 +1,291 @@
+/* mpz_nextprime(p,t) - compute the next prime > t and store that in p.
+
+Copyright 1999-2001, 2008, 2009, 2012, 2020-2022 Free Software
+Foundation, Inc.
+
+Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+Improved by Seth Troisi.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+
+
+static const unsigned char primegap_small[] =
+{
+  2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,
+  2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2,
+  4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,2,10,2,6,4,6,8,4,2,4,12,8,4,8,4,6,
+  12,2,18,6,10
+};
+
+#define NUMBER_OF_PRIMES 100
+#define LAST_PRIME 557
+/* NP_SMALL_LIMIT = prevprime (LAST_PRIME ^ 2) */
+#define NP_SMALL_LIMIT 310243
+
+static unsigned long
+calculate_sievelimit(mp_bitcnt_t nbits) {
+  unsigned long sieve_limit;
+
+  /* Estimate a good sieve bound. Based on derivative of
+   *   Merten's 3rd theorem * avg gap * cost of mod
+   *      vs
+   *   Cost of PRP test O(N^2.55)
+   */
+  if (nbits < 12818)
+    {
+      mpz_t tmp;
+      /* sieve_limit ~= nbits ^ (5/2) / 124 */
+      mpz_init (tmp);
+      mpz_ui_pow_ui (tmp, nbits, 5);
+      mpz_tdiv_q_ui(tmp, tmp, 124*124);
+      /* tmp < 12818^5/(124*124) < 2^55 < 2^64 */
+      mpz_sqrt (tmp, tmp);
+
+      sieve_limit = mpz_get_ui(tmp);
+      mpz_clear (tmp);
+    }
+  else
+    {
+      /* Larger threshold is faster but takes (n/ln(n) + n/24) memory.
+       * For 33,000 bits limitting to 150M is ~12% slower than using the
+       * optimal 1.5G sieve_limit.
+       */
+      sieve_limit = 150000001;
+    }
+
+  ASSERT (1000 < sieve_limit && sieve_limit <= 150000001);
+  return sieve_limit;
+}
+
+static unsigned
+findnext_small (unsigned t, short diff)
+{
+  /* For diff= 2, expect t = 1 if operand was negative.
+   * For diff=-2, expect t >= 3
+   */
+  ASSERT (t >= 3 || (diff > 0 && t >= 1));
+  ASSERT (t < NP_SMALL_LIMIT);
+
+  /* Start from next candidate (2 or odd) */
+  t = diff > 0 ?
+    (t + 1) | (t != 1) :
+    ((t - 2) | 1) + (t == 3);
+
+  for (; ; t += diff)
+    {
+      unsigned prime = 3;
+      for (int i = 0; ; prime += primegap_small[i++])
+	{
+	  unsigned q, r;
+	  q = t / prime;
+	  r = t - q * prime; /* r = t % prime; */
+	  if (q < prime)
+	    return t;
+	  if (r == 0)
+	    break;
+	  ASSERT (i < NUMBER_OF_PRIMES);
+	}
+    }
+}
+
+static int
+findnext (mpz_ptr p,
+          unsigned long(*negative_mod_ui)(const mpz_t, unsigned long),
+          void(*increment_ui)(mpz_t, const mpz_t, unsigned long))
+{
+  char *composite;
+  const unsigned char *primegap;
+  unsigned long prime_limit;
+  mp_size_t pn;
+  mp_bitcnt_t nbits;
+  int i, m;
+  unsigned odds_in_composite_sieve;
+  TMP_DECL;
+
+  TMP_MARK;
+  pn = SIZ(p);
+  MPN_SIZEINBASE_2EXP(nbits, PTR(p), pn, 1);
+  /* Smaller numbers handled earlier */
+  ASSERT (nbits >= 3);
+  /* Make p odd */
+  PTR(p)[0] |= 1;
+
+  if (nbits / 2 <= NUMBER_OF_PRIMES)
+    {
+      primegap = primegap_small;
+      prime_limit = nbits / 2;
+    }
+  else
+    {
+      unsigned long sieve_limit;
+      mp_limb_t *sieve;
+      unsigned char *primegap_tmp;
+      unsigned long last_prime;
+
+      /* sieve numbers up to sieve_limit and save prime count */
+      sieve_limit = calculate_sievelimit(nbits);
+      sieve = TMP_ALLOC_LIMBS (primesieve_size (sieve_limit));
+      prime_limit = gmp_primesieve(sieve, sieve_limit);
+
+      /* TODO: Storing (prime - last_prime)/2 would allow this to go
+	 up to the gap 304599508537+514=304599509051 .
+	 With the current code our limit is 436273009+282=436273291 */
+      ASSERT (sieve_limit < 436273291);
+      /* THINK: Memory used by both sieve and primegap_tmp is kept
+	 allocated, but they may overlap if primegap is filled from
+	 larger down to smaller primes...
+       */
+
+      /* Needed to avoid assignment of read-only location */
+      primegap_tmp = TMP_ALLOC_TYPE (prime_limit, unsigned char);
+      primegap = primegap_tmp;
+
+      i = 0;
+      last_prime = 3;
+      /* THINK: should we get rid of sieve_limit and use (i < prime_limit)? */
+      for (mp_limb_t j = 4, *sp = sieve; j < sieve_limit; j += GMP_LIMB_BITS * 3)
+	for (mp_limb_t b = j, x = ~ *(sp++); x != 0; b += 3, x >>= 1)
+	  if (x & 1)
+	    {
+	      mp_limb_t prime = b | 1;
+	      primegap_tmp[i++] = prime - last_prime;
+	      last_prime = prime;
+	    }
+
+      /* Both primesieve and prime_limit ignore the first two primes. */
+      ASSERT(i == prime_limit);
+    }
+
+  if (nbits <= 32)
+    odds_in_composite_sieve = 336 / 2;
+  else if (nbits <= 64)
+    odds_in_composite_sieve = 1550 / 2;
+  else
+    /* Corresponds to a merit 14 prime_gap, which is rare. */
+    odds_in_composite_sieve = 5 * nbits;
+
+  /* composite[2*i] stores if p+2*i is a known composite */
+  composite = TMP_ALLOC_TYPE (odds_in_composite_sieve, char);
+
+  for (;;)
+    {
+      unsigned long difference;
+      unsigned long incr, prime;
+      int primetest;
+
+      memset (composite, 0, odds_in_composite_sieve);
+      prime = 3;
+      for (i = 0; i < prime_limit; i++)
+        {
+          /* Distance to next multiple of prime */
+          m = negative_mod_ui(p, prime);
+          /* Only care about odd multiplies of prime. */
+          if (m & 1)
+            m += prime;
+          m >>= 1;
+
+          /* Mark off any composites in sieve */
+          for (; m < odds_in_composite_sieve; m += prime)
+            composite[m] = 1;
+          prime += primegap[i];
+        }
+
+      difference = 0;
+      for (incr = 0; incr < odds_in_composite_sieve; difference += 2, incr += 1)
+        {
+          if (composite[incr])
+            continue;
+
+          increment_ui(p, p, difference);
+          difference = 0;
+
+          /* Miller-Rabin test */
+          primetest = mpz_millerrabin (p, 25);
+          if (primetest)
+	    {
+	      TMP_FREE;
+	      return primetest;
+	    }
+        }
+
+      /* Sieve next segment, very rare */
+      increment_ui(p, p, difference);
+  }
+}
+
+void
+mpz_nextprime (mpz_ptr p, mpz_srcptr n)
+{
+  /* Handle negative and small numbers */
+  if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0)
+    {
+      ASSERT (NP_SMALL_LIMIT < UINT_MAX);
+      mpz_set_ui (p, findnext_small (SIZ (n) > 0 ? mpz_get_ui (n) : 1, +2));
+      return;
+    }
+
+  /* First odd greater than n */
+  mpz_add_ui (p, n, 1);
+
+  findnext(p, mpz_cdiv_ui, mpz_add_ui);
+}
+
+int
+mpz_prevprime (mpz_ptr p, mpz_srcptr n)
+{
+  /* Handle negative and small numbers */
+  if (mpz_cmp_ui (n, 2) <= 0)
+    return 0;
+
+  if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0)
+    {
+      ASSERT (NP_SMALL_LIMIT < UINT_MAX);
+      mpz_set_ui (p, findnext_small (mpz_get_ui (n), -2));
+      return 2;
+    }
+
+  /* First odd less than n */
+  mpz_sub_ui (p, n, 2);
+
+  return findnext(p, mpz_tdiv_ui, mpz_sub_ui);
+}
+
diff --git a/mpz/oddfac_1.c b/mpz/oddfac_1.c
new file mode 100644
index 0000000..3f4c085
--- /dev/null
+++ b/mpz/oddfac_1.c
@@ -0,0 +1,435 @@
+/* mpz_oddfac_1(RESULT, N) -- Set RESULT to the odd factor of N!.
+
+Contributed to the GNU project by Marco Bodrato.
+
+THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
+IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
+IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
+DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2010-2012, 2015-2017, 2020, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* TODO:
+   - split this file in smaller parts with functions that can be recycled for different computations.
+ */
+
+/**************************************************************/
+/* Section macros: common macros, for mswing/fac/bin (&sieve) */
+/**************************************************************/
+
+#define FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I)			\
+  if ((PR) > (MAX_PR)) {					\
+    (VEC)[(I)++] = (PR);					\
+    (PR) = 1;							\
+  }
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if ((*__sieve & __mask) == 0)				\
+	{							\
+	  mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, *__sieve, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __sieve = (sieve) + __i / GMP_LIMB_BITS;			\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __sieve += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+#if WANT_ASSERT
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+#if WANT_ASSERT
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+#endif
+
+/*********************************************************/
+/* Section mswing: 2-multiswing factorial                */
+/*********************************************************/
+
+/* Returns an approximation of the sqare root of x.
+ * It gives:
+ *   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
+ * or
+ *   x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
+ */
+static mp_limb_t
+limb_apprsqrt (mp_limb_t x)
+{
+  int s;
+
+  ASSERT (x > 2);
+  count_leading_zeros (s, x);
+  s = (GMP_LIMB_BITS - s) >> 1;
+  return ((CNST_LIMB(1) << (s - 1)) + (x >> 1 >> s));
+}
+
+#if 0
+/* A count-then-exponentiate variant for SWING_A_PRIME */
+#define SWING_A_PRIME(P, N, PR, MAX_PR, VEC, I)		\
+  do {							\
+    mp_limb_t __q, __prime;				\
+    int __exp;						\
+    __prime = (P);					\
+    __exp = 0;						\
+    __q = (N);						\
+    do {						\
+      __q /= __prime;					\
+      __exp += __q & 1;					\
+    } while (__q >= __prime);				\
+    if (__exp) { /* Store $prime^{exp}$ */		\
+      for (__q = __prime; --__exp; __q *= __prime);	\
+      FACTOR_LIST_STORE(__q, PR, MAX_PR, VEC, I);	\
+    };							\
+  } while (0)
+#else
+#define SWING_A_PRIME(P, N, PR, MAX_PR, VEC, I)	\
+  do {						\
+    mp_limb_t __q, __prime;			\
+    __prime = (P);				\
+    FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I);	\
+    __q = (N);					\
+    do {					\
+      __q /= __prime;				\
+      if ((__q & 1) != 0) (PR) *= __prime;	\
+    } while (__q >= __prime);			\
+  } while (0)
+#endif
+
+#define SH_SWING_A_PRIME(P, N, PR, MAX_PR, VEC, I)	\
+  do {							\
+    mp_limb_t __prime;					\
+    __prime = (P);					\
+    if ((((N) / __prime) & 1) != 0)			\
+      FACTOR_LIST_STORE(__prime, PR, MAX_PR, VEC, I);	\
+  } while (0)
+
+/* mpz_2multiswing_1 computes the odd part of the 2-multiswing
+   factorial of the parameter n.  The result x is an odd positive
+   integer so that multiswing(n,2) = x 2^a.
+
+   Uses the algorithm described by Peter Luschny in "Divide, Swing and
+   Conquer the Factorial!".
+
+   The pointer sieve points to primesieve_size(n) limbs containing a
+   bit-array where primes are marked as 0.
+   Enough (FIXME: explain :-) limbs must be pointed by factors.
+ */
+
+static void
+mpz_2multiswing_1 (mpz_ptr x, mp_limb_t n, mp_ptr sieve, mp_ptr factors)
+{
+  mp_limb_t prod, max_prod;
+  mp_size_t j;
+
+  ASSERT (n > 25);
+
+  j = 0;
+  prod  = -(n & 1);
+  n &= ~ CNST_LIMB(1); /* n-1, if n is odd */
+
+  prod = (prod & n) + 1; /* the original n, if it was odd, 1 otherwise */
+  max_prod = GMP_NUMB_MAX / (n-1);
+
+  /* Handle prime = 3 separately. */
+  SWING_A_PRIME (3, n, prod, max_prod, factors, j);
+
+  /* Swing primes from 5 to n/3 */
+  {
+    mp_limb_t s, l_max_prod;
+
+    s = limb_apprsqrt(n);
+    ASSERT (s >= 5);
+    s = n_to_bit (s);
+    ASSERT (bit_to_n (s+1) * bit_to_n (s+1) > n);
+    ASSERT (s < n_to_bit (n / 3));
+    LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (5), s, 0,sieve);
+    SWING_A_PRIME (prime, n, prod, max_prod, factors, j);
+    LOOP_ON_SIEVE_STOP;
+
+    ASSERT (max_prod <= GMP_NUMB_MAX / 3);
+
+    l_max_prod = max_prod * 3;
+
+    LOOP_ON_SIEVE_CONTINUE (prime, n_to_bit (n/3));
+    SH_SWING_A_PRIME (prime, n, prod, l_max_prod, factors, j);
+    LOOP_ON_SIEVE_END;
+  }
+
+  /* Store primes from (n+1)/2 to n */
+  LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (n >> 1) + 1, n_to_bit (n), 0,sieve);
+  FACTOR_LIST_STORE (prime, prod, max_prod, factors, j);
+  LOOP_ON_SIEVE_END;
+
+  if (LIKELY (j != 0))
+    {
+      factors[j++] = prod;
+      mpz_prodlimbs (x, factors, j);
+    }
+  else
+    {
+      ASSERT (ALLOC (x) > 0);
+      PTR (x)[0] = prod;
+      SIZ (x) = 1;
+    }
+}
+
+#undef SWING_A_PRIME
+#undef SH_SWING_A_PRIME
+#undef LOOP_ON_SIEVE_END
+#undef LOOP_ON_SIEVE_STOP
+#undef LOOP_ON_SIEVE_BEGIN
+#undef LOOP_ON_SIEVE_CONTINUE
+#undef FACTOR_LIST_APPEND
+
+/*********************************************************/
+/* Section oddfac: odd factorial, needed also by binomial*/
+/*********************************************************/
+
+/* FIXME: refine che following estimate. */
+
+#if TUNE_PROGRAM_BUILD
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS * 2 / (LOG2C(FAC_DSC_THRESHOLD_LIMIT*FAC_DSC_THRESHOLD_LIMIT-1)+1) - 1)
+#else
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS * 2 / (LOG2C(FAC_DSC_THRESHOLD*FAC_DSC_THRESHOLD-1)+1) - 1)
+#endif
+
+/* mpz_oddfac_1 computes the odd part of the factorial of the
+   parameter n.  I.e. n! = x 2^a, where x is the returned value: an
+   odd positive integer.
+
+   If flag != 0 a square is skipped in the DSC part, e.g.
+   if n is odd, n > FAC_DSC_THRESHOLD and flag = 1, x is set to n!!.
+
+   If n is too small, flag is ignored, and an ASSERT can be triggered.
+
+   TODO: FAC_DSC_THRESHOLD is used here with two different roles:
+    - to decide when prime factorisation is needed,
+    - to stop the recursion, once sieving is done.
+   Maybe two thresholds can do a better job.
+ */
+void
+mpz_oddfac_1 (mpz_ptr x, mp_limb_t n, unsigned flag)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+  ASSERT (flag == 0 || (flag == 1 && n > ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1 && ABOVE_THRESHOLD (n, FAC_DSC_THRESHOLD)));
+
+  if (n <= ODD_FACTORIAL_TABLE_LIMIT)
+    {
+      MPZ_NEWALLOC (x, 1)[0] = __gmp_oddfac_table[n];
+      SIZ (x) = 1;
+    }
+  else if (n <= ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1)
+    {
+      mp_ptr   px;
+
+      px = MPZ_NEWALLOC (x, 2);
+      umul_ppmm (px[1], px[0], __gmp_odd2fac_table[(n - 1) >> 1], __gmp_oddfac_table[n >> 1]);
+      SIZ (x) = 2;
+    }
+  else
+    {
+      unsigned s;
+      mp_ptr   factors;
+
+      s = 0;
+      {
+	mp_limb_t tn;
+	mp_limb_t prod, max_prod;
+	mp_size_t j;
+	TMP_SDECL;
+
+#if TUNE_PROGRAM_BUILD
+	ASSERT (FAC_DSC_THRESHOLD_LIMIT >= FAC_DSC_THRESHOLD);
+	ASSERT (FAC_DSC_THRESHOLD >= 2 * (ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 2));
+#endif
+
+	/* Compute the number of recursive steps for the DSC algorithm. */
+	for (tn = n; ABOVE_THRESHOLD (tn, FAC_DSC_THRESHOLD); s++)
+	  tn >>= 1;
+
+	j = 0;
+
+	TMP_SMARK;
+	factors = TMP_SALLOC_LIMBS (1 + tn / FACTORS_PER_LIMB);
+	ASSERT (tn >= FACTORS_PER_LIMB);
+
+	prod = 1;
+#if TUNE_PROGRAM_BUILD
+	max_prod = GMP_NUMB_MAX / (FAC_DSC_THRESHOLD_LIMIT * FAC_DSC_THRESHOLD_LIMIT);
+#else
+	max_prod = GMP_NUMB_MAX / (FAC_DSC_THRESHOLD * FAC_DSC_THRESHOLD);
+#endif
+
+	ASSERT (tn > ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1);
+	do {
+	  factors[j++] = ODD_DOUBLEFACTORIAL_TABLE_MAX;
+	  mp_limb_t diff = (tn - ODD_DOUBLEFACTORIAL_TABLE_LIMIT) & -CNST_LIMB (2);
+	  if ((diff & 2) != 0)
+	    {
+	      FACTOR_LIST_STORE (ODD_DOUBLEFACTORIAL_TABLE_LIMIT + diff, prod, max_prod, factors, j);
+	      diff -= 2;
+	    }
+	  if (diff != 0)
+	    {
+	      mp_limb_t fac = (ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 2) *
+		(ODD_DOUBLEFACTORIAL_TABLE_LIMIT + diff);
+	      do {
+		FACTOR_LIST_STORE (fac, prod, max_prod, factors, j);
+		diff -= 4;
+		fac += diff * 2;
+	      } while (diff != 0);
+	    }
+	  max_prod <<= 2;
+	  tn >>= 1;
+	} while (tn > ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1);
+
+	factors[j++] = prod;
+	factors[j++] = __gmp_odd2fac_table[(tn - 1) >> 1];
+	factors[j++] = __gmp_oddfac_table[tn >> 1];
+	mpz_prodlimbs (x, factors, j);
+
+	TMP_SFREE;
+      }
+
+      if (s != 0)
+	/* Use the algorithm described by Peter Luschny in "Divide,
+	   Swing and Conquer the Factorial!".
+
+	   Improvement: there are two temporary buffers, factors and
+	   square, that are never used together; with a good estimate
+	   of the maximal needed size, they could share a single
+	   allocation.
+	*/
+	{
+	  mpz_t mswing;
+	  mp_ptr sieve;
+	  mp_size_t size;
+	  TMP_DECL;
+
+	  TMP_MARK;
+
+	  flag--;
+	  size = n / GMP_NUMB_BITS + 4;
+	  ASSERT (primesieve_size (n - 1) <= size - (size / 2 + 1));
+	  /* 2-multiswing(n) < 2^(n-1)*sqrt(n/pi) < 2^(n+GMP_NUMB_BITS);
+	     one more can be overwritten by mul, another for the sieve */
+	  MPZ_TMP_INIT (mswing, size);
+	  /* Initialize size, so that ASSERT can check it correctly. */
+	  ASSERT_CODE (SIZ (mswing) = 0);
+
+	  /* Put the sieve on the second half, it will be overwritten by the last mswing. */
+	  sieve = PTR (mswing) + size / 2 + 1;
+
+	  size = (gmp_primesieve (sieve, n - 1) + 1) / log_n_max (n) + 1;
+
+	  factors = TMP_ALLOC_LIMBS (size);
+	  do {
+	    mp_ptr    square, px;
+	    mp_size_t nx, ns;
+	    mp_limb_t cy;
+	    TMP_DECL;
+
+	    s--;
+	    ASSERT (ABSIZ (mswing) < ALLOC (mswing) / 2); /* Check: sieve has not been overwritten */
+	    mpz_2multiswing_1 (mswing, n >> s, sieve, factors);
+
+	    TMP_MARK;
+	    nx = SIZ (x);
+	    if (s == flag) {
+	      size = nx;
+	      square = TMP_ALLOC_LIMBS (size);
+	      MPN_COPY (square, PTR (x), nx);
+	    } else {
+	      size = nx << 1;
+	      square = TMP_ALLOC_LIMBS (size);
+	      mpn_sqr (square, PTR (x), nx);
+	      size -= (square[size - 1] == 0);
+	    }
+	    ns = SIZ (mswing);
+	    nx = size + ns;
+	    px = MPZ_NEWALLOC (x, nx);
+	    ASSERT (ns <= size);
+	    cy = mpn_mul (px, square, size, PTR(mswing), ns); /* n!= n$ * floor(n/2)!^2 */
+
+	    SIZ(x) = nx - (cy == 0);
+	    TMP_FREE;
+	  } while (s != 0);
+	  TMP_FREE;
+	}
+    }
+}
+
+#undef FACTORS_PER_LIMB
+#undef FACTOR_LIST_STORE
diff --git a/mpz/out_raw.c b/mpz/out_raw.c
new file mode 100644
index 0000000..b9fd086
--- /dev/null
+++ b/mpz/out_raw.c
@@ -0,0 +1,172 @@
+/* mpz_out_raw -- write an mpz_t in raw format.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* HTON_LIMB_STORE takes a normal host byte order limb and stores it as
+   network byte order (ie. big endian). */
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define HTON_LIMB_STORE(dst, limb)  do { *(dst) = (limb); } while (0)
+#endif
+
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HTON_LIMB_STORE(dst, limb)  BSWAP_LIMB_STORE (dst, limb)
+#endif
+
+#ifndef HTON_LIMB_STORE
+#define HTON_LIMB_STORE(dst, limb)                                      \
+  do {                                                                  \
+    mp_limb_t  __limb = (limb);                                         \
+    char      *__p = (char *) (dst);                                    \
+    int        __i;                                                     \
+    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)                       \
+      __p[__i] = (char) (__limb >> ((GMP_LIMB_BYTES-1 - __i) * 8));  \
+  } while (0)
+#endif
+
+
+size_t
+mpz_out_raw (FILE *fp, mpz_srcptr x)
+{
+  mp_size_t   xsize, abs_xsize, bytes, i;
+  mp_srcptr   xp;
+  char        *tp, *bp;
+  mp_limb_t   xlimb;
+  int         zeros;
+  size_t      tsize, ssize;
+
+  xsize = SIZ(x);
+  abs_xsize = ABS (xsize);
+  bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8;
+  tsize = ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES) + bytes;
+
+  tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char);
+  bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES);
+
+  if (bytes != 0)
+    {
+      bp += bytes;
+      xp = PTR (x);
+      i = abs_xsize;
+
+      if (GMP_NAIL_BITS == 0)
+	{
+	  /* reverse limb order, and byte swap if necessary */
+#ifdef _CRAY
+	  _Pragma ("_CRI ivdep");
+#endif
+	  do
+	    {
+	      bp -= GMP_LIMB_BYTES;
+	      xlimb = *xp;
+	      HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
+	      xp++;
+	    }
+	  while (--i > 0);
+
+	  /* strip high zero bytes (without fetching from bp) */
+	  count_leading_zeros (zeros, xlimb);
+	  zeros /= 8;
+	  bp += zeros;
+	  bytes -= zeros;
+	}
+      else
+	{
+	  mp_limb_t  new_xlimb;
+	  int        bits;
+	  ASSERT_CODE (char *bp_orig = bp - bytes);
+
+	  ASSERT_ALWAYS (GMP_NUMB_BITS >= 8);
+
+	  bits = 0;
+	  xlimb = 0;
+	  for (;;)
+	    {
+	      while (bits >= 8)
+		{
+		  ASSERT (bp > bp_orig);
+		  *--bp = xlimb & 0xFF;
+		  xlimb >>= 8;
+		  bits -= 8;
+		}
+
+	      if (i == 0)
+		break;
+
+	      new_xlimb = *xp++;
+	      i--;
+	      ASSERT (bp > bp_orig);
+	      *--bp = (xlimb | (new_xlimb << bits)) & 0xFF;
+	      xlimb = new_xlimb >> (8 - bits);
+	      bits += GMP_NUMB_BITS - 8;
+	    }
+
+	  if (bits != 0)
+	    {
+	      ASSERT (bp > bp_orig);
+	      *--bp = xlimb;
+	    }
+
+	  ASSERT (bp == bp_orig);
+	  while (*bp == 0)
+	    {
+	      bp++;
+	      bytes--;
+	    }
+	}
+    }
+
+  /* total bytes to be written */
+  ssize = 4 + bytes;
+
+  /* twos complement negative for the size value */
+  bytes = (xsize >= 0 ? bytes : -bytes);
+
+  /* so we don't rely on sign extension in ">>" */
+  ASSERT_ALWAYS (sizeof (bytes) >= 4);
+
+  bp[-4] = bytes >> 24;
+  bp[-3] = bytes >> 16;
+  bp[-2] = bytes >> 8;
+  bp[-1] = bytes;
+  bp -= 4;
+
+  if (fp == 0)
+    fp = stdout;
+  if (fwrite (bp, ssize, 1, fp) != 1)
+    ssize = 0;
+
+  (*__gmp_free_func) (tp, tsize);
+  return ssize;
+}
diff --git a/mpz/out_str.c b/mpz/out_str.c
new file mode 100644
index 0000000..b1d8ae8
--- /dev/null
+++ b/mpz/out_str.c
@@ -0,0 +1,108 @@
+/* mpz_out_str(stream, base, integer) -- Output to STREAM the multi prec.
+   integer INTEGER in base BASE.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2005, 2011, 2012, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+size_t
+mpz_out_str (FILE *stream, int base, mpz_srcptr x)
+{
+  mp_ptr xp;
+  mp_size_t x_size = SIZ (x);
+  unsigned char *str;
+  size_t str_size;
+  size_t i;
+  size_t written;
+  const char *num_to_text;
+  TMP_DECL;
+
+  if (stream == 0)
+    stream = stdout;
+
+  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (UNLIKELY (base > 62))
+	    return 0;
+    }
+  else if (base > -2)
+    {
+      base = 10;
+    }
+  else
+    {
+      base = -base;
+      if (UNLIKELY (base > 36))
+	return 0;
+    }
+
+  written = 0;
+
+  if (x_size < 0)
+    {
+      fputc ('-', stream);
+      x_size = -x_size;
+      written = 1;
+    }
+
+  TMP_MARK;
+
+  DIGITS_IN_BASE_PER_LIMB (str_size, x_size, base);
+  str_size += 3;
+  str = (unsigned char *) TMP_ALLOC (str_size);
+
+  xp = PTR (x);
+  if (! POW2_P (base))
+    {
+      xp = TMP_ALLOC_LIMBS (x_size | 1);  /* |1 in case x_size==0 */
+      MPN_COPY (xp, PTR (x), x_size);
+    }
+
+  str_size = mpn_get_str (str, base, xp, x_size);
+
+  /* Convert result to printable chars.  */
+  for (i = 0; i < str_size; i++)
+    str[i] = num_to_text[str[i]];
+  str[str_size] = 0;
+
+  {
+    size_t fwret;
+    fwret = fwrite ((char *) str, 1, str_size, stream);
+    written += fwret;
+  }
+
+  TMP_FREE;
+  return ferror (stream) ? 0 : written;
+}
diff --git a/mpz/perfpow.c b/mpz/perfpow.c
new file mode 100644
index 0000000..9bbb497
--- /dev/null
+++ b/mpz/perfpow.c
@@ -0,0 +1,38 @@
+/* mpz_perfect_power_p(arg) -- Return non-zero if ARG is a perfect power,
+   zero otherwise.
+
+Copyright 1998-2001, 2005, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_perfect_power_p (mpz_srcptr u)
+{
+  return mpn_perfect_power_p (PTR (u), SIZ (u));
+}
diff --git a/mpz/perfsqr.c b/mpz/perfsqr.c
new file mode 100644
index 0000000..c2ac924
--- /dev/null
+++ b/mpz/perfsqr.c
@@ -0,0 +1,34 @@
+/* mpz_perfect_square_p(arg) -- Return non-zero if ARG is a perfect square,
+   zero otherwise.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_perfect_square_p 1
+
+#include "gmp-impl.h"
diff --git a/mpz/popcount.c b/mpz/popcount.c
new file mode 100644
index 0000000..e9a85bb
--- /dev/null
+++ b/mpz/popcount.c
@@ -0,0 +1,34 @@
+/* mpz_popcount(mpz_ptr op) -- Population count of OP.  If the operand is
+   negative, return ~0 (a novel representation of infinity).
+
+Copyright 1994, 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_popcount 1
+
+#include "gmp-impl.h"
diff --git a/mpz/pow_ui.c b/mpz/pow_ui.c
new file mode 100644
index 0000000..8bafaa7
--- /dev/null
+++ b/mpz/pow_ui.c
@@ -0,0 +1,52 @@
+/* mpz_pow_ui -- mpz raised to ulong.
+
+Copyright 2001, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_pow_ui (mpz_ptr r, mpz_srcptr b, unsigned long int e)
+{
+  /* We test some small exponents here, mainly to avoid the overhead of
+     mpz_n_pow_ui for small bases and exponents.  */
+  switch (e)
+    {
+    case 0:
+      mpz_set_ui (r, 1);
+      break;
+    case 1:
+      mpz_set (r, b);
+      break;
+    case 2:
+      mpz_mul (r, b, b);
+      break;
+    default:
+      mpz_n_pow_ui (r, PTR(b), (mp_size_t) SIZ(b), e);
+    }
+}
diff --git a/mpz/powm.c b/mpz/powm.c
new file mode 100644
index 0000000..f1bf8e3
--- /dev/null
+++ b/mpz/powm.c
@@ -0,0 +1,282 @@
+/* mpz_powm(res,base,exp,mod) -- Set R to (U^E) mod M.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2008, 2009,
+2011, 2012, 2015, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* TODO
+
+ * Improve handling of buffers.  It is pretty ugly now.
+
+ * For even moduli, we compute a binvert of its odd part both here and in
+   mpn_powm.  How can we avoid this recomputation?
+*/
+
+/*
+  b ^ e mod m   res
+  0   0     0    ?
+  0   e     0    ?
+  0   0     m    ?
+  0   e     m    0
+  b   0     0    ?
+  b   e     0    ?
+  b   0     m    1 mod m
+  b   e     m    b^e mod m
+*/
+
+#define HANDLE_NEGATIVE_EXPONENT 1
+
+void
+mpz_powm (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m)
+{
+  mp_size_t n, nodd, ncnt;
+  int cnt;
+  mp_ptr rp, tp;
+  mp_srcptr bp, ep, mp;
+  mp_size_t rn, bn, es, en, itch;
+  mpz_t new_b;			/* note: value lives long via 'b' */
+  TMP_DECL;
+
+  n = ABSIZ(m);
+  if (UNLIKELY (n == 0))
+    DIVIDE_BY_ZERO;
+
+  mp = PTR(m);
+
+  TMP_MARK;
+
+  es = SIZ(e);
+  if (UNLIKELY (es <= 0))
+    {
+      if (es == 0)
+	{
+	  /* b^0 mod m,  b is anything and m is non-zero.
+	     Result is 1 mod m, i.e., 1 or 0 depending on if m = 1.  */
+	  SIZ(r) = n != 1 || mp[0] != 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	  TMP_FREE;	/* we haven't really allocated anything here */
+	  return;
+	}
+#if HANDLE_NEGATIVE_EXPONENT
+      MPZ_TMP_INIT (new_b, n + 1);
+
+      if (UNLIKELY (! mpz_invert (new_b, b, m)))
+	DIVIDE_BY_ZERO;
+      b = new_b;
+      es = -es;
+#else
+      DIVIDE_BY_ZERO;
+#endif
+    }
+  en = es;
+
+  bn = ABSIZ(b);
+
+  if (UNLIKELY (bn == 0))
+    {
+      SIZ(r) = 0;
+      TMP_FREE;
+      return;
+    }
+
+  ep = PTR(e);
+
+  /* Handle (b^1 mod m) early, since mpn_pow* do not handle that case.  */
+  if (UNLIKELY (en == 1 && ep[0] == 1))
+    {
+      rp = TMP_ALLOC_LIMBS (n);
+      bp = PTR(b);
+      if (bn >= n)
+	{
+	  mp_ptr qp = TMP_ALLOC_LIMBS (bn - n + 1);
+	  mpn_tdiv_qr (qp, rp, 0L, bp, bn, mp, n);
+	  rn = n;
+	  MPN_NORMALIZE (rp, rn);
+
+	  if (rn != 0 && SIZ(b) < 0)
+	    {
+	      mpn_sub (rp, mp, n, rp, rn);
+	      rn = n;
+	      MPN_NORMALIZE_NOT_ZERO (rp, rn);
+	    }
+	}
+      else
+	{
+	  if (SIZ(b) < 0)
+	    {
+	      mpn_sub (rp, mp, n, bp, bn);
+	      rn = n;
+	      MPN_NORMALIZE_NOT_ZERO (rp, rn);
+	    }
+	  else
+	    {
+	      MPN_COPY (rp, bp, bn);
+	      rn = bn;
+	    }
+	}
+      goto ret;
+    }
+
+  /* Remove low zero limbs from M.  This loop will terminate for correctly
+     represented mpz numbers.  */
+  ncnt = 0;
+  while (UNLIKELY (mp[0] == 0))
+    {
+      mp++;
+      ncnt++;
+    }
+  nodd = n - ncnt;
+  cnt = 0;
+  if (mp[0] % 2 == 0)
+    {
+      mp_ptr newmp = TMP_ALLOC_LIMBS (nodd);
+      count_trailing_zeros (cnt, mp[0]);
+      mpn_rshift (newmp, mp, nodd, cnt);
+      nodd -= newmp[nodd - 1] == 0;
+      mp = newmp;
+      ncnt++;
+    }
+
+  if (ncnt != 0)
+    {
+      /* We will call both mpn_powm and mpn_powlo.  */
+      /* rp needs n, mpn_powlo needs 4n, the 2 mpn_binvert might need more */
+      mp_size_t n_largest_binvert = MAX (ncnt, nodd);
+      mp_size_t itch_binvert = mpn_binvert_itch (n_largest_binvert);
+      itch = 3 * n + MAX (itch_binvert, 2 * n);
+    }
+  else
+    {
+      /* We will call just mpn_powm.  */
+      mp_size_t itch_binvert = mpn_binvert_itch (nodd);
+      itch = n + MAX (itch_binvert, 2 * n);
+    }
+  tp = TMP_ALLOC_LIMBS (itch);
+
+  rp = tp;  tp += n;
+
+  bp = PTR(b);
+  mpn_powm (rp, bp, bn, ep, en, mp, nodd, tp);
+
+  rn = n;
+
+  if (ncnt != 0)
+    {
+      mp_ptr r2, xp, yp, odd_inv_2exp;
+      unsigned long t;
+      int bcnt;
+
+      if (bn < ncnt)
+	{
+	  mp_ptr newbp = TMP_ALLOC_LIMBS (ncnt);
+	  MPN_COPY (newbp, bp, bn);
+	  MPN_ZERO (newbp + bn, ncnt - bn);
+	  bp = newbp;
+	}
+
+      r2 = tp;
+
+      if (bp[0] % 2 == 0)
+	{
+	  if (en > 1)
+	    {
+	      MPN_ZERO (r2, ncnt);
+	      goto zero;
+	    }
+
+	  ASSERT (en == 1);
+	  t = (ncnt - (cnt != 0)) * GMP_NUMB_BITS + cnt;
+
+	  /* Count number of low zero bits in B, up to 3.  */
+	  bcnt = (0x1213 >> ((bp[0] & 7) << 1)) & 0x3;
+	  /* Note that ep[0] * bcnt might overflow, but that just results
+	     in a missed optimization.  */
+	  if (ep[0] * bcnt >= t)
+	    {
+	      MPN_ZERO (r2, ncnt);
+	      goto zero;
+	    }
+	}
+
+      mpn_powlo (r2, bp, ep, en, ncnt, tp + ncnt);
+
+    zero:
+      if (nodd < ncnt)
+	{
+	  mp_ptr newmp = TMP_ALLOC_LIMBS (ncnt);
+	  MPN_COPY (newmp, mp, nodd);
+	  MPN_ZERO (newmp + nodd, ncnt - nodd);
+	  mp = newmp;
+	}
+
+      odd_inv_2exp = tp + n;
+      mpn_binvert (odd_inv_2exp, mp, ncnt, tp + 2 * n);
+
+      mpn_sub (r2, r2, ncnt, rp, nodd > ncnt ? ncnt : nodd);
+
+      xp = tp + 2 * n;
+      mpn_mullo_n (xp, odd_inv_2exp, r2, ncnt);
+
+      if (cnt != 0)
+	xp[ncnt - 1] &= (CNST_LIMB(1) << cnt) - 1;
+
+      yp = tp;
+      if (ncnt > nodd)
+	mpn_mul (yp, xp, ncnt, mp, nodd);
+      else
+	mpn_mul (yp, mp, nodd, xp, ncnt);
+
+      mpn_add (rp, yp, n, rp, nodd);
+
+      ASSERT (nodd + ncnt >= n);
+      ASSERT (nodd + ncnt <= n + 1);
+    }
+
+  MPN_NORMALIZE (rp, rn);
+
+  if ((ep[0] & 1) && SIZ(b) < 0 && rn != 0)
+    {
+      mpn_sub (rp, PTR(m), n, rp, rn);
+      rn = n;
+      MPN_NORMALIZE (rp, rn);
+    }
+
+ ret:
+  MPZ_NEWALLOC (r, rn);
+  SIZ(r) = rn;
+  MPN_COPY (PTR(r), rp, rn);
+
+  TMP_FREE;
+}
diff --git a/mpz/powm_sec.c b/mpz/powm_sec.c
new file mode 100644
index 0000000..a2581a8
--- /dev/null
+++ b/mpz/powm_sec.c
@@ -0,0 +1,102 @@
+/* mpz_powm_sec(res,base,exp,mod) -- Set R to (U^E) mod M.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2008, 2009,
+2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+void
+mpz_powm_sec (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m)
+{
+  mp_size_t n;
+  mp_ptr rp, tp;
+  mp_srcptr bp, ep, mp;
+  mp_size_t rn, bn, es, en;
+  TMP_DECL;
+
+  n = ABSIZ(m);
+
+  mp = PTR(m);
+
+  if (UNLIKELY ((n == 0) || (mp[0] % 2 == 0)))
+    DIVIDE_BY_ZERO;
+
+  es = SIZ(e);
+  if (UNLIKELY (es <= 0))
+    {
+      if (es == 0)
+	{
+	  /* b^0 mod m,  b is anything and m is non-zero.
+	     Result is 1 mod m, i.e., 1 or 0 depending on if m = 1.  */
+	  SIZ(r) = n != 1 || mp[0] != 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	  return;
+	}
+      DIVIDE_BY_ZERO;
+    }
+  en = es;
+
+  bn = ABSIZ(b);
+
+  if (UNLIKELY (bn == 0))
+    {
+      SIZ(r) = 0;
+      return;
+    }
+
+  TMP_MARK;
+  TMP_ALLOC_LIMBS_2 (rp, n,
+		     tp, mpn_sec_powm_itch (bn, en * GMP_NUMB_BITS, n));
+
+  bp = PTR(b);
+  ep = PTR(e);
+
+  mpn_sec_powm (rp, bp, bn, ep, en * GMP_NUMB_BITS, mp, n, tp);
+
+  rn = n;
+
+  MPN_NORMALIZE (rp, rn);
+
+  if ((ep[0] & 1) && SIZ(b) < 0 && rn != 0)
+    {
+      mpn_sub (rp, PTR(m), n, rp, rn);
+      rn = n;
+      MPN_NORMALIZE (rp, rn);
+    }
+
+  MPZ_NEWALLOC (r, rn);
+  SIZ(r) = rn;
+  MPN_COPY (PTR(r), rp, rn);
+
+  TMP_FREE;
+}
diff --git a/mpz/powm_ui.c b/mpz/powm_ui.c
new file mode 100644
index 0000000..23d3ed8
--- /dev/null
+++ b/mpz/powm_ui.c
@@ -0,0 +1,281 @@
+/* mpz_powm_ui(res,base,exp,mod) -- Set R to (B^E) mod M.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2008, 2009,
+2011-2013, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This code is very old, and should be rewritten to current GMP standard.  It
+   is slower than mpz_powm for large exponents, but also for small exponents
+   when the mod argument is small.
+
+   As an intermediate solution, we now deflect to mpz_powm for exponents >= 20.
+*/
+
+/*
+  b ^ e mod m   res
+  0   0     0    ?
+  0   e     0    ?
+  0   0     m    ?
+  0   e     m    0
+  b   0     0    ?
+  b   e     0    ?
+  b   0     m    1 mod m
+  b   e     m    b^e mod m
+*/
+
+static void
+mod (mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv, mp_ptr tp)
+{
+  mp_ptr qp = tp;
+
+  if (dn == 1)
+    {
+      np[0] = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, dp[0]);
+    }
+  else if (dn == 2)
+    {
+      mpn_div_qr_2n_pi1 (qp, np, np, nn, dp[1], dp[0], dinv->inv32);
+    }
+  else if (BELOW_THRESHOLD (dn, DC_DIV_QR_THRESHOLD) ||
+	   BELOW_THRESHOLD (nn - dn, DC_DIV_QR_THRESHOLD))
+    {
+      mpn_sbpi1_div_qr (qp, np, nn, dp, dn, dinv->inv32);
+    }
+  else if (BELOW_THRESHOLD (dn, MUPI_DIV_QR_THRESHOLD) ||   /* fast condition */
+	   BELOW_THRESHOLD (nn, 2 * MU_DIV_QR_THRESHOLD) || /* fast condition */
+	   (double) (2 * (MU_DIV_QR_THRESHOLD - MUPI_DIV_QR_THRESHOLD)) * dn /* slow... */
+	   + (double) MUPI_DIV_QR_THRESHOLD * nn > (double) dn * nn)    /* ...condition */
+    {
+      mpn_dcpi1_div_qr (qp, np, nn, dp, dn, dinv);
+    }
+  else
+    {
+      /* We need to allocate separate remainder area, since mpn_mu_div_qr does
+	 not handle overlap between the numerator and remainder areas.
+	 FIXME: Make it handle such overlap.  */
+      mp_ptr rp, scratch;
+      mp_size_t itch;
+      TMP_DECL;
+      TMP_MARK;
+
+      itch = mpn_mu_div_qr_itch (nn, dn, 0);
+      rp = TMP_BALLOC_LIMBS (dn);
+      scratch = TMP_BALLOC_LIMBS (itch);
+
+      mpn_mu_div_qr (qp, rp, np, nn, dp, dn, scratch);
+      MPN_COPY (np, rp, dn);
+
+      TMP_FREE;
+    }
+}
+
+/* Compute t = a mod m, a is defined by (ap,an), m is defined by (mp,mn), and
+   t is defined by (tp,mn).  */
+static void
+reduce (mp_ptr tp, mp_srcptr ap, mp_size_t an, mp_srcptr mp, mp_size_t mn, gmp_pi1_t *dinv)
+{
+  mp_ptr rp, scratch;
+  TMP_DECL;
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (rp, an, scratch, an - mn + 1);
+  MPN_COPY (rp, ap, an);
+  mod (rp, an, mp, mn, dinv, scratch);
+  MPN_COPY (tp, rp, mn);
+
+  TMP_FREE;
+}
+
+void
+mpz_powm_ui (mpz_ptr r, mpz_srcptr b, unsigned long int el, mpz_srcptr m)
+{
+  if (el < 20)
+    {
+      mp_ptr xp, tp, mp, bp, scratch;
+      mp_size_t xn, tn, mn, bn;
+      int m_zero_cnt;
+      int c;
+      mp_limb_t e, m2;
+      gmp_pi1_t dinv;
+      TMP_DECL;
+
+      mp = PTR(m);
+      mn = ABSIZ(m);
+      if (UNLIKELY (mn == 0))
+	DIVIDE_BY_ZERO;
+
+      if (el <= 1)
+	{
+	  if (el == 1)
+	    {
+	      mpz_mod (r, b, m);
+	      return;
+	    }
+	  /* Exponent is zero, result is 1 mod M, i.e., 1 or 0 depending on if
+	     M equals 1.  */
+	  SIZ(r) = mn != 1 || mp[0] != 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	  return;
+	}
+
+      TMP_MARK;
+
+      /* Normalize m (i.e. make its most significant bit set) as required by
+	 division functions below.  */
+      count_leading_zeros (m_zero_cnt, mp[mn - 1]);
+      m_zero_cnt -= GMP_NAIL_BITS;
+      if (m_zero_cnt != 0)
+	{
+	  mp_ptr new_mp = TMP_ALLOC_LIMBS (mn);
+	  mpn_lshift (new_mp, mp, mn, m_zero_cnt);
+	  mp = new_mp;
+	}
+
+      m2 = mn == 1 ? 0 : mp[mn - 2];
+      invert_pi1 (dinv, mp[mn - 1], m2);
+
+      bn = ABSIZ(b);
+      bp = PTR(b);
+      if (bn > mn)
+	{
+	  /* Reduce possibly huge base.  Use a function call to reduce, since we
+	     don't want the quotient allocation to live until function return.  */
+	  mp_ptr new_bp = TMP_ALLOC_LIMBS (mn);
+	  reduce (new_bp, bp, bn, mp, mn, &dinv);
+	  bp = new_bp;
+	  bn = mn;
+	  /* Canonicalize the base, since we are potentially going to multiply with
+	     it quite a few times.  */
+	  MPN_NORMALIZE (bp, bn);
+	}
+
+      if (bn == 0)
+	{
+	  SIZ(r) = 0;
+	  TMP_FREE;
+	  return;
+	}
+
+      TMP_ALLOC_LIMBS_3 (xp, mn, scratch, mn + 1, tp, 2 * mn + 1);
+
+      MPN_COPY (xp, bp, bn);
+      xn = bn;
+
+      e = el;
+      count_leading_zeros (c, e);
+      e = (e << c) << 1;		/* shift the exp bits to the left, lose msb */
+      c = GMP_LIMB_BITS - 1 - c;
+
+      ASSERT (c != 0); /* el > 1 */
+	{
+	  /* Main loop. */
+	  do
+	    {
+	      mpn_sqr (tp, xp, xn);
+	      tn = 2 * xn; tn -= tp[tn - 1] == 0;
+	      if (tn < mn)
+		{
+		  MPN_COPY (xp, tp, tn);
+		  xn = tn;
+		}
+	      else
+		{
+		  mod (tp, tn, mp, mn, &dinv, scratch);
+		  MPN_COPY (xp, tp, mn);
+		  xn = mn;
+		}
+
+	      if ((mp_limb_signed_t) e < 0)
+		{
+		  mpn_mul (tp, xp, xn, bp, bn);
+		  tn = xn + bn; tn -= tp[tn - 1] == 0;
+		  if (tn < mn)
+		    {
+		      MPN_COPY (xp, tp, tn);
+		      xn = tn;
+		    }
+		  else
+		    {
+		      mod (tp, tn, mp, mn, &dinv, scratch);
+		      MPN_COPY (xp, tp, mn);
+		      xn = mn;
+		    }
+		}
+	      e <<= 1;
+	      c--;
+	    }
+	  while (c != 0);
+	}
+
+      /* We shifted m left m_zero_cnt steps.  Adjust the result by reducing it
+	 with the original M.  */
+      if (m_zero_cnt != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_lshift (tp, xp, xn, m_zero_cnt);
+	  tp[xn] = cy; xn += cy != 0;
+
+	  if (xn >= mn)
+	    {
+	      mod (tp, xn, mp, mn, &dinv, scratch);
+	      xn = mn;
+	    }
+	  mpn_rshift (xp, tp, xn, m_zero_cnt);
+	}
+      MPN_NORMALIZE (xp, xn);
+
+      if ((el & 1) != 0 && SIZ(b) < 0 && xn != 0)
+	{
+	  mp = PTR(m);			/* want original, unnormalized m */
+	  mpn_sub (xp, mp, mn, xp, xn);
+	  xn = mn;
+	  MPN_NORMALIZE (xp, xn);
+	}
+      MPZ_NEWALLOC (r, xn);
+      SIZ (r) = xn;
+      MPN_COPY (PTR(r), xp, xn);
+
+      TMP_FREE;
+    }
+  else
+    {
+      /* For large exponents, fake an mpz_t exponent and deflect to the more
+	 sophisticated mpz_powm.  */
+      mpz_t e;
+      mp_limb_t ep[LIMBS_PER_ULONG];
+      MPZ_FAKE_UI (e, ep, el);
+      mpz_powm (r, b, e, m);
+    }
+}
diff --git a/mpz/pprime_p.c b/mpz/pprime_p.c
new file mode 100644
index 0000000..b8a21c2
--- /dev/null
+++ b/mpz/pprime_p.c
@@ -0,0 +1,166 @@
+/* mpz_probab_prime_p --
+   An implementation of the probabilistic primality test found in Knuth's
+   Seminumerical Algorithms book.  If the function mpz_probab_prime_p()
+   returns 0 then n is not prime.  If it returns 1, then n is 'probably'
+   prime.  If it returns 2, n is surely prime.  The probability of a false
+   positive is (1/4)**reps, where reps is the number of internal passes of the
+   probabilistic algorithm.  Knuth indicates that 25 passes are reasonable.
+
+Copyright 1991, 1993, 1994, 1996-2002, 2005, 2015, 2016 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static int isprime (unsigned long int);
+
+
+/* MPN_MOD_OR_MODEXACT_1_ODD can be used instead of mpn_mod_1 for the trial
+   division.  It gives a result which is not the actual remainder r but a
+   value congruent to r*2^n mod d.  Since all the primes being tested are
+   odd, r*2^n mod p will be 0 if and only if r mod p is 0.  */
+
+int
+mpz_probab_prime_p (mpz_srcptr n, int reps)
+{
+  mp_limb_t r;
+  mpz_t n2;
+
+  /* Handle small and negative n.  */
+  if (mpz_cmp_ui (n, 1000000L) <= 0)
+    {
+      if (mpz_cmpabs_ui (n, 1000000L) <= 0)
+	{
+	  int is_prime;
+	  unsigned long n0;
+	  n0 = mpz_get_ui (n);
+	  is_prime = n0 & (n0 > 1) ? isprime (n0) : n0 == 2;
+	  return is_prime ? 2 : 0;
+	}
+      /* Negative number.  Negate and fall out.  */
+      PTR(n2) = PTR(n);
+      SIZ(n2) = -SIZ(n);
+      n = n2;
+    }
+
+  /* If n is now even, it is not a prime.  */
+  if (mpz_even_p (n))
+    return 0;
+
+#if defined (PP)
+  /* Check if n has small factors.  */
+#if defined (PP_INVERTED)
+  r = MPN_MOD_OR_PREINV_MOD_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP,
+			       (mp_limb_t) PP_INVERTED);
+#else
+  r = mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP);
+#endif
+  if (r % 3 == 0
+#if GMP_LIMB_BITS >= 4
+      || r % 5 == 0
+#endif
+#if GMP_LIMB_BITS >= 8
+      || r % 7 == 0
+#endif
+#if GMP_LIMB_BITS >= 16
+      || r % 11 == 0 || r % 13 == 0
+#endif
+#if GMP_LIMB_BITS >= 32
+      || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0
+#endif
+#if GMP_LIMB_BITS >= 64
+      || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0
+      || r % 47 == 0 || r % 53 == 0
+#endif
+      )
+    {
+      return 0;
+    }
+#endif /* PP */
+
+  /* Do more dividing.  We collect small primes, using umul_ppmm, until we
+     overflow a single limb.  We divide our number by the small primes product,
+     and look for factors in the remainder.  */
+  {
+    unsigned long int ln2;
+    unsigned long int q;
+    mp_limb_t p1, p0, p;
+    unsigned int primes[15];
+    int nprimes;
+
+    nprimes = 0;
+    p = 1;
+    ln2 = mpz_sizeinbase (n, 2);	/* FIXME: tune this limit */
+    for (q = PP_FIRST_OMITTED; q < ln2; q += 2)
+      {
+	if (isprime (q))
+	  {
+	    umul_ppmm (p1, p0, p, q);
+	    if (p1 != 0)
+	      {
+		r = MPN_MOD_OR_MODEXACT_1_ODD (PTR(n), (mp_size_t) SIZ(n), p);
+		while (--nprimes >= 0)
+		  if (r % primes[nprimes] == 0)
+		    {
+		      ASSERT_ALWAYS (mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) primes[nprimes]) == 0);
+		      return 0;
+		    }
+		p = q;
+		nprimes = 0;
+	      }
+	    else
+	      {
+		p = p0;
+	      }
+	    primes[nprimes++] = q;
+	  }
+      }
+  }
+
+  /* Perform a number of Miller-Rabin tests.  */
+  return mpz_millerrabin (n, reps);
+}
+
+static int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  ASSERT (t >= 3 && (t & 1) != 0);
+
+  d = 3;
+  do {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      d += 2;
+  } while (r != 0);
+  return 0;
+}
diff --git a/mpz/primorial_ui.c b/mpz/primorial_ui.c
new file mode 100644
index 0000000..b1176c7
--- /dev/null
+++ b/mpz/primorial_ui.c
@@ -0,0 +1,131 @@
+/* mpz_primorial_ui(RES, N) -- Set RES to N# the product of primes <= N.
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2012, 2015, 2016, 2021 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* TODO: Remove duplicated constants / macros / static functions...
+ */
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+#if WANT_ASSERT
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+#endif
+
+/*********************************************************/
+/* Section primorial: implementation                     */
+/*********************************************************/
+
+void
+mpz_primorial_ui (mpz_ptr res, unsigned long n)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+
+  if (n < 5)
+    {
+      /* The smallest 5 results for primorial are stored */
+      /* in a 15-bits constant (five octal digits)	 */
+      MPZ_NEWALLOC (res, 1)[0] = (066211 >> (n * 3)) & 7;
+      SIZ (res) = 1;
+    }
+  else
+    {
+      mp_limb_t *sieve, *factors;
+      mp_size_t size, j;
+      mp_limb_t prod;
+      TMP_DECL;
+
+      /* Try to estimate the result size, to avoid	*/
+      /* resizing, and to initially store the sieve.	*/
+      size = n / GMP_NUMB_BITS;
+      size = size + (size >> 1) + 1;
+      ASSERT (size >= primesieve_size (n));
+      sieve = MPZ_NEWALLOC (res, size);
+      size = (gmp_primesieve (sieve, n) + 1) / log_n_max (n) + 1;
+
+      TMP_MARK;
+      factors = TMP_ALLOC_LIMBS (size);
+
+      j = 0;
+
+      prod = 6;
+
+      /* Store primes from 5 to n */
+      {
+	mp_limb_t max_prod;
+
+	max_prod = GMP_NUMB_MAX / n;
+
+	/* Loop on sieved primes. */
+	for (mp_limb_t i = 4, *sp = sieve; i < n; i += GMP_LIMB_BITS * 3)
+	  for (mp_limb_t b = i, x = ~ *(sp++); x != 0; b += 3, x >>= 1)
+	    if (x & 1)
+	      {
+		mp_limb_t prime = b | 1;
+		FACTOR_LIST_STORE (prime, prod, max_prod, factors, j);
+	      }
+      }
+
+      if (j != 0)
+	{
+	  factors[j++] = prod;
+	  mpz_prodlimbs (res, factors, j);
+	}
+      else
+	{
+	  PTR (res)[0] = prod;
+	  SIZ (res) = 1;
+	}
+
+      TMP_FREE;
+    }
+}
diff --git a/mpz/prodlimbs.c b/mpz/prodlimbs.c
new file mode 100644
index 0000000..23f06a1
--- /dev/null
+++ b/mpz/prodlimbs.c
@@ -0,0 +1,108 @@
+/* mpz_prodlimbs(RESULT, V, LEN) -- Set RESULT to V[0]*V[1]*...*V[LEN-1].
+
+Contributed to the GNU project by Marco Bodrato.
+
+THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
+IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
+IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
+DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2010-2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*********************************************************/
+/* Section list-prod: product of a list -> mpz_t         */
+/*********************************************************/
+
+/* FIXME: should be tuned */
+#ifndef RECURSIVE_PROD_THRESHOLD
+#define RECURSIVE_PROD_THRESHOLD (MUL_TOOM22_THRESHOLD)
+#endif
+
+/* Computes the product of the j>1 limbs pointed by factors, puts the
+ * result in x. It assumes that all limbs are non-zero. Above
+ * Karatsuba's threshold it uses a binary splitting strategy, to gain
+ * speed by the asymptotically fast multiplication algorithms.
+ *
+ * The list in  {factors, j} is overwritten.
+ * Returns the size of the result
+ */
+
+mp_size_t
+mpz_prodlimbs (mpz_ptr x, mp_ptr factors, mp_size_t j)
+{
+  mp_limb_t cy;
+  mp_size_t size, i;
+  mp_ptr    prod;
+
+  ASSERT (j > 1);
+  ASSERT (RECURSIVE_PROD_THRESHOLD > 3);
+
+  if (BELOW_THRESHOLD (j, RECURSIVE_PROD_THRESHOLD)) {
+    j--;
+    size = 1;
+
+    for (i = 1; i < j; i++)
+      {
+	cy = mpn_mul_1 (factors, factors, size, factors[i]);
+	factors[size] = cy;
+	size += cy != 0;
+      };
+
+    prod = MPZ_NEWALLOC (x, size + 1);
+
+    cy = mpn_mul_1 (prod, factors, size, factors[i]);
+    prod[size] = cy;
+    return SIZ (x) = size + (cy != 0);
+  } else {
+    mpz_t x1, x2;
+    TMP_DECL;
+
+    i = j >> 1;
+    j -= i;
+    TMP_MARK;
+
+    MPZ_TMP_INIT (x2, j);
+
+    PTR (x1) = factors + i;
+    ALLOC (x1) = j;
+    j = mpz_prodlimbs (x2, factors + i, j);
+    i = mpz_prodlimbs (x1, factors, i);
+    size = i + j;
+    prod = MPZ_NEWALLOC (x, size);
+    if (i >= j)
+      cy = mpn_mul (prod, PTR(x1), i, PTR(x2), j);
+    else
+      cy = mpn_mul (prod, PTR(x2), j, PTR(x1), i);
+    TMP_FREE;
+
+    return SIZ (x) = size - (cy == 0);
+  }
+}
diff --git a/mpz/random.c b/mpz/random.c
new file mode 100644
index 0000000..1a1e515
--- /dev/null
+++ b/mpz/random.c
@@ -0,0 +1,39 @@
+/* mpz_random -- Generate a random mpz_t of specified size in limbs.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_random (mpz_ptr x, mp_size_t size)
+{
+  mpz_urandomb (x, RANDS, (unsigned long) (ABS (size) * GMP_NUMB_BITS));
+  if (size < 0)
+    SIZ(x) = -SIZ(x);
+}
diff --git a/mpz/random2.c b/mpz/random2.c
new file mode 100644
index 0000000..2c72540
--- /dev/null
+++ b/mpz/random2.c
@@ -0,0 +1,51 @@
+/* mpz_random2 -- Generate a positive random mpz_t of specified size, with
+   long runs of consecutive ones and zeros in the binary representation.
+   Meant for testing of other MP routines.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_random2 (mpz_ptr x, mp_size_t size)
+{
+  mp_size_t abs_size;
+  mp_ptr xp;
+
+  abs_size = ABS (size);
+  if (abs_size != 0)
+    {
+      xp = MPZ_NEWALLOC (x, abs_size);
+
+      mpn_random2 (xp, abs_size);
+    }
+
+  SIZ (x) = size;
+}
diff --git a/mpz/realloc.c b/mpz/realloc.c
new file mode 100644
index 0000000..4288ef1
--- /dev/null
+++ b/mpz/realloc.c
@@ -0,0 +1,70 @@
+/* _mpz_realloc -- make the mpz_t have NEW_ALLOC digits allocated.
+
+Copyright 1991, 1993-1995, 2000, 2001, 2008, 2015, 2021, 2022 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void *
+_mpz_realloc (mpz_ptr m, mp_size_t new_alloc)
+{
+  mp_ptr mp;
+
+  /* Never allocate zero space. */
+  new_alloc = MAX (new_alloc, 1);
+
+  if (sizeof (mp_size_t) == sizeof (int))
+    {
+      if (UNLIKELY (new_alloc > ULONG_MAX / GMP_NUMB_BITS))
+	MPZ_OVERFLOW;
+    }
+  else
+    {
+      if (UNLIKELY (new_alloc > INT_MAX))
+	MPZ_OVERFLOW;
+    }
+
+  if (ALLOC (m) == 0)
+    {
+      mp = __GMP_ALLOCATE_FUNC_LIMBS (new_alloc);
+    }
+  else
+    {
+      mp = __GMP_REALLOCATE_FUNC_LIMBS (PTR (m), ALLOC (m), new_alloc);
+
+      /* Don't create an invalid number; if the current value doesn't fit after
+	 reallocation, clear it to 0.  */
+      if (UNLIKELY (ABSIZ (m) > new_alloc))
+	SIZ (m) = 0;
+    }
+
+  PTR (m) = mp;
+  ALLOC(m) = new_alloc;
+  return (void *) mp;
+}
diff --git a/mpz/realloc2.c b/mpz/realloc2.c
new file mode 100644
index 0000000..633077e
--- /dev/null
+++ b/mpz/realloc2.c
@@ -0,0 +1,63 @@
+/* mpz_realloc2 -- change allocated data size.
+
+Copyright 2001, 2002, 2008, 2015, 2021, 2022 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_realloc2 (mpz_ptr m, mp_bitcnt_t bits)
+{
+  mp_size_t new_alloc;
+
+  bits -= (bits != 0);		/* Round down, except if 0 */
+  new_alloc = 1 + bits / GMP_NUMB_BITS;
+
+  if (sizeof (unsigned long) > sizeof (int)) /* param vs _mp_size field */
+    {
+      if (UNLIKELY (new_alloc > INT_MAX))
+	MPZ_OVERFLOW;
+    }
+
+  if (ALLOC (m) == 0)
+    {
+      PTR (m) = __GMP_ALLOCATE_FUNC_LIMBS (new_alloc);
+    }
+  else
+    {
+      PTR (m) = __GMP_REALLOCATE_FUNC_LIMBS (PTR(m), ALLOC(m), new_alloc);
+
+      /* Don't create an invalid number; if the current value doesn't fit after
+	 reallocation, clear it to 0.  */
+      if (ABSIZ(m) > new_alloc)
+	SIZ(m) = 0;
+    }
+
+  ALLOC(m) = new_alloc;
+}
diff --git a/mpz/remove.c b/mpz/remove.c
new file mode 100644
index 0000000..a655121
--- /dev/null
+++ b/mpz/remove.c
@@ -0,0 +1,146 @@
+/* mpz_remove -- divide out a factor and return its multiplicity.
+
+Copyright 1998-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_bitcnt_t
+mpz_remove (mpz_ptr dest, mpz_srcptr src, mpz_srcptr f)
+{
+  mp_bitcnt_t pwr;
+  mp_srcptr fp;
+  mp_size_t sn, fn, afn;
+  mp_limb_t fp0;
+
+  sn = SIZ (src);
+  fn = SIZ (f);
+  fp = PTR (f);
+  afn = ABS (fn);
+  fp0 = fp[0];
+
+  if (UNLIKELY ((afn <= (fp0 == 1)) /* mpz_cmpabs_ui (f, 1) <= 0 */
+		| (sn == 0)))
+    {
+      /*  f = 0 or f = +- 1 or src = 0 */
+      if (afn == 0)
+	DIVIDE_BY_ZERO;
+      mpz_set (dest, src);
+      return 0;
+    }
+
+  if ((fp0 & 1) != 0)
+    { /* f is odd */
+      mp_ptr dp;
+      mp_size_t dn;
+
+      dn = ABS (sn);
+      dp = MPZ_REALLOC (dest, dn);
+
+      pwr = mpn_remove (dp, &dn, PTR(src), dn, PTR(f), afn, ~(mp_bitcnt_t) 0);
+
+      SIZ (dest) = ((pwr & (fn < 0)) ^ (sn < 0)) ? -dn : dn;
+    }
+  else if (afn == (fp0 == 2))
+    { /* mpz_cmpabs_ui (f, 2) == 0 */
+      pwr = mpz_scan1 (src, 0);
+      mpz_div_2exp (dest, src, pwr);
+      if (pwr & (fn < 0)) /*((pwr % 2 == 1) && (SIZ (f) < 0))*/
+	mpz_neg (dest, dest);
+    }
+  else
+    { /* f != +-2 */
+      mpz_t x, rem;
+
+      mpz_init (rem);
+      mpz_init (x);
+
+      pwr = 0;
+      mpz_tdiv_qr (x, rem, src, f);
+      if (SIZ (rem) == 0)
+	{
+	  mpz_t fpow[GMP_LIMB_BITS];		/* Really MP_SIZE_T_BITS */
+	  int p;
+
+#if WANT_ORIGINAL_DEST
+	  mp_ptr dp;
+	  dp = PTR (dest);
+#endif
+      /* We could perhaps compute mpz_scan1(src,0)/mpz_scan1(f,0).  It is an
+	 upper bound of the result we're seeking.  We could also shift down the
+	 operands so that they become odd, to make intermediate values
+	 smaller.  */
+	  mpz_init_set (fpow[0], f);
+	  mpz_swap (dest, x);
+
+	  p = 1;
+      /* Divide by f, f^2 ... f^(2^k) until we get a remainder for f^(2^k).  */
+	  while (ABSIZ (dest) >= 2 * ABSIZ (fpow[p - 1]) - 1)
+	    {
+	      mpz_init (fpow[p]);
+	      mpz_mul (fpow[p], fpow[p - 1], fpow[p - 1]);
+	      mpz_tdiv_qr (x, rem, dest, fpow[p]);
+	      if (SIZ (rem) != 0) {
+		mpz_clear (fpow[p]);
+		break;
+	      }
+	      mpz_swap (dest, x);
+	      p++;
+	    }
+
+	  pwr = ((mp_bitcnt_t)1 << p) - 1;
+
+      /* Divide by f^(2^(k-1)), f^(2^(k-2)), ..., f for all divisors that give
+	 a zero remainder.  */
+	  while (--p >= 0)
+	    {
+	      mpz_tdiv_qr (x, rem, dest, fpow[p]);
+	      if (SIZ (rem) == 0)
+		{
+		  pwr += (mp_bitcnt_t)1 << p;
+		  mpz_swap (dest, x);
+		}
+	      mpz_clear (fpow[p]);
+	    }
+
+#if WANT_ORIGINAL_DEST
+	  if (PTR (x) == dp) {
+	    mpz_swap (dest, x);
+	    mpz_set (dest, x);
+	  }
+#endif
+	}
+      else
+	mpz_set (dest, src);
+
+      mpz_clear (x);
+      mpz_clear (rem);
+    }
+
+  return pwr;
+}
diff --git a/mpz/roinit_n.c b/mpz/roinit_n.c
new file mode 100644
index 0000000..9125466
--- /dev/null
+++ b/mpz/roinit_n.c
@@ -0,0 +1,43 @@
+/* mpz_roinit_n -- Initialize mpz with read-only limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mpz_srcptr
+mpz_roinit_n (mpz_ptr x, mp_srcptr xp, mp_size_t xs)
+{
+  mp_size_t xn = ABS(xs);
+  MPN_NORMALIZE (xp, xn);
+
+  ALLOC (x) = 0;
+  SIZ (x) = xs < 0 ? -xn : xn;
+  PTR (x) = (mp_ptr) xp;
+  return x;
+}
diff --git a/mpz/root.c b/mpz/root.c
new file mode 100644
index 0000000..7c8d368
--- /dev/null
+++ b/mpz/root.c
@@ -0,0 +1,90 @@
+/* mpz_root(root, u, nth) --  Set ROOT to floor(U^(1/nth)).
+   Return an indication if the result is exact.
+
+Copyright 1999-2003, 2005, 2012, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>		/* for NULL */
+#include "gmp-impl.h"
+
+int
+mpz_root (mpz_ptr root, mpz_srcptr u, unsigned long int nth)
+{
+  mp_ptr rootp, up;
+  mp_size_t us, un, rootn, remn;
+  TMP_DECL;
+
+  us = SIZ(u);
+
+  /* even roots of negatives provoke an exception */
+  if (UNLIKELY (us < 0 && (nth & 1) == 0))
+    SQRT_OF_NEGATIVE;
+
+  if (UNLIKELY (nth <= 1))
+    {
+      /* root extraction interpreted as c^(1/nth) means a zeroth root should
+	 provoke a divide by zero, do this even if c==0 */
+      if (UNLIKELY (nth == 0))
+	DIVIDE_BY_ZERO;
+      /* nth == 1 */
+      if (root != NULL && u != root)
+	mpz_set (root, u);
+      return 1;			/* exact result */
+    }
+
+  if (us == 0)
+    {
+      if (root != NULL)
+	SIZ(root) = 0;
+      return 1;			/* exact result */
+    }
+
+  un = ABS (us);
+  rootn = (un - 1) / nth + 1;
+
+  TMP_MARK;
+
+  /* FIXME: Perhaps disallow root == NULL */
+  if (root != NULL && u != root)
+    rootp = MPZ_NEWALLOC (root, rootn);
+  else
+    rootp = TMP_ALLOC_LIMBS (rootn);
+
+  up = PTR(u);
+  remn = mpn_rootrem (rootp, NULL, up, un, (mp_limb_t) nth);
+
+  if (root != NULL)
+    {
+      SIZ(root) = us >= 0 ? rootn : -rootn;
+      if (u == root)
+	MPN_COPY (up, rootp, rootn);
+    }
+
+  TMP_FREE;
+  return remn == 0;
+}
diff --git a/mpz/rootrem.c b/mpz/rootrem.c
new file mode 100644
index 0000000..67953db
--- /dev/null
+++ b/mpz/rootrem.c
@@ -0,0 +1,100 @@
+/* mpz_rootrem(root, rem, u, nth) --  Set ROOT to trunc(U^(1/nth)) and
+   set REM to the remainder.
+
+Copyright 1999-2003, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>		/* for NULL */
+#include "gmp-impl.h"
+
+void
+mpz_rootrem (mpz_ptr root, mpz_ptr rem, mpz_srcptr u, unsigned long int nth)
+{
+  mp_ptr rootp, up, remp;
+  mp_size_t us, un, rootn, remn;
+  TMP_DECL;
+
+  us = SIZ(u);
+
+  /* even roots of negatives provoke an exception */
+  if (UNLIKELY (us < 0 && (nth & 1) == 0))
+    SQRT_OF_NEGATIVE;
+
+  /* root extraction interpreted as c^(1/nth) means a zeroth root should
+     provoke a divide by zero, do this even if c==0 */
+  if (UNLIKELY (nth == 0))
+    DIVIDE_BY_ZERO;
+
+  if (us == 0)
+    {
+      if (root != NULL)
+	SIZ(root) = 0;
+      SIZ(rem) = 0;
+      return;
+    }
+
+  un = ABS (us);
+  rootn = (un - 1) / nth + 1;
+
+  TMP_MARK;
+
+  /* FIXME: Perhaps disallow root == NULL */
+  if (root != NULL && u != root)
+    rootp = MPZ_NEWALLOC (root, rootn);
+  else
+    rootp = TMP_ALLOC_LIMBS (rootn);
+
+  if (u != rem)
+    remp = MPZ_NEWALLOC (rem, un);
+  else
+    remp = TMP_ALLOC_LIMBS (un);
+
+  up = PTR(u);
+
+  if (nth == 1)
+    {
+      MPN_COPY (rootp, up, un);
+      remn = 0;
+    }
+  else
+    {
+      remn = mpn_rootrem (rootp, remp, up, un, (mp_limb_t) nth);
+    }
+
+  if (root != NULL)
+    {
+      SIZ(root) = us >= 0 ? rootn : -rootn;
+      if (u == root)
+	MPN_COPY (up, rootp, rootn);
+    }
+
+  if (u == rem)
+    MPN_COPY (up, remp, remn);
+  SIZ(rem) = us >= 0 ? remn : -remn;
+  TMP_FREE;
+}
diff --git a/mpz/rrandomb.c b/mpz/rrandomb.c
new file mode 100644
index 0000000..ae0c9e8
--- /dev/null
+++ b/mpz/rrandomb.c
@@ -0,0 +1,102 @@
+/* mpz_rrandomb -- Generate a positive random mpz_t of specified bit size, with
+   long runs of consecutive ones and zeros in the binary representation.
+   Meant for testing of other MP routines.
+
+Copyright 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+static void gmp_rrandomb (mp_ptr, gmp_randstate_ptr, mp_bitcnt_t);
+
+void
+mpz_rrandomb (mpz_ptr x, gmp_randstate_ptr rstate, mp_bitcnt_t nbits)
+{
+  mp_size_t nl;
+  mp_ptr xp;
+
+  nl = BITS_TO_LIMBS (nbits);
+  if (nbits != 0)
+    {
+      xp = MPZ_NEWALLOC (x, nl);
+      gmp_rrandomb (xp, rstate, nbits);
+    }
+
+  SIZ(x) = nl;
+}
+
+/* Ask _gmp_rand for 32 bits per call unless that's more than a limb can hold.
+   Thus, we get the same random number sequence in the common cases.
+   FIXME: We should always generate the same random number sequence!  */
+#if GMP_NUMB_BITS < 32
+#define BITS_PER_RANDCALL GMP_NUMB_BITS
+#else
+#define BITS_PER_RANDCALL 32
+#endif
+
+static void
+gmp_rrandomb (mp_ptr rp, gmp_randstate_ptr rstate, mp_bitcnt_t nbits)
+{
+  mp_bitcnt_t bi;
+  mp_limb_t ranm;		/* buffer for random bits */
+  unsigned cap_chunksize, chunksize;
+  mp_size_t i;
+
+  /* Set entire result to 111..1  */
+  i = BITS_TO_LIMBS (nbits) - 1;
+  rp[i] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - (nbits % GMP_NUMB_BITS)) % GMP_NUMB_BITS;
+  for (i = i - 1; i >= 0; i--)
+    rp[i] = GMP_NUMB_MAX;
+
+  _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+  cap_chunksize = nbits / (ranm % 4 + 1);
+  cap_chunksize += cap_chunksize == 0; /* make it at least 1 */
+
+  bi = nbits;
+
+  for (;;)
+    {
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      if (bi == 0)
+	break;			/* low chunk is ...1 */
+
+      rp[bi / GMP_NUMB_BITS] ^= CNST_LIMB (1) << bi % GMP_NUMB_BITS;
+
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      mpn_incr_u (rp + bi / GMP_NUMB_BITS, CNST_LIMB (1) << bi % GMP_NUMB_BITS);
+
+      if (bi == 0)
+	break;			/* low chunk is ...0 */
+    }
+}
diff --git a/mpz/scan0.c b/mpz/scan0.c
new file mode 100644
index 0000000..4b0f1ef
--- /dev/null
+++ b/mpz/scan0.c
@@ -0,0 +1,129 @@
+/* mpz_scan0 -- search for a 0 bit.
+
+Copyright 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* mpn_scan0 can't be used for the u>0 search since there might not be a 0
+   bit before the end of the data.  mpn_scan1 could be used for the inverted
+   search under u<0, but usually the search won't go very far so it seems
+   reasonable to inline that code.  */
+
+mp_bitcnt_t
+mpz_scan0 (mpz_srcptr u, mp_bitcnt_t starting_bit) __GMP_NOTHROW
+{
+  mp_srcptr      u_ptr = PTR(u);
+  mp_size_t      size = SIZ(u);
+  mp_size_t      abs_size = ABS(size);
+  mp_srcptr      u_end = u_ptr + abs_size;
+  mp_size_t      starting_limb = starting_bit / GMP_NUMB_BITS;
+  mp_srcptr      p = u_ptr + starting_limb;
+  mp_limb_t      limb;
+  int            cnt;
+
+  /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
+     u<0.  Notice this test picks up all cases of u==0 too. */
+  if (starting_limb >= abs_size)
+    return (size >= 0 ? starting_bit : ~(mp_bitcnt_t) 0);
+
+  limb = *p;
+
+  if (size >= 0)
+    {
+      /* Mask to 1 all bits before starting_bit, thus ignoring them. */
+      limb |= (CNST_LIMB(1) << (starting_bit % GMP_NUMB_BITS)) - 1;
+
+      /* Search for a limb which isn't all ones.  If the end is reached then
+	 the zero bit immediately past the end is returned.  */
+      while (limb == GMP_NUMB_MAX)
+	{
+	  p++;
+	  if (p == u_end)
+	    return (mp_bitcnt_t) abs_size * GMP_NUMB_BITS;
+	  limb = *p;
+	}
+
+      /* Now seek low 1 bit. */
+      limb = ~limb;
+    }
+  else
+    {
+      mp_srcptr  q;
+
+      /* If there's a non-zero limb before ours then we're in the ones
+	 complement region.  Search from *(p-1) downwards since that might
+	 give better cache locality, and since a non-zero in the middle of a
+	 number is perhaps a touch more likely than at the end.  */
+      q = p;
+      while (q != u_ptr)
+	{
+	  q--;
+	  if (*q != 0)
+	    goto inverted;
+	}
+
+      /* Adjust so ~limb implied by searching for 1 bit below becomes -limb.
+	 If limb==0 here then this isn't the beginning of twos complement
+	 inversion, but that doesn't matter because limb==0 is a zero bit
+	 immediately (-1 is all ones for below).  */
+      limb--;
+
+    inverted:
+      /* Now seeking a 1 bit. */
+
+      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+      limb &= (MP_LIMB_T_MAX << (starting_bit % GMP_NUMB_BITS));
+
+      if (limb == 0)
+	{
+	  /* If the high limb is zero after masking, then no 1 bits past
+	     starting_bit.  */
+	  p++;
+	  if (p == u_end)
+	    return ~(mp_bitcnt_t) 0;
+
+	  /* Search further for a non-zero limb.  The high limb is non-zero,
+	     if nothing else.  */
+	  for (;;)
+	    {
+	      limb = *p;
+	      if (limb != 0)
+		break;
+	      p++;
+	      ASSERT (p < u_end);
+	    }
+	}
+    }
+
+  ASSERT (limb != 0);
+  count_trailing_zeros (cnt, limb);
+  return (mp_bitcnt_t) (p - u_ptr) * GMP_NUMB_BITS + cnt;
+}
diff --git a/mpz/scan1.c b/mpz/scan1.c
new file mode 100644
index 0000000..d096147
--- /dev/null
+++ b/mpz/scan1.c
@@ -0,0 +1,123 @@
+/* mpz_scan1 -- search for a 1 bit.
+
+Copyright 2000-2002, 2004, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* mpn_scan0 can't be used for the inverted u<0 search since there might not
+   be a 0 bit before the end of the data.  mpn_scan1 could be used under u>0
+   (except when in the high limb), but usually the search won't go very far
+   so it seems reasonable to inline that code.  */
+
+mp_bitcnt_t
+mpz_scan1 (mpz_srcptr u, mp_bitcnt_t starting_bit) __GMP_NOTHROW
+{
+  mp_srcptr      u_ptr = PTR(u);
+  mp_size_t      size = SIZ(u);
+  mp_size_t      abs_size = ABS(size);
+  mp_srcptr      u_end = u_ptr + abs_size - 1;
+  mp_size_t      starting_limb = starting_bit / GMP_NUMB_BITS;
+  mp_srcptr      p = u_ptr + starting_limb;
+  mp_limb_t      limb;
+  int            cnt;
+
+  /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit for u<0.
+     Notice this test picks up any u==0 too. */
+  if (starting_limb >= abs_size)
+    return (size >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
+
+  /* This is an important case, where sign is not relevant! */
+  if (starting_bit == 0)
+    goto short_cut;
+
+  limb = *p;
+
+  if (size >= 0)
+    {
+      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+      limb &= (MP_LIMB_T_MAX << (starting_bit % GMP_NUMB_BITS));
+
+      if (limb == 0)
+	{
+	  /* If it's the high limb which is zero after masking, then there's
+	     no 1 bits after starting_bit.  */
+	  if (p == u_end)
+	    return ~(mp_bitcnt_t) 0;
+
+	  /* Otherwise search further for a non-zero limb.  The high limb is
+	     non-zero, if nothing else.  */
+	search_nonzero:
+	  do
+	    {
+	      ASSERT (p != u_end);
+	      p++;
+	    short_cut:
+	      limb = *p;
+	    }
+	  while (limb == 0);
+	}
+    }
+  else
+    {
+      /* If there's a non-zero limb before ours then we're in the ones
+	 complement region.  */
+      if (starting_limb == 0 || mpn_zero_p (u_ptr, starting_limb)) {
+	if (limb == 0)
+	  /* Seeking for the first non-zero bit, it is the same for u and -u. */
+	  goto search_nonzero;
+
+	/* Adjust so ~limb implied by searching for 0 bit becomes -limb.  */
+	limb--;
+      }
+
+      /* Now seeking a 0 bit. */
+
+      /* Mask to 1 all bits before starting_bit, thus ignoring them. */
+      limb |= (CNST_LIMB(1) << (starting_bit % GMP_NUMB_BITS)) - 1;
+
+      /* Search for a limb which is not all ones.  If the end is reached
+	 then the zero immediately past the end is the result.  */
+      while (limb == GMP_NUMB_MAX)
+	{
+	  if (p == u_end)
+	    return (mp_bitcnt_t) abs_size * GMP_NUMB_BITS;
+	  p++;
+	  limb = *p;
+	}
+
+      /* Now seeking low 1 bit. */
+      limb = ~limb;
+    }
+
+  ASSERT (limb != 0);
+  count_trailing_zeros (cnt, limb);
+  return (mp_bitcnt_t) (p - u_ptr) * GMP_NUMB_BITS + cnt;
+}
diff --git a/mpz/set.c b/mpz/set.c
new file mode 100644
index 0000000..7789af3
--- /dev/null
+++ b/mpz/set.c
@@ -0,0 +1,49 @@
+/* mpz_set (dest_integer, src_integer) -- Assign DEST_INTEGER from SRC_INTEGER.
+
+Copyright 1991, 1993-1995, 2000, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpz_set (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp, up;
+  mp_size_t usize, size;
+
+  usize = SIZ(u);
+  size = ABS (usize);
+
+  wp = MPZ_NEWALLOC (w, size);
+
+  up = PTR(u);
+
+  MPN_COPY (wp, up, size);
+  SIZ(w) = usize;
+}
diff --git a/mpz/set_d.c b/mpz/set_d.c
new file mode 100644
index 0000000..8cbda11
--- /dev/null
+++ b/mpz/set_d.c
@@ -0,0 +1,113 @@
+/* mpz_set_d(integer, val) -- Assign INTEGER with a double value VAL.
+
+Copyright 1995, 1996, 2000-2003, 2006, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* We used to have a special case for d < MP_BASE_AS_DOUBLE, just casting
+   double -> limb.  Unfortunately gcc 3.3 on powerpc970-apple-darwin6.8.5
+   got this wrong.  (It assumed __fixunsdfdi returned its result in a single
+   64-bit register, where instead that function followed the calling
+   conventions and gave the result in two parts r3 and r4.)  Hence the use
+   of __gmp_extract_double in all cases.  */
+
+void
+mpz_set_d (mpz_ptr r, double d)
+{
+  int negative;
+  mp_limb_t tp[LIMBS_PER_DOUBLE];
+  mp_ptr rp;
+  mp_size_t rn;
+
+  DOUBLE_NAN_INF_ACTION (d,
+			 __gmp_invalid_operation (),
+			 __gmp_invalid_operation ());
+
+  negative = d < 0;
+  d = ABS (d);
+
+  rn = __gmp_extract_double (tp, d);
+
+  if (rn <= 0)
+    rn = 0;
+
+  rp = MPZ_NEWALLOC (r, rn);
+
+  switch (rn)
+    {
+    default:
+      MPN_ZERO (rp, rn - LIMBS_PER_DOUBLE);
+      rp += rn - LIMBS_PER_DOUBLE;
+      /* fall through */
+#if LIMBS_PER_DOUBLE == 2
+    case 2:
+      rp[1] = tp[1], rp[0] = tp[0];
+      break;
+    case 1:
+      rp[0] = tp[1];
+      break;
+#endif
+#if LIMBS_PER_DOUBLE == 3
+    case 3:
+      rp[2] = tp[2], rp[1] = tp[1], rp[0] = tp[0];
+      break;
+    case 2:
+      rp[1] = tp[2], rp[0] = tp[1];
+      break;
+    case 1:
+      rp[0] = tp[2];
+      break;
+#endif
+#if LIMBS_PER_DOUBLE == 4
+    case 4:
+      rp[3] = tp[3], rp[2] = tp[2], rp[1] = tp[1], rp[0] = tp[0];
+      break;
+    case 3:
+      rp[2] = tp[3], rp[1] = tp[2], rp[0] = tp[1];
+      break;
+    case 2:
+      rp[1] = tp[3], rp[0] = tp[2];
+      break;
+    case 1:
+      rp[0] = tp[3];
+      break;
+#endif
+    case 0:
+      break;
+    }
+
+  SIZ(r) = negative ? -rn : rn;
+}
diff --git a/mpz/set_f.c b/mpz/set_f.c
new file mode 100644
index 0000000..b3ecc0b
--- /dev/null
+++ b/mpz/set_f.c
@@ -0,0 +1,71 @@
+/* mpz_set_f (dest_integer, src_float) -- Assign DEST_INTEGER from SRC_FLOAT.
+
+Copyright 1996, 2001, 2012, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpz_set_f (mpz_ptr w, mpf_srcptr u)
+{
+  mp_ptr    wp, up;
+  mp_size_t size;
+  mp_exp_t  exp;
+
+  /* abs(u)<1 truncates to zero */
+  exp = EXP (u);
+  if (exp <= 0)
+    {
+      SIZ(w) = 0;
+      return;
+    }
+
+  wp = MPZ_NEWALLOC (w, exp);
+  up = PTR(u);
+
+  size = SIZ (u);
+  SIZ(w) = (size >= 0 ? exp : -exp);
+  size = ABS (size);
+
+  if (exp > size)
+    {
+      /* pad with low zeros to get a total "exp" many limbs */
+      mp_size_t  zeros = exp - size;
+      MPN_ZERO (wp, zeros);
+      wp += zeros;
+    }
+  else
+    {
+      /* exp<=size, truncate to the high "exp" many limbs */
+      up += (size - exp);
+      size = exp;
+    }
+
+  MPN_COPY (wp, up, size);
+}
diff --git a/mpz/set_q.c b/mpz/set_q.c
new file mode 100644
index 0000000..2280247
--- /dev/null
+++ b/mpz/set_q.c
@@ -0,0 +1,34 @@
+/* mpz_set_q (dest_integer, src_rational) -- Assign DEST_INTEGER from
+   SRC_rational.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_set_q 1
+
+#include "gmp-impl.h"
diff --git a/mpz/set_si.c b/mpz/set_si.c
new file mode 100644
index 0000000..973aef8
--- /dev/null
+++ b/mpz/set_si.c
@@ -0,0 +1,55 @@
+/* mpz_set_si(dest,val) -- Assign DEST with a small value VAL.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_set_si (mpz_ptr dest, signed long int val)
+{
+  mp_size_t size;
+  mp_limb_t vl;
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  MPZ_NEWALLOC (dest, 1)[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if GMP_NAIL_BITS != 0
+  if (vl > GMP_NUMB_MAX)
+    {
+      MPZ_REALLOC (dest, 2);
+      PTR (dest)[1] = vl >> GMP_NUMB_BITS;
+      size = 2;
+    }
+#endif
+
+  SIZ (dest) = val >= 0 ? size : -size;
+}
diff --git a/mpz/set_str.c b/mpz/set_str.c
new file mode 100644
index 0000000..26c102b
--- /dev/null
+++ b/mpz/set_str.c
@@ -0,0 +1,144 @@
+/* mpz_set_str(mp_dest, string, base) -- Convert the \0-terminated
+   string STRING in base BASE to multiple precision integer in
+   MP_DEST.  Allow white space in the string.  If BASE == 0 determine
+   the base in the C standard way, i.e.  0xhh...h means base 16,
+   0oo...o means base 8, otherwise assume base 10.
+
+Copyright 1991, 1993, 1994, 1996-1998, 2000-2003, 2005, 2011-2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <string.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define digit_value_tab __gmp_digit_value_tab
+
+int
+mpz_set_str (mpz_ptr x, const char *str, int base)
+{
+  size_t str_size;
+  char *s, *begs;
+  size_t i;
+  mp_size_t xsize;
+  int c;
+  int negative;
+  const unsigned char *digit_value;
+  TMP_DECL;
+
+  digit_value = digit_value_tab;
+  if (base > 36)
+    {
+      /* For bases > 36, use the collating sequence
+	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
+      digit_value += 208;
+      if (UNLIKELY (base > 62))
+	return -1;		/* too large base */
+    }
+
+  /* Skip whitespace.  */
+  do
+    c = (unsigned char) *str++;
+  while (isspace (c));
+
+  negative = 0;
+  if (c == '-')
+    {
+      negative = 1;
+      c = (unsigned char) *str++;
+    }
+
+  if (digit_value[c] >= (base == 0 ? 10 : base))
+    return -1;			/* error if no valid digits */
+
+  /* If BASE is 0, try to find out the base by looking at the initial
+     characters.  */
+  if (base == 0)
+    {
+      base = 10;
+      if (c == '0')
+	{
+	  base = 8;
+	  c = (unsigned char) *str++;
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      c = (unsigned char) *str++;
+	    }
+	  else if (c == 'b' || c == 'B')
+	    {
+	      base = 2;
+	      c = (unsigned char) *str++;
+	    }
+	}
+    }
+
+  /* Skip leading zeros and white space.  */
+  while (c == '0' || isspace (c))
+    c = (unsigned char) *str++;
+  /* Make sure the string does not become empty, mpn_set_str would fail.  */
+  if (c == 0)
+    {
+      SIZ (x) = 0;
+      return 0;
+    }
+
+  TMP_MARK;
+  str_size = strlen (str - 1);
+  s = begs = (char *) TMP_ALLOC (str_size + 1);
+
+  /* Remove spaces from the string and convert the result from ASCII to a
+     byte array.  */
+  for (i = 0; i < str_size; i++)
+    {
+      if (!isspace (c))
+	{
+	  int dig = digit_value[c];
+	  if (UNLIKELY (dig >= base))
+	    {
+	      TMP_FREE;
+	      return -1;
+	    }
+	  *s++ = dig;
+	}
+      c = (unsigned char) *str++;
+    }
+
+  str_size = s - begs;
+
+  LIMBS_PER_DIGIT_IN_BASE (xsize, str_size, base);
+  MPZ_NEWALLOC (x, xsize);
+
+  /* Convert the byte array in base BASE to our bignum format.  */
+  xsize = mpn_set_str (PTR (x), (unsigned char *) begs, str_size, base);
+  SIZ (x) = negative ? -xsize : xsize;
+
+  TMP_FREE;
+  return 0;
+}
diff --git a/mpz/set_ui.c b/mpz/set_ui.c
new file mode 100644
index 0000000..12e95d1
--- /dev/null
+++ b/mpz/set_ui.c
@@ -0,0 +1,52 @@
+/* mpz_set_ui(integer, val) -- Assign INTEGER with a small value VAL.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_set_ui (mpz_ptr dest, unsigned long int val)
+{
+  mp_size_t size;
+
+  MPZ_NEWALLOC (dest, 1)[0] = val & GMP_NUMB_MASK;
+  size = val != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (val > GMP_NUMB_MAX)
+    {
+      MPZ_REALLOC (dest, 2);
+      PTR (dest)[1] = val >> GMP_NUMB_BITS;
+      size = 2;
+    }
+#endif
+
+  SIZ (dest) = size;
+}
diff --git a/mpz/setbit.c b/mpz/setbit.c
new file mode 100644
index 0000000..228a564
--- /dev/null
+++ b/mpz/setbit.c
@@ -0,0 +1,104 @@
+/* mpz_setbit -- set a specified bit.
+
+Copyright 1991, 1993-1995, 1997, 1999, 2001, 2002, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_setbit (mpz_ptr d, mp_bitcnt_t bit_idx)
+{
+  mp_size_t dsize = SIZ (d);
+  mp_ptr dp = PTR (d);
+  mp_size_t limb_idx;
+  mp_limb_t mask;
+
+  limb_idx = bit_idx / GMP_NUMB_BITS;
+  mask = CNST_LIMB(1) << (bit_idx % GMP_NUMB_BITS);
+  if (dsize >= 0)
+    {
+      if (limb_idx < dsize)
+	{
+	  dp[limb_idx] |= mask;
+	}
+      else
+	{
+	  /* Ugh.  The bit should be set outside of the end of the
+	     number.  We have to increase the size of the number.  */
+	  dp = MPZ_REALLOC (d, limb_idx + 1);
+	  SIZ (d) = limb_idx + 1;
+	  MPN_ZERO (dp + dsize, limb_idx - dsize);
+	  dp[limb_idx] = mask;
+	}
+    }
+  else
+    {
+      /* Simulate two's complement arithmetic, i.e. simulate
+	 1. Set OP = ~(OP - 1) [with infinitely many leading ones].
+	 2. Set the bit.
+	 3. Set OP = ~OP + 1.  */
+
+      dsize = -dsize;
+
+      if (limb_idx < dsize)
+	{
+	  mp_size_t zero_bound;
+	  /* No index upper bound on this loop, we're sure there's a non-zero limb
+	     sooner or later.  */
+	  zero_bound = 0;
+	  while (dp[zero_bound] == 0)
+	    zero_bound++;
+
+	  if (limb_idx > zero_bound)
+	    {
+	      mp_limb_t	 dlimb;
+	      dlimb = dp[limb_idx] & ~mask;
+	      dp[limb_idx] = dlimb;
+
+	      if (UNLIKELY ((dlimb == 0) + limb_idx == dsize)) /* dsize == limb_idx + 1 */
+		{
+		  /* high limb became zero, must normalize */
+		  MPN_NORMALIZE (dp, limb_idx);
+		  SIZ (d) = -limb_idx;
+		}
+	    }
+	  else if (limb_idx == zero_bound)
+	    {
+	      dp[limb_idx] = ((dp[limb_idx] - 1) & ~mask) + 1;
+	      ASSERT (dp[limb_idx] != 0);
+	    }
+	  else
+	    {
+	      MPN_DECR_U (dp + limb_idx, dsize - limb_idx, mask);
+	      dsize -= dp[dsize - 1] == 0;
+	      SIZ (d) = -dsize;
+	    }
+	}
+    }
+}
diff --git a/mpz/size.c b/mpz/size.c
new file mode 100644
index 0000000..b8aa59e
--- /dev/null
+++ b/mpz/size.c
@@ -0,0 +1,34 @@
+/* mpz_size(x) -- return the number of lims currently used by the
+   value of integer X.
+
+Copyright 1991, 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_size 1
+
+#include "gmp-impl.h"
diff --git a/mpz/sizeinbase.c b/mpz/sizeinbase.c
new file mode 100644
index 0000000..7a1bd01
--- /dev/null
+++ b/mpz/sizeinbase.c
@@ -0,0 +1,42 @@
+/* mpz_sizeinbase(x, base) -- return an approximation to the number of
+   character the integer X would have printed in base BASE.  The
+   approximation is never too small.
+
+Copyright 1991, 1993-1995, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+size_t
+mpz_sizeinbase (mpz_srcptr x, int base) __GMP_NOTHROW
+{
+  size_t  result;
+  MPN_SIZEINBASE (result, PTR(x), ABSIZ(x), base);
+  return result;
+}
diff --git a/mpz/sqrt.c b/mpz/sqrt.c
new file mode 100644
index 0000000..74d2f75
--- /dev/null
+++ b/mpz/sqrt.c
@@ -0,0 +1,76 @@
+/* mpz_sqrt(root, u) --  Set ROOT to floor(sqrt(U)).
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2012, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+void
+mpz_sqrt (mpz_ptr root, mpz_srcptr op)
+{
+  mp_size_t op_size, root_size;
+  mp_ptr root_ptr, op_ptr;
+
+  op_size = SIZ (op);
+  if (UNLIKELY (op_size <= 0))
+    {
+      if (UNLIKELY (op_size < 0))
+	SQRT_OF_NEGATIVE;
+      SIZ(root) = 0;
+      return;
+    }
+
+  /* The size of the root is accurate after this simple calculation.  */
+  root_size = (op_size + 1) / 2;
+  SIZ (root) = root_size;
+
+  op_ptr = PTR (op);
+
+  if (root == op)
+    {
+      /* Allocate temp space for the root, which we then copy to the
+	 shared OP/ROOT variable.  */
+      TMP_DECL;
+      TMP_MARK;
+
+      root_ptr = TMP_ALLOC_LIMBS (root_size);
+      mpn_sqrtrem (root_ptr, NULL, op_ptr, op_size);
+
+      MPN_COPY (op_ptr, root_ptr, root_size);
+
+      TMP_FREE;
+    }
+  else
+    {
+      root_ptr = MPZ_NEWALLOC (root, root_size);
+
+      mpn_sqrtrem (root_ptr, NULL, op_ptr, op_size);
+    }
+}
diff --git a/mpz/sqrtrem.c b/mpz/sqrtrem.c
new file mode 100644
index 0000000..a580d95
--- /dev/null
+++ b/mpz/sqrtrem.c
@@ -0,0 +1,85 @@
+/* mpz_sqrtrem(root,rem,x) -- Set ROOT to floor(sqrt(X)) and REM
+   to the remainder, i.e. X - ROOT**2.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2011, 2012, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_sqrtrem (mpz_ptr root, mpz_ptr rem, mpz_srcptr op)
+{
+  mp_size_t op_size, root_size, rem_size;
+  mp_ptr root_ptr, op_ptr, rem_ptr;
+
+  op_size = SIZ (op);
+  if (UNLIKELY (op_size <= 0))
+    {
+      if (UNLIKELY (op_size < 0))
+	SQRT_OF_NEGATIVE;
+      SIZ(root) = 0;
+      SIZ(rem) = 0;
+      return;
+    }
+
+  /* No-op if rem == op */
+  rem_ptr = MPZ_NEWALLOC (rem, op_size);
+
+  /* The size of the root is accurate after this simple calculation.  */
+  root_size = (op_size + 1) / 2;
+  SIZ (root) = root_size;
+
+  op_ptr = PTR (op);
+
+  if (root == op)
+    {
+      /* Allocate temp space for the root, which we then copy to the
+	 shared OP/ROOT variable.  */
+      TMP_DECL;
+      TMP_MARK;
+
+      root_ptr = TMP_ALLOC_LIMBS (root_size);
+      rem_size = mpn_sqrtrem (root_ptr, rem_ptr, op_ptr, op_size);
+
+      if (rem != root)	/* Don't overwrite remainder */
+	MPN_COPY (op_ptr, root_ptr, root_size);
+
+      TMP_FREE;
+    }
+  else
+    {
+      root_ptr = MPZ_NEWALLOC (root, root_size);
+
+      rem_size = mpn_sqrtrem (root_ptr, rem_ptr, op_ptr, op_size);
+    }
+
+  /* Write remainder size last, to make this function give only the square root
+     remainder, when passed ROOT == REM.  */
+  SIZ (rem) = rem_size;
+}
diff --git a/mpz/stronglucas.c b/mpz/stronglucas.c
new file mode 100644
index 0000000..0bf1ce0
--- /dev/null
+++ b/mpz/stronglucas.c
@@ -0,0 +1,214 @@
+/* mpz_stronglucas(n, t1, t2) -- An implementation of the strong Lucas
+   primality test on n, using parameters as suggested by the BPSW test.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2018, 2020 Free Software Foundation, Inc.
+
+Contributed by Marco Bodrato.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Returns an approximation of the sqare root of x.
+ * It gives:
+ *   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
+ * or
+ *   x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
+ */
+static mp_limb_t
+limb_apprsqrt (mp_limb_t x)
+{
+  int s;
+
+  ASSERT (x > 2);
+  count_leading_zeros (s, x);
+  s = (GMP_LIMB_BITS - s) >> 1;
+  return ((CNST_LIMB(1) << (s - 1)) + (x >> 1 >> s));
+}
+
+static int
+mpz_oddjacobi_ui (mpz_t b, mp_limb_t a)
+{
+  mp_limb_t  b_rem;
+  int        result_bit1;
+
+  ASSERT (a & 1);
+  ASSERT (a > 1);
+  ASSERT (SIZ (b) > 0);
+  ASSERT ((*PTR (b) & 1) == 1);
+
+  result_bit1 = 0;
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, b_rem, PTR (b), SIZ (b), a);
+  if (UNLIKELY (b_rem == 0))
+    return 0;
+  else
+    return mpn_jacobi_base (b_rem, a, result_bit1);
+}
+
+
+/* Performs strong Lucas' test on x, with parameters suggested */
+/* for the BPSW test. Qk and V are passed to recycle variables. */
+/* Requires GCD (x,6) = 1.*/
+int
+mpz_stronglucas (mpz_srcptr x, mpz_ptr V, mpz_ptr Qk)
+{
+  mp_bitcnt_t b0;
+  mpz_t n;
+  mp_limb_t D; /* The absolute value is stored. */
+  mp_limb_t g;
+  long Q;
+  mpz_t T1, T2;
+
+  /* Test on the absolute value. */
+  mpz_roinit_n (n, PTR (x), ABSIZ (x));
+
+  ASSERT (mpz_odd_p (n));
+  /* ASSERT (mpz_gcd_ui (NULL, n, 6) == 1);	*/
+#if GMP_NUMB_BITS % 16 == 0
+  /* (2^12 - 1) | (2^{GMP_NUMB_BITS*3/4} - 1)	*/
+  g = mpn_mod_34lsub1 (PTR (n), SIZ (n));
+  /* (2^12 - 1) = 3^2 * 5 * 7 * 13		*/
+  ASSERT (g % 3 != 0 && g % 5 != 0 && g % 7 != 0);
+  if ((g % 5 & 2) != 0)
+    /* (5/n) = -1, iff n = 2 or 3 (mod 5)	*/
+    /* D = 5; Q = -1 */
+    return mpn_strongfibo (PTR (n), SIZ (n), PTR (V));
+  else if (! POW2_P (g % 7))
+    /* (-7/n) = -1, iff n = 3,5 or 6 (mod 7)	*/
+    D = 7; /* Q = 2 */
+    /* (9/n) = -1, never: 9 = 3^2	*/
+  else if (mpz_oddjacobi_ui (n, 11) == -1)
+    /* (-11/n) = (n/11)	*/
+    D = 11; /* Q = 3 */
+  else if ((((g % 13 - (g % 13 >> 3)) & 7) > 4) ||
+	   (((g % 13 - (g % 13 >> 3)) & 7) == 2))
+    /* (13/n) = -1, iff n = 2,5,6,7,8 or 11 (mod 13)	*/
+    D = 13; /* Q = -3 */
+  else if (g % 3 == 2)
+    /* (-15/n) = (n/15) = (n/5)*(n/3)	*/
+    /* Here, (n/5) = 1, and		*/
+    /* (n/3) = -1, iff n = 2 (mod 3)	*/
+    D = 15; /* Q = 4 */
+#if GMP_NUMB_BITS % 32 == 0
+  /* (2^24 - 1) | (2^{GMP_NUMB_BITS*3/4} - 1)	*/
+  /* (2^24 - 1) = (2^12 - 1) * 17 * 241		*/
+  else if (! POW2_P (g % 17) && ! POW2_P (17 - g % 17))
+    /* (17/n) = -1, iff n != +-1,+-2,+-4,+-8 (mod 17)	*/
+    D = 17; /* Q = -4 */
+#endif
+#else
+  if (mpz_oddjacobi_ui (n, 5) == -1)
+    return mpn_strongfibo (PTR (n), SIZ (n), PTR (V));
+#endif
+  else
+  {
+    mp_limb_t maxD;
+    int jac;
+
+    /* n is odd, to possibly be a square, n % 8 = 1 is needed. */
+    if (((*PTR (n) & 6) == 0) && UNLIKELY (mpz_perfect_square_p (n)))
+      return 0; /* A square is composite. */
+
+    /* Check Ds up to square root (in case, n is prime)
+       or avoid overflows */
+    if (SIZ (n) == 1)
+      maxD = limb_apprsqrt (* PTR (n));
+    else if (BITS_PER_ULONG >= GMP_NUMB_BITS && SIZ (n) == 2)
+      mpn_sqrtrem (&maxD, (mp_ptr) NULL, PTR (n), 2);
+    else
+      maxD = GMP_NUMB_MAX;
+    maxD = MIN (maxD, ULONG_MAX);
+
+    unsigned Ddiff = 2;
+#if GMP_NUMB_BITS % 16 == 0
+    const unsigned D2 = 6;
+#if GMP_NUMB_BITS % 32 == 0
+    D = 19;
+    Ddiff = 4;
+#else
+    D = 17;
+#endif
+#else
+    const unsigned D2 = 4;
+    D = 7;
+#endif
+
+    /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,..	*/
+    /* For those Ds we have (D/n) = (n/|D|)	*/
+    /* FIXME: Should we loop only on prime Ds?	*/
+    /* The only interesting composite D is 15, because 3 is not tested.	*/
+    for (;;)
+      {
+	jac = mpz_oddjacobi_ui (n, D);
+	if (jac != 1)
+	  break;
+	if (UNLIKELY (D >= maxD))
+	  return 1;
+	D += Ddiff;
+	Ddiff = D2 - Ddiff;
+      }
+
+    if (UNLIKELY (jac == 0))
+      return 0;
+  }
+
+  /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
+  Q = (D & 2) ? (D >> 2) + 1 : -(long) (D >> 2);
+  /* ASSERT (mpz_si_kronecker ((D & 2) ? NEG_CAST (long, D) : D, n) == -1); */
+
+  /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
+  b0 = mpz_scan0 (n, 0);
+
+  mpz_init (T1);
+  mpz_init (T2);
+
+  /* If Ud != 0 && Vd != 0 */
+  if (mpz_lucas_mod (V, Qk, Q, b0, n, T1, T2) == 0)
+    if (LIKELY (--b0 != 0))
+      for (;;)
+	{
+	  /* V_{2k} <- V_k ^ 2 - 2Q^k */
+	  mpz_mul (T2, V, V);
+	  mpz_submul_ui (T2, Qk, 2);
+	  mpz_tdiv_r (V, T2, n);
+	  if (SIZ (V) == 0 || UNLIKELY (--b0 == 0))
+	    break;
+	  /* Q^{2k} = (Q^k)^2 */
+	  mpz_mul (T2, Qk, Qk);
+	  mpz_tdiv_r (Qk, T2, n);
+	}
+
+  mpz_clear (T1);
+  mpz_clear (T2);
+
+  return (b0 != 0);
+}
diff --git a/mpz/sub.c b/mpz/sub.c
new file mode 100644
index 0000000..7cb022e
--- /dev/null
+++ b/mpz/sub.c
@@ -0,0 +1,33 @@
+/* mpz_sub -- subtract integers.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_sub
+#include "aors.h"
diff --git a/mpz/sub_ui.c b/mpz/sub_ui.c
new file mode 100644
index 0000000..3ce23d3
--- /dev/null
+++ b/mpz/sub_ui.c
@@ -0,0 +1,33 @@
+/* mpz_sub_ui -- Subtract an mpz_t and an unsigned one-word integer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_sub_ui
+#include "aors_ui.h"
diff --git a/mpz/swap.c b/mpz/swap.c
new file mode 100644
index 0000000..255fac0
--- /dev/null
+++ b/mpz/swap.c
@@ -0,0 +1,39 @@
+/* mpz_swap (dest_integer, src_integer) -- Swap U and V.
+
+Copyright 1997, 1998, 2001, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_swap (mpz_ptr u, mpz_ptr v) __GMP_NOTHROW
+{
+  MP_SIZE_T_SWAP (ALLOC(u), ALLOC(v));
+  MP_SIZE_T_SWAP (SIZ(u), SIZ(v));
+  MP_PTR_SWAP (PTR(v), PTR(u));
+}
diff --git a/mpz/tdiv_q.c b/mpz/tdiv_q.c
new file mode 100644
index 0000000..8c5001d
--- /dev/null
+++ b/mpz/tdiv_q.c
@@ -0,0 +1,87 @@
+/* mpz_tdiv_q -- divide two integers and produce a quotient.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpz_tdiv_q (mpz_ptr quot, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_size_t ql;
+  mp_size_t ns, ds, nl, dl;
+  mp_ptr np, dp, qp, tp;
+  TMP_DECL;
+
+  ns = SIZ (num);
+  ds = SIZ (den);
+  nl = ABS (ns);
+  dl = ABS (ds);
+  ql = nl - dl + 1;
+
+  if (UNLIKELY (dl == 0))
+    DIVIDE_BY_ZERO;
+
+  if (ql <= 0)
+    {
+      SIZ (quot) = 0;
+      return;
+    }
+
+  qp = MPZ_REALLOC (quot, ql);
+
+  TMP_MARK;
+  dp = PTR (den);
+
+  /* Copy denominator to temporary space if it overlaps with the quotient.  */
+  if (dp == qp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (dl);
+      MPN_COPY (tp, dp, dl);
+      dp = tp;
+    }
+
+  tp = TMP_ALLOC_LIMBS (nl + 1);
+  np = PTR (num);
+  /* Copy numerator to temporary space if it overlaps with the quotient.  */
+  if (np == qp)
+    {
+      MPN_COPY (tp, np, nl);
+      /* Overlap dividend and scratch.  */
+      np = tp;
+    }
+  mpn_div_q (qp, np, nl, dp, dl, tp);
+
+  ql -=  qp[ql - 1] == 0;
+
+  SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql;
+  TMP_FREE;
+}
diff --git a/mpz/tdiv_q_2exp.c b/mpz/tdiv_q_2exp.c
new file mode 100644
index 0000000..c6b9bd0
--- /dev/null
+++ b/mpz/tdiv_q_2exp.c
@@ -0,0 +1,67 @@
+/* mpz_tdiv_q_2exp -- Divide an integer by 2**CNT.  Round the quotient
+   towards -infinity.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2002, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_tdiv_q_2exp (mpz_ptr r, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  mp_size_t un, rn;
+  mp_size_t limb_cnt;
+  mp_ptr rp;
+  mp_srcptr up;
+
+  un = SIZ(u);
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  rn = ABS (un) - limb_cnt;
+
+  if (rn <= 0)
+    rn = 0;
+  else
+    {
+      rp = MPZ_REALLOC (r, rn);
+      up = PTR(u) + limb_cnt;
+
+      cnt %= GMP_NUMB_BITS;
+      if (cnt != 0)
+	{
+	  mpn_rshift (rp, up, rn, cnt);
+	  rn -= rp[rn - 1] == 0;
+	}
+      else
+	{
+	  MPN_COPY_INCR (rp, up, rn);
+	}
+    }
+
+  SIZ(r) = un >= 0 ? rn : -rn;
+}
diff --git a/mpz/tdiv_q_ui.c b/mpz/tdiv_q_ui.c
new file mode 100644
index 0000000..a11c51e
--- /dev/null
+++ b/mpz/tdiv_q_ui.c
@@ -0,0 +1,83 @@
+/* mpz_tdiv_q_ui(quot, dividend, divisor_limb)
+   -- Divide DIVIDEND by DIVISOR_LIMB and store the result in QUOT.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2001, 2002, 2004, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_tdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  SIZ(quot) = 0;
+	  rl = np[0];
+	  return rl;
+	}
+
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      qn = nn - 2 + 1; qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/mpz/tdiv_qr.c b/mpz/tdiv_qr.c
new file mode 100644
index 0000000..ad82945
--- /dev/null
+++ b/mpz/tdiv_qr.c
@@ -0,0 +1,111 @@
+/* mpz_tdiv_qr(quot,rem,dividend,divisor) -- Set QUOT to DIVIDEND/DIVISOR,
+   and REM to DIVIDEND mod DIVISOR.
+
+Copyright 1991, 1993, 1994, 2000, 2001, 2005, 2011, 2012, 2021 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpz_tdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_size_t ql, n0;
+  mp_size_t ns, ds, nl, dl;
+  mp_ptr np, dp, qp, rp;
+  TMP_DECL;
+
+  ns = SIZ (num);
+  ds = SIZ (den);
+  nl = ABS (ns);
+  dl = ABS (ds);
+  ql = nl - dl + 1;
+
+  if (UNLIKELY (dl == 0))
+    DIVIDE_BY_ZERO;
+
+  rp = MPZ_REALLOC (rem, dl);
+
+  if (ql <= 0)
+    {
+      if (num != rem)
+	{
+	  np = PTR (num);
+	  MPN_COPY (rp, np, nl);
+	  SIZ (rem) = SIZ (num);
+	}
+      /* This needs to follow the assignment to rem, in case the
+	 numerator and quotient are the same.  */
+      SIZ (quot) = 0;
+      return;
+    }
+
+  qp = MPZ_REALLOC (quot, ql);
+
+  TMP_MARK;
+  np = PTR (num);
+  dp = PTR (den);
+
+  /* FIXME: We should think about how to handle the temporary allocation.
+     Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+     allocate temp space.  */
+
+  /* Copy denominator to temporary space if it overlaps with the quotient
+     or remainder.  */
+  if (dp == rp || dp == qp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (dl);
+      MPN_COPY (tp, dp, dl);
+      dp = tp;
+    }
+  /* Copy numerator to temporary space if it overlaps with the quotient or
+     remainder.  */
+  if (np == rp || np == qp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (nl);
+      MPN_COPY (tp, np, nl);
+      np = tp;
+    }
+
+  for (n0 = 0; *dp == 0; ++dp)
+    {
+      rp [n0++] = *np++;
+      --nl;
+    }
+  mpn_tdiv_qr (qp, rp + n0, 0L, np, nl, dp, dl - n0);
+
+  ql -=  qp[ql - 1] == 0;
+  MPN_NORMALIZE (rp, dl);
+
+  SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql;
+  SIZ (rem) = ns >= 0 ? dl : -dl;
+  TMP_FREE;
+}
diff --git a/mpz/tdiv_qr_ui.c b/mpz/tdiv_qr_ui.c
new file mode 100644
index 0000000..4e1c9fa
--- /dev/null
+++ b/mpz/tdiv_qr_ui.c
@@ -0,0 +1,100 @@
+/* mpz_tdiv_qr_ui(quot,rem,dividend,short_divisor) --
+   Set QUOT to DIVIDEND / SHORT_DIVISOR
+   and REM to DIVIDEND mod SHORT_DIVISOR.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2001, 2002, 2004, 2012, 2015
+Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_tdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp;
+      mp_size_t rn;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  SIZ(quot) = 0;
+	  rl = np[0];
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  return rl;
+	}
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      qn = nn - 2 + 1; qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+      rn = 2 - (rp[1] == 0);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = ns >= 0 ? rn : -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	}
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/mpz/tdiv_r.c b/mpz/tdiv_r.c
new file mode 100644
index 0000000..b0c38d6
--- /dev/null
+++ b/mpz/tdiv_r.c
@@ -0,0 +1,102 @@
+/* mpz_tdiv_r(rem, dividend, divisor) -- Set REM to DIVIDEND mod DIVISOR.
+
+Copyright 1991, 1993, 1994, 2000, 2001, 2005, 2012, 2021 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpz_tdiv_r (mpz_ptr rem, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_size_t ql, n0;
+  mp_size_t ns, nl, dl;
+  mp_ptr np, dp, qp, rp;
+  TMP_DECL;
+
+  ns = SIZ (num);
+  nl = ABS (ns);
+  dl = ABSIZ (den);
+  ql = nl - dl + 1;
+
+  if (UNLIKELY (dl == 0))
+    DIVIDE_BY_ZERO;
+
+  if (ql <= 0)
+    {
+      if (num != rem)
+	{
+	  SIZ (rem) = ns;
+	  rp = MPZ_NEWALLOC (rem, nl);
+	  np = PTR (num);
+	  MPN_COPY (rp, np, nl);
+	}
+      return;
+    }
+
+  rp = MPZ_REALLOC (rem, dl);
+
+  TMP_MARK;
+  qp = TMP_ALLOC_LIMBS (ql);
+  np = PTR (num);
+  dp = PTR (den);
+
+  /* FIXME: We should think about how to handle the temporary allocation.
+     Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+     allocate temp space.  */
+
+  /* Copy denominator to temporary space if it overlaps with the remainder.  */
+  if (dp == rp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (dl);
+      MPN_COPY (tp, dp, dl);
+      dp = tp;
+    }
+  /* Copy numerator to temporary space if it overlaps with the remainder.  */
+  if (np == rp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (nl);
+      MPN_COPY (tp, np, nl);
+      np = tp;
+    }
+
+  for (n0 = 0; *dp == 0; ++dp)
+    {
+      rp [n0++] = *np++;
+      --nl;
+    }
+  mpn_tdiv_qr (qp, rp + n0, 0L, np, nl, dp, dl - n0);
+
+  MPN_NORMALIZE (rp, dl);
+
+  SIZ (rem) = ns >= 0 ? dl : -dl;
+  TMP_FREE;
+}
diff --git a/mpz/tdiv_r_2exp.c b/mpz/tdiv_r_2exp.c
new file mode 100644
index 0000000..96a81f7
--- /dev/null
+++ b/mpz/tdiv_r_2exp.c
@@ -0,0 +1,76 @@
+/* mpz_tdiv_r_2exp -- Divide an integer by 2**CNT and produce a remainder.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_tdiv_r_2exp (mpz_ptr res, mpz_srcptr in, mp_bitcnt_t cnt)
+{
+  mp_size_t in_size = ABSIZ (in);
+  mp_size_t res_size;
+  mp_size_t limb_cnt = cnt / GMP_NUMB_BITS;
+  mp_srcptr in_ptr = PTR (in);
+
+  if (in_size > limb_cnt)
+    {
+      /* The input operand is (probably) greater than 2**CNT.  */
+      mp_limb_t x;
+
+      x = in_ptr[limb_cnt] & (((mp_limb_t) 1 << cnt % GMP_NUMB_BITS) - 1);
+      if (x != 0)
+	{
+	  res_size = limb_cnt + 1;
+	  MPZ_REALLOC (res, res_size);
+
+	  PTR (res)[limb_cnt] = x;
+	}
+      else
+	{
+	  MPN_NORMALIZE (in_ptr, limb_cnt);
+
+	  MPZ_REALLOC (res, limb_cnt);
+
+	  res_size = limb_cnt;
+	}
+    }
+  else
+    {
+      /* The input operand is smaller than 2**CNT.  We perform a no-op,
+	 apart from that we might need to copy IN to RES.  */
+      limb_cnt = in_size;
+      MPZ_REALLOC (res, limb_cnt);
+
+      res_size = limb_cnt;
+    }
+
+  if (res != in)
+    MPN_COPY (PTR (res), PTR (in), limb_cnt);
+  SIZ (res) = SIZ (in) >= 0 ? res_size : -res_size;
+}
diff --git a/mpz/tdiv_r_ui.c b/mpz/tdiv_r_ui.c
new file mode 100644
index 0000000..f3da8ef
--- /dev/null
+++ b/mpz/tdiv_r_ui.c
@@ -0,0 +1,96 @@
+/* mpz_tdiv_r_ui(rem, dividend, divisor_limb)
+   -- Set REM to DIVDEND mod DIVISOR_LIMB.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2001, 2002, 2004, 2005, 2012,
+2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_tdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp, qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  return rl;
+	}
+
+      rp = MPZ_NEWALLOC (rem, 2);
+
+      TMP_MARK;
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      TMP_FREE;
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      rn = 2 - (rp[1] == 0);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = ns >= 0 ? rn : -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	}
+    }
+
+  return rl;
+}
diff --git a/mpz/tdiv_ui.c b/mpz/tdiv_ui.c
new file mode 100644
index 0000000..4618599
--- /dev/null
+++ b/mpz/tdiv_ui.c
@@ -0,0 +1,84 @@
+/* mpz_tdiv_ui(dividend, divisor_limb) -- Return DIVDEND mod DIVISOR_LIMB.
+
+Copyright 1991, 1993, 1994, 1996-1998, 2001, 2002, 2004, 2005, 2012 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+unsigned long int
+mpz_tdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+      mp_ptr qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  return rl;
+	}
+
+      TMP_MARK;
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      TMP_FREE;
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      rn = 2 - (rp[1] == 0);  rn -= (rp[rn - 1] == 0);
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+    }
+
+  return rl;
+}
diff --git a/mpz/tstbit.c b/mpz/tstbit.c
new file mode 100644
index 0000000..48725d4
--- /dev/null
+++ b/mpz/tstbit.c
@@ -0,0 +1,80 @@
+/* mpz_tstbit -- test a specified bit.
+
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* For negatives the effective twos complement is achieved by negating the
+   limb tested, either with a ones or twos complement.  Twos complement
+   ("-") is used if there's only zero limbs below the one being tested.
+   Ones complement ("~") is used if there's a non-zero below.  Note that "-"
+   is correct even if the limb examined is 0 (and the true beginning of twos
+   complement is further up).
+
+   Testing the limbs below p is unavoidable on negatives, but will usually
+   need to examine only *(p-1).  The search is done from *(p-1) down to
+   *u_ptr, since that might give better cache locality, and because a
+   non-zero limb is perhaps a touch more likely in the middle of a number
+   than at the low end.
+
+   Bits past the end of available data simply follow sign of u.  Notice that
+   the limb_index >= abs_size test covers u=0 too.  */
+
+int
+mpz_tstbit (mpz_srcptr u, mp_bitcnt_t bit_index) __GMP_NOTHROW
+{
+  mp_srcptr      u_ptr      = PTR(u);
+  mp_size_t      size       = SIZ(u);
+  unsigned       abs_size   = ABS(size);
+  mp_size_t      limb_index = bit_index / GMP_NUMB_BITS;
+  mp_srcptr      p          = u_ptr + limb_index;
+  mp_limb_t      limb;
+
+  if (limb_index >= abs_size)
+    return (size < 0);
+
+  limb = *p;
+  if (size < 0)
+    {
+      limb = -limb;     /* twos complement */
+
+      while (p != u_ptr)
+	{
+	  p--;
+	  if (*p != 0)
+	    {
+	      limb--;	/* make it a ones complement instead */
+	      break;
+	    }
+	}
+    }
+
+  return (limb >> (bit_index % GMP_NUMB_BITS)) & 1;
+}
diff --git a/mpz/ui_pow_ui.c b/mpz/ui_pow_ui.c
new file mode 100644
index 0000000..87f2d3a
--- /dev/null
+++ b/mpz/ui_pow_ui.c
@@ -0,0 +1,58 @@
+/* mpz_ui_pow_ui -- ulong raised to ulong.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpz_ui_pow_ui (mpz_ptr r, unsigned long b, unsigned long e)
+{
+#if GMP_NAIL_BITS != 0
+  if (b > GMP_NUMB_MAX)
+    {
+      mp_limb_t bb[2];
+      bb[0] = b & GMP_NUMB_MASK;
+      bb[1] = b >> GMP_NUMB_BITS;
+      mpz_n_pow_ui (r, bb, (mp_size_t) 2, e);
+    }
+  else
+#endif
+    {
+#ifdef _LONG_LONG_LIMB
+      /* i386 gcc 2.95.3 doesn't recognise blimb can be eliminated when
+	 mp_limb_t is an unsigned long, so only use a separate blimb when
+	 necessary.  */
+      mp_limb_t  blimb = b;
+      mpz_n_pow_ui (r, &blimb, (mp_size_t) (b != 0), e);
+#else
+      mpz_n_pow_ui (r, &b,     (mp_size_t) (b != 0), e);
+#endif
+    }
+}
diff --git a/mpz/ui_sub.c b/mpz/ui_sub.c
new file mode 100644
index 0000000..1d0edb9
--- /dev/null
+++ b/mpz/ui_sub.c
@@ -0,0 +1,90 @@
+/* mpz_ui_sub -- Subtract an unsigned one-word integer and an mpz_t.
+
+Copyright 2002, 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_ui_sub (mpz_ptr w, unsigned long int uval, mpz_srcptr v)
+{
+  mp_ptr vp, wp;
+  mp_size_t vn, wn;
+  mp_limb_t cy;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (uval > GMP_NUMB_MAX)
+    {
+      mpz_t u;
+      mp_limb_t ul[2];
+      PTR(u) = ul;
+      ul[0] = uval & GMP_NUMB_MASK;
+      ul[1] = uval >> GMP_NUMB_BITS;
+      SIZ(u) = 2;
+      mpz_sub (w, u, v);
+      return;
+    }
+#endif
+
+  vn = SIZ(v);
+
+  if (vn > 1)
+    {
+      wp = MPZ_REALLOC (w, vn);
+      vp = PTR(v);
+      mpn_sub_1 (wp, vp, vn, (mp_limb_t) uval);
+      wn = -(vn - (wp[vn - 1] == 0));
+    }
+  else if (vn >= 0)
+    {
+      mp_limb_t vp0;
+      vp0 = PTR (v)[0] & - (mp_limb_t) vn;
+      wp = MPZ_NEWALLOC (w, 1);
+      if (uval >= vp0)
+	{
+	  wp[0] = uval - vp0;
+	  wn = wp[0] != 0;
+	}
+      else
+	{
+	  wp[0] = vp0 - uval;
+	  wn = -1;
+	}
+    }
+  else /* (vn < 0) */
+    {
+      vn = -vn;
+      wp = MPZ_REALLOC (w, vn + 1);
+      vp = PTR(v);
+      cy = mpn_add_1 (wp, vp, vn, (mp_limb_t) uval);
+      wp[vn] = cy;
+      wn = vn + (cy != 0);
+    }
+
+  SIZ(w) = wn;
+}
diff --git a/mpz/urandomb.c b/mpz/urandomb.c
new file mode 100644
index 0000000..5c6ad77
--- /dev/null
+++ b/mpz/urandomb.c
@@ -0,0 +1,47 @@
+/* mpz_urandomb (rop, state, n) -- Generate a uniform pseudorandom
+   integer in the range 0 to 2^N - 1, inclusive, using STATE as the
+   random state previously initialized by a call to gmp_randinit().
+
+Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_urandomb (mpz_ptr rop, gmp_randstate_ptr rstate, mp_bitcnt_t nbits)
+{
+  mp_ptr rp;
+  mp_size_t size;
+
+  size = BITS_TO_LIMBS (nbits);
+  rp = MPZ_NEWALLOC (rop, size);
+
+  _gmp_rand (rp, rstate, nbits);
+  MPN_NORMALIZE (rp, size);
+  SIZ (rop) = size;
+}
diff --git a/mpz/urandomm.c b/mpz/urandomm.c
new file mode 100644
index 0000000..4e6b0ba
--- /dev/null
+++ b/mpz/urandomm.c
@@ -0,0 +1,98 @@
+/* mpz_urandomm (rop, state, n) -- Generate a uniform pseudorandom
+   integer in the range 0 to N-1, using STATE as the random state
+   previously initialized by a call to gmp_randinit().
+
+Copyright 2000, 2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h" /* for count_leading_zeros */
+
+
+#define MAX_URANDOMM_ITER  80
+
+void
+mpz_urandomm (mpz_ptr rop, gmp_randstate_ptr rstate, mpz_srcptr n)
+{
+  mp_ptr rp, np;
+  mp_size_t nbits, size;
+  mp_limb_t nh;
+  int count;
+  int pow2;
+  int cmp;
+  TMP_DECL;
+
+  size = ABSIZ (n);
+  if (UNLIKELY (size == 0))
+    DIVIDE_BY_ZERO;
+
+  np = PTR (n);
+  nh = np[size - 1];
+
+  /* Detect whether n is a power of 2.  */
+  pow2 = POW2_P (nh) && (size == 1 || mpn_zero_p (np, size - 1));
+
+  count_leading_zeros (count, nh);
+  nbits = size * GMP_NUMB_BITS - (count - GMP_NAIL_BITS) - pow2;
+  if (nbits == 0)		/* nbits == 0 means that n was == 1.  */
+    {
+      SIZ (rop) = 0;
+      return;
+    }
+
+  TMP_MARK;
+  if (rop == n)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (size);
+      MPN_COPY (tp, np, size);
+      np = tp;
+    }
+
+  /* Here the allocated size can be one too much if n is a power of
+     (2^GMP_NUMB_BITS) but it's convenient for using mpn_cmp below.  */
+  rp = MPZ_NEWALLOC (rop, size);
+  /* Clear last limb to prevent the case in which size is one too much.  */
+  rp[size - 1] = 0;
+
+  count = MAX_URANDOMM_ITER;	/* Set iteration count limit.  */
+  do
+    {
+      _gmp_rand (rp, rstate, nbits);
+      MPN_CMP (cmp, rp, np, size);
+    }
+  while (cmp >= 0 && --count != 0);
+
+  if (count == 0)
+    /* Too many iterations; return result mod n == result - n */
+    mpn_sub_n (rp, rp, np, size);
+
+  MPN_NORMALIZE (rp, size);
+  SIZ (rop) = size;
+  TMP_FREE;
+}
diff --git a/mpz/xor.c b/mpz/xor.c
new file mode 100644
index 0000000..5ec657a
--- /dev/null
+++ b/mpz/xor.c
@@ -0,0 +1,146 @@
+/* mpz_xor -- Logical xor.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+{
+  mp_srcptr op1_ptr, op2_ptr;
+  mp_size_t op1_size, op2_size;
+  mp_ptr res_ptr;
+  mp_size_t res_size;
+
+  op1_size = SIZ(op1);
+  op2_size = SIZ(op2);
+
+  if (op1_size < op2_size)
+    {
+      MPZ_SRCPTR_SWAP (op1, op2);
+      MP_SIZE_T_SWAP (op1_size, op2_size);
+    }
+
+  op1_ptr = PTR(op1);
+  res_ptr = PTR(res);
+
+  if (op2_size >= 0)
+    {
+      if (res_ptr != op1_ptr)
+	{
+	  res_ptr = MPZ_REALLOC (res, op1_size);
+	  MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+		    op1_size - op2_size);
+	}
+      if (LIKELY (op2_size != 0))
+	mpn_xor_n (res_ptr, op1_ptr, PTR(op2), op2_size);
+      res_size = op1_size;
+
+      MPN_NORMALIZE (res_ptr, res_size);
+      SIZ(res) = res_size;
+    }
+  else
+    {
+      mp_ptr opx;
+      TMP_DECL;
+
+      op2_size = -op2_size;
+      TMP_MARK;
+      if (op1_size < 0)
+	{
+	  mp_ptr opy;
+
+	  /* Both operands are negative, the result will be positive.
+	      (-OP1) ^ (-OP2) =
+	     = ~(OP1 - 1) ^ ~(OP2 - 1) =
+	     = (OP1 - 1) ^ (OP2 - 1)  */
+
+	  op1_size = -op1_size;
+
+	  /* Possible optimization: Decrease mpn_sub precision,
+	     as we won't use the entire res of both.  */
+	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
+	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
+	  op1_ptr = opx;
+
+	  mpn_sub_1 (opy, PTR(op2), op2_size, (mp_limb_t) 1);
+	  op2_ptr = opy;
+
+	  res_ptr = MPZ_NEWALLOC (res, op2_size);
+	  /* Don't re-read OP1_PTR and OP2_PTR.  They point to temporary
+	     space--never to the space PTR(res) used to point to before
+	     reallocation.  */
+
+	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+		    op2_size - op1_size);
+	  mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
+	  TMP_FREE;
+	  res_size = op2_size;
+
+	  MPN_NORMALIZE (res_ptr, res_size);
+	  SIZ(res) = res_size;
+	}
+      else
+	{
+	  /* Operand 2 negative, so will be the result.
+	     -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
+	     = ~(OP1 ^ ~(OP2 - 1)) + 1 =
+	     = (OP1 ^ (OP2 - 1)) + 1      */
+
+	  res_size = MAX (op1_size, op2_size);
+	  res_ptr = MPZ_REALLOC (res, res_size + 1);
+	  op1_ptr = PTR(op1);
+
+	  opx = TMP_ALLOC_LIMBS (op2_size);
+	  mpn_sub_1 (opx, PTR(op2), op2_size, (mp_limb_t) 1);
+	  op2_ptr = opx;
+
+	  if (res_size == op1_size)
+	    {
+	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
+	      mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
+	    }
+	  else
+	    {
+	      MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
+	      if (LIKELY (op1_size != 0))
+		mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
+	    }
+	  TMP_FREE;
+
+	  res_ptr[res_size] = 0;
+	  MPN_INCR_U (res_ptr, res_size + 1, (mp_limb_t) 1);
+	  res_size += res_ptr[res_size];
+
+	  MPN_NORMALIZE_NOT_ZERO (res_ptr, res_size);
+	  SIZ(res) = -res_size;
+	}
+    }
+}
diff --git a/nextprime.c b/nextprime.c
new file mode 100644
index 0000000..e8e60dd
--- /dev/null
+++ b/nextprime.c
@@ -0,0 +1,166 @@
+/* gmp_nextprime -- generate small primes reasonably efficiently for internal
+   GMP needs.
+
+   Contributed to the GNU project by Torbjorn Granlund.  Miscellaneous
+   improvements by Martin Boij.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  Optimisation ideas:
+
+  1. Unroll the sieving loops.  Should reach 1 write/cycle.  That would be a 2x
+     improvement.
+
+  2. Separate sieving with primes p < SIEVESIZE and p >= SIEVESIZE.  The latter
+     will need at most one write, and thus not need any inner loop.
+
+  3. For primes p >= SIEVESIZE, i.e., typically the majority of primes, we
+     perform more than one division per sieving write.  That might dominate the
+     entire run time for the nextprime function.  A incrementally initialised
+     remainder table of Pi(65536) = 6542 16-bit entries could replace that
+     division.
+*/
+
+#include "gmp-impl.h"
+#include <string.h>		/* for memset */
+
+
+unsigned long int
+gmp_nextprime (gmp_primesieve_t *ps)
+{
+  unsigned long p, d, pi;
+  unsigned char *sp;
+  static unsigned char addtab[] =
+    { 2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,
+      2,4,6,2,6,4,2,4,2,10,2,10 };
+  unsigned char *addp = addtab;
+  unsigned long ai;
+
+  /* Look for already sieved primes.  A sentinel at the end of the sieving
+     area allows us to use a very simple loop here.  */
+  d = ps->d;
+  sp = ps->s + d;
+  while (*sp != 0)
+    sp++;
+  if (sp != ps->s + SIEVESIZE)
+    {
+      d = sp - ps->s;
+      ps->d = d + 1;
+      return ps->s0 + 2 * d;
+    }
+
+  /* Handle the number 2 separately.  */
+  if (ps->s0 < 3)
+    {
+      ps->s0 = 3 - 2 * SIEVESIZE; /* Tricky */
+      return 2;
+    }
+
+  /* Exhausted computed primes.  Resieve, then call ourselves recursively.  */
+
+#if 0
+  for (sp = ps->s; sp < ps->s + SIEVESIZE; sp++)
+    *sp = 0;
+#else
+  memset (ps->s, 0, SIEVESIZE);
+#endif
+
+  ps->s0 += 2 * SIEVESIZE;
+
+  /* Update sqrt_s0 as needed.  */
+  while ((ps->sqrt_s0 + 1) * (ps->sqrt_s0 + 1) <= ps->s0 + 2 * SIEVESIZE - 1)
+    ps->sqrt_s0++;
+
+  pi = ((ps->s0 + 3) / 2) % 3;
+  if (pi > 0)
+    pi = 3 - pi;
+  if (ps->s0 + 2 * pi <= 3)
+    pi += 3;
+  sp = ps->s + pi;
+  while (sp < ps->s + SIEVESIZE)
+    {
+      *sp = 1, sp += 3;
+    }
+
+  pi = ((ps->s0 + 5) / 2) % 5;
+  if (pi > 0)
+    pi = 5 - pi;
+  if (ps->s0 + 2 * pi <= 5)
+    pi += 5;
+  sp = ps->s + pi;
+  while (sp < ps->s + SIEVESIZE)
+    {
+      *sp = 1, sp += 5;
+    }
+
+  pi = ((ps->s0 + 7) / 2) % 7;
+  if (pi > 0)
+    pi = 7 - pi;
+  if (ps->s0 + 2 * pi <= 7)
+    pi += 7;
+  sp = ps->s + pi;
+  while (sp < ps->s + SIEVESIZE)
+    {
+      *sp = 1, sp += 7;
+    }
+
+  p = 11;
+  ai = 0;
+  while (p <= ps->sqrt_s0)
+    {
+      pi = ((ps->s0 + p) / 2) % p;
+      if (pi > 0)
+	pi = p - pi;
+      if (ps->s0 + 2 * pi <= p)
+	  pi += p;
+      sp = ps->s + pi;
+      while (sp < ps->s + SIEVESIZE)
+	{
+	  *sp = 1, sp += p;
+	}
+      p += addp[ai];
+      ai = (ai + 1) % 48;
+    }
+  ps->d = 0;
+  return gmp_nextprime (ps);
+}
+
+void
+gmp_init_primesieve (gmp_primesieve_t *ps)
+{
+  ps->s0 = 0;
+  ps->sqrt_s0 = 0;
+  ps->d = SIEVESIZE;
+  ps->s[SIEVESIZE] = 0;		/* sentinel */
+}
diff --git a/patches/exceptions.diff b/patches/exceptions.diff
new file mode 100644
index 0000000..0e6a4f9
--- /dev/null
+++ b/patches/exceptions.diff
@@ -0,0 +1,340 @@
+Make GMP compile in a noexcept environment
+
+GMP throws exceptions to indicate errors like failed allocation or negative
+factorials. Change these to print a terse error message and SIGABRT.
+
+Ideally, these would `LOG(FATAL)`. However, giving GMP an Abseil dependency
+breaks Haskell binaries. (The problematic dependency chain appears to be
+Haskell -> GMP -> Abseil -> libunwind.) Instead, just log using `std::cerr` and
+call `std::abort`; the abnormal termination will trigger a stack trace in
+google3 binaries anyway.
+
+This is an updated version of cl/50915228.
+
+--- a/gmpxx.h
++++ b/gmpxx.h
+@@ -39,7 +39,12 @@ see https://www.gnu.org/licenses/.  */
+ #include <utility>
+ #include <algorithm>  /* swap */
+ #include <string>
++#ifdef __EXCEPTIONS
+ #include <stdexcept>
++#else
++#include <cstdlib>
++#include <iostream>
++#endif
+ #include <cfloat>
+ #include <gmp.h>
+ 
+@@ -1240,7 +1245,14 @@ struct __gmp_fac_function
+   static void eval(mpz_ptr z, signed long l)
+   {
+     if (l < 0)
++#ifdef __EXCEPTIONS
+       throw std::domain_error ("factorial(negative)");
++#else
++      {
++        std::cerr << "std::domain_error: factorial(negative)\n";
++        std::abort();
++      }
++#endif
+     eval(z, static_cast<unsigned long>(l));
+   }
+   static void eval(mpz_ptr z, mpz_srcptr w)
+@@ -1248,9 +1260,23 @@ struct __gmp_fac_function
+     if (!mpz_fits_ulong_p(w))
+       {
+ 	if (mpz_sgn(w) < 0)
++#ifdef __EXCEPTIONS
+ 	  throw std::domain_error ("factorial(negative)");
++#else
++         {
++	    std::cerr << "std::domain_error: factorial(negative)\n";
++           std::abort();
++         }
++#endif
+ 	else
++#ifdef __EXCEPTIONS
+ 	  throw std::bad_alloc(); // or std::overflow_error ("factorial")?
++#else
++         {
++	    std::cerr << "std::bad_alloc\n";
++           std::abort();
++         }
++#endif
+       }
+     eval(z, mpz_get_ui(w));
+   }
+@@ -1264,7 +1290,14 @@ struct __gmp_primorial_function
+   static void eval(mpz_ptr z, signed long l)
+   {
+     if (l < 0)
++#ifdef __EXCEPTIONS
+       throw std::domain_error ("primorial(negative)");
++#else
++      {
++        std::cerr << "std::domain_error: primorial(negative)\n";
++        std::abort();
++      }
++#endif
+     eval(z, static_cast<unsigned long>(l));
+   }
+   static void eval(mpz_ptr z, mpz_srcptr w)
+@@ -1272,9 +1305,23 @@ struct __gmp_primorial_function
+     if (!mpz_fits_ulong_p(w))
+       {
+ 	if (mpz_sgn(w) < 0)
++#ifdef __EXCEPTIONS
+ 	  throw std::domain_error ("primorial(negative)");
++#else
++         {
++	    std::cerr << "std::domain_error: primorial(negative)\n";
++           std::abort();
++         }
++#endif
+ 	else
++#ifdef __EXCEPTIONS
+ 	  throw std::bad_alloc(); // or std::overflow_error ("primorial")?
++#else
++         {
++	    std::cerr << "std::bad_alloc\n";
++           std::abort();
++         }
++#endif
+       }
+     eval(z, mpz_get_ui(w));
+   }
+@@ -1299,7 +1346,14 @@ struct __gmp_fib_function
+   static void eval(mpz_ptr z, mpz_srcptr w)
+   {
+     if (!mpz_fits_slong_p(w))
++#ifdef __EXCEPTIONS
+       throw std::bad_alloc(); // or std::overflow_error ("fibonacci")?
++#else
++      {
++        std::cerr << "std::bad_alloc\n";
++        std::abort();
++      }
++#endif
+     eval(z, mpz_get_si(w));
+   }
+   static void eval(mpz_ptr z, double d)
+@@ -1650,7 +1704,14 @@ public:
+     if (mpz_init_set_str (mp, s, base) != 0)
+       {
+         mpz_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpz_set_str");
++#else
++        {
++          std::cerr << "std::invalid_argument: mpz_set_str\n";
++          std::abort();
++        }
++#endif
+       }
+   }
+   explicit __gmp_expr(const std::string &s, int base = 0)
+@@ -1658,7 +1719,14 @@ public:
+     if (mpz_init_set_str(mp, s.c_str(), base) != 0)
+       {
+         mpz_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpz_set_str");
++#else
++        {
++          std::cerr << "std::invalid_argument: mpz_set_str\n";
++          std::abort();
++        }
++#endif
+       }
+   }
+ 
+@@ -1685,13 +1753,27 @@ public:
+   __gmp_expr & operator=(const char *s)
+   {
+     if (mpz_set_str (mp, s, 0) != 0)
++#ifdef __EXCEPTIONS
+       throw std::invalid_argument ("mpz_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpz_set_str\n";
++        std::abort();
++      }
++#endif
+     return *this;
+   }
+   __gmp_expr & operator=(const std::string &s)
+   {
+     if (mpz_set_str(mp, s.c_str(), 0) != 0)
++#ifdef __EXCEPTIONS
+       throw std::invalid_argument ("mpz_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpz_set_str\n";
++        std::abort();
++      }
++#endif
+     return *this;
+   }
+ 
+@@ -1828,7 +1910,14 @@ public:
+     else if (mpq_set_str(mp, s, base) != 0)
+       {
+         mpq_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpq_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpq_set_str\n";
++        std::abort();
++      }
++#endif
+       }
+   }
+   explicit __gmp_expr(const std::string &s, int base = 0)
+@@ -1837,7 +1926,14 @@ public:
+     if (mpq_set_str (mp, s.c_str(), base) != 0)
+       {
+         mpq_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpq_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpq_set_str\n";
++        std::abort();
++      }
++#endif
+       }
+   }
+   explicit __gmp_expr(mpq_srcptr q)
+@@ -1874,13 +1970,27 @@ public:
+   __gmp_expr & operator=(const char *s)
+   {
+     if (mpq_set_str (mp, s, 0) != 0)
++#ifdef __EXCEPTIONS
+       throw std::invalid_argument ("mpq_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpq_set_str\n";
++        std::abort();
++      }
++#endif
+     return *this;
+   }
+   __gmp_expr & operator=(const std::string &s)
+   {
+     if (mpq_set_str(mp, s.c_str(), 0) != 0)
++#ifdef __EXCEPTIONS
+       throw std::invalid_argument ("mpq_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpq_set_str\n";
++        std::abort();
++      }
++#endif
+     return *this;
+   }
+ 
+@@ -2038,7 +2148,14 @@ public:
+     if (mpf_init_set_str (mp, s, 0) != 0)
+       {
+         mpf_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpf_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpf_set_str\n";
++        std::abort();
++      }
++#endif
+       }
+   }
+   __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0)
+@@ -2047,7 +2164,14 @@ public:
+     if (mpf_set_str(mp, s, base) != 0)
+       {
+         mpf_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpf_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpf_set_str\n";
++        std::abort();
++      }
++#endif
+       }
+   }
+   explicit __gmp_expr(const std::string &s)
+@@ -2055,7 +2179,14 @@ public:
+     if (mpf_init_set_str(mp, s.c_str(), 0) != 0)
+       {
+         mpf_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpf_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpf_set_str\n";
++        std::abort();
++      }
++#endif
+       }
+   }
+   __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0)
+@@ -2064,7 +2195,14 @@ public:
+     if (mpf_set_str(mp, s.c_str(), base) != 0)
+       {
+         mpf_clear (mp);
++#ifdef __EXCEPTIONS
+         throw std::invalid_argument ("mpf_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpf_set_str\n";
++        std::abort();
++      }
++#endif
+       }
+   }
+ 
+@@ -2093,13 +2231,27 @@ public:
+   __gmp_expr & operator=(const char *s)
+   {
+     if (mpf_set_str (mp, s, 0) != 0)
++#ifdef __EXCEPTIONS
+       throw std::invalid_argument ("mpf_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpf_set_str\n";
++        std::abort();
++      }
++#endif
+     return *this;
+   }
+   __gmp_expr & operator=(const std::string &s)
+   {
+     if (mpf_set_str(mp, s.c_str(), 0) != 0)
++#ifdef __EXCEPTIONS
+       throw std::invalid_argument ("mpf_set_str");
++#else
++      {
++        std::cerr << "std::invalid_argument: mpf_set_str\n";
++        std::abort();
++      }
++#endif
+     return *this;
+   }
+ 
+@@ -3505,7 +3657,14 @@ public:
+ 		mp_bitcnt_t size)
+   {
+     if (f (state, size) == 0)
++#ifdef __EXCEPTIONS
+       throw std::length_error ("gmp_randinit_lc_2exp_size");
++#else
++      {
++        std::cerr << "std::length_error: gmp_randinit_lc_2exp_size\n";
++        std::abort();
++      }
++#endif
+   }
+ 
+   ~gmp_randclass() { gmp_randclear(state); }
diff --git a/patches/overflow.diff b/patches/overflow.diff
new file mode 100644
index 0000000..960bf54
--- /dev/null
+++ b/patches/overflow.diff
@@ -0,0 +1,22 @@
+Fix incorrect overflow test, that itself overflowed.
+
+"(unsigned long)(x * y)" will multiply ints x and y into a new int, then
+converts the int into an unsigned long. Replace it with
+"(unsigned long)(x) * (unsigned long)(y)" which performs the multiplication in a
+larger space.
+
+Converted from cl/147088677.
+
+--- a/mpn/generic/get_d.c
++++ b/mpn/generic/get_d.c
+@@ -151,8 +151,8 @@ mpn_get_d (mp_srcptr up, mp_size_t size,
+   /* Adjust exp to a radix point just above {up,size}, guarding against
+      overflow.  After this exp can of course be reduced to anywhere within
+      the {up,size} region without underflow.  */
+-  if (UNLIKELY ((unsigned long) (GMP_NUMB_BITS * size)
+-		> ((unsigned long) LONG_MAX - exp)))
++  if (UNLIKELY ((unsigned long) (GMP_NUMB_BITS) * (unsigned long) (size)
++		> (LONG_MAX - (unsigned long) exp)))
+     {
+ #if _GMP_IEEE_FLOATS
+       goto ieee_infinity;
diff --git a/patches/series b/patches/series
new file mode 100644
index 0000000..161b008
--- /dev/null
+++ b/patches/series
@@ -0,0 +1,2 @@
+exceptions.diff
+overflow.diff
diff --git a/primesieve.c b/primesieve.c
new file mode 100644
index 0000000..567fab0
--- /dev/null
+++ b/primesieve.c
@@ -0,0 +1,321 @@
+/* primesieve (BIT_ARRAY, N) -- Fills the BIT_ARRAY with a mask for primes up to N.
+
+Contributed to the GNU project by Marco Bodrato.
+
+THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
+IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
+IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
+DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2010-2012, 2015, 2016, 2021, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if 0
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_fto_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_fto_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+/* n_cto_bit (n) = ((n-2)&(-CNST_LIMB(2)))/3U */
+static mp_limb_t
+n_cto_bit (mp_limb_t n) { return (n|1)/3U-1; }
+
+#if 0
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_fto_bit(n) / GMP_LIMB_BITS + 1; }
+#endif
+
+#define SET_OFF1(m1, m2, M1, M2, off, BITS)		\
+  if (off) {						\
+    if (off < GMP_LIMB_BITS) {				\
+      m1 = (M1 >> off) | (M2 << (GMP_LIMB_BITS - off));	\
+      if (off <= BITS - GMP_LIMB_BITS) {		\
+	m2 = M1 << (BITS - GMP_LIMB_BITS - off)		\
+	  | M2 >> off;					\
+      } else {						\
+	m1 |= M1 << (BITS - off);			\
+	m2 = M1 >> (off + GMP_LIMB_BITS - BITS);	\
+      }							\
+    } else {						\
+      m1 = M1 << (BITS - off)				\
+	| M2 >> (off - GMP_LIMB_BITS);			\
+      m2 = M2 << (BITS - off)				\
+	| M1 >> (off + GMP_LIMB_BITS - BITS);		\
+    }							\
+  } else {						\
+    m1 = M1; m2 = M2;					\
+  }
+
+#define SET_OFF2(m1, m2, m3, M1, M2, M3, off, BITS)	\
+  if (off) {						\
+    if (off <= GMP_LIMB_BITS) {				\
+      m1 = M2 << (GMP_LIMB_BITS - off);			\
+      m2 = M3 << (GMP_LIMB_BITS - off);			\
+      if (off != GMP_LIMB_BITS) {			\
+	m1 |= (M1 >> off);				\
+	m2 |= (M2 >> off);				\
+      }							\
+      if (off <= BITS - 2 * GMP_LIMB_BITS) {		\
+	m3 = M1 << (BITS - 2 * GMP_LIMB_BITS - off)	\
+	  | M3 >> off;					\
+      } else {						\
+	m2 |= M1 << (BITS - GMP_LIMB_BITS - off);	\
+	m3 = M1 >> (off + 2 * GMP_LIMB_BITS - BITS);	\
+      }							\
+    } else if (off < 2 *GMP_LIMB_BITS) {		\
+      m1 = M2 >> (off - GMP_LIMB_BITS)			\
+	| M3 << (2 * GMP_LIMB_BITS - off);		\
+      if (off <= BITS - GMP_LIMB_BITS) {		\
+	m2 = M3 >> (off - GMP_LIMB_BITS)		\
+	  | M1 << (BITS - GMP_LIMB_BITS - off);		\
+	m3 = M2 << (BITS - GMP_LIMB_BITS - off);	\
+	if (off != BITS - GMP_LIMB_BITS) {		\
+	  m3 |= M1 >> (off + 2 * GMP_LIMB_BITS - BITS);	\
+	}						\
+      } else {						\
+	m1 |= M1 << (BITS - off);			\
+	m2 = M2 << (BITS - off)				\
+	  | M1 >> (GMP_LIMB_BITS - BITS + off);		\
+	m3 = M2 >> (GMP_LIMB_BITS - BITS + off);	\
+      }							\
+    } else {						\
+      m1 = M1 << (BITS - off)				\
+	| M3 >> (off - 2 * GMP_LIMB_BITS);		\
+      m2 = M2 << (BITS - off)				\
+	| M1 >> (off + GMP_LIMB_BITS - BITS);		\
+      m3 = M3 << (BITS - off)				\
+	| M2 >> (off + GMP_LIMB_BITS - BITS);		\
+    }							\
+  } else {						\
+    m1 = M1; m2 = M2; m3 = M3;				\
+  }
+
+#define ROTATE1(m1, m2, BITS)			\
+  do {						\
+    mp_limb_t __tmp;				\
+    __tmp = m1 >> (2 * GMP_LIMB_BITS - BITS);	\
+    m1 = (m1 << (BITS - GMP_LIMB_BITS)) | m2;	\
+    m2 = __tmp;					\
+  } while (0)
+
+#define ROTATE2(m1, m2, m3, BITS)		\
+  do {						\
+    mp_limb_t __tmp;				\
+    __tmp = m2 >> (3 * GMP_LIMB_BITS - BITS);	\
+    m2 = m2 << (BITS - GMP_LIMB_BITS * 2)	\
+      | m1 >> (3 * GMP_LIMB_BITS - BITS);	\
+    m1 = m1 << (BITS - GMP_LIMB_BITS * 2) | m3;	\
+    m3 = __tmp;					\
+  } while (0)
+
+static mp_limb_t
+fill_bitpattern (mp_ptr bit_array, mp_size_t limbs, mp_limb_t offset)
+{
+#ifdef SIEVE_2MSK2
+  mp_limb_t m11, m12, m21, m22, m23;
+
+  { /* correctly handle offset == 0... */
+    mp_limb_t off1 = offset % (11 * 5 * 2);
+    SET_OFF1 (m11, m12, SIEVE_MASK1, SIEVE_MASKT, off1, 11 * 5 * 2);
+    offset %= 13 * 7 * 2;
+    SET_OFF2 (m21, m22, m23, SIEVE_2MSK1, SIEVE_2MSK2, SIEVE_2MSKT, offset, 13 * 7 * 2);
+  }
+  /* THINK: Consider handling odd values of 'limbs' outside the loop,
+     to have a single exit condition. */
+  do {
+    bit_array[0] = m11 | m21;
+    if (--limbs == 0)
+      break;
+    ROTATE1 (m11, m12, 11 * 5 * 2);
+    bit_array[1] = m11 | m22;
+    bit_array += 2;
+    ROTATE1 (m11, m12, 11 * 5 * 2);
+    ROTATE2 (m21, m22, m23, 13 * 7 * 2);
+  } while (--limbs != 0);
+  return n_cto_bit (13 + 1);
+#else
+#ifdef SIEVE_MASK2
+  mp_limb_t mask, mask2, tail;
+
+  { /* correctly handle offset == 0... */
+    offset %= 7 * 5 * 2;
+    SET_OFF2 (mask, mask2, tail, SIEVE_MASK1, SIEVE_MASK2, SIEVE_MASKT, offset, 7 * 5 * 2);
+  }
+  /* THINK: Consider handling odd values of 'limbs' outside the loop,
+     to have a single exit condition. */
+  do {
+    bit_array[0] = mask;
+    if (--limbs == 0)
+      break;
+    bit_array[1] = mask2;
+    bit_array += 2;
+    ROTATE2 (mask, mask2, tail, 7 * 5 * 2);
+  } while (--limbs != 0);
+  return n_cto_bit (7 + 1);
+#else
+  MPN_FILL (bit_array, limbs, CNST_LIMB(0));
+  return 0;
+#endif
+#endif
+}
+
+static void
+block_resieve (mp_ptr bit_array, mp_size_t limbs, mp_limb_t offset,
+	       mp_srcptr sieve)
+{
+  mp_size_t bits, off = offset;
+  mp_limb_t mask, i;
+
+  ASSERT (limbs > 0);
+
+  bits = limbs * GMP_LIMB_BITS - 1;
+
+  i = fill_bitpattern (bit_array, limbs, offset);
+
+  ASSERT (i < GMP_LIMB_BITS);
+
+  mask = CNST_LIMB(1) << i;
+  do {
+    ++i;
+    if ((*sieve & mask) == 0)
+      {
+	mp_size_t step, lindex;
+	mp_limb_t lmask;
+	unsigned  maskrot;
+
+	step = id_to_n(i);
+
+/*	lindex = n_to_bit(id_to_n(i)*id_to_n(i)); */
+	lindex = i*(step+1)-1+(-(i&1)&(i+1));
+/*	lindex = i*(step+1+(i&1))-1+(i&1); */
+	if (lindex > bits + off)
+	  break;
+
+	step <<= 1;
+	maskrot = step % GMP_LIMB_BITS;
+
+	if (lindex < off)
+	  lindex += step * ((off - lindex - 1) / step + 1);
+
+	lindex -= off;
+
+	lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
+	for ( ; lindex <= bits; lindex += step) {
+	  bit_array[lindex / GMP_LIMB_BITS] |= lmask;
+	  lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
+	};
+
+/*	lindex = n_to_bit(id_to_n(i)*bit_to_n(i)); */
+	lindex = i*(i*3+6)+(i&1);
+
+	if (lindex < off)
+	  lindex += step * ((off - lindex - 1) / step + 1);
+
+	lindex -= off;
+
+	lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
+	for ( ; lindex <= bits; lindex += step) {
+	  bit_array[lindex / GMP_LIMB_BITS] |= lmask;
+	  lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
+	};
+      }
+      mask = mask << 1 | mask >> (GMP_LIMB_BITS-1);
+      sieve += mask & 1;
+  } while (1);
+}
+
+#define BLOCK_SIZE 2048
+
+/* Fills bit_array with the characteristic function of composite
+   numbers up to the parameter n. I.e. a bit set to "1" represents a
+   composite, a "0" represents a prime.
+
+   The primesieve_size(n) limbs pointed to by bit_array are
+   overwritten. The returned value counts prime integers in the
+   interval [4, n]. Note that n > 4.
+
+   Even numbers and multiples of 3 are excluded "a priori", only
+   numbers equivalent to +/- 1 mod 6 have their bit in the array.
+
+   Once sieved, if the bit b is ZERO it represent a prime, the
+   represented prime is bit_to_n(b), if the LSbit is bit 0, or
+   id_to_n(b), if you call "1" the first bit.
+ */
+
+mp_limb_t
+gmp_primesieve (mp_ptr bit_array, mp_limb_t n)
+{
+  mp_size_t size;
+  mp_limb_t bits;
+  static mp_limb_t presieved[] = {PRIMESIEVE_INIT_TABLE};
+
+  ASSERT (n > 4);
+
+  bits = n_fto_bit(n);
+  size = bits / GMP_LIMB_BITS + 1;
+
+  for (mp_size_t j = 0, lim = MIN (size, PRIMESIEVE_NUMBEROF_TABLE);
+       j < lim; ++j)
+    bit_array [j] = presieved [j]; /* memcopy? */
+
+  if (size > PRIMESIEVE_NUMBEROF_TABLE) {
+    mp_size_t off;
+    off = size > 2 * BLOCK_SIZE ? BLOCK_SIZE + (size % BLOCK_SIZE) : size;
+    block_resieve (bit_array + PRIMESIEVE_NUMBEROF_TABLE,
+		   off - PRIMESIEVE_NUMBEROF_TABLE,
+		   GMP_LIMB_BITS * PRIMESIEVE_NUMBEROF_TABLE, bit_array);
+    for (; off < size; off += BLOCK_SIZE)
+      block_resieve (bit_array + off, BLOCK_SIZE, off * GMP_LIMB_BITS, bit_array);
+  }
+
+  if ((bits + 1) % GMP_LIMB_BITS != 0)
+    bit_array[size-1] |= MP_LIMB_T_MAX << ((bits + 1) % GMP_LIMB_BITS);
+
+  return size * GMP_LIMB_BITS - mpn_popcount (bit_array, size);
+}
+
+#undef BLOCK_SIZE
+#undef SIEVE_MASK1
+#undef SIEVE_MASK2
+#undef SIEVE_MASKT
+#undef SIEVE_2MSK1
+#undef SIEVE_2MSK2
+#undef SIEVE_2MSKT
+#undef SET_OFF1
+#undef SET_OFF2
+#undef ROTATE1
+#undef ROTATE2
diff --git a/printf/asprintf.c b/printf/asprintf.c
new file mode 100644
index 0000000..da87b75
--- /dev/null
+++ b/printf/asprintf.c
@@ -0,0 +1,47 @@
+/* gmp_asprintf -- formatted output to an allocated space.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_asprintf (char **result, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = gmp_vasprintf (result, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/printf/asprntffuns.c b/printf/asprntffuns.c
new file mode 100644
index 0000000..022a80c
--- /dev/null
+++ b/printf/asprntffuns.c
@@ -0,0 +1,71 @@
+/* __gmp_asprintf_memory etc -- formatted output to allocated space.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* These routines are in a separate file so that the mpz_t, mpq_t and mpf_t
+   operator<< routines can avoid dragging vsnprintf into the link (via
+   __gmp_asprintf_format).  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+__gmp_asprintf_memory (struct gmp_asprintf_t *d, const char *str, size_t len)
+{
+  GMP_ASPRINTF_T_NEED (d, len);
+  memcpy (d->buf + d->size, str, len);
+  d->size += len;
+  return len;
+}
+
+int
+__gmp_asprintf_reps (struct gmp_asprintf_t *d, int c, int reps)
+{
+  GMP_ASPRINTF_T_NEED (d, reps);
+  memset (d->buf + d->size, c, reps);
+  d->size += reps;
+  return reps;
+}
+
+int
+__gmp_asprintf_final (struct gmp_asprintf_t *d)
+{
+  char  *buf = d->buf;
+  ASSERT (d->alloc >= d->size + 1);
+  buf[d->size] = '\0';
+  __GMP_REALLOCATE_FUNC_MAYBE_TYPE (buf, d->alloc, d->size+1, char);
+  *d->result = buf;
+  return 0;
+}
diff --git a/printf/doprnt.c b/printf/doprnt.c
new file mode 100644
index 0000000..3b86613
--- /dev/null
+++ b/printf/doprnt.c
@@ -0,0 +1,625 @@
+/* __gmp_doprnt -- printf style formatted output.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in glibc langinfo.h */
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+#include <ctype.h>     /* for isdigit */
+#include <stddef.h>    /* for ptrdiff_t */
+#include <string.h>
+#include <stdio.h>     /* for NULL */
+#include <stdlib.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h> /* for quad_t */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* Should be portable, but in any case this is only used under some ASSERTs. */
+#define va_equal(x, y)                           \
+  (memcmp (&(x), &(y), sizeof(va_list)) == 0)
+
+
+/* printf is convenient because it allows various types to be printed in one
+   fairly compact call, so having gmp_printf support the standard types as
+   well as the gmp ones is important.  This ends up meaning all the standard
+   parsing must be duplicated, to get a new routine recognising the gmp
+   extras.
+
+   With the currently favoured handling of mpz etc as Z, Q and F type
+   markers, it's not possible to use glibc register_printf_function since
+   that only accepts new conversion characters, not new types.  If Z was a
+   conversion there'd be no way to specify hex, decimal or octal, or
+   similarly with F no way to specify fixed point or scientific format.
+
+   It seems wisest to pass conversions %f, %e and %g of float, double and
+   long double over to the standard printf.  It'd be hard to be sure of
+   getting the right handling for NaNs, rounding, etc.  Integer conversions
+   %d etc and string conversions %s on the other hand could be easily enough
+   handled within gmp_doprnt, but if floats are going to libc then it's just
+   as easy to send all non-gmp types there.
+
+   "Z" was a type marker for size_t in old glibc, but there seems no need to
+   provide access to that now "z" is standard.
+
+   In GMP 4.1.1 we documented "ll" and "L" as being equivalent, but in C99
+   in fact "ll" is just for long long and "L" just for long double.
+   Apparently GLIBC allows "L" for long long though.  This doesn't affect
+   us as such, since both are passed through to the C library.  To be
+   consistent with what we said before, the two are treated equivalently
+   here, and it's left to the C library to do what it thinks with them.
+
+   Possibilities:
+
+   "b" might be nice for binary output, and could even be supported for the
+   standard C types too if desired.
+
+   POSIX style "%n$" parameter numbering would be possible, but would need
+   to be handled completely within gmp_doprnt, since the numbering will be
+   all different once the format string it cut into pieces.
+
+   Some options for mpq formatting would be good.  Perhaps a non-zero
+   precision field could give a width for the denominator and mean always
+   put a "/".  A form "n+p/q" might interesting too, though perhaps that's
+   better left to applications.
+
+   Right now there's no way for an application to know whether types like
+   intmax_t are supported here.  If configure is doing its job and the same
+   compiler is used for gmp as for the application then there shouldn't be
+   any problem, but perhaps gmp.h should have some preprocessor symbols to
+   say what libgmp can do.  */
+
+
+
+/* If a gmp format is the very first thing or there are two gmp formats with
+   nothing in between then we'll reach here with this_fmt == last_fmt and we
+   can do nothing in that case.
+
+   last_ap is always replaced after a FLUSH, so it doesn't matter if va_list
+   is a call-by-reference and the funs->format routine modifies it.  */
+
+#define FLUSH()                                         \
+  do {                                                  \
+    if (this_fmt == last_fmt)                           \
+      {                                                 \
+	TRACE (printf ("nothing to flush\n"));          \
+	ASSERT (va_equal (this_ap, last_ap));           \
+      }                                                 \
+    else                                                \
+      {                                                 \
+	ASSERT (*this_fmt == '%');                      \
+	*this_fmt = '\0';                               \
+	TRACE (printf ("flush \"%s\"\n", last_fmt));    \
+	DOPRNT_FORMAT (last_fmt, last_ap);              \
+      }                                                 \
+  } while (0)
+
+
+/* Parse up the given format string and do the appropriate output using the
+   given "funs" routines.  The data parameter is passed through to those
+   routines.  */
+
+int
+__gmp_doprnt (const struct doprnt_funs_t *funs, void *data,
+	      const char *orig_fmt, va_list orig_ap)
+{
+  va_list  ap, this_ap, last_ap;
+  size_t   alloc_fmt_size, orig_fmt_size;
+  char     *fmt, *alloc_fmt, *last_fmt, *this_fmt, *gmp_str;
+  int      retval = 0;
+  int      type, fchar, *value, seen_precision;
+  struct doprnt_params_t param;
+
+  TRACE (printf ("gmp_doprnt \"%s\"\n", orig_fmt));
+
+  /* Don't modify orig_ap, if va_list is actually an array and hence call by
+     reference.  It could be argued that it'd be more efficient to leave the
+     caller to make a copy if it cared, but doing so here is going to be a
+     very small part of the total work, and we may as well keep applications
+     out of trouble.  */
+  va_copy (ap, orig_ap);
+
+  /* The format string is chopped up into pieces to be passed to
+     funs->format.  Unfortunately that means it has to be copied so each
+     piece can be null-terminated.  We're not going to be very fast here, so
+     use __gmp_allocate_func rather than TMP_ALLOC, to avoid overflowing the
+     stack if a long output string is given.  */
+  alloc_fmt_size = orig_fmt_size = strlen (orig_fmt) + 1;
+#if _LONG_LONG_LIMB
+  /* for a long long limb we change %Mx to %llx, so could need an extra 1
+     char for every 3 existing */
+  alloc_fmt_size += alloc_fmt_size / 3;
+#endif
+  alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char);
+  fmt = alloc_fmt;
+  memcpy (fmt, orig_fmt, orig_fmt_size);
+
+  /* last_fmt and last_ap are just after the last output, and hence where
+     the next output will begin, when that's done */
+  last_fmt = fmt;
+  va_copy (last_ap, ap);
+
+  for (;;)
+    {
+      TRACE (printf ("next: \"%s\"\n", fmt));
+
+      fmt = strchr (fmt, '%');
+      if (fmt == NULL)
+	break;
+
+      /* this_fmt and this_ap are the current '%' sequence being considered */
+      this_fmt = fmt;
+      va_copy (this_ap, ap);
+      fmt++; /* skip the '%' */
+
+      TRACE (printf ("considering\n");
+	     printf ("  last: \"%s\"\n", last_fmt);
+	     printf ("  this: \"%s\"\n", this_fmt));
+
+      type = '\0';
+      value = &param.width;
+
+      param.base = 10;
+      param.conv = 0;
+      param.expfmt = "e%c%02ld";
+      param.exptimes4 = 0;
+      param.fill = ' ';
+      param.justify = DOPRNT_JUSTIFY_RIGHT;
+      param.prec = 6;
+      param.showbase = DOPRNT_SHOWBASE_NO;
+      param.showpoint = 0;
+      param.showtrailing = 1;
+      param.sign = '\0';
+      param.width = 0;
+      seen_precision = 0;
+
+      /* This loop parses a single % sequence.  "break" from the switch
+	 means continue with this %, "goto next" means the conversion
+	 character has been seen and a new % should be sought.  */
+      for (;;)
+	{
+	  fchar = *fmt++;
+	  if (fchar == '\0')
+	    break;
+
+	  switch (fchar) {
+
+	  case 'a':
+	    /* %a behaves like %e, but defaults to all significant digits,
+	       and there's no leading zeros on the exponent (which is in
+	       fact bit-based) */
+	    param.base = 16;
+	    param.expfmt = "p%c%ld";
+	    goto conv_a;
+	  case 'A':
+	    param.base = -16;
+	    param.expfmt = "P%c%ld";
+	  conv_a:
+	    param.conv = DOPRNT_CONV_SCIENTIFIC;
+	    param.exptimes4 = 1;
+	    if (! seen_precision)
+	      param.prec = -1;  /* default to all digits */
+	    param.showbase = DOPRNT_SHOWBASE_YES;
+	    param.showtrailing = 1;
+	    goto floating_a;
+
+	  case 'c':
+	    /* Let's assume wchar_t will be promoted to "int" in the call,
+	       the same as char will be. */
+	    (void) va_arg (ap, int);
+	    goto next;
+
+	  case 'd':
+	  case 'i':
+	  case 'u':
+	  integer:
+	    TRACE (printf ("integer, base=%d\n", param.base));
+	    if (! seen_precision)
+	      param.prec = -1;
+	    switch (type) {
+	    case 'j':
+	      /* Let's assume uintmax_t is the same size as intmax_t. */
+#if HAVE_INTMAX_T
+	      (void) va_arg (ap, intmax_t);
+#else
+	      ASSERT_FAIL (intmax_t not available);
+#endif
+	      break;
+	    case 'l':
+	      (void) va_arg (ap, long);
+	      break;
+	    case 'L':
+#if HAVE_LONG_LONG
+	      (void) va_arg (ap, long long);
+#else
+	      ASSERT_FAIL (long long not available);
+#endif
+	      break;
+	    case 'N':
+	      {
+		mp_ptr     xp;
+		mp_size_t  xsize, abs_xsize;
+		mpz_t      z;
+		FLUSH ();
+		xp = va_arg (ap, mp_ptr);
+		PTR(z) = xp;
+		xsize = (int) va_arg (ap, mp_size_t);
+		abs_xsize = ABS (xsize);
+		MPN_NORMALIZE (xp, abs_xsize);
+		SIZ(z) = (xsize >= 0 ? abs_xsize : -abs_xsize);
+		ASSERT_CODE (ALLOC(z) = abs_xsize);
+		gmp_str = mpz_get_str (NULL, param.base, z);
+		goto gmp_integer;
+	      }
+	      /* break; */
+	    case 'q':
+	      /* quad_t is probably the same as long long, but let's treat
+		 it separately just to be sure.  Also let's assume u_quad_t
+		 will be the same size as quad_t.  */
+#if HAVE_QUAD_T
+	      (void) va_arg (ap, quad_t);
+#else
+	      ASSERT_FAIL (quad_t not available);
+#endif
+	      break;
+	    case 'Q':
+	      FLUSH ();
+	      gmp_str = mpq_get_str (NULL, param.base, va_arg(ap, mpq_srcptr));
+	      goto gmp_integer;
+	    case 't':
+#if HAVE_PTRDIFF_T
+	      (void) va_arg (ap, ptrdiff_t);
+#else
+	      ASSERT_FAIL (ptrdiff_t not available);
+#endif
+	      break;
+	    case 'z':
+	      (void) va_arg (ap, size_t);
+	      break;
+	    case 'Z':
+	      {
+		int   ret;
+		FLUSH ();
+		gmp_str = mpz_get_str (NULL, param.base,
+				       va_arg (ap, mpz_srcptr));
+	      gmp_integer:
+		ret = __gmp_doprnt_integer (funs, data, &param, gmp_str);
+		 __GMP_FREE_FUNC_TYPE (gmp_str, strlen(gmp_str)+1, char);
+		DOPRNT_ACCUMULATE (ret);
+		va_copy (last_ap, ap);
+		last_fmt = fmt;
+	      }
+	      break;
+	    default:
+	      /* default is an "int", and this includes h=short and hh=char
+		 since they're promoted to int in a function call */
+	      (void) va_arg (ap, int);
+	      break;
+	    }
+	    goto next;
+
+	  case 'E':
+	    param.base = -10;
+	    param.expfmt = "E%c%02ld";
+	    /*FALLTHRU*/
+	  case 'e':
+	    param.conv = DOPRNT_CONV_SCIENTIFIC;
+	  floating:
+	    if (param.showbase == DOPRNT_SHOWBASE_NONZERO)
+	      {
+		/* # in %e, %f and %g */
+		param.showpoint = 1;
+		param.showtrailing = 1;
+	      }
+	  floating_a:
+	    switch (type) {
+	    case 'F':
+	      FLUSH ();
+	      DOPRNT_ACCUMULATE (__gmp_doprnt_mpf (funs, data, &param,
+						   GMP_DECIMAL_POINT,
+						   va_arg (ap, mpf_srcptr)));
+	      va_copy (last_ap, ap);
+	      last_fmt = fmt;
+	      break;
+	    case 'L':
+#if HAVE_LONG_DOUBLE
+	      (void) va_arg (ap, long double);
+#else
+	      ASSERT_FAIL (long double not available);
+#endif
+	      break;
+	    default:
+	      (void) va_arg (ap, double);
+	      break;
+	    }
+	    goto next;
+
+	  case 'f':
+	    param.conv = DOPRNT_CONV_FIXED;
+	    goto floating;
+
+	  case 'F': /* mpf_t     */
+	  case 'j': /* intmax_t  */
+	  case 'L': /* long long */
+	  case 'N': /* mpn       */
+	  case 'q': /* quad_t    */
+	  case 'Q': /* mpq_t     */
+	  case 't': /* ptrdiff_t */
+	  case 'z': /* size_t    */
+	  case 'Z': /* mpz_t     */
+	  set_type:
+	    type = fchar;
+	    break;
+
+	  case 'G':
+	    param.base = -10;
+	    param.expfmt = "E%c%02ld";
+	    /*FALLTHRU*/
+	  case 'g':
+	    param.conv = DOPRNT_CONV_GENERAL;
+	    param.showtrailing = 0;
+	    goto floating;
+
+	  case 'h':
+	    if (type != 'h')
+	      goto set_type;
+	    type = 'H';   /* internal code for "hh" */
+	    break;
+
+	  case 'l':
+	    if (type != 'l')
+	      goto set_type;
+	    type = 'L';   /* "ll" means "L" */
+	    break;
+
+	  case 'm':
+	    /* glibc strerror(errno), no argument */
+	    goto next;
+
+	  case 'M': /* mp_limb_t */
+	    /* mung format string to l or ll and let plain printf handle it */
+#if _LONG_LONG_LIMB
+	    memmove (fmt+1, fmt, strlen (fmt)+1);
+	    fmt[-1] = 'l';
+	    fmt[0] = 'l';
+	    fmt++;
+	    type = 'L';
+#else
+	    fmt[-1] = 'l';
+	    type = 'l';
+#endif
+	    break;
+
+	  case 'n':
+	    {
+	      void  *p;
+	      FLUSH ();
+	      p = va_arg (ap, void *);
+	      switch (type) {
+	      case '\0': * (int       *) p = retval; break;
+	      case 'F':  mpf_set_si ((mpf_ptr) p, (long) retval); break;
+	      case 'H':  * (char      *) p = retval; break;
+	      case 'h':  * (short     *) p = retval; break;
+#if HAVE_INTMAX_T
+	      case 'j':  * (intmax_t  *) p = retval; break;
+#else
+	      case 'j':  ASSERT_FAIL (intmax_t not available); break;
+#endif
+	      case 'l':  * (long      *) p = retval; break;
+#if HAVE_QUAD_T && HAVE_LONG_LONG
+	      case 'q':
+		ASSERT_ALWAYS (sizeof (quad_t) == sizeof (long long));
+		/*FALLTHRU*/
+#else
+	      case 'q':  ASSERT_FAIL (quad_t not available); break;
+#endif
+#if HAVE_LONG_LONG
+	      case 'L':  * (long long *) p = retval; break;
+#else
+	      case 'L':  ASSERT_FAIL (long long not available); break;
+#endif
+	      case 'N':
+		{
+		  mp_size_t  n;
+		  n = va_arg (ap, mp_size_t);
+		  n = ABS (n);
+		  if (n != 0)
+		    {
+		      * (mp_ptr) p = retval;
+		      MPN_ZERO ((mp_ptr) p + 1, n - 1);
+		    }
+		}
+		break;
+	      case 'Q':  mpq_set_si ((mpq_ptr) p, (long) retval, 1L); break;
+#if HAVE_PTRDIFF_T
+	      case 't':  * (ptrdiff_t *) p = retval; break;
+#else
+	      case 't':  ASSERT_FAIL (ptrdiff_t not available); break;
+#endif
+	      case 'z':  * (size_t    *) p = retval; break;
+	      case 'Z':  mpz_set_si ((mpz_ptr) p, (long) retval); break;
+	      }
+	    }
+	    va_copy (last_ap, ap);
+	    last_fmt = fmt;
+	    goto next;
+
+	  case 'o':
+	    param.base = 8;
+	    goto integer;
+
+	  case 'p':
+	  case 's':
+	    /* "void *" will be good enough for "char *" or "wchar_t *", no
+	       need for separate code.  */
+	    (void) va_arg (ap, const void *);
+	    goto next;
+
+	  case 'x':
+	    param.base = 16;
+	    goto integer;
+	  case 'X':
+	    param.base = -16;
+	    goto integer;
+
+	  case '%':
+	    goto next;
+
+	  case '#':
+	    param.showbase = DOPRNT_SHOWBASE_NONZERO;
+	    break;
+
+	  case '\'':
+	    /* glibc digit grouping, just pass it through, no support for it
+	       on gmp types */
+	    break;
+
+	  case '+':
+	  case ' ':
+	    param.sign = fchar;
+	    break;
+
+	  case '-':
+	    param.justify = DOPRNT_JUSTIFY_LEFT;
+	    break;
+	  case '.':
+	    seen_precision = 1;
+	    param.prec = -1; /* "." alone means all necessary digits */
+	    value = &param.prec;
+	    break;
+
+	  case '*':
+	    {
+	      int n = va_arg (ap, int);
+
+	      if (value == &param.width)
+		{
+		  /* negative width means left justify */
+		  if (n < 0)
+		    {
+		      param.justify = DOPRNT_JUSTIFY_LEFT;
+		      n = -n;
+		    }
+		  param.width = n;
+		}
+	      else
+		{
+		  /* don't allow negative precision */
+		  param.prec = MAX (0, n);
+		}
+	    }
+	    break;
+
+	  case '0':
+	    if (value == &param.width)
+	      {
+		/* in width field, set fill */
+		param.fill = '0';
+
+		/* for right justify, put the fill after any minus sign */
+		if (param.justify == DOPRNT_JUSTIFY_RIGHT)
+		  param.justify = DOPRNT_JUSTIFY_INTERNAL;
+	      }
+	    else
+	      {
+		/* in precision field, set value */
+		*value = 0;
+	      }
+	    break;
+
+	  case '1': case '2': case '3': case '4': case '5':
+	  case '6': case '7': case '8': case '9':
+	    /* process all digits to form a value */
+	    {
+	      int  n = 0;
+	      do {
+		n = n * 10 + (fchar-'0');
+		fchar = *fmt++;
+	      } while (isascii (fchar) && isdigit (fchar));
+	      fmt--; /* unget the non-digit */
+	      *value = n;
+	    }
+	    break;
+
+	  default:
+	    /* something invalid */
+	    ASSERT (0);
+	    goto next;
+	  }
+	}
+
+    next:
+      /* Stop parsing the current "%" format, look for a new one. */
+      ;
+    }
+
+  TRACE (printf ("remainder: \"%s\"\n", last_fmt));
+  if (*last_fmt != '\0')
+    DOPRNT_FORMAT (last_fmt, last_ap);
+
+  if (funs->final != NULL)
+    if ((*funs->final) (data) == -1)
+      goto error;
+
+ done:
+  __GMP_FREE_FUNC_TYPE (alloc_fmt, alloc_fmt_size, char);
+  return retval;
+
+ error:
+  retval = -1;
+  goto done;
+}
diff --git a/printf/doprntf.c b/printf/doprntf.c
new file mode 100644
index 0000000..2a7e0d2
--- /dev/null
+++ b/printf/doprntf.c
@@ -0,0 +1,389 @@
+/* __gmp_doprnt_mpf -- mpf formatted output.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* The separate of __gmp_doprnt_float_digits and __gmp_doprnt_float is so
+   some C++ can do the mpf_get_str and release it in case of an exception */
+
+#define DIGIT_VALUE(c)                  \
+  (isdigit (c)   ? (c) - '0'            \
+   : islower (c) ? (c) - 'a' + 10       \
+   :               (c) - 'A' + 10)
+
+int
+__gmp_doprnt_mpf (const struct doprnt_funs_t *funs,
+		  void *data,
+		  const struct doprnt_params_t *p,
+		  const char *point,
+		  mpf_srcptr f)
+{
+  int         prec, ndigits, free_size, len, newlen, justify, justlen, explen;
+  int         showbaselen, sign, signlen, intlen, intzeros, pointlen;
+  int         fraczeros, fraclen, preczeros;
+  char        *s, *free_ptr;
+  mp_exp_t    exp;
+  char        exponent[GMP_LIMB_BITS + 10];
+  const char  *showbase;
+  int         retval = 0;
+
+  TRACE (printf ("__gmp_doprnt_float\n");
+	 printf ("  conv=%d prec=%d\n", p->conv, p->prec));
+
+  prec = p->prec;
+  if (prec <= -1)
+    {
+      /* all digits */
+      ndigits = 0;
+
+      /* arrange the fixed/scientific decision on a "prec" implied by how
+	 many significant digits there are */
+      if (p->conv == DOPRNT_CONV_GENERAL)
+	MPF_SIGNIFICANT_DIGITS (prec, PREC(f), ABS(p->base));
+    }
+  else
+    {
+      switch (p->conv) {
+      case DOPRNT_CONV_FIXED:
+	/* Precision is digits after the radix point.  Try not to generate
+	   too many more than will actually be required.  If f>=1 then
+	   overestimate the integer part, and add prec.  If f<1 then
+	   underestimate the zeros between the radix point and the first
+	   digit and subtract that from prec.  In either case add 2 so the
+	   round to nearest can be applied accurately.  Finally, we add 1 to
+	   handle the case of 1-eps where EXP(f) = 0 but mpf_get_str returns
+	   exp as 1.  */
+	ndigits = prec + 2 + 1
+	  + EXP(f) * (mp_bases[ABS(p->base)].chars_per_limb + (EXP(f)>=0));
+	ndigits = MAX (ndigits, 1);
+	break;
+
+      case DOPRNT_CONV_SCIENTIFIC:
+	/* precision is digits after the radix point, and there's one digit
+	   before */
+	ndigits = prec + 1;
+	break;
+
+      default:
+	ASSERT (0);
+	/*FALLTHRU*/
+
+      case DOPRNT_CONV_GENERAL:
+	/* precision is total digits, but be sure to ask mpf_get_str for at
+	   least 1, not 0 */
+	ndigits = MAX (prec, 1);
+	break;
+      }
+    }
+  TRACE (printf ("  ndigits %d\n", ndigits));
+
+  s = mpf_get_str (NULL, &exp, p->base, ndigits, f);
+  len = strlen (s);
+  free_ptr = s;
+  free_size = len + 1;
+  TRACE (printf ("  s   %s\n", s);
+	 printf ("  exp %ld\n", exp);
+	 printf ("  len %d\n", len));
+
+  /* For fixed mode check the ndigits formed above was in fact enough for
+     the integer part plus p->prec after the radix point. */
+  ASSERT ((p->conv == DOPRNT_CONV_FIXED && p->prec > -1)
+	  ? ndigits >= MAX (1, exp + p->prec + 2) : 1);
+
+  sign = p->sign;
+  if (s[0] == '-')
+    {
+      sign = s[0];
+      s++, len--;
+    }
+  signlen = (sign != '\0');
+  TRACE (printf ("  sign %c  signlen %d\n", sign, signlen));
+
+  switch (p->conv) {
+  case DOPRNT_CONV_FIXED:
+    if (prec <= -1)
+      prec = MAX (0, len-exp);   /* retain all digits */
+
+    /* Truncate if necessary so fraction will be at most prec digits. */
+    ASSERT (prec >= 0);
+    newlen = exp + prec;
+    if (newlen < 0)
+      {
+	/* first non-zero digit is below target prec, and at least one zero
+	   digit in between, so print zero */
+	len = 0;
+	exp = 0;
+      }
+    else if (len <= newlen)
+      {
+	/* already got few enough digits */
+      }
+    else
+      {
+	/* discard excess digits and round to nearest */
+
+	const char  *num_to_text = (p->base >= 0
+				    ? "0123456789abcdefghijklmnopqrstuvwxyz"
+				    : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+	int  base = ABS(p->base);
+	int  n;
+
+	ASSERT (base <= 36);
+
+	len = newlen;
+	n = DIGIT_VALUE (s[len]);
+	TRACE (printf ("  rounding with %d\n", n));
+	if (n >= (base + 1) / 2)
+	  {
+	    /* propagate a carry */
+	    for (;;)
+	      {
+		if (len == 0)
+		  {
+		    s[0] = '1';
+		    len = 1;
+		    exp++;
+		    break;
+		  }
+		n = DIGIT_VALUE (s[len-1]);
+		ASSERT (n >= 0 && n < base);
+		n++;
+		if (n != base)
+		  {
+		    TRACE (printf ("  storing now %d\n", n));
+		    s[len-1] = num_to_text[n];
+		    break;
+		  }
+		len--;
+	      }
+	  }
+	else
+	  {
+	    /* truncate only, strip any trailing zeros now exposed */
+	    while (len > 0 && s[len-1] == '0')
+	      len--;
+	  }
+
+	/* Can have newlen==0, in which case the truncate was just to check
+	   for a carry turning it into "1".  If we're left with len==0 then
+	   adjust exp to match.  */
+	if (len == 0)
+	  exp = 0;
+      }
+
+  fixed:
+    ASSERT (len == 0 ? exp == 0 : 1);
+    if (exp <= 0)
+      {
+	TRACE (printf ("  fixed 0.000sss\n"));
+	intlen = 0;
+	intzeros = 1;
+	fraczeros = -exp;
+	fraclen = len;
+      }
+    else
+      {
+	TRACE (printf ("  fixed sss.sss or sss000\n"));
+	intlen = MIN (len, exp);
+	intzeros = exp - intlen;
+	fraczeros = 0;
+	fraclen = len - intlen;
+      }
+    explen = 0;
+    break;
+
+  case DOPRNT_CONV_SCIENTIFIC:
+    {
+      long int expval;
+      char  expsign;
+
+      if (prec <= -1)
+	prec = MAX (0, len-1);   /* retain all digits */
+
+    scientific:
+      TRACE (printf ("  scientific s.sss\n"));
+
+      intlen = MIN (1, len);
+      intzeros = (intlen == 0 ? 1 : 0);
+      fraczeros = 0;
+      fraclen = len - intlen;
+
+      expval = (exp-intlen);
+      if (p->exptimes4)
+	expval <<= 2;
+
+      /* Split out the sign since %o or %x in expfmt give negatives as twos
+	 complement, not with a sign. */
+      expsign = (expval >= 0 ? '+' : '-');
+      expval = ABS (expval);
+
+#if HAVE_VSNPRINTF
+      explen = snprintf (exponent, sizeof(exponent),
+			 p->expfmt, expsign, expval);
+      /* test for < sizeof-1 since a glibc 2.0.x return of sizeof-1 might
+	 mean truncation */
+      ASSERT (explen >= 0 && explen < sizeof(exponent)-1);
+#else
+      sprintf (exponent, p->expfmt, expsign, expval);
+      explen = strlen (exponent);
+      ASSERT (explen < sizeof(exponent));
+#endif
+      TRACE (printf ("  expfmt %s gives %s\n", p->expfmt, exponent));
+    }
+    break;
+
+  default:
+    ASSERT (0);
+    /*FALLTHRU*/  /* to stop variables looking uninitialized */
+
+  case DOPRNT_CONV_GENERAL:
+    /* The exponent for "scientific" will be exp-1, choose scientific if
+       this is < -4 or >= prec (and minimum 1 for prec).  For f==0 will have
+       exp==0 and get the desired "fixed".  This rule follows glibc.  For
+       fixed there's no need to truncate, the desired ndigits will already
+       be as required.  */
+    if (exp-1 < -4 || exp-1 >= MAX (1, prec))
+      goto scientific;
+    else
+      goto fixed;
+  }
+
+  TRACE (printf ("  intlen %d intzeros %d fraczeros %d fraclen %d\n",
+		 intlen, intzeros, fraczeros, fraclen));
+  ASSERT (p->prec <= -1
+	  ? intlen + fraclen == strlen (s)
+	  : intlen + fraclen <= strlen (s));
+
+  if (p->showtrailing)
+    {
+      /* Pad to requested precision with trailing zeros, for general this is
+	 all digits, for fixed and scientific just the fraction.  */
+      preczeros = prec - (fraczeros + fraclen
+			  + (p->conv == DOPRNT_CONV_GENERAL
+			     ? intlen + intzeros : 0));
+      preczeros = MAX (0, preczeros);
+    }
+  else
+    preczeros = 0;
+  TRACE (printf ("  prec=%d showtrailing=%d, pad with preczeros %d\n",
+		 prec, p->showtrailing, preczeros));
+
+  /* radix point if needed, or if forced */
+  pointlen = ((fraczeros + fraclen + preczeros) != 0 || p->showpoint != 0)
+    ? strlen (point) : 0;
+  TRACE (printf ("  point |%s|  pointlen %d\n", point, pointlen));
+
+  /* Notice the test for a non-zero value is done after any truncation for
+     DOPRNT_CONV_FIXED. */
+  showbase = NULL;
+  showbaselen = 0;
+  switch (p->showbase) {
+  default:
+    ASSERT (0);
+    /*FALLTHRU*/
+  case DOPRNT_SHOWBASE_NO:
+    break;
+  case DOPRNT_SHOWBASE_NONZERO:
+    if (intlen == 0 && fraclen == 0)
+      break;
+    /*FALLTHRU*/
+  case DOPRNT_SHOWBASE_YES:
+    switch (p->base) {
+    case 16:  showbase = "0x"; showbaselen = 2; break;
+    case -16: showbase = "0X"; showbaselen = 2; break;
+    case 8:   showbase = "0";  showbaselen = 1; break;
+    }
+    break;
+  }
+  TRACE (printf ("  showbase %s showbaselen %d\n",
+		 showbase == NULL ? "" : showbase, showbaselen));
+
+  /* left over field width */
+  justlen = p->width - (signlen + showbaselen + intlen + intzeros + pointlen
+			+ fraczeros + fraclen + preczeros + explen);
+  TRACE (printf ("  justlen %d fill 0x%X\n", justlen, p->fill));
+
+  justify = p->justify;
+  if (justlen <= 0) /* no justifying if exceed width */
+    justify = DOPRNT_JUSTIFY_NONE;
+
+  TRACE (printf ("  justify type %d  intlen %d pointlen %d fraclen %d\n",
+		 justify, intlen, pointlen, fraclen));
+
+  if (justify == DOPRNT_JUSTIFY_RIGHT)         /* pad for right */
+    DOPRNT_REPS (p->fill, justlen);
+
+  if (signlen)                                 /* sign */
+    DOPRNT_REPS (sign, 1);
+
+  DOPRNT_MEMORY_MAYBE (showbase, showbaselen); /* base */
+
+  if (justify == DOPRNT_JUSTIFY_INTERNAL)      /* pad for internal */
+    DOPRNT_REPS (p->fill, justlen);
+
+  DOPRNT_MEMORY (s, intlen);                   /* integer */
+  DOPRNT_REPS_MAYBE ('0', intzeros);
+
+  DOPRNT_MEMORY_MAYBE (point, pointlen);       /* point */
+
+  DOPRNT_REPS_MAYBE ('0', fraczeros);          /* frac */
+  DOPRNT_MEMORY_MAYBE (s+intlen, fraclen);
+
+  DOPRNT_REPS_MAYBE ('0', preczeros);          /* prec */
+
+  DOPRNT_MEMORY_MAYBE (exponent, explen);      /* exp */
+
+  if (justify == DOPRNT_JUSTIFY_LEFT)          /* pad for left */
+    DOPRNT_REPS (p->fill, justlen);
+
+ done:
+  __GMP_FREE_FUNC_TYPE (free_ptr, free_size, char);
+  return retval;
+
+ error:
+  retval = -1;
+  goto done;
+}
diff --git a/printf/doprnti.c b/printf/doprnti.c
new file mode 100644
index 0000000..61ff643
--- /dev/null
+++ b/printf/doprnti.c
@@ -0,0 +1,136 @@
+/* __gmp_doprnt_integer -- integer style formatted output.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+
+
+int
+__gmp_doprnt_integer (const struct doprnt_funs_t *funs,
+		      void *data,
+		      const struct doprnt_params_t *p,
+		      const char *s)
+{
+  int         retval = 0;
+  int         slen, justlen, showbaselen, sign, signlen, slashlen, zeros;
+  int         justify, den_showbaselen;
+  const char  *slash, *showbase;
+
+  /* '+' or ' ' if wanted, and don't already have '-' */
+  sign = p->sign;
+  if (s[0] == '-')
+    {
+      sign = s[0];
+      s++;
+    }
+  signlen = (sign != '\0');
+
+  /* if the precision was explicitly 0, print nothing for a 0 value */
+  if (*s == '0' && p->prec == 0)
+    s++;
+
+  slen = strlen (s);
+  slash = strchr (s, '/');
+
+  showbase = NULL;
+  showbaselen = 0;
+
+  if (p->showbase != DOPRNT_SHOWBASE_NO)
+    {
+      switch (p->base) {
+      case 16:  showbase = "0x"; showbaselen = 2; break;
+      case -16: showbase = "0X"; showbaselen = 2; break;
+      case 8:   showbase = "0";  showbaselen = 1; break;
+      }
+    }
+
+  den_showbaselen = showbaselen;
+  if (slash == NULL
+      || (p->showbase == DOPRNT_SHOWBASE_NONZERO && slash[1] == '0'))
+    den_showbaselen = 0;
+
+  if (p->showbase == DOPRNT_SHOWBASE_NONZERO && s[0] == '0')
+    showbaselen = 0;
+
+  /* the influence of p->prec on mpq is currently undefined */
+  zeros = MAX (0, p->prec - slen);
+
+  /* space left over after actual output length */
+  justlen = p->width
+    - (strlen(s) + signlen + showbaselen + den_showbaselen + zeros);
+
+  justify = p->justify;
+  if (justlen <= 0) /* no justifying if exceed width */
+    justify = DOPRNT_JUSTIFY_NONE;
+
+  if (justify == DOPRNT_JUSTIFY_RIGHT)             /* pad right */
+    DOPRNT_REPS (p->fill, justlen);
+
+  DOPRNT_REPS_MAYBE (sign, signlen);               /* sign */
+
+  DOPRNT_MEMORY_MAYBE (showbase, showbaselen);     /* base */
+
+  DOPRNT_REPS_MAYBE ('0', zeros);                  /* zeros */
+
+  if (justify == DOPRNT_JUSTIFY_INTERNAL)          /* pad internal */
+    DOPRNT_REPS (p->fill, justlen);
+
+  /* if there's a showbase on the denominator, then print the numerator
+     separately so it can be inserted */
+  if (den_showbaselen != 0)
+    {
+      ASSERT (slash != NULL);
+      slashlen = slash+1 - s;
+      DOPRNT_MEMORY (s, slashlen);                 /* numerator and slash */
+      slen -= slashlen;
+      s += slashlen;
+      DOPRNT_MEMORY (showbase, den_showbaselen);
+    }
+
+  DOPRNT_MEMORY (s, slen);                         /* number, or denominator */
+
+  if (justify == DOPRNT_JUSTIFY_LEFT)              /* pad left */
+    DOPRNT_REPS (p->fill, justlen);
+
+ done:
+  return retval;
+
+ error:
+  retval = -1;
+  goto done;
+}
diff --git a/printf/fprintf.c b/printf/fprintf.c
new file mode 100644
index 0000000..0008b3b
--- /dev/null
+++ b/printf/fprintf.c
@@ -0,0 +1,48 @@
+/* gmp_fprintf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_fprintf (FILE *fp, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = __gmp_doprnt (&__gmp_fprintf_funs, fp, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/printf/obprintf.c b/printf/obprintf.c
new file mode 100644
index 0000000..c12d6de
--- /dev/null
+++ b/printf/obprintf.c
@@ -0,0 +1,60 @@
+/* gmp_obstack_printf -- formatted output to an obstack.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_OBSTACK_VPRINTF
+
+#include <stdarg.h>
+#include <obstack.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_obstack_printf (struct obstack *ob, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ASSERT (! MEM_OVERLAP_P (obstack_base(ob), obstack_object_size(ob),
+                           fmt, strlen(fmt)+1));
+
+  ret = __gmp_doprnt (&__gmp_obstack_printf_funs, ob, fmt, ap);
+  va_end (ap);
+  return ret;
+}
+
+#else
+typedef int __gmp_dummy_typedef;
+#endif /* HAVE_OBSTACK_VPRINTF */
diff --git a/printf/obprntffuns.c b/printf/obprntffuns.c
new file mode 100644
index 0000000..a23e4e8
--- /dev/null
+++ b/printf/obprntffuns.c
@@ -0,0 +1,73 @@
+/* __gmp_obstack_printf_funs -- support for gmp_obstack_printf and
+   gmp_obstack_vprintf.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_OBSTACK_VPRINTF
+
+#define _GNU_SOURCE   /* ask glibc <stdio.h> for obstack_vprintf */
+
+#include <stdarg.h>
+#include <stdio.h>    /* for obstack_vprintf */
+#include <string.h>
+#include <obstack.h>
+
+#include "gmp-impl.h"
+
+
+static int
+gmp_obstack_memory (struct obstack *ob, const char *ptr, size_t len)
+{
+  obstack_grow (ob, ptr, len);
+  return len;
+}
+
+static int
+gmp_obstack_reps (struct obstack *ob, int c, int reps)
+{
+  obstack_blank (ob, reps);
+  memset ((char *) obstack_next_free(ob) - reps, c, reps);
+  return reps;
+}
+
+const struct doprnt_funs_t  __gmp_obstack_printf_funs = {
+  (doprnt_format_t) obstack_vprintf,
+  (doprnt_memory_t) gmp_obstack_memory,
+  (doprnt_reps_t)   gmp_obstack_reps
+};
+
+#else
+typedef int __gmp_dummy_typedef;
+#endif /* HAVE_OBSTACK_VPRINTF */
diff --git a/printf/obvprintf.c b/printf/obvprintf.c
new file mode 100644
index 0000000..7563c11
--- /dev/null
+++ b/printf/obvprintf.c
@@ -0,0 +1,53 @@
+/* gmp_obstack_vprintf -- formatted output to an obstack.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_OBSTACK_VPRINTF
+
+#include <stdarg.h>
+#include <obstack.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_obstack_vprintf (struct obstack *ob, const char *fmt, va_list ap)
+{
+  ASSERT (! MEM_OVERLAP_P (obstack_base(ob), obstack_object_size(ob),
+                           fmt, strlen(fmt)+1));
+
+  return __gmp_doprnt (&__gmp_obstack_printf_funs, ob, fmt, ap);
+}
+
+#else
+typedef int __gmp_dummy_typedef;
+#endif /* HAVE_OBSTACK_VPRINTF */
diff --git a/printf/printf.c b/printf/printf.c
new file mode 100644
index 0000000..4becb0b
--- /dev/null
+++ b/printf/printf.c
@@ -0,0 +1,48 @@
+/* gmp_printf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_printf (const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = __gmp_doprnt (&__gmp_fprintf_funs, stdout, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/printf/printffuns.c b/printf/printffuns.c
new file mode 100644
index 0000000..957381d
--- /dev/null
+++ b/printf/printffuns.c
@@ -0,0 +1,79 @@
+/* __gmp_fprintf_funs -- support for formatted output to FILEs.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+/* SunOS 4 stdio.h doesn't provide a prototype for this */
+#if ! HAVE_DECL_VFPRINTF
+int vfprintf (FILE *, const char *, va_list);
+#endif
+
+
+static int
+gmp_fprintf_memory (FILE *fp, const char *str, size_t len)
+{
+  return fwrite (str, 1, len, fp);
+}
+
+/* glibc putc is a function, at least when it's in multi-threaded mode or
+   some such, so fwrite chunks instead of making many calls. */
+static int
+gmp_fprintf_reps (FILE *fp, int c, int reps)
+{
+  char  buf[256];
+  int   i, piece, ret;
+  ASSERT (reps >= 0);
+
+  memset (buf, c, MIN (reps, sizeof (buf)));
+  for (i = reps; i > 0; i -= sizeof (buf))
+    {
+      piece = MIN (i, sizeof (buf));
+      ret = fwrite (buf, 1, piece, fp);
+      if (ret == -1)
+        return ret;
+      ASSERT (ret == piece);
+    }
+
+  return reps;
+}
+
+const struct doprnt_funs_t  __gmp_fprintf_funs = {
+  (doprnt_format_t) vfprintf,
+  (doprnt_memory_t) gmp_fprintf_memory,
+  (doprnt_reps_t)   gmp_fprintf_reps,
+};
diff --git a/printf/repl-vsnprintf.c b/printf/repl-vsnprintf.c
new file mode 100644
index 0000000..81b404d
--- /dev/null
+++ b/printf/repl-vsnprintf.c
@@ -0,0 +1,393 @@
+/* __gmp_replacement_vsnprintf -- for systems which don't have vsnprintf, or
+   only have a broken one.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#define _GNU_SOURCE    /* for strnlen prototype */
+
+#include <stdarg.h>
+#include <ctype.h>     /* for isdigit */
+#include <stddef.h>    /* for ptrdiff_t */
+#include <string.h>
+#include <stdio.h>     /* for NULL */
+#include <stdlib.h>
+
+#if HAVE_FLOAT_H
+#include <float.h>     /* for DBL_MAX_10_EXP etc */
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h> /* for quad_t */
+#endif
+
+#include "gmp-impl.h"
+
+
+#if ! HAVE_VSNPRINTF   /* only need this file if we don't have vsnprintf */
+
+/* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
+   doesn't affect us since __gmp_replacement_vsnprintf is not required on
+   that system.  */
+#if ! HAVE_STRNLEN
+static size_t
+strnlen (const char *s, size_t n)
+{
+  size_t  i;
+  for (i = 0; i < n; i++)
+    if (s[i] == '\0')
+      break;
+  return i;
+}
+#endif
+
+
+/* The approach here is to parse the fmt string, and decide how much space
+   it requires, then use vsprintf into a big enough buffer.  The space
+   calculated isn't an exact amount, but it's certainly no less than
+   required.
+
+   This code was inspired by GNU libiberty/vasprintf.c but we support more
+   datatypes, when available.
+
+   mingw32 - doesn't have vsnprintf, it seems.  Because gcc is used a full
+       set of types are available, but "long double" is just a plain IEEE
+       64-bit "double" and LDBL_MAX_EXP_10 is correspondingly defined, so we
+       avoid the big 15-bit exponent estimate.  */
+
+int
+__gmp_replacement_vsnprintf (char *buf, size_t buf_size,
+			     const char *orig_fmt, va_list orig_ap)
+{
+  va_list     ap;
+  const char  *fmt;
+  size_t      total_width, integer_sizeof, floating_sizeof, len;
+  char        fchar, type;
+  int         width, prec, seen_prec, double_digits, long_double_digits;
+  int         *value;
+
+  /* preserve orig_ap for use after size estimation */
+  va_copy (ap, orig_ap);
+
+  fmt = orig_fmt;
+  total_width = strlen (fmt) + 1;   /* 1 extra for the '\0' */
+
+  integer_sizeof = sizeof (long);
+#if HAVE_LONG_LONG
+  integer_sizeof = MAX (integer_sizeof, sizeof (long long));
+#endif
+#if HAVE_QUAD_T
+  integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
+#endif
+
+  floating_sizeof = sizeof (double);
+#if HAVE_LONG_DOUBLE
+  floating_sizeof = MAX (floating_sizeof, sizeof (long double));
+#endif
+
+  /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
+     a maximum 308 decimal digits.  VAX D floats have only an 8 bit
+     exponent, but we don't bother trying to detect that directly.  */
+  double_digits = 308;
+#ifdef DBL_MAX_10_EXP
+  /* but in any case prefer a value the compiler says */
+  double_digits = DBL_MAX_10_EXP;
+#endif
+
+  /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
+     bit exponents, so the default is a maximum 4932 decimal digits.  */
+  long_double_digits = 4932;
+  /* but if double == long double, then go with that size */
+#if HAVE_LONG_DOUBLE
+  if (sizeof (double) == sizeof (long double))
+    long_double_digits = double_digits;
+#endif
+#ifdef LDBL_MAX_10_EXP
+  /* but in any case prefer a value the compiler says */
+  long_double_digits = LDBL_MAX_10_EXP;
+#endif
+
+  for (;;)
+    {
+      fmt = strchr (fmt, '%');
+      if (fmt == NULL)
+	break;
+      fmt++;
+
+      type = '\0';
+      width = 0;
+      prec = 6;
+      seen_prec = 0;
+      value = &width;
+
+      for (;;)
+	{
+	  fchar = *fmt++;
+	  switch (fchar) {
+
+	  case 'c':
+	    /* char, already accounted for by strlen(fmt) */
+	    goto next;
+
+	  case 'd':
+	  case 'i':
+	  case 'o':
+	  case 'x':
+	  case 'X':
+	  case 'u':
+	    /* at most 3 digits per byte in hex, dec or octal, plus a sign */
+	    total_width += 3 * integer_sizeof + 1;
+
+	    switch (type) {
+	    case 'j':
+	      /* Let's assume uintmax_t is the same size as intmax_t. */
+#if HAVE_INTMAX_T
+	      (void) va_arg (ap, intmax_t);
+#else
+	      ASSERT_FAIL (intmax_t not available);
+#endif
+	      break;
+	    case 'l':
+	      (void) va_arg (ap, long);
+	      break;
+	    case 'L':
+#if HAVE_LONG_LONG
+	      (void) va_arg (ap, long long);
+#else
+	      ASSERT_FAIL (long long not available);
+#endif
+	      break;
+	    case 'q':
+	      /* quad_t is probably the same as long long, but let's treat
+		 it separately just to be sure.  Also let's assume u_quad_t
+		 will be the same size as quad_t.  */
+#if HAVE_QUAD_T
+	      (void) va_arg (ap, quad_t);
+#else
+	      ASSERT_FAIL (quad_t not available);
+#endif
+	      break;
+	    case 't':
+#if HAVE_PTRDIFF_T
+	      (void) va_arg (ap, ptrdiff_t);
+#else
+	      ASSERT_FAIL (ptrdiff_t not available);
+#endif
+	      break;
+	    case 'z':
+	      (void) va_arg (ap, size_t);
+	      break;
+	    default:
+	      /* default is an "int", and this includes h=short and hh=char
+		 since they're promoted to int in a function call */
+	      (void) va_arg (ap, int);
+	      break;
+	    }
+	    goto next;
+
+	  case 'E':
+	  case 'e':
+	  case 'G':
+	  case 'g':
+	    /* Requested decimals, sign, point and e, plus an overestimate
+	       of exponent digits (the assumption is all the float is
+	       exponent!).  */
+	    total_width += prec + 3 + floating_sizeof * 3;
+	    if (type == 'L')
+	      {
+#if HAVE_LONG_DOUBLE
+		(void) va_arg (ap, long double);
+#else
+		ASSERT_FAIL (long double not available);
+#endif
+	      }
+	    else
+	      (void) va_arg (ap, double);
+	    goto next;
+
+	  case 'f':
+	    /* Requested decimals, sign and point, and a margin for error,
+	       then add the maximum digits that can be in the integer part,
+	       based on the maximum exponent value. */
+	    total_width += prec + 2 + 10;
+	    if (type == 'L')
+	      {
+#if HAVE_LONG_DOUBLE
+		(void) va_arg (ap, long double);
+		total_width += long_double_digits;
+#else
+		ASSERT_FAIL (long double not available);
+#endif
+	      }
+	    else
+	      {
+		(void) va_arg (ap, double);
+		total_width += double_digits;
+	      }
+	    goto next;
+
+	  case 'h':  /* short or char */
+	  case 'j':  /* intmax_t */
+	  case 'L':  /* long long or long double */
+	  case 'q':  /* quad_t */
+	  case 't':  /* ptrdiff_t */
+	  case 'z':  /* size_t */
+	  set_type:
+	    type = fchar;
+	    break;
+
+	  case 'l':
+	    /* long or long long */
+	    if (type != 'l')
+	      goto set_type;
+	    type = 'L';   /* "ll" means "L" */
+	    break;
+
+	  case 'n':
+	    /* bytes written, no output as such */
+	    (void) va_arg (ap, void *);
+	    goto next;
+
+	  case 's':
+	    /* If no precision was given, then determine the string length
+	       and put it there, to be added to the total under "next".  If
+	       a precision was given then that's already the maximum from
+	       this field, but see whether the string is shorter than that,
+	       in case the limit was very big.  */
+	    {
+	      const char  *s = va_arg (ap, const char *);
+	      prec = (seen_prec ? strnlen (s, prec) : strlen (s));
+	    }
+	    goto next;
+
+	  case 'p':
+	    /* pointer, let's assume at worst it's octal with some padding */
+	    (void) va_arg (ap, const void *);
+	    total_width += 3 * sizeof (void *) + 16;
+	    goto next;
+
+	  case '%':
+	    /* literal %, already accounted for by strlen(fmt) */
+	    goto next;
+
+	  case '#':
+	    /* showbase, at most 2 for "0x" */
+	    total_width += 2;
+	    break;
+
+	  case '+':
+	  case ' ':
+	    /* sign, already accounted for under numerics */
+	    break;
+
+	  case '-':
+	    /* left justify, no effect on total width */
+	    break;
+
+	  case '.':
+	    seen_prec = 1;
+	    value = &prec;
+	    break;
+
+	  case '*':
+	    {
+	      /* negative width means left justify which can be ignored,
+		 negative prec would be invalid, just use absolute value */
+	      int n = va_arg (ap, int);
+	      *value = ABS (n);
+	    }
+	    break;
+
+	  case '0': case '1': case '2': case '3': case '4':
+	  case '5': case '6': case '7': case '8': case '9':
+	    /* process all digits to form a value */
+	    {
+	      int  n = 0;
+	      do {
+		n = n * 10 + (fchar-'0');
+		fchar = *fmt++;
+	      } while (isascii (fchar) && isdigit (fchar));
+	      fmt--; /* unget the non-digit */
+	      *value = n;
+	    }
+	    break;
+
+	  default:
+	    /* incomplete or invalid % sequence */
+	    ASSERT (0);
+	    goto next;
+	  }
+	}
+
+    next:
+      total_width += width;
+      total_width += prec;
+    }
+
+  if (total_width <= buf_size)
+    {
+      vsprintf (buf, orig_fmt, orig_ap);
+      len = strlen (buf);
+    }
+  else
+    {
+      char  *s;
+
+      s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
+      vsprintf (s, orig_fmt, orig_ap);
+      len = strlen (s);
+      if (buf_size != 0)
+	{
+	  size_t  copylen = MIN (len, buf_size-1);
+	  memcpy (buf, s, copylen);
+	  buf[copylen] = '\0';
+	}
+      __GMP_FREE_FUNC_TYPE (s, total_width, char);
+    }
+
+  /* If total_width was somehow wrong then chances are we've already
+     clobbered memory, but maybe this check will still work.  */
+  ASSERT_ALWAYS (len < total_width);
+
+  return len;
+}
+
+#endif /* ! HAVE_VSNPRINTF */
diff --git a/printf/snprintf.c b/printf/snprintf.c
new file mode 100644
index 0000000..8da33f8
--- /dev/null
+++ b/printf/snprintf.c
@@ -0,0 +1,53 @@
+/* gmp_snprintf -- formatted output to an fixed size buffer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_snprintf (char *buf, size_t size, const char *fmt, ...)
+{
+  struct gmp_snprintf_t d;
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+  d.buf = buf;
+  d.size = size;
+
+  ASSERT (! MEM_OVERLAP_P (buf, size, fmt, strlen(fmt)+1));
+
+  ret = __gmp_doprnt (&__gmp_snprintf_funs, &d, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/printf/snprntffuns.c b/printf/snprntffuns.c
new file mode 100644
index 0000000..885c7ab
--- /dev/null
+++ b/printf/snprntffuns.c
@@ -0,0 +1,157 @@
+/* __gmp_snprintf_funs -- support for gmp_snprintf and gmp_vsnprintf.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+#if ! HAVE_VSNPRINTF
+#define vsnprintf  __gmp_replacement_vsnprintf
+#endif
+
+
+/* glibc 2.0.x vsnprintf returns either -1 or size-1 for an overflow, with
+   no indication how big the output would have been.  It's necessary to
+   re-run to determine that size.
+
+   "size-1" would mean success from a C99 vsnprintf, and the re-run is
+   unnecessary in this case, but we don't bother to try to detect what sort
+   of vsnprintf we've got.  size-1 should occur rarely in normal
+   circumstances.
+
+   vsnprintf might trash it's given ap (it does for instance in glibc 2.1.3
+   on powerpc), so copy it in case we need to use it to probe for the size
+   output that would have been produced.  Note there's no need to preserve
+   it for our callers, just for ourselves.  */
+
+static int
+gmp_snprintf_format (struct gmp_snprintf_t *d, const char *fmt,
+                     va_list orig_ap)
+{
+  int      ret;
+  size_t   step, alloc, avail;
+  va_list  ap;
+  char     *p;
+
+  ASSERT (d->size >= 0);
+
+  avail = d->size;
+  if (avail > 1)
+    {
+      va_copy (ap, orig_ap);
+      ret = vsnprintf (d->buf, avail, fmt, ap);
+      if (ret == -1)
+        return ret;
+
+      step = MIN (ret, avail-1);
+      d->size -= step;
+      d->buf += step;
+
+      if (ret != avail-1)
+        return ret;
+
+      /* probably glibc 2.0.x truncated output, probe for actual size */
+      alloc = MAX (128, ret);
+    }
+  else
+    {
+      /* no space to write anything, just probe for size */
+      alloc = 128;
+    }
+
+  do
+    {
+      alloc *= 2;
+      p = __GMP_ALLOCATE_FUNC_TYPE (alloc, char);
+      va_copy (ap, orig_ap);
+      ret = vsnprintf (p, alloc, fmt, ap);
+      __GMP_FREE_FUNC_TYPE (p, alloc, char);
+    }
+  while (ret == alloc-1);
+
+  return ret;
+}
+
+static int
+gmp_snprintf_memory (struct gmp_snprintf_t *d, const char *str, size_t len)
+{
+  size_t n;
+
+  ASSERT (d->size >= 0);
+
+  if (d->size > 1)
+    {
+      n = MIN (d->size-1, len);
+      memcpy (d->buf, str, n);
+      d->buf += n;
+      d->size -= n;
+    }
+  return len;
+}
+
+static int
+gmp_snprintf_reps (struct gmp_snprintf_t *d, int c, int reps)
+{
+  size_t n;
+
+  ASSERT (reps >= 0);
+  ASSERT (d->size >= 0);
+
+  if (d->size > 1)
+    {
+      n = MIN (d->size-1, reps);
+      memset (d->buf, c, n);
+      d->buf += n;
+      d->size -= n;
+    }
+  return reps;
+}
+
+static int
+gmp_snprintf_final (struct gmp_snprintf_t *d)
+{
+  if (d->size >= 1)
+    d->buf[0] = '\0';
+  return 0;
+}
+
+const struct doprnt_funs_t  __gmp_snprintf_funs = {
+  (doprnt_format_t) gmp_snprintf_format,
+  (doprnt_memory_t) gmp_snprintf_memory,
+  (doprnt_reps_t)   gmp_snprintf_reps,
+  (doprnt_final_t)  gmp_snprintf_final
+};
diff --git a/printf/sprintf.c b/printf/sprintf.c
new file mode 100644
index 0000000..0952a53
--- /dev/null
+++ b/printf/sprintf.c
@@ -0,0 +1,54 @@
+/* gmp_sprintf -- formatted output to an unrestricted string.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_sprintf (char *buf, const char *fmt, ...)
+{
+#if WANT_ASSERT
+  int      fmtlen = strlen(fmt);
+#endif
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = __gmp_doprnt (&__gmp_sprintf_funs, &buf, fmt, ap);
+  va_end (ap);
+
+  ASSERT (! MEM_OVERLAP_P (buf, strlen(buf)+1, fmt, fmtlen+1));
+
+  return ret;
+}
diff --git a/printf/sprintffuns.c b/printf/sprintffuns.c
new file mode 100644
index 0000000..6781f25
--- /dev/null
+++ b/printf/sprintffuns.c
@@ -0,0 +1,94 @@
+/* __gmp_sprintf_funs -- support for gmp_sprintf and gmp_vsprintf.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+/* The data parameter "bufp" points to a "char *buf" which is the next
+   character to be written, having started as the destination from the
+   application.  This is then increased each time output is produced.  */
+
+
+/* If vsprintf returns -1 then pass it upwards.  It doesn't matter that
+   "*bufp" is ruined in this case, since gmp_doprint will bail out
+   immediately anyway.  */
+static int
+gmp_sprintf_format (char **bufp, const char *fmt, va_list ap)
+{
+  char  *buf = *bufp;
+  int   ret;
+  vsprintf (buf, fmt, ap);
+  ret = strlen (buf);
+  *bufp = buf + ret;
+  return ret;
+}
+
+static int
+gmp_sprintf_memory (char **bufp, const char *str, size_t len)
+{
+  char  *buf = *bufp;
+  *bufp = buf + len;
+  memcpy (buf, str, len);
+  return len;
+}
+
+static int
+gmp_sprintf_reps (char **bufp, int c, int reps)
+{
+  char  *buf = *bufp;
+  ASSERT (reps >= 0);
+  *bufp = buf + reps;
+  memset (buf, c, reps);
+  return reps;
+}
+
+static int
+gmp_sprintf_final (char **bufp)
+{
+  char  *buf = *bufp;
+  *buf = '\0';
+  return 0;
+}
+
+const struct doprnt_funs_t  __gmp_sprintf_funs = {
+  (doprnt_format_t) gmp_sprintf_format,
+  (doprnt_memory_t) gmp_sprintf_memory,
+  (doprnt_reps_t)   gmp_sprintf_reps,
+  (doprnt_final_t)  gmp_sprintf_final
+};
diff --git a/printf/vasprintf.c b/printf/vasprintf.c
new file mode 100644
index 0000000..8a29a12
--- /dev/null
+++ b/printf/vasprintf.c
@@ -0,0 +1,116 @@
+/* gmp_vasprintf -- formatted output to an allocated space.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+#if ! HAVE_VSNPRINTF
+#define vsnprintf  __gmp_replacement_vsnprintf
+#endif
+
+
+/* vasprintf isn't used since we prefer all GMP allocs to go through
+   __gmp_allocate_func, and in particular we don't want the -1 return from
+   vasprintf for out-of-memory, instead __gmp_allocate_func should handle
+   that.  Using vsnprintf unfortunately means we might have to re-run it if
+   our current space is insufficient.
+
+   The initial guess for the needed space is an arbitrary 256 bytes.  If
+   that (and any extra GMP_ASPRINTF_T_NEED might give) isn't enough then an
+   ISO C99 standard vsnprintf will tell us what we really need.
+
+   GLIBC 2.0.x vsnprintf returns either -1 or space-1 to indicate overflow,
+   without giving any indication how much is really needed.  In this case
+   keep trying with double the space each time.
+
+   A return of space-1 is success on a C99 vsnprintf, but we're not
+   bothering to identify which style vsnprintf we've got, so just take the
+   pessimistic option and assume it's glibc 2.0.x.
+
+   Notice the use of ret+2 for the new space in the C99 case.  This ensures
+   the next vsnprintf return value will be space-2, which is unambiguously
+   successful.  But actually GMP_ASPRINTF_T_NEED() will realloc to even
+   bigger than that ret+2.
+
+   vsnprintf might trash it's given ap, so copy it in case we need to use it
+   more than once.  See comments with gmp_snprintf_format.  */
+
+static int
+gmp_asprintf_format (struct gmp_asprintf_t *d, const char *fmt,
+                     va_list orig_ap)
+{
+  int      ret;
+  va_list  ap;
+  size_t   space = 256;
+
+  for (;;)
+    {
+      GMP_ASPRINTF_T_NEED (d, space);
+      space = d->alloc - d->size;
+      va_copy (ap, orig_ap);
+      ret = vsnprintf (d->buf + d->size, space, fmt, ap);
+      if (ret == -1)
+        {
+          ASSERT (strlen (d->buf + d->size) == space-1);
+          ret = space-1;
+        }
+
+      /* done if output fits in our space */
+      if (ret < space-1)
+        break;
+
+      if (ret == space-1)
+        space *= 2;     /* possible glibc 2.0.x, so double */
+      else
+        space = ret+2;  /* C99, so now know space required */
+    }
+
+  d->size += ret;
+  return ret;
+}
+
+const struct doprnt_funs_t  __gmp_asprintf_funs = {
+  (doprnt_format_t) gmp_asprintf_format,
+  (doprnt_memory_t) __gmp_asprintf_memory,
+  (doprnt_reps_t)   __gmp_asprintf_reps,
+  (doprnt_final_t)  __gmp_asprintf_final
+};
+
+int
+gmp_vasprintf (char **result, const char *fmt, va_list ap)
+{
+  struct gmp_asprintf_t  d;
+  GMP_ASPRINTF_T_INIT (d, result);
+  return __gmp_doprnt (&__gmp_asprintf_funs, &d, fmt, ap);
+}
diff --git a/printf/vfprintf.c b/printf/vfprintf.c
new file mode 100644
index 0000000..b2d1906
--- /dev/null
+++ b/printf/vfprintf.c
@@ -0,0 +1,41 @@
+/* gmp_vfprintf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vfprintf (FILE *fp, const char *fmt, va_list ap)
+{
+  return __gmp_doprnt (&__gmp_fprintf_funs, fp, fmt, ap);
+}
diff --git a/printf/vprintf.c b/printf/vprintf.c
new file mode 100644
index 0000000..60a2233
--- /dev/null
+++ b/printf/vprintf.c
@@ -0,0 +1,41 @@
+/* gmp_vprintf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vprintf (const char *fmt, va_list ap)
+{
+  return __gmp_doprnt (&__gmp_fprintf_funs, stdout, fmt, ap);
+}
diff --git a/printf/vsnprintf.c b/printf/vsnprintf.c
new file mode 100644
index 0000000..2432f5d
--- /dev/null
+++ b/printf/vsnprintf.c
@@ -0,0 +1,47 @@
+/* gmp_vsnprintf -- formatted output to an fixed size buffer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vsnprintf (char *buf, size_t size, const char *fmt, va_list ap)
+{
+  struct gmp_snprintf_t d;
+
+  ASSERT (! MEM_OVERLAP_P (buf, size, fmt, strlen(fmt)+1));
+
+  d.buf = buf;
+  d.size = size;
+  return __gmp_doprnt (&__gmp_snprintf_funs, &d, fmt, ap);
+}
diff --git a/printf/vsprintf.c b/printf/vsprintf.c
new file mode 100644
index 0000000..26de193
--- /dev/null
+++ b/printf/vsprintf.c
@@ -0,0 +1,50 @@
+/* gmp_vsprintf -- formatted output to an unrestricted string.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vsprintf (char *buf, const char *fmt, va_list ap)
+{
+#if WANT_ASSERT
+  int  fmtlen = strlen(fmt);
+#endif
+  int  ret;
+
+  ret = __gmp_doprnt (&__gmp_sprintf_funs, &buf, fmt, ap);
+
+  ASSERT (! MEM_OVERLAP_P (buf, strlen(buf)+1, fmt, fmtlen+1));
+
+  return ret;
+}
diff --git a/rand/rand.c b/rand/rand.c
new file mode 100644
index 0000000..e594c7d
--- /dev/null
+++ b/rand/rand.c
@@ -0,0 +1,51 @@
+/* gmp_randinit (state, algorithm, ...) -- Initialize a random state.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include "gmp-impl.h"
+
+void
+gmp_randinit (gmp_randstate_ptr rstate, gmp_randalg_t alg, ...)
+{
+  va_list ap;
+  va_start (ap, alg);
+
+  switch (alg) {
+  case GMP_RAND_ALG_LC:
+    if (! gmp_randinit_lc_2exp_size (rstate, va_arg (ap, unsigned long)))
+      gmp_errno |= GMP_ERROR_INVALID_ARGUMENT;
+    break;
+  default:
+    gmp_errno |= GMP_ERROR_UNSUPPORTED_ARGUMENT;
+    break;
+  }
+  va_end (ap);
+}
diff --git a/rand/randbui.c b/rand/randbui.c
new file mode 100644
index 0000000..de9e95b
--- /dev/null
+++ b/rand/randbui.c
@@ -0,0 +1,56 @@
+/* gmp_urandomb_ui -- random bits returned in a ulong.
+
+Copyright 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Currently bits>=BITS_PER_ULONG is quietly truncated to BITS_PER_ULONG,
+   maybe this should raise an exception or something.  */
+
+unsigned long
+gmp_urandomb_ui (gmp_randstate_ptr rstate, unsigned long bits)
+{
+  mp_limb_t  a[LIMBS_PER_ULONG];
+
+  /* start with zeros, since if bits==0 then _gmp_rand will store nothing at
+     all, or if bits <= GMP_NUMB_BITS then it will store only a[0] */
+  a[0] = 0;
+#if LIMBS_PER_ULONG > 1
+  a[1] = 0;
+#endif
+
+  _gmp_rand (a, rstate, MIN (bits, BITS_PER_ULONG));
+
+#if LIMBS_PER_ULONG == 1
+  return a[0];
+#else
+  return a[0] | (a[1] << GMP_NUMB_BITS);
+#endif
+}
diff --git a/rand/randclr.c b/rand/randclr.c
new file mode 100644
index 0000000..3fa94fe
--- /dev/null
+++ b/rand/randclr.c
@@ -0,0 +1,37 @@
+/* gmp_randclear (state) -- Clear and deallocate random state STATE.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randclear (gmp_randstate_ptr rstate)
+{
+  (*((gmp_randfnptr_t *) RNG_FNPTR (rstate))->randclear_fn) (rstate);
+}
diff --git a/rand/randdef.c b/rand/randdef.c
new file mode 100644
index 0000000..74d9cce
--- /dev/null
+++ b/rand/randdef.c
@@ -0,0 +1,37 @@
+/* gmp_randinit_default -- initialize a random state with a default algorithm.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randinit_default (gmp_randstate_ptr rstate)
+{
+  gmp_randinit_mt (rstate);
+}
diff --git a/rand/randiset.c b/rand/randiset.c
new file mode 100644
index 0000000..11b5b97
--- /dev/null
+++ b/rand/randiset.c
@@ -0,0 +1,38 @@
+/* gmp_randinit_set -- initialize with a copy of another gmp_randstate_t.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+gmp_randinit_set (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
+{
+  (*((gmp_randfnptr_t *) RNG_FNPTR (src))->randiset_fn) (dst, src);
+}
diff --git a/rand/randlc2s.c b/rand/randlc2s.c
new file mode 100644
index 0000000..7a5fa49
--- /dev/null
+++ b/rand/randlc2s.c
@@ -0,0 +1,92 @@
+/* gmp_randinit_lc_2exp_size -- initialize a random state with a linear
+   congruential generator of a requested size.
+
+Copyright 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+/* Array of LC-schemes, ordered in increasing order of the first
+   member (the 'm2exp' value).  The end of the array is indicated with
+   an entry containing all zeros.  */
+
+/* All multipliers are in the range 0.01*m and 0.99*m, and are
+congruent to 5 (mod 8).
+They all pass the spectral test with Vt >= 2^(30/t) and merit >= 1.
+(Up to and including 196 bits, merit is >= 3.)  */
+
+struct __gmp_rand_lc_scheme_struct
+{
+  unsigned long int m2exp;	/* Modulus is 2 ^ m2exp. */
+  const char *astr;		/* Multiplier in string form. */
+  unsigned long int c;		/* Addend. */
+};
+
+static const struct __gmp_rand_lc_scheme_struct __gmp_rand_lc_scheme[] =
+{
+  {32, "29CF535",	     1},
+  {33, "51F666D",	     1},
+  {34, "A3D73AD",	     1},
+  {35, "147E5B85",	     1},
+  {36, "28F725C5",	     1},
+  {37, "51EE3105",	     1},
+  {38, "A3DD5CDD",	     1},
+  {39, "147AF833D",	     1},
+  {40, "28F5DA175",	     1},
+  {56, "AA7D735234C0DD",  1},
+  {64, "BAECD515DAF0B49D", 1},
+  {100, "292787EBD3329AD7E7575E2FD", 1},
+  {128, "48A74F367FA7B5C8ACBB36901308FA85", 1},
+  {156, "78A7FDDDC43611B527C3F1D760F36E5D7FC7C45", 1},
+  {196, "41BA2E104EE34C66B3520CE706A56498DE6D44721E5E24F5", 1},
+  {200, "4E5A24C38B981EAFE84CD9D0BEC48E83911362C114F30072C5", 1},
+  {256, "AF66BA932AAF58A071FD8F0742A99A0C76982D648509973DB802303128A14CB5", 1},
+  {0, NULL, 0}			/* End of array. */
+};
+
+int
+gmp_randinit_lc_2exp_size (gmp_randstate_ptr rstate, mp_bitcnt_t size)
+{
+  const struct __gmp_rand_lc_scheme_struct *sp;
+  mpz_t a;
+
+  /* Pick a scheme.  */
+  for (sp = __gmp_rand_lc_scheme; sp->m2exp != 0; sp++)
+    if (sp->m2exp / 2 >= size)
+      goto found;
+  return 0;
+
+ found:
+  /* Install scheme.  */
+  mpz_init_set_str (a, sp->astr, 16);
+  gmp_randinit_lc_2exp (rstate, a, sp->c, sp->m2exp);
+  mpz_clear (a);
+  return 1;
+}
diff --git a/rand/randlc2x.c b/rand/randlc2x.c
new file mode 100644
index 0000000..03cb368
--- /dev/null
+++ b/rand/randlc2x.c
@@ -0,0 +1,331 @@
+/* Linear Congruential pseudo-random number generator functions.
+
+Copyright 1999-2003, 2005, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* State structure for LC, the RNG_STATE() pointer in a gmp_randstate_t.
+
+   _mp_seed holds the current seed value, in the range 0 to 2^m2exp-1.
+   SIZ(_mp_seed) is fixed at BITS_TO_LIMBS(_mp_m2exp) and the value is
+   padded with high zero limbs if necessary.  ALLOC(_mp_seed) is the current
+   size of PTR(_mp_seed) in the usual way.  There only needs to be
+   BITS_TO_LIMBS(_mp_m2exp) allocated, but the mpz functions in the
+   initialization and seeding end up making it a bit more than this.
+
+   _mp_a is the "a" multiplier, in the range 0 to 2^m2exp-1.  SIZ(_mp_a) is
+   the size of the value in the normal way for an mpz_t, except that a value
+   of zero is held with SIZ(_mp_a)==1 and PTR(_mp_a)[0]==0.  This makes it
+   easy to call mpn_mul, and the case of a==0 is highly un-random and not
+   worth any trouble to optimize.
+
+   {_cp,_cn} is the "c" addend.  Normally _cn is 1, but when nails are in
+   use a ulong can be bigger than one limb, and in this case _cn is 2 if
+   necessary.  c==0 is stored as _cp[0]==0 and _cn==1, which makes it easy
+   to call __GMPN_ADD.  c==0 is fairly un-random so isn't worth optimizing.
+
+   _mp_m2exp gives the modulus, namely 2^m2exp.  We demand m2exp>=1, since
+   m2exp==0 would mean no bits at all out of each iteration, which makes no
+   sense.  */
+
+typedef struct {
+  mpz_t          _mp_seed;
+  mpz_t          _mp_a;
+  mp_size_t      _cn;
+  mp_limb_t      _cp[LIMBS_PER_ULONG];
+  unsigned long  _mp_m2exp;
+} gmp_rand_lc_struct;
+
+
+/* lc (rp, state) -- Generate next number in LC sequence.  Return the
+   number of valid bits in the result.  Discards the lower half of the
+   result.  */
+
+static unsigned long int
+lc (mp_ptr rp, gmp_randstate_ptr rstate)
+{
+  mp_ptr tp, seedp, ap;
+  mp_size_t ta;
+  mp_size_t tn, seedn, an;
+  unsigned long int m2exp;
+  unsigned long int bits;
+  mp_size_t xn;
+  gmp_rand_lc_struct *p;
+  TMP_DECL;
+
+  p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+
+  m2exp = p->_mp_m2exp;
+
+  seedp = PTR (p->_mp_seed);
+  seedn = SIZ (p->_mp_seed);
+
+  ap = PTR (p->_mp_a);
+  an = SIZ (p->_mp_a);
+
+  /* Allocate temporary storage.  Let there be room for calculation of
+     (A * seed + C) % M, or M if bigger than that.  */
+
+  TMP_MARK;
+
+  ta = an + seedn + 1;
+  tn = BITS_TO_LIMBS (m2exp);
+  if (ta <= tn) /* that is, if (ta < tn + 1) */
+    {
+      mp_size_t tmp = an + seedn;
+      ta = tn + 1;
+      tp = TMP_ALLOC_LIMBS (ta);
+      MPN_ZERO (&tp[tmp], ta - tmp); /* mpn_mul won't zero it out.  */
+    }
+  else
+    tp = TMP_ALLOC_LIMBS (ta);
+
+  /* t = a * seed.  NOTE: an is always > 0; see initialization.  */
+  ASSERT (seedn >= an && an > 0);
+  mpn_mul (tp, seedp, seedn, ap, an);
+
+  /* t = t + c.  NOTE: tn is always >= p->_cn (precondition for __GMPN_ADD);
+     see initialization.  */
+  ASSERT (tn >= p->_cn);
+  mpn_add (tp, tp, tn, p->_cp, p->_cn);
+
+  /* t = t % m */
+  tp[m2exp / GMP_NUMB_BITS] &= (CNST_LIMB (1) << m2exp % GMP_NUMB_BITS) - 1;
+
+  /* Save result as next seed.  */
+  MPN_COPY (PTR (p->_mp_seed), tp, tn);
+
+  /* Discard the lower m2exp/2 of the result.  */
+  bits = m2exp / 2;
+  xn = bits / GMP_NUMB_BITS;
+
+  tn -= xn;
+  if (tn > 0)
+    {
+      unsigned int cnt = bits % GMP_NUMB_BITS;
+      if (cnt != 0)
+	{
+	  mpn_rshift (tp, tp + xn, tn, cnt);
+	  MPN_COPY_INCR (rp, tp, xn + 1);
+	}
+      else			/* Even limb boundary.  */
+	MPN_COPY_INCR (rp, tp + xn, tn);
+    }
+
+  TMP_FREE;
+
+  /* Return number of valid bits in the result.  */
+  return (m2exp + 1) / 2;
+}
+
+
+/* Obtain a sequence of random numbers.  */
+static void
+randget_lc (gmp_randstate_ptr rstate, mp_ptr rp, unsigned long int nbits)
+{
+  unsigned long int rbitpos;
+  int chunk_nbits;
+  mp_ptr tp;
+  mp_size_t tn;
+  gmp_rand_lc_struct *p;
+  TMP_DECL;
+
+  p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+
+  TMP_MARK;
+
+  chunk_nbits = p->_mp_m2exp / 2;
+  tn = BITS_TO_LIMBS (chunk_nbits);
+
+  tp = TMP_ALLOC_LIMBS (tn);
+
+  rbitpos = 0;
+  while (rbitpos + chunk_nbits <= nbits)
+    {
+      mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
+
+      if (rbitpos % GMP_NUMB_BITS != 0)
+	{
+	  mp_limb_t savelimb, rcy;
+	  /* Target of new chunk is not bit aligned.  Use temp space
+	     and align things by shifting it up.  */
+	  lc (tp, rstate);
+	  savelimb = r2p[0];
+	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
+	  r2p[0] |= savelimb;
+	  /* bogus */
+	  if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS)
+	      > GMP_NUMB_BITS)
+	    r2p[tn] = rcy;
+	}
+      else
+	{
+	  /* Target of new chunk is bit aligned.  Let `lc' put bits
+	     directly into our target variable.  */
+	  lc (r2p, rstate);
+	}
+      rbitpos += chunk_nbits;
+    }
+
+  /* Handle last [0..chunk_nbits) bits.  */
+  if (rbitpos != nbits)
+    {
+      mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
+      int last_nbits = nbits - rbitpos;
+      tn = BITS_TO_LIMBS (last_nbits);
+      lc (tp, rstate);
+      if (rbitpos % GMP_NUMB_BITS != 0)
+	{
+	  mp_limb_t savelimb, rcy;
+	  /* Target of new chunk is not bit aligned.  Use temp space
+	     and align things by shifting it up.  */
+	  savelimb = r2p[0];
+	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
+	  r2p[0] |= savelimb;
+	  if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits)
+	    r2p[tn] = rcy;
+	}
+      else
+	{
+	  MPN_COPY (r2p, tp, tn);
+	}
+      /* Mask off top bits if needed.  */
+      if (nbits % GMP_NUMB_BITS != 0)
+	rp[nbits / GMP_NUMB_BITS]
+	  &= ~(~CNST_LIMB (0) << nbits % GMP_NUMB_BITS);
+    }
+
+  TMP_FREE;
+}
+
+
+static void
+randseed_lc (gmp_randstate_ptr rstate, mpz_srcptr seed)
+{
+  gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+  mpz_ptr seedz = p->_mp_seed;
+  mp_size_t seedn = BITS_TO_LIMBS (p->_mp_m2exp);
+
+  /* Store p->_mp_seed as an unnormalized integer with size enough
+     for numbers up to 2^m2exp-1.  That size can't be zero.  */
+  mpz_fdiv_r_2exp (seedz, seed, p->_mp_m2exp);
+  MPN_ZERO (&PTR (seedz)[SIZ (seedz)], seedn - SIZ (seedz));
+  SIZ (seedz) = seedn;
+}
+
+
+static void
+randclear_lc (gmp_randstate_ptr rstate)
+{
+  gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+
+  mpz_clear (p->_mp_seed);
+  mpz_clear (p->_mp_a);
+  (*__gmp_free_func) (p, sizeof (gmp_rand_lc_struct));
+}
+
+static void randiset_lc (gmp_randstate_ptr, gmp_randstate_srcptr);
+
+static const gmp_randfnptr_t Linear_Congruential_Generator = {
+  randseed_lc,
+  randget_lc,
+  randclear_lc,
+  randiset_lc
+};
+
+static void
+randiset_lc (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
+{
+  gmp_rand_lc_struct *dstp, *srcp;
+
+  srcp = (gmp_rand_lc_struct *) RNG_STATE (src);
+  dstp = (gmp_rand_lc_struct *) (*__gmp_allocate_func) (sizeof (gmp_rand_lc_struct));
+
+  RNG_STATE (dst) = (mp_limb_t *) (void *) dstp;
+  RNG_FNPTR (dst) = (void *) &Linear_Congruential_Generator;
+
+  /* _mp_seed and _mp_a might be unnormalized (high zero limbs), but
+     mpz_init_set won't worry about that */
+  mpz_init_set (dstp->_mp_seed, srcp->_mp_seed);
+  mpz_init_set (dstp->_mp_a,    srcp->_mp_a);
+
+  dstp->_cn = srcp->_cn;
+
+  dstp->_cp[0] = srcp->_cp[0];
+  if (LIMBS_PER_ULONG > 1)
+    dstp->_cp[1] = srcp->_cp[1];
+  if (LIMBS_PER_ULONG > 2)  /* usually there's only 1 or 2 */
+    MPN_COPY (dstp->_cp + 2, srcp->_cp + 2, LIMBS_PER_ULONG - 2);
+
+  dstp->_mp_m2exp = srcp->_mp_m2exp;
+}
+
+
+void
+gmp_randinit_lc_2exp (gmp_randstate_ptr rstate,
+		      mpz_srcptr a,
+		      unsigned long int c,
+		      mp_bitcnt_t m2exp)
+{
+  gmp_rand_lc_struct *p;
+  mp_size_t seedn = BITS_TO_LIMBS (m2exp);
+
+  ASSERT_ALWAYS (m2exp != 0);
+
+  p = __GMP_ALLOCATE_FUNC_TYPE (1, gmp_rand_lc_struct);
+  RNG_STATE (rstate) = (mp_limb_t *) (void *) p;
+  RNG_FNPTR (rstate) = (void *) &Linear_Congruential_Generator;
+
+  /* allocate m2exp bits of space for p->_mp_seed, and initial seed "1" */
+  mpz_init2 (p->_mp_seed, m2exp);
+  MPN_ZERO (PTR (p->_mp_seed), seedn);
+  SIZ (p->_mp_seed) = seedn;
+  PTR (p->_mp_seed)[0] = 1;
+
+  /* "a", forced to 0 to 2^m2exp-1 */
+  mpz_init (p->_mp_a);
+  mpz_fdiv_r_2exp (p->_mp_a, a, m2exp);
+
+  /* Avoid SIZ(a) == 0 to avoid checking for special case in lc().  */
+  if (SIZ (p->_mp_a) == 0)
+    {
+      SIZ (p->_mp_a) = 1;
+      MPZ_NEWALLOC (p->_mp_a, 1)[0] = CNST_LIMB (0);
+    }
+
+  MPN_SET_UI (p->_cp, p->_cn, c);
+
+  /* Internally we may discard any bits of c above m2exp.  The following
+     code ensures that __GMPN_ADD in lc() will always work.  */
+  if (seedn < p->_cn)
+    p->_cn = (p->_cp[0] != 0);
+
+  p->_mp_m2exp = m2exp;
+}
diff --git a/rand/randmt.c b/rand/randmt.c
new file mode 100644
index 0000000..daf8894
--- /dev/null
+++ b/rand/randmt.c
@@ -0,0 +1,415 @@
+/* Mersenne Twister pseudo-random number generator functions.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>   /* for NULL */
+
+#include "gmp-impl.h"
+#include "randmt.h"
+
+
+/* This code implements the Mersenne Twister pseudorandom number generator
+   by Takuji Nishimura and Makoto Matsumoto.  The buffer initialization
+   function is different in order to permit seeds greater than 2^32-1.
+
+   This file contains a special __gmp_randinit_mt_noseed which excludes the
+   seeding function from the gmp_randfnptr_t routines.  This is for use by
+   mpn_random and mpn_random2 on the global random generator.  MT seeding
+   uses mpz functions, and we don't want mpn routines dragging mpz functions
+   into the link.  */
+
+
+/* Default seed to use when the generator is not initialized.  */
+#define DEFAULT_SEED 5489 /* was 4357 */
+
+/* Tempering masks.  */
+#define MASK_1 0x9D2C5680
+#define MASK_2 0xEFC60000
+
+/* Initial state of buffer when initialized with default seed.  */
+static const gmp_uint_least32_t default_state[N] =
+{
+  0xD247B233,0x9E5AA8F1,0x0FFA981B,0x9DCB0980,0x74200F2B,0xA576D044,
+  0xE9F05ADF,0x1538BFF5,0x59818BBF,0xCF9E58D8,0x09FCE032,0x6A1C663F,
+  0x5116E78A,0x69B3E0FA,0x6D92D665,0xD0A8BE98,0xF669B734,0x41AC1B68,
+  0x630423F1,0x4B8D6B8A,0xC2C46DD7,0x5680747D,0x43703E8F,0x3B6103D2,
+  0x49E5EB3F,0xCBDAB4C1,0x9C988E23,0x747BEE0B,0x9111E329,0x9F031B5A,
+  0xECCA71B9,0x2AFE4EF8,0x8421C7ED,0xAC89AFF1,0xAED90DF3,0x2DD74F01,
+  0x14906A13,0x75873FA9,0xFF83F877,0x5028A0C9,0x11B4C41D,0x7CAEDBC4,
+  0x8672D0A7,0x48A7C109,0x8320E59F,0xBC0B3D5F,0x75A30886,0xF9E0D128,
+  0x41AF7580,0x239BB94D,0xC67A3C81,0x74EEBD6E,0xBC02B53C,0x727EA449,
+  0x6B8A2806,0x5853B0DA,0xBDE032F4,0xCE234885,0x320D6145,0x48CC053F,
+  0x00DBC4D2,0xD55A2397,0xE1059B6F,0x1C3E05D1,0x09657C64,0xD07CB661,
+  0x6E982E34,0x6DD1D777,0xEDED1071,0xD79DFD65,0xF816DDCE,0xB6FAF1E4,
+  0x1C771074,0x311835BD,0x18F952F7,0xF8F40350,0x4ECED354,0x7C8AC12B,
+  0x31A9994D,0x4FD47747,0xDC227A23,0x6DFAFDDF,0x6796E748,0x0C6F634F,
+  0xF992FA1D,0x4CF670C9,0x067DFD31,0xA7A3E1A5,0x8CD7D9DF,0x972CCB34,
+  0x67C82156,0xD548F6A8,0x045CEC21,0xF3240BFB,0xDEF656A7,0x43DE08C5,
+  0xDAD1F92F,0x3726C56B,0x1409F19A,0x942FD147,0xB926749C,0xADDC31B8,
+  0x53D0D869,0xD1BA52FE,0x6722DF8C,0x22D95A74,0x7DC1B52A,0x1DEC6FD5,
+  0x7262874D,0x0A725DC9,0xE6A8193D,0xA052835A,0xDC9AD928,0xE59EBB90,
+  0x70DBA9FF,0xD612749D,0x5A5A638C,0x6086EC37,0x2A579709,0x1449EA3A,
+  0xBC8E3C06,0x2F900666,0xFBE74FD1,0x6B35B911,0xF8335008,0xEF1E979D,
+  0x738AB29D,0xA2DC0FDC,0x7696305D,0xF5429DAC,0x8C41813B,0x8073E02E,
+  0xBEF83CCD,0x7B50A95A,0x05EE5862,0x00829ECE,0x8CA1958C,0xBE4EA2E2,
+  0x4293BB73,0x656F7B23,0x417316D8,0x4467D7CF,0x2200E63B,0x109050C8,
+  0x814CBE47,0x36B1D4A8,0x36AF9305,0x308327B3,0xEBCD7344,0xA738DE27,
+  0x5A10C399,0x4142371D,0x64A18528,0x0B31E8B2,0x641057B9,0x6AFC363B,
+  0x108AD953,0x9D4DA234,0x0C2D9159,0x1C8A1A1F,0x310C66BA,0x87AA1070,
+  0xDAC832FF,0x0A433422,0x7AF15812,0x2D8D9BD0,0x995A25E9,0x25326CAC,
+  0xA34384DB,0x4C8421CC,0x4F0315EC,0x29E8649E,0xA7732D6F,0x2E94D3E3,
+  0x7D98A340,0x397C4D74,0x659DB4DE,0x747D4E9A,0xD9DB8435,0x4659DBE9,
+  0x313E6DC5,0x29D104DC,0x9F226CBA,0x452F18B0,0xD0BC5068,0x844CA299,
+  0x782B294E,0x4AE2EB7B,0xA4C475F8,0x70A81311,0x4B3E8BCC,0x7E20D4BA,
+  0xABCA33C9,0x57BE2960,0x44F9B419,0x2E567746,0x72EB757A,0x102CC0E8,
+  0xB07F32B9,0xD0DABD59,0xBA85AD6B,0xF3E20667,0x98D77D81,0x197AFA47,
+  0x518EE9AC,0xE10CE5A2,0x01CF2C2A,0xD3A3AF3D,0x16DDFD65,0x669232F8,
+  0x1C50A301,0xB93D9151,0x9354D3F4,0x847D79D0,0xD5FE2EC6,0x1F7B0610,
+  0xFA6B90A5,0xC5879041,0x2E7DC05E,0x423F1F32,0xEF623DDB,0x49C13280,
+  0x98714E92,0xC7B6E4AD,0xC4318466,0x0737F312,0x4D3C003F,0x9ACC1F1F,
+  0x5F1C926D,0x085FA771,0x185A83A2,0xF9AA159D,0x0B0B0132,0xF98E7A43,
+  0xCD9EBDBE,0x0190CB29,0x10D93FB6,0x3B8A4D97,0x66A65A41,0xE43E766F,
+  0x77BE3C41,0xB9686364,0xCB36994D,0x6846A287,0x567E77F7,0x36178DD8,
+  0xBDE6B1F2,0xB6EFDC64,0x82950324,0x42053F47,0xC09BE51C,0x0942D762,
+  0x35F92C7F,0x367DEC61,0x6EE3D983,0xDBAAF78A,0x265D2C47,0x8EB4BF5C,
+  0x33B232D7,0xB0137E77,0x373C39A7,0x8D2B2E76,0xC7510F01,0x50F9E032,
+  0x7B1FDDDB,0x724C2AAE,0xB10ECB31,0xCCA3D1B8,0x7F0BCF10,0x4254BBBD,
+  0xE3F93B97,0x2305039B,0x53120E22,0x1A2F3B9A,0x0FDDBD97,0x0118561E,
+  0x0A798E13,0x9E0B3ACD,0xDB6C9F15,0xF512D0A2,0x9E8C3A28,0xEE2184AE,
+  0x0051EC2F,0x2432F74F,0xB0AA66EA,0x55128D88,0xF7D83A38,0x4DAE8E82,
+  0x3FDC98D6,0x5F0BD341,0x7244BE1D,0xC7B48E78,0x2D473053,0x43892E20,
+  0xBA0F1F2A,0x524D4895,0x2E10BCB1,0x4C372D81,0x5C3E50CD,0xCF61CC2E,
+  0x931709AB,0x81B3AEFC,0x39E9405E,0x7FFE108C,0x4FBB3FF8,0x06ABE450,
+  0x7F5BF51E,0xA4E3CDFD,0xDB0F6C6F,0x159A1227,0x3B9FED55,0xD20B6F7F,
+  0xFBE9CC83,0x64856619,0xBF52B8AF,0x9D7006B0,0x71165BC6,0xAE324AEE,
+  0x29D27F2C,0x794C2086,0x74445CE2,0x782915CC,0xD4CE6886,0x3289AE7C,
+  0x53DEF297,0x4185F7ED,0x88B72400,0x3C09DC11,0xBCE3AAB6,0x6A75934A,
+  0xB267E399,0x000DF1BF,0x193BA5E2,0xFA3E1977,0x179E14F6,0x1EEDE298,
+  0x691F0B06,0xB84F78AC,0xC1C15316,0xFFFF3AD6,0x0B457383,0x518CD612,
+  0x05A00F3E,0xD5B7D275,0x4C5ECCD7,0xE02CD0BE,0x5558E9F2,0x0C89BBF0,
+  0xA3D96227,0x2832D2B2,0xF667B897,0xD4556554,0xF9D2F01F,0xFA1E3FAE,
+  0x52C2E1EE,0xE5451F31,0x7E849729,0xDABDB67A,0x54BF5E7E,0xF831C271,
+  0x5F1A17E3,0x9D140AFE,0x92741C47,0x48CFABCE,0x9CBBE477,0x9C3EE57F,
+  0xB07D4C39,0xCC21BCE2,0x697708B1,0x58DA2A6B,0x2370DB16,0x6E641948,
+  0xACC5BD52,0x868F24CC,0xCA1DB0F5,0x4CADA492,0x3F443E54,0xC4A4D5E9,
+  0xF00AD670,0xE93C86E0,0xFE90651A,0xDDE532A3,0xA66458DF,0xAB7D7151,
+  0x0E2E775F,0xC9109F99,0x8D96D59F,0x73CEF14C,0xC74E88E9,0x02712DC0,
+  0x04F41735,0x2E5914A2,0x59F4B2FB,0x0287FC83,0x80BC0343,0xF6B32559,
+  0xC74178D4,0xF1D99123,0x383CCC07,0xACC0637D,0x0863A548,0xA6FCAC85,
+  0x2A13EFF0,0xAF2EEDB1,0x41E72750,0xE0C6B342,0x5DA22B46,0x635559E0,
+  0xD2EA40AC,0x10AA98C0,0x19096497,0x112C542B,0x2C85040C,0xA868E7D0,
+  0x6E260188,0xF596D390,0xC3BB5D7A,0x7A2AA937,0xDFD15032,0x6780AE3B,
+  0xDB5F9CD8,0x8BD266B0,0x7744AF12,0xB463B1B0,0x589629C9,0xE30DBC6E,
+  0x880F5569,0x209E6E16,0x9DECA50C,0x02987A57,0xBED3EA57,0xD3A678AA,
+  0x70DD030D,0x0CFD9C5D,0x92A18E99,0xF5740619,0x7F6F0A7D,0x134CAF9A,
+  0x70F5BAE4,0x23DCA7B5,0x4D788FCD,0xC7F07847,0xBCF77DA1,0x9071D568,
+  0xFC627EA1,0xAE004B77,0x66B54BCB,0x7EF2DAAC,0xDCD5AC30,0xB9BDF730,
+  0x505A97A7,0x9D881FD3,0xADB796CC,0x94A1D202,0x97535D7F,0x31EC20C0,
+  0xB1887A98,0xC1475069,0xA6F73AF3,0x71E4E067,0x46A569DE,0xD2ADE430,
+  0x6F0762C7,0xF50876F4,0x53510542,0x03741C3E,0x53502224,0xD8E54D60,
+  0x3C44AB1A,0x34972B46,0x74BFA89D,0xD7D768E0,0x37E605DC,0xE13D1BDF,
+  0x5051C421,0xB9E057BE,0xB717A14C,0xA1730C43,0xB99638BE,0xB5D5F36D,
+  0xE960D9EA,0x6B1388D3,0xECB6D3B6,0xBDBE8B83,0x2E29AFC5,0x764D71EC,
+  0x4B8F4F43,0xC21DDC00,0xA63F657F,0x82678130,0xDBF535AC,0xA594FC58,
+  0x942686BC,0xBD9B657B,0x4A0F9B61,0x44FF184F,0x38E10A2F,0x61910626,
+  0x5E247636,0x7106D137,0xC62802F0,0xBD1D1F00,0x7CC0DCB2,0xED634909,
+  0xDC13B24E,0x9799C499,0xD77E3D6A,0x14773B68,0x967A4FB7,0x35EECFB1,
+  0x2A5110B8,0xE2F0AF94,0x9D09DEA5,0x20255D27,0x5771D34B,0xE1089EE4,
+  0x246F330B,0x8F7CAEE5,0xD3064712,0x75CAFBEE,0xB94F7028,0xED953666,
+  0x5D1975B4,0x5AF81271,0x13BE2025,0x85194659,0x30805331,0xEC9D46C0,
+  0xBC027C36,0x2AF84188,0xC2141B80,0xC02B1E4A,0x04D36177,0xFC50E9D7,
+  0x39CE79DA,0x917E0A00,0xEF7A0BF4,0xA98BD8D1,0x19424DD2,0x9439DF1F,
+  0xC42AF746,0xADDBE83E,0x85221F0D,0x45563E90,0x9095EC52,0x77887B25,
+  0x8AE46064,0xBD43B71A,0xBB541956,0x7366CF9D,0xEE8E1737,0xB5A727C9,
+  0x5076B3E7,0xFC70BACA,0xCE135B75,0xC4E91AA3,0xF0341911,0x53430C3F,
+  0x886B0824,0x6BB5B8B7,0x33E21254,0xF193B456,0x5B09617F,0x215FFF50,
+  0x48D97EF1,0x356479AB,0x6EA9DDC4,0x0D352746,0xA2F5CE43,0xB226A1B3,
+  0x1329EA3C,0x7A337CC2,0xB5CCE13D,0x563E3B5B,0x534E8E8F,0x561399C9,
+  0xE1596392,0xB0F03125,0x4586645B,0x1F371847,0x94EAABD1,0x41F97EDD,
+  0xE3E5A39B,0x71C774E2,0x507296F4,0x5960133B,0x7852C494,0x3F5B2691,
+  0xA3F87774,0x5A7AF89E,0x17DA3F28,0xE9D9516D,0xFCC1C1D5,0xE4618628,
+  0x04081047,0xD8E4DB5F,0xDC380416,0x8C4933E2,0x95074D53,0xB1B0032D,
+  0xCC8102EA,0x71641243,0x98D6EB6A,0x90FEC945,0xA0914345,0x6FAB037D,
+  0x70F49C4D,0x05BF5B0E,0x927AAF7F,0xA1940F61,0xFEE0756F,0xF815369F,
+  0x5C00253B,0xF2B9762F,0x4AEB3CCC,0x1069F386,0xFBA4E7B9,0x70332665,
+  0x6BCA810E,0x85AB8058,0xAE4B2B2F,0x9D120712,0xBEE8EACB,0x776A1112
+};
+
+void
+__gmp_mt_recalc_buffer (gmp_uint_least32_t mt[])
+{
+  gmp_uint_least32_t y;
+  int kk;
+
+  for (kk = 0; kk < N - M; kk++)
+    {
+      y = (mt[kk] & 0x80000000) | (mt[kk + 1] & 0x7FFFFFFF);
+      mt[kk] = mt[kk + M] ^ (y >> 1) ^ ((y & 0x01) != 0 ? MATRIX_A : 0);
+    }
+  for (; kk < N - 1; kk++)
+    {
+      y = (mt[kk] & 0x80000000) | (mt[kk + 1] & 0x7FFFFFFF);
+      mt[kk] = mt[kk - (N - M)] ^ (y >> 1) ^ ((y & 0x01) != 0 ? MATRIX_A : 0);
+    }
+
+  y = (mt[N - 1] & 0x80000000) | (mt[0] & 0x7FFFFFFF);
+  mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ ((y & 0x01) != 0 ? MATRIX_A : 0);
+}
+
+
+/* Get nbits bits of output from the generator into dest.
+   Note that Mersenne Twister is designed to produce outputs in
+   32-bit words.  */
+void
+__gmp_randget_mt (gmp_randstate_ptr rstate, mp_ptr dest, unsigned long int nbits)
+{
+  gmp_uint_least32_t y;
+  int rbits;
+  mp_size_t i;
+  mp_size_t nlimbs;
+  int *pmti;
+  gmp_uint_least32_t *mt;
+
+  pmti = &((gmp_rand_mt_struct *) RNG_STATE (rstate))->mti;
+  mt = ((gmp_rand_mt_struct *) RNG_STATE (rstate))->mt;
+
+  nlimbs = nbits / GMP_NUMB_BITS;
+  rbits = nbits % GMP_NUMB_BITS;
+
+#define NEXT_RANDOM			\
+  do					\
+    {					\
+      if (*pmti >= N)			\
+	{				\
+	  __gmp_mt_recalc_buffer (mt);  \
+	  *pmti = 0;			\
+	}				\
+      y = mt[(*pmti)++];		\
+      y ^= (y >> 11);			\
+      y ^= (y << 7) & MASK_1;		\
+      y ^= (y << 15) & MASK_2;		\
+      y ^= (y >> 18);			\
+    }					\
+  while (0)
+
+
+  /* Handle the common cases of 32- or 64-bit limbs with fast,
+     optimized routines, and the rest of cases with a general
+     routine.  In all cases, no more than 31 bits are rejected
+     for the last limb so that every version of the code is
+     consistent with the others.  */
+
+#if (GMP_NUMB_BITS == 32)
+
+  for (i = 0; i < nlimbs; i++)
+    {
+      NEXT_RANDOM;
+      dest[i] = (mp_limb_t) y;
+    }
+  if (rbits)
+    {
+      NEXT_RANDOM;
+      dest[nlimbs] = (mp_limb_t) (y & ~(ULONG_MAX << rbits));
+    }
+
+#else /* GMP_NUMB_BITS != 32 */
+#if (GMP_NUMB_BITS == 64)
+
+  for (i = 0; i < nlimbs; i++)
+    {
+      NEXT_RANDOM;
+      dest[i] = (mp_limb_t) y;
+      NEXT_RANDOM;
+      dest[i] |= (mp_limb_t) y << 32;
+    }
+  if (rbits)
+    {
+      if (rbits < 32)
+	{
+	  NEXT_RANDOM;
+	  dest[nlimbs] = (mp_limb_t) (y & ~(ULONG_MAX << rbits));
+	}
+      else
+	{
+	  NEXT_RANDOM;
+	  dest[nlimbs] = (mp_limb_t) y;
+	  if (rbits > 32)
+	    {
+	      NEXT_RANDOM;
+	      dest[nlimbs] |=
+		((mp_limb_t) (y & ~(ULONG_MAX << (rbits-32)))) << 32;
+	    }
+	}
+    }
+
+#else /* GMP_NUMB_BITS != 64 */
+
+  {
+    /* Fall back to a general algorithm.  This algorithm works by
+       keeping a pool of up to 64 bits (2 outputs from MT) acting
+       as a shift register from which bits are consumed as needed.
+       Bits are consumed using the LSB bits of bitpool_l, and
+       inserted via bitpool_h and shifted to the right place.  */
+
+    gmp_uint_least32_t bitpool_h = 0;
+    gmp_uint_least32_t bitpool_l = 0;
+    int bits_in_pool = 0;	/* Holds number of valid bits in the pool.  */
+    int bits_to_fill;		/* Holds total number of bits to put in
+				   destination.  */
+    int bitidx;			/* Holds the destination bit position.  */
+    mp_size_t nlimbs2;		/* Number of whole+partial limbs to fill.  */
+
+    nlimbs2 = nlimbs + (rbits != 0);
+
+    for (i = 0; i < nlimbs2; i++)
+      {
+	bitidx = 0;
+	if (i < nlimbs)
+	  bits_to_fill = GMP_NUMB_BITS;
+	else
+	  bits_to_fill = rbits;
+
+	dest[i] = CNST_LIMB (0);
+	while (bits_to_fill >= 32) /* Process whole 32-bit blocks first.  */
+	  {
+	    if (bits_in_pool < 32)	/* Need more bits.  */
+	      {
+		/* 64-bit right shift.  */
+		NEXT_RANDOM;
+		bitpool_h = y;
+		bitpool_l |= (bitpool_h << bits_in_pool) & 0xFFFFFFFF;
+		if (bits_in_pool == 0)
+		  bitpool_h = 0;
+		else
+		  bitpool_h >>= 32 - bits_in_pool;
+		bits_in_pool += 32;	/* We've got 32 more bits.  */
+	      }
+
+	    /* Fill a 32-bit chunk.  */
+	    dest[i] |= ((mp_limb_t) bitpool_l) << bitidx;
+	    bitpool_l = bitpool_h;
+	    bits_in_pool -= 32;
+	    bits_to_fill -= 32;
+	    bitidx += 32;
+	  }
+
+	/* Cover the case where GMP_NUMB_BITS is not a multiple of 32.  */
+	if (bits_to_fill != 0)
+	  {
+	    if (bits_in_pool < bits_to_fill)
+	      {
+		NEXT_RANDOM;
+		bitpool_h = y;
+		bitpool_l |= (bitpool_h << bits_in_pool) & 0xFFFFFFFF;
+		if (bits_in_pool == 0)
+		  bitpool_h = 0;
+		else
+		  bitpool_h >>= 32 - bits_in_pool;
+		bits_in_pool += 32;
+	      }
+
+	    dest[i] |= (((mp_limb_t) bitpool_l
+			 & ~(~CNST_LIMB (0) << bits_to_fill))
+			<< bitidx);
+	    bitpool_l = ((bitpool_l >> bits_to_fill)
+			 | (bitpool_h << (32 - bits_to_fill))) & 0xFFFFFFFF;
+	    bitpool_h >>= bits_to_fill;
+	    bits_in_pool -= bits_to_fill;
+	  }
+      }
+  }
+
+#endif /* GMP_NUMB_BITS != 64 */
+#endif /* GMP_NUMB_BITS != 32 */
+}
+
+void
+__gmp_randclear_mt (gmp_randstate_ptr rstate)
+{
+  (*__gmp_free_func) ((void *) RNG_STATE (rstate),
+		      ALLOC (rstate->_mp_seed) * GMP_LIMB_BYTES);
+}
+
+void __gmp_randiset_mt (gmp_randstate_ptr, gmp_randstate_srcptr);
+
+static const gmp_randfnptr_t Mersenne_Twister_Generator_Noseed = {
+  NULL,
+  __gmp_randget_mt,
+  __gmp_randclear_mt,
+  __gmp_randiset_mt
+};
+
+void
+__gmp_randiset_mt (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
+{
+  const mp_size_t sz = ((sizeof (gmp_rand_mt_struct) - 1) / GMP_LIMB_BYTES) + 1;
+  gmp_rand_mt_struct *dstp, *srcp;
+  mp_size_t i;
+
+  /* Set the generator functions.  */
+  RNG_FNPTR (dst) = RNG_FNPTR(src);
+
+  /* Allocate the MT-specific state.  */
+  dstp = (gmp_rand_mt_struct *) __GMP_ALLOCATE_FUNC_LIMBS (sz);
+  RNG_STATE (dst) = (mp_ptr) dstp;
+  ALLOC (dst->_mp_seed) = sz;     /* Initialize alloc field to placate Camm.  */
+
+  /* Copy state.  */
+  srcp = (gmp_rand_mt_struct *) RNG_STATE (src);
+  for (i = 0; i < N; i++)
+    dstp->mt[i] = srcp->mt[i];
+
+  dstp->mti = srcp->mti;
+}
+
+void
+__gmp_randinit_mt_noseed (gmp_randstate_ptr dst)
+{
+  const mp_size_t sz = ((sizeof (gmp_rand_mt_struct) - 1) / GMP_LIMB_BYTES) + 1;
+  gmp_rand_mt_struct *dstp;
+  mp_size_t i;
+
+  /* Set the generator functions.  */
+  RNG_FNPTR (dst) = (void *) &Mersenne_Twister_Generator_Noseed;
+
+  /* Allocate the MT-specific state.  */
+  dstp = (gmp_rand_mt_struct *) __GMP_ALLOCATE_FUNC_LIMBS (sz);
+  RNG_STATE (dst) = (mp_ptr) dstp;
+  ALLOC (dst->_mp_seed) = sz;     /* Initialize alloc field to placate Camm.  */
+
+  /* Set state for default seed.  */
+  for (i = 0; i < N; i++)
+    dstp->mt[i] = default_state[i];
+
+  dstp->mti = WARM_UP % N;
+}
diff --git a/rand/randmt.h b/rand/randmt.h
new file mode 100644
index 0000000..61f8b4f
--- /dev/null
+++ b/rand/randmt.h
@@ -0,0 +1,51 @@
+/* Mersenne Twister pseudo-random number generator defines.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Number of extractions used to warm the buffer up.  */
+#define WARM_UP 2000
+
+/* Period parameters.  */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908B0DF   /* Constant vector a.  */
+
+/* State structure for MT.  */
+typedef struct
+{
+  gmp_uint_least32_t mt[N];    /* State array.  */
+  int mti;                     /* Index of current value.  */
+} gmp_rand_mt_struct;
+
+
+void __gmp_mt_recalc_buffer (gmp_uint_least32_t *);
+void __gmp_randget_mt (gmp_randstate_ptr, mp_ptr, unsigned long int);
+void __gmp_randclear_mt (gmp_randstate_ptr);
+void __gmp_randiset_mt (gmp_randstate_ptr, gmp_randstate_srcptr);
diff --git a/rand/randmts.c b/rand/randmts.c
new file mode 100644
index 0000000..2b95a2a
--- /dev/null
+++ b/rand/randmts.c
@@ -0,0 +1,171 @@
+/* Mersenne Twister pseudo-random number generator functions.
+
+Copyright 2002, 2003, 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "randmt.h"
+
+
+/* Calculate (b^e) mod (2^n-k) for e=1074888996, n=19937 and k=20023,
+   needed by the seeding function below.  */
+static void
+mangle_seed (mpz_ptr r)
+{
+  mpz_t          t, b;
+  unsigned long  e = 0x40118124;
+  unsigned long  bit = 0x20000000;
+
+  mpz_init2 (t, 19937L);
+  mpz_init_set (b, r);
+
+  do
+    {
+      mpz_mul (r, r, r);
+
+    reduce:
+      for (;;)
+        {
+          mpz_tdiv_q_2exp (t, r, 19937L);
+          if (SIZ (t) == 0)
+            break;
+          mpz_tdiv_r_2exp (r, r, 19937L);
+          mpz_addmul_ui (r, t, 20023L);
+        }
+
+      if ((e & bit) != 0)
+        {
+          e ^= bit;
+          mpz_mul (r, r, b);
+          goto reduce;
+        }
+
+      bit >>= 1;
+    }
+  while (bit != 0);
+
+  mpz_clear (t);
+  mpz_clear (b);
+}
+
+
+/* Seeding function.  Uses powering modulo a non-Mersenne prime to obtain
+   a permutation of the input seed space.  The modulus is 2^19937-20023,
+   which is probably prime.  The power is 1074888996.  In order to avoid
+   seeds 0 and 1 generating invalid or strange output, the input seed is
+   first manipulated as follows:
+
+     seed1 = seed mod (2^19937-20027) + 2
+
+   so that seed1 lies between 2 and 2^19937-20026 inclusive. Then the
+   powering is performed as follows:
+
+     seed2 = (seed1^1074888996) mod (2^19937-20023)
+
+   and then seed2 is used to bootstrap the buffer.
+
+   This method aims to give guarantees that:
+     a) seed2 will never be zero,
+     b) seed2 will very seldom have a very low population of ones in its
+	binary representation, and
+     c) every seed between 0 and 2^19937-20028 (inclusive) will yield a
+	different sequence.
+
+   CAVEATS:
+
+   The period of the seeding function is 2^19937-20027.  This means that
+   with seeds 2^19937-20027, 2^19937-20026, ... the exact same sequences
+   are obtained as with seeds 0, 1, etc.; it also means that seed -1
+   produces the same sequence as seed 2^19937-20028, etc.
+
+   Moreover, c) is not guaranted, there are many seeds yielding to the
+   same sequence, because gcd (1074888996, 2^19937 - 20023 - 1) = 12.
+   E.g. x and x'=x*19^((2^19937-20023-1) / 12) mod (2^19937-20023), if
+   chosen as seed1, generate the same seed2, for every x.
+   Similarly x" can be obtained from x', obtaining 12 different
+   values.
+ */
+
+static void
+randseed_mt (gmp_randstate_ptr rstate, mpz_srcptr seed)
+{
+  int i;
+  size_t cnt;
+
+  gmp_rand_mt_struct *p;
+  mpz_t mod;    /* Modulus.  */
+  mpz_t seed1;  /* Intermediate result.  */
+
+  p = (gmp_rand_mt_struct *) RNG_STATE (rstate);
+
+  mpz_init2 (mod, 19938L);
+  mpz_init2 (seed1, 19937L);
+
+  mpz_setbit (mod, 19937L);
+  mpz_sub_ui (mod, mod, 20027L);
+  mpz_mod (seed1, seed, mod);	/* Reduce `seed' modulo `mod'.  */
+  mpz_clear (mod);
+  mpz_add_ui (seed1, seed1, 2L);	/* seed1 is now ready.  */
+  mangle_seed (seed1);	/* Perform the mangling by powering.  */
+
+  /* Copy the last bit into bit 31 of mt[0] and clear it.  */
+  p->mt[0] = (mpz_tstbit (seed1, 19936L) != 0) ? 0x80000000 : 0;
+  mpz_clrbit (seed1, 19936L);
+
+  /* Split seed1 into N-1 32-bit chunks.  */
+  mpz_export (&p->mt[1], &cnt, -1, sizeof (p->mt[1]), 0,
+              8 * sizeof (p->mt[1]) - 32, seed1);
+  mpz_clear (seed1);
+  cnt++;
+  ASSERT (cnt <= N);
+  while (cnt < N)
+    p->mt[cnt++] = 0;
+
+  /* Warm the generator up if necessary.  */
+  if (WARM_UP != 0)
+    for (i = 0; i < WARM_UP / N; i++)
+      __gmp_mt_recalc_buffer (p->mt);
+
+  p->mti = WARM_UP % N;
+}
+
+
+static const gmp_randfnptr_t Mersenne_Twister_Generator = {
+  randseed_mt,
+  __gmp_randget_mt,
+  __gmp_randclear_mt,
+  __gmp_randiset_mt
+};
+
+/* Initialize MT-specific data.  */
+void
+gmp_randinit_mt (gmp_randstate_ptr rstate)
+{
+  __gmp_randinit_mt_noseed (rstate);
+  RNG_FNPTR (rstate) = (void *) &Mersenne_Twister_Generator;
+}
diff --git a/rand/randmui.c b/rand/randmui.c
new file mode 100644
index 0000000..d3292db
--- /dev/null
+++ b/rand/randmui.c
@@ -0,0 +1,85 @@
+/* gmp_urandomm_ui -- uniform random number 0 to N-1 for ulong N.
+
+Copyright 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* If n is a power of 2 then the test ret<n is always true and the loop is
+   unnecessary, but there's no need to add special code for this.  Just get
+   the "bits" calculation correct and let it go through normally.
+
+   If n is 1 then will have bits==0 and _gmp_rand will produce no output and
+   we always return 0.  Again there seems no need for a special case, just
+   initialize a[0]=0 and let it go through normally.  */
+
+#define MAX_URANDOMM_ITER  80
+
+unsigned long
+gmp_urandomm_ui (gmp_randstate_ptr rstate, unsigned long n)
+{
+  mp_limb_t      a[LIMBS_PER_ULONG];
+  unsigned long  ret, bits, leading;
+  int            i;
+
+  if (UNLIKELY (n == 0))
+    DIVIDE_BY_ZERO;
+
+  /* start with zeros, since if bits==0 then _gmp_rand will store nothing at
+     all (bits==0 arises when n==1), or if bits <= GMP_NUMB_BITS then it
+     will store only a[0].  */
+  a[0] = 0;
+#if LIMBS_PER_ULONG > 1
+  a[1] = 0;
+#endif
+
+  count_leading_zeros (leading, (mp_limb_t) n);
+  bits = GMP_LIMB_BITS - leading - (POW2_P(n) != 0);
+
+  for (i = 0; i < MAX_URANDOMM_ITER; i++)
+    {
+      _gmp_rand (a, rstate, bits);
+#if LIMBS_PER_ULONG == 1
+      ret = a[0];
+#else
+      ret = a[0] | (a[1] << GMP_NUMB_BITS);
+#endif
+      if (LIKELY (ret < n))   /* usually one iteration suffices */
+        goto done;
+    }
+
+  /* Too many iterations, there must be something degenerate about the
+     rstate algorithm.  Return r%n.  */
+  ret -= n;
+  ASSERT (ret < n);
+
+ done:
+  return ret;
+}
diff --git a/rand/rands.c b/rand/rands.c
new file mode 100644
index 0000000..af436a4
--- /dev/null
+++ b/rand/rands.c
@@ -0,0 +1,41 @@
+/* __gmp_rands -- global random state for old-style random functions.
+
+   EVERYTHING IN THIS FILE IS FOR INTERNAL USE ONLY.  IT'S ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN FUTURE GNU
+   MP RELEASES.  */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Use this via the RANDS macro in gmp-impl.h */
+char             __gmp_rands_initialized = 0;
+gmp_randstate_t  __gmp_rands;
diff --git a/rand/randsd.c b/rand/randsd.c
new file mode 100644
index 0000000..880a148
--- /dev/null
+++ b/rand/randsd.c
@@ -0,0 +1,38 @@
+/* gmp_randseed (state, seed) -- Set initial seed SEED in random state STATE.
+
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randseed (gmp_randstate_ptr rstate,
+	      mpz_srcptr seed)
+{
+  (*((gmp_randfnptr_t *) RNG_FNPTR (rstate))->randseed_fn) (rstate, seed);
+}
diff --git a/rand/randsdui.c b/rand/randsdui.c
new file mode 100644
index 0000000..a91a148
--- /dev/null
+++ b/rand/randsdui.c
@@ -0,0 +1,43 @@
+/* gmp_randseed_ui (state, seed) -- Set initial seed SEED in random
+   state STATE.
+
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randseed_ui (gmp_randstate_ptr rstate,
+                 unsigned long int seed)
+{
+  mpz_t zseed;
+  mp_limb_t zlimbs[LIMBS_PER_ULONG];
+
+  MPZ_FAKE_UI (zseed, zlimbs, seed);
+  gmp_randseed (rstate, zseed);
+}
diff --git a/scanf/doscan.c b/scanf/doscan.c
new file mode 100644
index 0000000..35273a3
--- /dev/null
+++ b/scanf/doscan.c
@@ -0,0 +1,766 @@
+/* __gmp_doscan -- formatted input internals.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+#include <ctype.h>
+#include <stddef.h>    /* for ptrdiff_t */
+#include <stdio.h>
+#include <stdlib.h>    /* for strtol */
+#include <string.h>
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h> /* for quad_t */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* General:
+
+       It's necessary to parse up the format string to recognise the GMP
+       extra types F, Q and Z.  Other types and conversions are passed
+       across to the standard sscanf or fscanf via funs->scan, for ease of
+       implementation.  This is essential in the case of something like glibc
+       %p where the pointer format isn't actually documented.
+
+       Because funs->scan doesn't get the whole input it can't put the right
+       values in for %n, so that's handled in __gmp_doscan.  Neither sscanf
+       nor fscanf directly indicate how many characters were read, so an
+       extra %n is appended to each run for that.  For fscanf this merely
+       supports our %n output, but for sscanf it lets funs->step move us
+       along the input string.
+
+       Whitespace and literal matches in the format string, including %%,
+       are handled directly within __gmp_doscan.  This is reasonably
+       efficient, and avoids some suspicious behaviour observed in various
+       system libc's.  GLIBC 2.2.4 for instance returns 0 on
+
+	   sscanf(" ", " x")
+       or
+	   sscanf(" ", " x%d",&n)
+
+       whereas we think they should return EOF, since end-of-string is
+       reached when a match of "x" is required.
+
+       For standard % conversions, funs->scan is called once for each
+       conversion.  If we had vfscanf and vsscanf and could rely on their
+       fixed text matching behaviour then we could call them with multiple
+       consecutive standard conversions.  But plain fscanf and sscanf work
+       fine, and parsing one field at a time shouldn't be too much of a
+       slowdown.
+
+   gmpscan:
+
+       gmpscan reads a gmp type.  It's only used from one place, but is a
+       separate subroutine to avoid a big chunk of complicated code in the
+       middle of __gmp_doscan.  Within gmpscan a couple of loopbacks make it
+       possible to share code for parsing integers, rationals and floats.
+
+       In gmpscan normally one char of lookahead is maintained, but when width
+       is reached that stops, on the principle that an fgetc/ungetc of a char
+       past where we're told to stop would be undesirable.  "chars" is how many
+       characters have been read so far, including the current c.  When
+       chars==width and another character is desired then a jump is done to the
+       "convert" stage.  c is invalid and mustn't be unget'ed in this case;
+       chars is set to width+1 to indicate that.
+
+       gmpscan normally returns the number of characters read.  -1 means an
+       invalid field, -2 means EOF reached before any matching characters
+       were read.
+
+       For hex floats, the mantissa part is passed to mpf_set_str, then the
+       exponent is applied with mpf_mul_exp or mpf_div_2exp.  This is easier
+       than teaching mpf_set_str about an exponent factor (ie. 2) differing
+       from the mantissa radix point factor (ie. 16).  mpf_mul_exp and
+       mpf_div_2exp will preserve the application requested precision, so
+       nothing in that respect is lost by making this a two-step process.
+
+   Matching and errors:
+
+       C99 7.19.6.2 paras 9 and 10 say an input item is read as the longest
+       string which is a match for the appropriate type, or a prefix of a
+       match.  With that done, if it's only a prefix then the result is a
+       matching failure, ie. invalid input.
+
+       This rule seems fairly clear, but doesn't seem to be universally
+       applied in system C libraries.  Even GLIBC doesn't seem to get it
+       right, insofar as it seems to accept some apparently invalid forms.
+       Eg. glibc 2.3.1 accepts "0x" for a "%i", where a reading of the
+       standard would suggest a non-empty sequence of digits should be
+       required after an "0x".
+
+       A footnote to 7.19.6.2 para 17 notes how this input item reading can
+       mean inputs acceptable to strtol are not acceptable to fscanf.  We
+       think this confirms our reading of "0x" as invalid.
+
+       Clearly gmp_sscanf could backtrack to a longest input which was a
+       valid match for a given item, but this is not done, since C99 says
+       sscanf is identical to fscanf, so we make gmp_sscanf identical to
+       gmp_fscanf.
+
+   Types:
+
+       C99 says "ll" is for long long, and "L" is for long double floats.
+       Unfortunately in GMP 4.1.1 we documented the two as equivalent.  This
+       doesn't affect us directly, since both are passed through to plain
+       scanf.  It seems wisest not to try to enforce the C99 rule.  This is
+       consistent with what we said before, though whether it actually
+       worked was always up to the C library.
+
+   Alternatives:
+
+       Consideration was given to using separate code for gmp_fscanf and
+       gmp_sscanf.  The sscanf case could zip across a string doing literal
+       matches or recognising digits in gmpscan, rather than making a
+       function call fun->get per character.  The fscanf could use getc
+       rather than fgetc too, which might help those systems where getc is a
+       macro or otherwise inlined.  But none of this scanning and converting
+       will be particularly fast, so the two are done together to keep it a
+       little simpler for now.
+
+       Various multibyte string issues are not addressed, for a start C99
+       scanf says the format string is multibyte.  Since we pass %c, %s and
+       %[ to the system scanf, they might do multibyte reads already, but
+       it's another matter whether or not that can be used, since our digit
+       and whitespace parsing is only unibyte.  The plan is to quietly
+       ignore multibyte locales for now.  This is not as bad as it sounds,
+       since GMP is presumably used mostly on numbers, which can be
+       perfectly adequately treated in plain ASCII.
+
+*/
+
+
+struct gmp_doscan_params_t {
+  int	base;
+  int	ignore;
+  char	type;
+  int	width;
+};
+
+
+#define GET(c)			\
+  do {				\
+    ASSERT (chars <= width);	\
+    chars++;			\
+    if (chars > width)		\
+      goto convert;		\
+    (c) = (*funs->get) (data);	\
+  } while (0)
+
+/* store into "s", extending if necessary */
+#define STORE(c)							\
+  do {									\
+    ASSERT (s_upto <= s_alloc);						\
+    if (s_upto >= s_alloc)						\
+      {									\
+	size_t	s_alloc_new = s_alloc + S_ALLOC_STEP;			\
+	s = __GMP_REALLOCATE_FUNC_TYPE (s, s_alloc, s_alloc_new, char); \
+	s_alloc = s_alloc_new;						\
+      }									\
+    s[s_upto++] = c;							\
+  } while (0)
+
+#define S_ALLOC_STEP  512
+
+static int
+gmpscan (const struct gmp_doscan_funs_t *funs, void *data,
+	 const struct gmp_doscan_params_t *p, void *dst)
+{
+  int	  chars, c, base, first, width, seen_point, seen_digit, hexfloat;
+  size_t  s_upto, s_alloc, hexexp;
+  char	  *s;
+  int	  invalid = 0;
+
+  TRACE (printf ("gmpscan\n"));
+
+  ASSERT (p->type == 'F' || p->type == 'Q' || p->type == 'Z');
+
+  c = (*funs->get) (data);
+  if (c == EOF)
+    return -2;
+
+  chars = 1;
+  first = 1;
+  seen_point = 0;
+  width = (p->width == 0 ? INT_MAX-1 : p->width);
+  base = p->base;
+  s_alloc = S_ALLOC_STEP;
+  s = __GMP_ALLOCATE_FUNC_TYPE (s_alloc, char);
+  s_upto = 0;
+  hexfloat = 0;
+  hexexp = 0;
+
+ another:
+  seen_digit = 0;
+  if (c == '-')
+    {
+      STORE (c);
+      goto get_for_sign;
+    }
+  else if (c == '+')
+    {
+      /* don't store '+', it's not accepted by mpz_set_str etc */
+    get_for_sign:
+      GET (c);
+    }
+
+  if (base == 0)
+    {
+      base = 10;		  /* decimal if no base indicator */
+      if (c == '0')
+	{
+	  seen_digit = 1;	  /* 0 alone is a valid number */
+	  if (p->type != 'F')
+	    base = 8;		  /* leading 0 is octal, for non-floats */
+	  STORE (c);
+	  GET (c);
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      seen_digit = 0;	  /* must have digits after an 0x */
+	      if (p->type == 'F') /* don't pass 'x' to mpf_set_str_point */
+		hexfloat = 1;
+	      else
+		STORE (c);
+	      GET (c);
+	    }
+	}
+    }
+
+ digits:
+  for (;;)
+    {
+      if (base == 16)
+	{
+	  if (! isxdigit (c))
+	    break;
+	}
+      else
+	{
+	  if (! isdigit (c))
+	    break;
+	  if (base == 8 && (c == '8' || c == '9'))
+	    break;
+	}
+
+      seen_digit = 1;
+      STORE (c);
+      GET (c);
+    }
+
+  if (first)
+    {
+      /* decimal point */
+      if (p->type == 'F' && ! seen_point)
+	{
+	  /* For a multi-character decimal point, if the first character is
+	     present then all of it must be, otherwise the input is
+	     considered invalid.  */
+	  const char  *point = GMP_DECIMAL_POINT;
+	  int	      pc = (unsigned char) *point++;
+	  if (c == pc)
+	    {
+	      for (;;)
+		{
+		  STORE (c);
+		  GET (c);
+		  pc = (unsigned char) *point++;
+		  if (pc == '\0')
+		    break;
+		  if (c != pc)
+		    goto set_invalid;
+		}
+	      seen_point = 1;
+	      goto digits;
+	    }
+	}
+
+      /* exponent */
+      if (p->type == 'F')
+	{
+	  if (hexfloat && (c == 'p' || c == 'P'))
+	    {
+	      hexexp = s_upto; /* exponent location */
+	      base = 10;       /* exponent in decimal */
+	      goto exponent;
+	    }
+	  else if (! hexfloat && (c == 'e' || c == 'E'))
+	    {
+	    exponent:
+	      /* must have at least one digit in the mantissa, just an exponent
+		 is not good enough */
+	      if (! seen_digit)
+		goto set_invalid;
+
+	    do_second:
+	      first = 0;
+	      STORE (c);
+	      GET (c);
+	      goto another;
+	    }
+	}
+
+      /* denominator */
+      if (p->type == 'Q' && c == '/')
+	{
+	  /* must have at least one digit in the numerator */
+	  if (! seen_digit)
+	    goto set_invalid;
+
+	  /* now look for at least one digit in the denominator */
+	  seen_digit = 0;
+
+	  /* allow the base to be redetermined for "%i" */
+	  base = p->base;
+	  goto do_second;
+	}
+    }
+
+ convert:
+  if (! seen_digit)
+    {
+    set_invalid:
+      invalid = 1;
+      goto done;
+    }
+
+  if (! p->ignore)
+    {
+      STORE ('\0');
+      TRACE (printf ("	convert \"%s\"\n", s));
+
+      /* We ought to have parsed out a valid string above, so just test
+	 mpz_set_str etc with an ASSERT.  */
+      switch (p->type) {
+      case 'F':
+	{
+	  mpf_ptr  f = (mpf_ptr) dst;
+	  if (hexexp != 0)
+	    s[hexexp] = '\0';
+	  ASSERT_NOCARRY (mpf_set_str (f, s, hexfloat ? 16 : 10));
+	  if (hexexp != 0)
+	    {
+	      char *dummy;
+	      long  exp;
+	      exp = strtol (s + hexexp + 1, &dummy, 10);
+	      if (exp >= 0)
+		mpf_mul_2exp (f, f, (unsigned long) exp);
+	      else
+		mpf_div_2exp (f, f, NEG_CAST (unsigned long, exp));
+	    }
+	}
+	break;
+      case 'Q':
+	ASSERT_NOCARRY (mpq_set_str ((mpq_ptr) dst, s, p->base));
+	break;
+      case 'Z':
+	ASSERT_NOCARRY (mpz_set_str ((mpz_ptr) dst, s, p->base));
+	break;
+      default:
+	ASSERT (0);
+	/*FALLTHRU*/
+	break;
+      }
+    }
+
+ done:
+  ASSERT (chars <= width+1);
+  if (chars != width+1)
+    {
+      (*funs->unget) (c, data);
+      TRACE (printf ("	ungetc %d, to give %d chars\n", c, chars-1));
+    }
+  chars--;
+
+  (*__gmp_free_func) (s, s_alloc);
+
+  if (invalid)
+    {
+      TRACE (printf ("	invalid\n"));
+      return -1;
+    }
+
+  TRACE (printf ("  return %d chars (cf width %d)\n", chars, width));
+  return chars;
+}
+
+
+/* Read and discard whitespace, if any.  Return number of chars skipped.
+   Whitespace skipping never provokes the EOF return from __gmp_doscan, so
+   it's not necessary to watch for EOF from funs->get, */
+static int
+skip_white (const struct gmp_doscan_funs_t *funs, void *data)
+{
+  int  c;
+  int  ret = 0;
+
+  do
+    {
+      c = (funs->get) (data);
+      ret++;
+    }
+  while (isspace (c));
+
+  (funs->unget) (c, data);
+  ret--;
+
+  TRACE (printf ("  skip white %d\n", ret));
+  return ret;
+}
+
+
+int
+__gmp_doscan (const struct gmp_doscan_funs_t *funs, void *data,
+	      const char *orig_fmt, va_list orig_ap)
+{
+  struct gmp_doscan_params_t  param;
+  va_list     ap;
+  char	      *alloc_fmt;
+  const char  *fmt, *this_fmt, *end_fmt;
+  size_t      orig_fmt_len, alloc_fmt_size, len;
+  int	      new_fields, new_chars;
+  char	      fchar;
+  int	      fields = 0;
+  int	      chars = 0;
+
+  TRACE (printf ("__gmp_doscan \"%s\"\n", orig_fmt);
+	 if (funs->scan == (gmp_doscan_scan_t) sscanf)
+	   printf ("  s=\"%s\"\n", * (const char **) data));
+
+  /* Don't modify orig_ap, if va_list is actually an array and hence call by
+     reference.  It could be argued that it'd be more efficient to leave
+     callers to make a copy if they care, but doing so here is going to be a
+     very small part of the total work, and we may as well keep applications
+     out of trouble.  */
+  va_copy (ap, orig_ap);
+
+  /* Parts of the format string are going to be copied so that a " %n" can
+     be appended.  alloc_fmt is some space for that.  orig_fmt_len+4 will be
+     needed if fmt consists of a single "%" specifier, but otherwise is an
+     overestimate.  We're not going to be very fast here, so use
+     __gmp_allocate_func rather than TMP_ALLOC.  */
+  orig_fmt_len = strlen (orig_fmt);
+  alloc_fmt_size = orig_fmt_len + 4;
+  alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char);
+
+  fmt = orig_fmt;
+  ASSERT_CODE (end_fmt = orig_fmt + orig_fmt_len);
+
+  for (;;)
+    {
+    next:
+      fchar = *fmt++;
+
+      if (fchar == '\0')
+	break;
+
+      if (isspace (fchar))
+	{
+	  chars += skip_white (funs, data);
+	  continue;
+	}
+
+      if (fchar != '%')
+	{
+	  int  c;
+	literal:
+	  c = (funs->get) (data);
+	  if (c != fchar)
+	    {
+	      (funs->unget) (c, data);
+	      if (c == EOF)
+		{
+		eof_no_match:
+		  if (fields == 0)
+		    fields = EOF;
+		}
+	      goto done;
+	    }
+	  chars++;
+	  continue;
+	}
+
+      param.type = '\0';
+      param.base = 0;	 /* for e,f,g,i */
+      param.ignore = 0;
+      param.width = 0;
+
+      this_fmt = fmt-1;
+      TRACE (printf ("	this_fmt \"%s\"\n", this_fmt));
+
+      for (;;)
+	{
+	  ASSERT (fmt <= end_fmt);
+
+	  fchar = *fmt++;
+	  switch (fchar) {
+
+	  case '\0':  /* unterminated % sequence */
+	    ASSERT (0);
+	    goto done;
+
+	  case '%':   /* literal % */
+	    goto literal;
+
+	  case '[':   /* character range */
+	    fchar = *fmt++;
+	    if (fchar == '^')
+	      fchar = *fmt++;
+	    /* ']' allowed as the first char (possibly after '^') */
+	    if (fchar == ']')
+	      fchar = *fmt++;
+	    for (;;)
+	      {
+		ASSERT (fmt <= end_fmt);
+		if (fchar == '\0')
+		  {
+		    /* unterminated % sequence */
+		    ASSERT (0);
+		    goto done;
+		  }
+		if (fchar == ']')
+		  break;
+		fchar = *fmt++;
+	      }
+	    /*FALLTHRU*/
+	  case 'c':   /* characters */
+	  case 's':   /* string of non-whitespace */
+	  case 'p':   /* pointer */
+	  libc_type:
+	    len = fmt - this_fmt;
+	    memcpy (alloc_fmt, this_fmt, len);
+	    alloc_fmt[len++] = '%';
+	    alloc_fmt[len++] = 'n';
+	    alloc_fmt[len] = '\0';
+
+	    TRACE (printf ("  scan \"%s\"\n", alloc_fmt);
+		   if (funs->scan == (gmp_doscan_scan_t) sscanf)
+		     printf ("	s=\"%s\"\n", * (const char **) data));
+
+	    new_chars = -1;
+	    if (param.ignore)
+	      {
+		new_fields = (*funs->scan) (data, alloc_fmt, &new_chars, NULL);
+		ASSERT (new_fields == 0 || new_fields == EOF);
+	      }
+	    else
+	      {
+		void *arg = va_arg (ap, void *);
+		new_fields = (*funs->scan) (data, alloc_fmt, arg, &new_chars);
+		ASSERT (new_fields==0 || new_fields==1 || new_fields==EOF);
+
+		if (new_fields == 0)
+		  goto done;  /* invalid input */
+
+		if (new_fields == 1)
+		  ASSERT (new_chars != -1);
+	      }
+	    TRACE (printf ("  new_fields %d   new_chars %d\n",
+			   new_fields, new_chars));
+
+	    if (new_fields == -1)
+	      goto eof_no_match;  /* EOF before anything matched */
+
+	    /* Under param.ignore, when new_fields==0 we don't know if
+	       it's a successful match or an invalid field.  new_chars
+	       won't have been assigned if it was an invalid field.  */
+	    if (new_chars == -1)
+	      goto done;  /* invalid input */
+
+	    chars += new_chars;
+	    (*funs->step) (data, new_chars);
+
+	  increment_fields:
+	    if (! param.ignore)
+	      fields++;
+	    goto next;
+
+	  case 'd':   /* decimal */
+	  case 'u':   /* decimal */
+	    param.base = 10;
+	    goto numeric;
+
+	  case 'e':   /* float */
+	  case 'E':   /* float */
+	  case 'f':   /* float */
+	  case 'g':   /* float */
+	  case 'G':   /* float */
+	  case 'i':   /* integer with base marker */
+	  numeric:
+	    if (param.type != 'F' && param.type != 'Q' && param.type != 'Z')
+	      goto libc_type;
+
+	    chars += skip_white (funs, data);
+
+	    new_chars = gmpscan (funs, data, &param,
+				 param.ignore ? NULL : va_arg (ap, void*));
+	    if (new_chars == -2)
+	      goto eof_no_match;
+	    if (new_chars == -1)
+	      goto done;
+
+	    ASSERT (new_chars >= 0);
+	    chars += new_chars;
+	    goto increment_fields;
+
+	  case 'a':   /* glibc allocate string */
+	  case '\'':  /* glibc digit groupings */
+	    break;
+
+	  case 'F':   /* mpf_t */
+	  case 'j':   /* intmax_t */
+	  case 'L':   /* long long */
+	  case 'q':   /* quad_t */
+	  case 'Q':   /* mpq_t */
+	  case 't':   /* ptrdiff_t */
+	  case 'z':   /* size_t */
+	  case 'Z':   /* mpz_t */
+	  set_type:
+	    param.type = fchar;
+	    break;
+
+	  case 'h':   /* short or char */
+	    if (param.type != 'h')
+	      goto set_type;
+	    param.type = 'H';	/* internal code for "hh" */
+	    break;
+
+	    goto numeric;
+
+	  case 'l':   /* long, long long, double or long double */
+	    if (param.type != 'l')
+	      goto set_type;
+	    param.type = 'L';	/* "ll" means "L" */
+	    break;
+
+	  case 'n':
+	    if (! param.ignore)
+	      {
+		void  *p;
+		p = va_arg (ap, void *);
+		TRACE (printf ("  store %%n to %p\n", p));
+		switch (param.type) {
+		case '\0': * (int	*) p = chars; break;
+		case 'F':  mpf_set_si ((mpf_ptr) p, (long) chars); break;
+		case 'H':  * (char	*) p = chars; break;
+		case 'h':  * (short	*) p = chars; break;
+#if HAVE_INTMAX_T
+		case 'j':  * (intmax_t	*) p = chars; break;
+#else
+		case 'j':  ASSERT_FAIL (intmax_t not available); break;
+#endif
+		case 'l':  * (long	*) p = chars; break;
+#if HAVE_QUAD_T && HAVE_LONG_LONG
+		case 'q':
+		  ASSERT_ALWAYS (sizeof (quad_t) == sizeof (long long));
+		  /*FALLTHRU*/
+#else
+		case 'q':  ASSERT_FAIL (quad_t not available); break;
+#endif
+#if HAVE_LONG_LONG
+		case 'L':  * (long long *) p = chars; break;
+#else
+		case 'L':  ASSERT_FAIL (long long not available); break;
+#endif
+		case 'Q':  mpq_set_si ((mpq_ptr) p, (long) chars, 1L); break;
+#if HAVE_PTRDIFF_T
+		case 't':  * (ptrdiff_t *) p = chars; break;
+#else
+		case 't':  ASSERT_FAIL (ptrdiff_t not available); break;
+#endif
+		case 'z':  * (size_t	*) p = chars; break;
+		case 'Z':  mpz_set_si ((mpz_ptr) p, (long) chars); break;
+		default: ASSERT (0); break;
+		}
+	      }
+	    goto next;
+
+	  case 'o':
+	    param.base = 8;
+	    goto numeric;
+
+	  case 'x':
+	  case 'X':
+	    param.base = 16;
+	    goto numeric;
+
+	  case '0': case '1': case '2': case '3': case '4':
+	  case '5': case '6': case '7': case '8': case '9':
+	    param.width = 0;
+	    do {
+	      param.width = param.width * 10 + (fchar-'0');
+	      fchar = *fmt++;
+	    } while (isdigit (fchar));
+	    fmt--; /* unget the non-digit */
+	    break;
+
+	  case '*':
+	    param.ignore = 1;
+	    break;
+
+	  default:
+	    /* something invalid in a % sequence */
+	    ASSERT (0);
+	    goto next;
+	  }
+	}
+    }
+
+ done:
+  (*__gmp_free_func) (alloc_fmt, alloc_fmt_size);
+  return fields;
+}
diff --git a/scanf/fscanf.c b/scanf/fscanf.c
new file mode 100644
index 0000000..ce74aa4
--- /dev/null
+++ b/scanf/fscanf.c
@@ -0,0 +1,47 @@
+/* gmp_fscanf -- formatted input from a FILE.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_fscanf (FILE *fp, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+  va_start (ap, fmt);
+
+  ret = __gmp_doscan (&__gmp_fscanf_funs, fp, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/scanf/fscanffuns.c b/scanf/fscanffuns.c
new file mode 100644
index 0000000..f2d2939
--- /dev/null
+++ b/scanf/fscanffuns.c
@@ -0,0 +1,61 @@
+/* __gmp_fscanf_funs -- support for formatted input from a FILE.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* SunOS 4 stdio.h doesn't provide prototypes for these */
+#if ! HAVE_DECL_FGETC
+int fgetc (FILE *);
+#endif
+#if ! HAVE_DECL_FSCANF
+int fscanf (FILE *, const char *, ...);
+#endif
+#if ! HAVE_DECL_UNGETC
+int ungetc (int, FILE *);
+#endif
+
+
+static void
+step (FILE *fp, int n)
+{
+}
+
+const struct gmp_doscan_funs_t  __gmp_fscanf_funs = {
+  (gmp_doscan_scan_t)  fscanf,
+  (gmp_doscan_step_t)  step,
+  (gmp_doscan_get_t)   fgetc,
+  (gmp_doscan_unget_t) ungetc,
+};
diff --git a/scanf/scanf.c b/scanf/scanf.c
new file mode 100644
index 0000000..645188c
--- /dev/null
+++ b/scanf/scanf.c
@@ -0,0 +1,47 @@
+/* gmp_scanf -- formatted input from stdin.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_scanf (const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+  va_start (ap, fmt);
+
+  ret = __gmp_doscan (&__gmp_fscanf_funs, stdin, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/scanf/sscanf.c b/scanf/sscanf.c
new file mode 100644
index 0000000..4486b83
--- /dev/null
+++ b/scanf/sscanf.c
@@ -0,0 +1,52 @@
+/* gmp_sscanf -- formatted input from a string.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_sscanf (const char *s, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+  va_start (ap, fmt);
+
+#if SSCANF_WRITABLE_INPUT
+  /* let gmp_vsscanf handle the copying */
+  ret = gmp_vsscanf (s, fmt, ap);
+#else
+  ret = __gmp_doscan (&__gmp_sscanf_funs, (void *) &s, fmt, ap);
+#endif
+  va_end (ap);
+  return ret;
+}
diff --git a/scanf/sscanffuns.c b/scanf/sscanffuns.c
new file mode 100644
index 0000000..3ee6b63
--- /dev/null
+++ b/scanf/sscanffuns.c
@@ -0,0 +1,123 @@
+/* __gmp_sscanf_funs -- support for formatted input from a string.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001-2003, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+
+#if 0
+static int
+scan (const char **sp, const char *fmt, ...)
+{
+    va_list ap;
+    int ret;
+
+    va_start(ap, fmt);
+    ret = vsscanf(*sp, fmt, ap);
+    va_end(ap);
+
+    return ret;
+}
+#else
+static int
+scan (const char **sp, const char *fmt, ...)
+{
+  va_list ap;
+  void *p1, *p2;
+  int ret;
+
+  va_start (ap, fmt);
+  p1 = va_arg (ap, void *);
+  p2 = va_arg (ap, void *);
+
+  ret = sscanf (*sp, fmt, p1, p2);
+
+  va_end (ap);
+
+  return ret;
+}
+#endif
+
+static void
+step (const char **sp, int n)
+{
+  ASSERT (n >= 0);
+
+  /* shouldn't push us past the end of the string */
+#if WANT_ASSERT
+  {
+    int  i;
+    for (i = 0; i < n; i++)
+      ASSERT ((*sp)[i] != '\0');
+  }
+#endif
+
+  (*sp) += n;
+}
+
+static int
+get (const char **sp)
+{
+  const char  *s;
+  int  c;
+  s = *sp;
+  c = (unsigned char) *s++;
+  if (c == '\0')
+    return EOF;
+  *sp = s;
+  return c;
+}
+
+static void
+unget (int c, const char **sp)
+{
+  const char  *s;
+  s = *sp;
+  if (c == EOF)
+    {
+      ASSERT (*s == '\0');
+      return;
+    }
+  s--;
+  ASSERT ((unsigned char) *s == c);
+  *sp = s;
+}
+
+const struct gmp_doscan_funs_t  __gmp_sscanf_funs = {
+  (gmp_doscan_scan_t)  scan,
+  (gmp_doscan_step_t)  step,
+  (gmp_doscan_get_t)   get,
+  (gmp_doscan_unget_t) unget,
+};
diff --git a/scanf/vfscanf.c b/scanf/vfscanf.c
new file mode 100644
index 0000000..98b810a
--- /dev/null
+++ b/scanf/vfscanf.c
@@ -0,0 +1,41 @@
+/* gmp_vfscanf -- formatted input from a FILE.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vfscanf (FILE *fp, const char *fmt, va_list ap)
+{
+  return __gmp_doscan (&__gmp_fscanf_funs, fp, fmt, ap);
+}
diff --git a/scanf/vscanf.c b/scanf/vscanf.c
new file mode 100644
index 0000000..2a8cfc1
--- /dev/null
+++ b/scanf/vscanf.c
@@ -0,0 +1,42 @@
+/* gmp_vscanf -- formatted input from stdin.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vscanf (const char *fmt, va_list ap)
+{
+  return __gmp_doscan (&__gmp_fscanf_funs, stdin, fmt, ap);
+}
diff --git a/scanf/vsscanf.c b/scanf/vsscanf.c
new file mode 100644
index 0000000..7c7b98a
--- /dev/null
+++ b/scanf/vsscanf.c
@@ -0,0 +1,60 @@
+/* gmp_vsscanf -- formatted input from a string.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vsscanf (const char *s, const char *fmt, va_list ap)
+{
+#if SSCANF_WRITABLE_INPUT
+  /* We only actually need this if there's standard C types in fmt, and if
+     "s" is not already writable, but it's too much trouble to check that,
+     and in any case this writable sscanf input business is only for a few
+     old systems. */
+  size_t size;
+  char   *alloc;
+  int    ret;
+  size = strlen (s) + 1;
+  alloc = __GMP_ALLOCATE_FUNC_TYPE (size, char);
+  memcpy (alloc, s, size);
+  s = alloc;
+  ret = __gmp_doscan (&__gmp_sscanf_funs, (void *) &s, fmt, ap);
+  (*__gmp_free_func) (alloc, size);
+  return ret;
+
+#else
+  return __gmp_doscan (&__gmp_sscanf_funs, (void *) &s, fmt, ap);
+#endif
+}
diff --git a/tal-debug.c b/tal-debug.c
new file mode 100644
index 0000000..38c27aa
--- /dev/null
+++ b/tal-debug.c
@@ -0,0 +1,150 @@
+/* TMP_ALLOC routines for debugging.
+
+Copyright 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+
+
+/* This method aims to help a malloc debugger find problems.  A linked list
+   of allocated block is kept for TMP_FREE to release.  This is reentrant
+   and thread safe.
+
+   Each TMP_ALLOC is a separate malloced block, so redzones or sentinels
+   applied by a malloc debugger either above or below can guard against
+   accesses outside the allocated area.
+
+   A marker is a "struct tmp_debug_t *" so that TMP_DECL can initialize it
+   to NULL and we can detect TMP_ALLOC without TMP_MARK.
+
+   It will work to realloc an MPZ_TMP_INIT variable, but when TMP_FREE comes
+   to release the memory it will have the old size, thereby triggering an
+   error from tests/memory.c.
+
+   Possibilities:
+
+   It'd be possible to keep a global list of active "struct tmp_debug_t"
+   records, so at the end of a program any TMP leaks could be printed.  But
+   if only a couple of routines are under test at any one time then the
+   likely culprit should be easy enough to spot.  */
+
+
+void
+__gmp_tmp_debug_mark (const char *file, int line,
+                      struct tmp_debug_t **markp, struct tmp_debug_t *mark,
+                      const char *decl_name, const char *mark_name)
+{
+  if (strcmp (mark_name, decl_name) != 0)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_MARK(%s) but TMP_DECL(%s) is in scope\n",
+               mark_name, decl_name);
+      abort ();
+    }
+
+  if (*markp != NULL)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: Repeat of TMP_MARK(%s)\n", mark_name);
+      if (mark->file != NULL && mark->file[0] != '\0' && mark->line != -1)
+        {
+          __gmp_assert_header (mark->file, mark->line);
+          fprintf (stderr, "previous was here\n");
+        }
+      abort ();
+    }
+
+  *markp = mark;
+  mark->file = file;
+  mark->line = line;
+  mark->list = NULL;
+}
+
+void *
+__gmp_tmp_debug_alloc (const char *file, int line, int dummy,
+                       struct tmp_debug_t **markp,
+                       const char *decl_name, size_t size)
+{
+  struct tmp_debug_t        *mark = *markp;
+  struct tmp_debug_entry_t  *p;
+
+  ASSERT_ALWAYS (size >= 1);
+
+  if (mark == NULL)
+    {
+      __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->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,
+                      const char *decl_name, const char *free_name)
+{
+  struct tmp_debug_t        *mark = *markp;
+  struct tmp_debug_entry_t  *p, *next;
+
+  if (mark == NULL)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_FREE(%s) without TMP_MARK(%s)\n",
+               free_name, decl_name);
+      abort ();
+    }
+
+  if (strcmp (free_name, decl_name) != 0)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_FREE(%s) when TMP_DECL(%s) is in scope\n",
+               free_name, decl_name);
+      abort ();
+    }
+
+  p = mark->list;
+  while (p != NULL)
+    {
+      next = p->next;
+      (*__gmp_free_func) (p->block, p->size);
+      __GMP_FREE_FUNC_TYPE (p, 1, struct tmp_debug_entry_t);
+      p = next;
+    }
+
+  *markp = NULL;
+}
diff --git a/tal-notreent.c b/tal-notreent.c
new file mode 100644
index 0000000..083fa84
--- /dev/null
+++ b/tal-notreent.c
@@ -0,0 +1,129 @@
+/* Stack allocation routines.  This is intended for machines without support
+   for the `alloca' function.
+
+Copyright 1996, 1997, 1999-2001, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+struct tmp_stack
+{
+  void *end;
+  void *alloc_point;
+  struct tmp_stack *prev;
+};
+typedef struct tmp_stack tmp_stack;
+
+
+static unsigned long max_total_allocation = 0;
+static unsigned long current_total_allocation = 0;
+
+static tmp_stack xxx = {&xxx, &xxx, 0};
+static tmp_stack *current = &xxx;
+
+/* The rounded size of the header of each allocation block.  */
+#define HSIZ   ROUND_UP_MULTIPLE (sizeof (tmp_stack), __TMP_ALIGN)
+
+
+/* Allocate a block of exactly <size> bytes.  This should only be called
+   through the TMP_ALLOC macro, which takes care of rounding/alignment.  */
+void *
+__gmp_tmp_alloc (unsigned long size)
+{
+  void *that;
+
+  ASSERT ((size % __TMP_ALIGN) == 0);
+  ASSERT (((unsigned) current->alloc_point % __TMP_ALIGN) == 0);
+
+  if (size > (char *) current->end - (char *) current->alloc_point)
+    {
+      void *chunk;
+      tmp_stack *header;
+      unsigned long chunk_size;
+      unsigned long now;
+
+      /* Allocate a chunk that makes the total current allocation somewhat
+	 larger than the maximum allocation ever.  If size is very large, we
+	 allocate that much.  */
+
+      now = current_total_allocation + size;
+      if (now > max_total_allocation)
+	{
+	  /* We need more temporary memory than ever before.  Increase
+	     for future needs.  */
+	  now = (now * 3 / 2 + __TMP_ALIGN - 1) & -__TMP_ALIGN;
+	  chunk_size = now - current_total_allocation + HSIZ;
+	  current_total_allocation = now;
+	  max_total_allocation = current_total_allocation;
+	}
+      else
+	{
+	  chunk_size = max_total_allocation - current_total_allocation + HSIZ;
+	  current_total_allocation = max_total_allocation;
+	}
+
+      chunk = (*__gmp_allocate_func) (chunk_size);
+      header = (tmp_stack *) chunk;
+      header->end = (char *) chunk + chunk_size;
+      header->alloc_point = (char *) chunk + HSIZ;
+      header->prev = current;
+      current = header;
+    }
+
+  that = current->alloc_point;
+  current->alloc_point = (char *) that + size;
+  ASSERT (((unsigned) that % __TMP_ALIGN) == 0);
+  return that;
+}
+
+/* Typically called at function entry.  <mark> is assigned so that
+   __gmp_tmp_free can later be used to reclaim all subsequently allocated
+   storage.  */
+void
+__gmp_tmp_mark (struct tmp_marker *mark)
+{
+  mark->which_chunk = current;
+  mark->alloc_point = current->alloc_point;
+}
+
+/* Free everything allocated since <mark> was assigned by __gmp_tmp_mark */
+void
+__gmp_tmp_free (struct tmp_marker *mark)
+{
+  while (mark->which_chunk != current)
+    {
+      tmp_stack *tmp;
+
+      tmp = current;
+      current = tmp->prev;
+      current_total_allocation -= (((char *) (tmp->end) - (char *) tmp) - HSIZ);
+      (*__gmp_free_func) (tmp, (char *) tmp->end - (char *) tmp);
+    }
+  current->alloc_point = mark->alloc_point;
+}
diff --git a/tal-reent.c b/tal-reent.c
new file mode 100644
index 0000000..fb43e06
--- /dev/null
+++ b/tal-reent.c
@@ -0,0 +1,81 @@
+/* TMP_ALLOC routines using malloc in a reentrant fashion.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* Each TMP_ALLOC uses __gmp_allocate_func to get a block of memory of the
+   size requested, plus a header at the start which is used to hold the
+   blocks on a linked list in the marker variable, ready for TMP_FREE to
+   release.
+
+   Callers should try to do multiple allocs with one call, in the style of
+   TMP_ALLOC_LIMBS_2 if it's easy to arrange, since that will keep down the
+   number of separate malloc calls.
+
+   Enhancements:
+
+   Could inline both TMP_ALLOC and TMP_FREE, though TMP_ALLOC would need the
+   compiler to have "inline" since it returns a value.  The calls to malloc
+   will be slow though, so it hardly seems worth worrying about one extra
+   level of function call.  */
+
+
+#define HSIZ   ROUND_UP_MULTIPLE (sizeof (struct tmp_reentrant_t), __TMP_ALIGN)
+
+void *
+__gmp_tmp_reentrant_alloc (struct tmp_reentrant_t **markp, size_t size)
+{
+  char    *p;
+  size_t  total_size;
+
+#define P   ((struct tmp_reentrant_t *) p)
+
+  total_size = size + HSIZ;
+  p = __GMP_ALLOCATE_FUNC_TYPE (total_size, char);
+  P->size = total_size;
+  P->next = *markp;
+  *markp = P;
+  return p + HSIZ;
+}
+
+void
+__gmp_tmp_reentrant_free (struct tmp_reentrant_t *mark)
+{
+  struct tmp_reentrant_t  *next;
+
+  while (mark != NULL)
+    {
+      next = mark->next;
+      (*__gmp_free_func) ((char *) mark, mark->size);
+      mark = next;
+    }
+}
diff --git a/tests/amd64call.asm b/tests/amd64call.asm
new file mode 100644
index 0000000..e43b01f
--- /dev/null
+++ b/tests/amd64call.asm
@@ -0,0 +1,167 @@
+dnl  AMD64 calling conventions checking.
+
+dnl  Copyright 2000, 2003, 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library test suite.
+
+dnl  The GNU MP Library test suite is free software; you can redistribute it
+dnl  and/or modify it under the terms of the GNU General Public License as
+dnl  published by the Free Software Foundation; either version 3 of the
+dnl  License, or (at your option) any later version.
+
+dnl  The GNU MP Library test suite is distributed in the hope that it will be
+dnl  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+dnl  Public License for more details.
+
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with the GNU MP Library test suite.  If not, see
+dnl  https://www.gnu.org/licenses/.
+
+
+dnl  The current version of the code attempts to keep the call/return
+dnl  prediction stack valid, but matching calls and returns.
+
+include(`config.m4')
+
+
+C void x86_fldcw (unsigned short cw);
+C
+C Execute an fldcw, setting the x87 control word to cw.
+
+PROLOGUE(x86_fldcw)
+	mov	%rdi, -8(%rsp)
+	fldcw	-8(%rsp)
+	ret
+EPILOGUE()
+
+
+C unsigned short x86_fstcw (void);
+C
+C Execute an fstcw, returning the current x87 control word.
+
+PROLOGUE(x86_fstcw)
+	movq	$0, -8(%rsp)
+	fstcw	-8(%rsp)
+	mov	-8(%rsp), %rax
+	ret
+EPILOGUE()
+
+
+dnl  Instrumented profiling won't come out quite right below, since we don't do
+dnl  an actual "ret".  There's only a few instructions here, so there's no
+dnl  great need to get them separately accounted, just let them get attributed
+dnl  to the caller.  FIXME this comment might no longer be true.
+
+ifelse(WANT_PROFILING,instrument,
+`define(`WANT_PROFILING',no)')
+
+
+C int calling_conventions (...);
+C
+C The global variable "calling_conventions_function" is the function to
+C call, with the arguments as passed here.
+C
+C Perhaps the finit should be done only if the tags word isn't clear, but
+C nothing uses the rounding mode or anything at the moment.
+
+define(`WANT_RBX', eval(8*0)($1))
+define(`WANT_RBP', eval(8*1)($1))
+define(`WANT_R12', eval(8*2)($1))
+define(`WANT_R13', eval(8*3)($1))
+define(`WANT_R14', eval(8*4)($1))
+define(`WANT_R15', eval(8*5)($1))
+
+define(`JUNK_RAX', eval(8*6)($1))
+define(`JUNK_R10', eval(8*7)($1))
+define(`JUNK_R11', eval(8*8)($1))
+
+define(`SAVE_RBX', eval(8*9)($1))
+define(`SAVE_RBP', eval(8*10)($1))
+define(`SAVE_R12', eval(8*11)($1))
+define(`SAVE_R13', eval(8*12)($1))
+define(`SAVE_R14', eval(8*13)($1))
+define(`SAVE_R15', eval(8*14)($1))
+
+define(`RETADDR',  eval(8*15)($1))
+
+define(`RBX',	   eval(8*16)($1))
+define(`RBP',	   eval(8*17)($1))
+define(`R12',	   eval(8*18)($1))
+define(`R13',	   eval(8*19)($1))
+define(`R14',	   eval(8*20)($1))
+define(`R15',	   eval(8*21)($1))
+define(`RFLAGS',   eval(8*22)($1))
+
+
+define(G,
+m4_assert_numargs(1)
+`GSYM_PREFIX`'$1')
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(calling_conventions)
+	mov	G(calling_conventions_values)@GOTPCREL(%rip), %rax
+	pop	RETADDR(%rax)
+
+	mov	%rbx, SAVE_RBX(%rax)
+	mov	%rbp, SAVE_RBP(%rax)
+	mov	%r12, SAVE_R12(%rax)
+	mov	%r13, SAVE_R13(%rax)
+	mov	%r14, SAVE_R14(%rax)
+	mov	%r15, SAVE_R15(%rax)
+
+	C Values we expect to see unchanged, as per amd64check.c
+	mov	WANT_RBX(%rax), %rbx
+	mov	WANT_RBP(%rax), %rbp
+	mov	WANT_R12(%rax), %r12
+	mov	WANT_R13(%rax), %r13
+	mov	WANT_R14(%rax), %r14
+	mov	WANT_R15(%rax), %r15
+
+	C Try to provoke a problem by starting with junk in the caller-saves
+	C registers, especially %rax which will be the return value.
+C	mov	JUNK_RAX(%rax), %rax		C overwritten below anyway
+	mov	JUNK_R10(%rax), %r10
+	mov	JUNK_R11(%rax), %r11
+
+	mov	G(calling_conventions_function)@GOTPCREL(%rip), %rax
+	call	*(%rax)
+
+	mov	G(calling_conventions_values)@GOTPCREL(%rip), %rcx
+
+	mov	%rbx, RBX(%rcx)
+	mov	%rbp, RBP(%rcx)
+	mov	%r12, R12(%rcx)
+	mov	%r13, R13(%rcx)
+	mov	%r14, R14(%rcx)
+	mov	%r15, R15(%rcx)
+
+	pushf
+	pop	%rbx
+	mov	%rbx, RFLAGS(%rcx)
+
+	mov	SAVE_RBX(%rcx), %rbx
+	mov	SAVE_RBP(%rcx), %rbp
+	mov	SAVE_R12(%rcx), %r12
+	mov	SAVE_R13(%rcx), %r13
+	mov	SAVE_R14(%rcx), %r14
+	mov	SAVE_R15(%rcx), %r15
+
+	C Overwrite parameter registers
+C	mov	JUNK_R9(%rcx), %r9
+C	mov	JUNK_R8(%rcx), %r8
+C	mov	JUNK_RCX(%rcx), %rcx
+C	mov	JUNK_RDX(%rcx), %rdx
+C	mov	JUNK_RSI(%rcx), %rsi
+C	mov	JUNK_RDI(%rcx), %rdi
+
+	push	RETADDR(%rcx)
+
+	mov	G(calling_conventions_fenv)@GOTPCREL(%rip), %rcx
+	fstenv	(%rcx)
+	finit
+
+	ret
+
+EPILOGUE()
diff --git a/tests/amd64check.c b/tests/amd64check.c
new file mode 100644
index 0000000..a8cdbe2
--- /dev/null
+++ b/tests/amd64check.c
@@ -0,0 +1,111 @@
+/* AMD64 calling conventions checking.
+
+Copyright 2000, 2001, 2004, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Vector if constants and register values.  We use one vector to allow access
+   via a base pointer, very beneficial for the PIC-enabled amd64call.asm.  */
+mp_limb_t calling_conventions_values[23] =
+{
+  CNST_LIMB(0x1234567887654321),	/* want_rbx */
+  CNST_LIMB(0x89ABCDEFFEDCBA98),	/* want_rbp */
+  CNST_LIMB(0xDEADBEEFBADECAFE),	/* want_r12 */
+  CNST_LIMB(0xFFEEDDCCBBAA9988),	/* want_r13 */
+  CNST_LIMB(0x0011223344556677),	/* want_r14 */
+  CNST_LIMB(0x1234432156788765),	/* want_r15 */
+
+  CNST_LIMB(0xFEEDABBACAAFBEED),	/* JUNK_RAX */
+  CNST_LIMB(0xAB78DE89FF5125BB),	/* JUNK_R10 */
+  CNST_LIMB(0x1238901890189031)		/* JUNK_R11 */
+
+  /* rest of array used for dynamic values.  */
+};
+
+/* Index starts for various regions in above vector.  */
+#define WANT	0
+#define JUNK	6
+#define SAVE	9
+#define RETADDR	15
+#define VAL	16
+#define RFLAGS	22
+
+/* values to check */
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct {
+  int  control;
+  int  status;
+  int  tag;
+  int  other[4];
+} calling_conventions_fenv;
+#ifdef __cplusplus
+}
+#endif
+
+
+const char *regname[6] = {"rbx", "rbp", "r12", "r13", "r14", "r15"};
+
+#define DIR_BIT(rflags)   (((rflags) & (1<<10)) != 0)
+
+
+/* Return 1 if ok, 0 if not */
+
+int
+calling_conventions_check (void)
+{
+  const char  *header = "Violated calling conventions:\n";
+  int  ret = 1;
+  int i;
+
+#define CHECK(callreg, regstr, value)			\
+  if (callreg != value)					\
+    {							\
+      printf ("%s   %s	got 0x%016lX want 0x%016lX\n",	\
+	      header, regstr, callreg, value);		\
+      header = "";					\
+      ret = 0;						\
+    }
+
+  for (i = 0; i < 6; i++)
+    {
+      CHECK (calling_conventions_values[VAL+i], regname[i], calling_conventions_values[WANT+i]);
+    }
+
+  if (DIR_BIT (calling_conventions_values[RFLAGS]) != 0)
+    {
+      printf ("%s   rflags dir bit  got %d want 0\n",
+	      header, DIR_BIT (calling_conventions_values[RFLAGS]));
+      header = "";
+      ret = 0;
+    }
+
+  if ((calling_conventions_fenv.tag & 0xFFFF) != 0xFFFF)
+    {
+      printf ("%s   fpu tags  got 0x%X want 0xFFFF\n",
+	      header, calling_conventions_fenv.tag & 0xFFFF);
+      header = "";
+      ret = 0;
+    }
+
+  return ret;
+}
diff --git a/tests/arm32call.asm b/tests/arm32call.asm
new file mode 100644
index 0000000..7fd4530
--- /dev/null
+++ b/tests/arm32call.asm
@@ -0,0 +1,83 @@
+dnl  ARM32 calling conventions checking.
+
+dnl  Copyright 2000, 2003, 2004, 2006, 2007, 2010, 2013, 2016 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library test suite.
+
+dnl  The GNU MP Library test suite is free software; you can redistribute it
+dnl  and/or modify it under the terms of the GNU General Public License as
+dnl  published by the Free Software Foundation; either version 3 of the
+dnl  License, or (at your option) any later version.
+
+dnl  The GNU MP Library test suite is distributed in the hope that it will be
+dnl  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+dnl  Public License for more details.
+
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with the GNU MP Library test suite.  If not, see
+dnl  https://www.gnu.org/licenses/.
+
+
+dnl  The current version of the code attempts to keep the call/return
+dnl  prediction stack valid, but matching calls and returns.
+
+include(`config.m4')
+
+
+C int calling_conventions (...);
+C
+C The global variable "calling_conventions_function" is the function to
+C call, with the arguments as passed here.
+
+define(`WANT_CALLEE_SAVES',	eval(4*0))
+define(`SAVE_CALLEE_SAVES',	eval(4*8))
+define(`RETADDR',		eval(4*16))
+define(`GOT_CALLEE_SAVES',	eval(4*17))
+define(`JUNK_PARAMS',		eval(4*25))
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(calling_conventions)
+	LEA(	r12, calling_conventions_values)
+
+	C Preserve callee-saves registers, including the link register r14
+	add	r12, r12, #SAVE_CALLEE_SAVES
+	stm	r12, {r4-r11,r14}
+	sub	r12, r12, #SAVE_CALLEE_SAVES
+
+	C Put chosen junk into callee-saves registers
+	add	r12, r12, #WANT_CALLEE_SAVES
+	ldm	r12, {r4-r11}
+	sub	r12, r12, #WANT_CALLEE_SAVES
+
+	C No callee-saves registers on arm except r12 and parameter registers
+	C
+
+	C Make the actual call
+	LEA(	r12, calling_conventions_function)
+	ldr	r12, [r12]
+	mov	r14, pc
+	return	r12
+
+	LEA(	r12, calling_conventions_values)
+
+	C Save callee-saves registers after call
+	add	r12, r12, #GOT_CALLEE_SAVES
+	stm	r12, {r4-r11}
+	sub	r12, r12, #GOT_CALLEE_SAVES
+
+	C Restore callee-saves registers, including the link register r14
+	add	r12, r12, #SAVE_CALLEE_SAVES
+	ldm	r12, {r4-r11,r14}
+	sub	r12, r12, #SAVE_CALLEE_SAVES
+
+	C Overwrite parameter registers.  Note that we overwrite r1, which
+	C could hold one half of a 64-bit return value, since we don't use that
+	C in GMP.
+	add	r12, r12, #JUNK_PARAMS
+	ldm	r12, {r1-r3}
+
+	return	r14
+EPILOGUE()
diff --git a/tests/arm32check.c b/tests/arm32check.c
new file mode 100644
index 0000000..0a9f86d
--- /dev/null
+++ b/tests/arm32check.c
@@ -0,0 +1,95 @@
+/* ARM32 calling conventions checking.
+
+Copyright 2000, 2001, 2004, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Vector if constants and register values.  */
+mp_limb_t calling_conventions_values[29] =
+{
+  0x12345678,	/*  0 want_r4 */
+  0x87654321,	/*  1 want_r5 */
+  0x89ABCDEF,	/*  2 want_r6 */
+  0xFEDCBA98,	/*  3 want_r7 */
+  0xDEADBEEF,	/*  4 want_r8 */
+  0xBADECAFE,	/*  5 want_r9 */
+  0xFFEEDDCC,	/*  6 want_r10 */
+  0xBBAA9988,	/*  7 want_r11 */
+
+  0x00000000,	/*  8 save_r4 */
+  0x00000000,	/*  9 save_r5 */
+  0x00000000,	/* 10 save_r6 */
+  0x00000000,	/* 11 save_r7 */
+  0x00000000,	/* 12 save_r8 */
+  0x00000000,	/* 13 save_r9 */
+  0x00000000,	/* 14 save_r10 */
+  0x00000000,	/* 15 save_r11 */
+  0x00000000,	/* 16 save_r14 */
+
+  0x00000000,	/* 17 got_r4 */
+  0x00000000,	/* 18 got_r5 */
+  0x00000000,	/* 19 got_r6 */
+  0x00000000,	/* 20 got_r7 */
+  0x00000000,	/* 21 got_r8 */
+  0x00000000,	/* 22 got_r9 */
+  0x00000000,	/* 23 got_r10 */
+  0x00000000,	/* 24 got_r11 */
+
+  0x00112233,	/* 25 junk_r0 */
+  0x44556677,	/* 26 junk_r1 */
+  0x12344321,	/* 27 junk_r2 */
+  0x56788765,	/* 28 junk_r3 */
+};
+
+/* Index starts for various regions in above vector.  */
+#define WANT_CALLEE_SAVES	0
+#define SAVE_CALLEE_SAVES	8
+#define RETADDR			16
+#define GOT_CALLEE_SAVES	17
+#define JUNK_PARAMS		25
+
+/* Return 1 if ok, 0 if not */
+
+int
+calling_conventions_check (void)
+{
+  const char  *header = "Violated calling conventions:\n";
+  int  ret = 1;
+  int i;
+
+#define CHECK(callreg, regnum, value)					\
+  if (callreg != value)							\
+    {									\
+      printf ("%s   r%d	got 0x%08lX want 0x%08lX\n",			\
+	      header, regnum, callreg, value);				\
+      header = "";							\
+      ret = 0;								\
+    }
+
+  for (i = 0; i < 8; i++)
+    {
+      CHECK (calling_conventions_values[GOT_CALLEE_SAVES + i],
+	     i + 4,
+	     calling_conventions_values[WANT_CALLEE_SAVES + i]);
+    }
+
+  return ret;
+}
diff --git a/tests/cxx/clocale.c b/tests/cxx/clocale.c
new file mode 100644
index 0000000..7f7c36e
--- /dev/null
+++ b/tests/cxx/clocale.c
@@ -0,0 +1,66 @@
+/* Manipulable localeconv and nl_langinfo.
+
+Copyright 2001, 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_NL_TYPES_H
+#include <nl_types.h>  /* for nl_item */
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for lconv */
+#endif
+
+
+/* Replace the libc localeconv and nl_langinfo with ones we can manipulate.
+
+   This is done in a C file since if it was in a C++ file then we'd have to
+   match the "throw" or lack thereof declared for localeconv in <locale.h>.
+   g++ 3.2 gives an error about mismatched throws under "-pedantic", other
+   C++ compilers may very possibly do so too.  */
+
+extern char point_string[];
+
+#if HAVE_LOCALECONV && ! defined __MINGW32__
+struct lconv *
+localeconv (void)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+  static struct lconv  l;
+  l.decimal_point = point_string;
+  return &l;
+}
+#endif
+
+#if HAVE_NL_LANGINFO
+char *
+nl_langinfo (nl_item n)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+  return point_string;
+}
+#endif
diff --git a/tests/cxx/t-assign.cc b/tests/cxx/t-assign.cc
new file mode 100644
index 0000000..a11b0d9
--- /dev/null
+++ b/tests/cxx/t-assign.cc
@@ -0,0 +1,603 @@
+/* Test mp*_class assignment operators.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+#include <string>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using std::string;
+using std::invalid_argument;
+
+
+void
+check_mpz (void)
+{
+  // operator=(const mpz_class &)
+  {
+    mpz_class a(123), b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // template <class T, class U> operator=(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // operator=(signed char)
+  {
+    signed char a = -127;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -127);
+  }
+
+  // operator=(unsigned char)
+  {
+    unsigned char a = 255;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpz_class a;
+    a = 'A'; ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpz_class a;
+    a = 'z'; ASSERT_ALWAYS(a == 122);
+  }
+
+  // operator=(signed int)
+  {
+    signed int a = 0;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 32767;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 32767);
+  }
+
+  // operator=(unsigned int)
+  {
+    unsigned int a = 65535u;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // operator=(signed short int)
+  {
+    signed short int a = -12345;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -12345);
+  }
+
+  // operator=(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // operator=(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // operator=(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // operator=(float)
+  {
+    float a = 123.0;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // operator=(double)
+  {
+    double a = 0.0;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    double a = -12.375;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -12);
+  }
+  {
+    double a = 6.789e+3;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 6789);
+  }
+  {
+    double a = 9.375e-1;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+
+  // operator=(long double)
+  // currently not implemented
+
+  // operator=(const char *)
+  {
+    const char *a = "1234567890";
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const std::string &)
+  {
+    string a("1234567890");
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpz_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // operator=(const std::string &) with invalid
+  {
+    try {
+      string a("def");
+      mpz_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // swap(mpz_class &)
+  {
+    mpz_class a(123);
+    mpz_class b(456);
+    a.swap(b);
+    a.swap(a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+
+  // swap(mpz_class &, mpz_class &)
+  {
+    mpz_class a(123);
+    mpz_class b(456);
+    ::swap(a, b);
+    ::swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+  {
+    using std::swap;
+    mpz_class a(123);
+    mpz_class b(456);
+    swap(a, b);
+    swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // operator=(const mpq_class &)
+  {
+    mpq_class a(1, 2), b;
+    b = a; ASSERT_ALWAYS(b == 0.5);
+  }
+
+  // template <class T, class U> operator=(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // operator=(signed char)
+  {
+    signed char a = -127;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -127);
+  }
+
+  // operator=(unsigned char)
+  {
+    unsigned char a = 255;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpq_class a;
+    a = 'A'; ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpq_class a;
+    a = 'z'; ASSERT_ALWAYS(a == 122);
+  }
+
+  // operator=(signed int)
+  {
+    signed int a = 0;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 32767;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 32767);
+  }
+
+  // operator=(unsigned int)
+  {
+    unsigned int a = 65535u;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // operator=(signed short int)
+  {
+    signed short int a = -12345;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -12345);
+  }
+
+  // operator=(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // operator=(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // operator=(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // operator=(float)
+  {
+    float a = 123.0;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // operator=(double)
+  {
+    double a = 0.0;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    double a = -12.375;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -12.375);
+  }
+  {
+    double a = 6.789e+3;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 6789);
+  }
+  {
+    double a = 9.375e-1;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 0.9375);
+  }
+
+  // operator=(long double)
+  // currently not implemented
+
+  // operator=(const char *)
+  {
+    const char *a = "1234567890";
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const std::string &)
+  {
+    string a("1234567890");
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpq_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // operator=(const std::string &) with invalid
+  {
+    try {
+      string a("def");
+      mpq_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // swap(mpq_class &)
+  {
+    mpq_class a(3, 2);
+    mpq_class b(-1, 4);
+    a.swap(b);
+    a.swap(a);
+    ASSERT_ALWAYS(a == -.25);
+    ASSERT_ALWAYS(b == 1.5);
+  }
+
+  // swap(mpq_class &, mpq_class &)
+  {
+    mpq_class a(3, 2);
+    mpq_class b(-1, 4);
+    ::swap(a, b);
+    ::swap(a, a);
+    ASSERT_ALWAYS(a == -.25);
+    ASSERT_ALWAYS(b == 1.5);
+  }
+  {
+    using std::swap;
+    mpq_class a(3, 2);
+    mpq_class b(-1, 4);
+    swap(a, b);
+    swap(a, a);
+    ASSERT_ALWAYS(a == -.25);
+    ASSERT_ALWAYS(b == 1.5);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // operator=(const mpf_class &)
+  {
+    mpf_class a(123), b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // template <class T, class U> operator=(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // operator=(signed char)
+  {
+    signed char a = -127;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -127);
+  }
+
+  // operator=(unsigned char)
+  {
+    unsigned char a = 255;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpf_class a;
+    a = 'A'; ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpf_class a;
+    a = 'z'; ASSERT_ALWAYS(a == 122);
+  }
+
+  // operator=(signed int)
+  {
+    signed int a = 0;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 32767;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 32767);
+  }
+
+  // operator=(unsigned int)
+  {
+    unsigned int a = 65535u;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // operator=(signed short int)
+  {
+    signed short int a = -12345;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -12345);
+  }
+
+  // operator=(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // operator=(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // operator=(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // operator=(float)
+  {
+    float a = 123.0;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // operator=(double)
+  {
+    double a = 0.0;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    double a = -12.375;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -12.375);
+  }
+  {
+    double a = 6.789e+3;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 6789);
+  }
+  {
+    double a = 9.375e-1;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 0.9375);
+  }
+
+  // operator=(long double)
+  // currently not implemented
+
+  // operator=(const char *)
+  {
+    const char *a = "1234567890";
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const std::string &)
+  {
+    string a("1234567890");
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpf_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // operator=(const std::string &) with invalid
+  {
+    try {
+      string a("def");
+      mpf_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // swap(mpf_class &)
+  {
+    mpf_class a(123);
+    mpf_class b(456);
+    a.swap(b);
+    a.swap(a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+
+  // swap(mpf_class &, mpf_class &)
+  {
+    mpf_class a(123);
+    mpf_class b(456);
+    ::swap(a, b);
+    ::swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+  {
+    using std::swap;
+    mpf_class a(123);
+    mpf_class b(456);
+    swap(a, b);
+    swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-binary.cc b/tests/cxx/t-binary.cc
new file mode 100644
index 0000000..697adfa
--- /dev/null
+++ b/tests/cxx/t-binary.cc
@@ -0,0 +1,465 @@
+/* Test mp*_class binary expressions.
+
+Copyright 2001-2003, 2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(1), b(2);
+    mpz_class c(a + b); ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpz_class a(3), b(4);
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == 12);
+  }
+  {
+    mpz_class a(5), b(3);
+    mpz_class c;
+    c = a % b; ASSERT_ALWAYS(c == 2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+  {
+    mpz_class a(1);
+    signed int b = 3;
+    mpz_class c(a - b); ASSERT_ALWAYS(c == -2);
+  }
+  {
+    mpz_class a(-8);
+    unsigned int b = 2;
+    mpz_class c;
+    c = a / b; ASSERT_ALWAYS(c == -4);
+  }
+  {
+    mpz_class a(2);
+    double b = 3.0;
+    mpz_class c(a + b); ASSERT_ALWAYS(c == 5);
+  }
+  {
+    mpz_class a(4);
+    mpz_class b;
+    b = a + 0; ASSERT_ALWAYS(b == 4);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(3);
+    signed int b = 9;
+    mpz_class c(b / a); ASSERT_ALWAYS(c == 3);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+  {
+    mpz_class a(3), b(4);
+    mpz_class c(a * (-b)); ASSERT_ALWAYS(c == -12);
+    c = c * (-b); ASSERT_ALWAYS(c == 48);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(3), b(2), c(1);
+    mpz_class d;
+    d = (a % b) + c; ASSERT_ALWAYS(d == 2);
+    d = (a % b) + d; ASSERT_ALWAYS(d == 3);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+  {
+    mpz_class a(-5);
+    unsigned int b = 2;
+    mpz_class c((-a) << b); ASSERT_ALWAYS(c == 20);
+  }
+  {
+    mpz_class a(5), b(-4);
+    signed int c = 3;
+    mpz_class d;
+    d = (a * b) >> c; ASSERT_ALWAYS(d == -3);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+  {
+    mpz_class a(2), b(4);
+    double c = 6;
+    mpz_class d(c / (a - b)); ASSERT_ALWAYS(d == -3);
+  }
+  {
+    mpz_class a(3), b(2);
+    double c = 1;
+    mpz_class d;
+    d = c + (a + b); ASSERT_ALWAYS(d == 6);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+  {
+    mpz_class a(3), b(5), c(7);
+    mpz_class d;
+    d = (a - b) * (-c); ASSERT_ALWAYS(d == 14);
+    d = (b - d) * (-a); ASSERT_ALWAYS(d == 27);
+    d = (a - b) * (-d); ASSERT_ALWAYS(d == 54);
+  }
+
+  {
+    mpz_class a(0xcafe), b(0xbeef), c, want;
+    c = a & b; ASSERT_ALWAYS (c == 0x8aee);
+    c = a | b; ASSERT_ALWAYS (c == 0xfeff);
+    c = a ^ b; ASSERT_ALWAYS (c == 0x7411);
+    c = a & 0xbeef; ASSERT_ALWAYS (c == 0x8aee);
+    c = a | 0xbeef; ASSERT_ALWAYS (c == 0xfeff);
+    c = a ^ 0xbeef; ASSERT_ALWAYS (c == 0x7411);
+    c = a & -0xbeef; ASSERT_ALWAYS (c == 0x4010);
+    c = a | -0xbeef; ASSERT_ALWAYS (c == -0x3401);
+    c = a ^ -0xbeef; ASSERT_ALWAYS (c == -0x7411);
+    c = a & 48879.0; ASSERT_ALWAYS (c == 0x8aee);
+    c = a | 48879.0; ASSERT_ALWAYS (c == 0xfeff);
+    c = a ^ 48879.0; ASSERT_ALWAYS (c == 0x7411);
+
+    c = a | 1267650600228229401496703205376.0; // 2^100
+    want = "0x1000000000000000000000cafe";
+    ASSERT_ALWAYS (c == want);
+  }
+
+}
+
+void
+check_mpq (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(1, 2), b(3, 4);
+    mpq_class c(a + b); ASSERT_ALWAYS(c == 1.25);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+  {
+    mpq_class a(1, 2);
+    signed int b = 3;
+    mpq_class c(a - b); ASSERT_ALWAYS(c == -2.5);
+  }
+  {
+    mpq_class a(1, 2);
+    mpq_class b;
+    b = a + 0; ASSERT_ALWAYS(b == 0.5);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(2, 3);
+    signed int b = 4;
+    mpq_class c;
+    c = b / a; ASSERT_ALWAYS(c == 6);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<U, V>, Op> >
+  {
+    mpq_class a(1, 2);
+    mpz_class b(1);
+    mpq_class c(a + b); ASSERT_ALWAYS(c == 1.5);
+  }
+  {
+    mpq_class a(2, 3);
+    mpz_class b(1);
+    double c = 2.0;
+    mpq_class d;
+    d = a * (b + c); ASSERT_ALWAYS(d == 2);
+    d = d * (b + c); ASSERT_ALWAYS(d == 6);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(2, 3);
+    mpz_class b(4);
+    mpq_class c(b / a); ASSERT_ALWAYS(c == 6);
+  }
+  {
+    mpq_class a(2, 3);
+    mpz_class b(1), c(4);
+    mpq_class d;
+    d = (b - c) * a; ASSERT_ALWAYS(d == -2);
+    d = (b - c) * d; ASSERT_ALWAYS(d == 6);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+  {
+    mpq_class a(1, 3), b(3, 4);
+    mpq_class c;
+    c = a * (-b); ASSERT_ALWAYS(c == -0.25);
+    a = a * (-b); ASSERT_ALWAYS(a == -0.25);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(1, 3), b(2, 3), c(1, 4);
+    mpq_class d((a / b) + c); ASSERT_ALWAYS(d == 0.75);
+    c = (a / b) + c; ASSERT_ALWAYS(c == 0.75);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+  {
+    mpq_class a(3, 8);
+    unsigned int b = 4;
+    mpq_class c((-a) << b); ASSERT_ALWAYS(c == -6);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+  {
+    mpq_class a(1, 2), b(1, 4);
+    double c = 6.0;
+    mpq_class d;
+    d = c / (a + b); ASSERT_ALWAYS(d == 8);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  {
+    mpq_class a(1, 2), b(1, 4);
+    mpz_class c(1);
+    mpq_class d((a + b) - c); ASSERT_ALWAYS(d == -0.25);
+    d = (a + d) - c; ASSERT_ALWAYS(d == -0.75);
+    d = (a + d) - d.get_num(); ASSERT_ALWAYS(d == 2.75);
+    d = (2 * d) * d.get_den(); ASSERT_ALWAYS(d == 22);
+    d = (b * d) / -d.get_num(); ASSERT_ALWAYS(d == -0.25);
+  }
+  {
+    mpq_class a(1, 3), b(3, 2);
+    mpz_class c(2), d(4);
+    mpq_class e;
+    e = (a * b) / (c - d); ASSERT_ALWAYS(e == -0.25);
+    e = (2 * e) / (c - d); ASSERT_ALWAYS(e ==  0.25);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  {
+    mpq_class a(1, 3), b(3, 4);
+    mpz_class c(-3);
+    mpq_class d(c * (a * b)); ASSERT_ALWAYS(d == -0.75);
+  }
+  {
+    mpq_class a(1, 3), b(3, 5);
+    mpz_class c(6);
+    signed int d = 4;
+    mpq_class e;
+    e = (c % d) / (a * b); ASSERT_ALWAYS(e == 10);
+    e = (e.get_num() % d) / (2 / e); ASSERT_ALWAYS(e == 10);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+  {
+    mpq_class a(1, 3), b(3, 4), c(2, 5);
+    mpq_class d;
+    d = (a * b) / (-c); ASSERT_ALWAYS(d == -0.625);
+    d = (c * d) / (-b); ASSERT_ALWAYS(3 * d == 1);
+    d = (a * c) / (-d); ASSERT_ALWAYS(5 * d == -2);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(1), b(2);
+    mpf_class c(a + b); ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpf_class a(1.5), b(6);
+    mpf_class c;
+    c = a / b; ASSERT_ALWAYS(c == 0.25);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+  {
+    mpf_class a(1);
+    signed int b = -2;
+    mpf_class c(a - b); ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = a + 0; ASSERT_ALWAYS(b == 2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(2);
+    unsigned int b = 3;
+    mpf_class c;
+    c = b / a; ASSERT_ALWAYS(c == 1.5);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<U, V>, Op> >
+  {
+    mpf_class a(2);
+    mpz_class b(3);
+    mpf_class c(a - b); ASSERT_ALWAYS(c == -1);
+  }
+  {
+    mpf_class a(3);
+    mpz_class b(2), c(1);
+    mpf_class d;
+    d = a * (b + c); ASSERT_ALWAYS(d == 9);
+    a = a * (b + c); ASSERT_ALWAYS(a == 9);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(6);
+    mpq_class b(3, 4);
+    mpf_class c(a * b); ASSERT_ALWAYS(c == 4.5);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+  {
+    mpf_class a(2), b(-3);
+    mpf_class c;
+    c = a * (-b); ASSERT_ALWAYS(c == 6);
+    c = c * (-b); ASSERT_ALWAYS(c == 18);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(3), b(4), c(5);
+    mpf_class d;
+    d = (a / b) - c; ASSERT_ALWAYS(d == -4.25);
+    c = (a / b) - c; ASSERT_ALWAYS(c == -4.25);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+  {
+    mpf_class a(3);
+    unsigned int b = 2;
+    mpf_class c((-a) >> b); ASSERT_ALWAYS(c == -0.75);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+  {
+    mpf_class a(2), b(3);
+    double c = 5.0;
+    mpf_class d;
+    d = c / (a + b); ASSERT_ALWAYS(d == 1);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  {
+    mpf_class a(2), b(3);
+    mpz_class c(4);
+    mpf_class d;
+    d = (a + b) * c; ASSERT_ALWAYS(d == 20);
+  }
+  {
+    mpf_class a(2), b(3);
+    mpq_class c(1, 2), d(1, 4);
+    mpf_class e;
+    e = (a * b) / (c + d); ASSERT_ALWAYS(e == 8);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  {
+    mpf_class a(1), b(2);
+    mpq_class c(3);
+    mpf_class d(c / (a + b)); ASSERT_ALWAYS(d == 1);
+  }
+  {
+    mpf_class a(1);
+    mpz_class b(2);
+    mpq_class c(3, 4);
+    mpf_class d;
+    d = (-c) + (a + b); ASSERT_ALWAYS(d == 2.25);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+  {
+    mpf_class a(1), b(2), c(3);
+    mpf_class d;
+    d = (a + b) * (-c); ASSERT_ALWAYS(d == -9);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-cast.cc b/tests/cxx/t-cast.cc
new file mode 100644
index 0000000..983b3b8
--- /dev/null
+++ b/tests/cxx/t-cast.cc
@@ -0,0 +1,56 @@
+/* Test g++ -Wold-style-cast cleanliness.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+
+
+/* This code doesn't do anything when run, it just expands various C macros
+   to see that they don't trigger compile-time warnings from g++
+   -Wold-style-cast.  This option isn't used in a normal build, it has to be
+   added manually to make this test worthwhile.  */
+
+void
+check_macros (void)
+{
+  mpz_t          z;
+  long           l = 123;
+  unsigned long  u = 456;
+  int            i;
+  mp_limb_t      limb;
+
+  mpz_init_set_ui (z, 0L);
+  i = mpz_odd_p (z);
+  i = mpz_even_p (z);
+  i = mpz_cmp_si (z, l);
+  i = mpz_cmp_ui (z, u);
+  mpz_clear (z);
+
+  limb = GMP_NUMB_MASK;
+  limb = GMP_NUMB_MAX;
+  limb = GMP_NAIL_MASK;
+
+  mpn_divmod (&limb, &limb, 1, &limb, 1);
+  mpn_divexact_by3 (&limb, &limb, 1);
+}
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/tests/cxx/t-constr.cc b/tests/cxx/t-constr.cc
new file mode 100644
index 0000000..500878e
--- /dev/null
+++ b/tests/cxx/t-constr.cc
@@ -0,0 +1,755 @@
+/* Test mp*_class constructors.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+#include <string>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // mpz_class()
+  {
+    mpz_class a; ASSERT_ALWAYS(a == 0);
+  }
+
+  // mpz_class(const mpz_class &)
+  // see below
+
+  // template <class T, class U> mpz_class(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // mpz_class(signed char)
+  {
+    signed char a = -127;
+    mpz_class b(a); ASSERT_ALWAYS(b == -127);
+  }
+
+  // mpz_class(unsigned char)
+  {
+    unsigned char a = 255;
+    mpz_class b(a); ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpz_class a('A'); ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpz_class a('z'); ASSERT_ALWAYS(a == 122);
+  }
+
+  // mpz_class(signed int)
+  {
+    signed int a = 0;
+    mpz_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpz_class b(a); ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 4567;
+    mpz_class b(a); ASSERT_ALWAYS(b == 4567);
+  }
+
+  // mpz_class(unsigned int)
+  {
+    unsigned int a = 890;
+    mpz_class b(a); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpz_class(signed short int)
+  {
+    signed short int a = -12345;
+    mpz_class b(a); ASSERT_ALWAYS(b == -12345);
+  }
+
+  // mpz_class(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpz_class b(a); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpz_class(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpz_class b(a); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpz_class(unsigned long int)
+  {
+    unsigned long int a = 1UL << 30;
+    mpz_class b(a); ASSERT_ALWAYS(b == 1073741824L);
+  }
+
+  // mpz_class(float)
+  {
+    float a = 123.45;
+    mpz_class b(a); ASSERT_ALWAYS(b == 123);
+  }
+
+  // mpz_class(double)
+  {
+    double a = 3.141592653589793238;
+    mpz_class b(a); ASSERT_ALWAYS(b == 3);
+  }
+
+  // mpz_class(long double)
+  // currently not implemented
+
+  // mpz_class(const char *)
+  {
+    const char *a = "1234567890";
+    mpz_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpz_class(const char *, int)
+  {
+    const char *a = "FFFF";
+    int base = 16;
+    mpz_class b(a, base); ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // mpz_class(const std::string &)
+  {
+    string a("1234567890");
+    mpz_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpz_class(const std::string &, int)
+  {
+    string a("7777");
+    int base = 8;
+    mpz_class b(a, base); ASSERT_ALWAYS(b == 4095);
+  }
+
+  // mpz_class(const char *) with invalid
+  {
+    try {
+      const char *a = "ABC";
+      mpz_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpz_class(const char *, int) with invalid
+  {
+    try {
+      const char *a = "GHI";
+      int base = 16;
+      mpz_class b(a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpz_class(const std::string &) with invalid
+  {
+    try {
+      string a("abc");
+      mpz_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpz_class(const std::string &, int) with invalid
+  {
+    try {
+      string a("ZZZ");
+      int base = 8;
+      mpz_class b(a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpz_class(mpz_srcptr)
+  {
+    mpz_t a;
+    mpz_init_set_ui(a, 100);
+    mpz_class b(a); ASSERT_ALWAYS(b == 100);
+    mpz_clear(a);
+  }
+
+  // mpz_class(const mpz_class &)
+  {
+    mpz_class a(12345); // tested above, assume it works
+    mpz_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // no constructor for bool, but it gets casted to int
+  {
+    bool a = true;
+    mpz_class b(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    mpz_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // mpq_class()
+  {
+    mpq_class a; ASSERT_ALWAYS(a == 0);
+  }
+
+  // mpq_class(const mpq_class &)
+  // see below
+
+  // template <class T, class U> mpq_class(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // mpq_class(signed char)
+  {
+    signed char a = -127;
+    mpq_class b(a); ASSERT_ALWAYS(b == -127);
+  }
+
+  // mpq_class(unsigned char)
+  {
+    unsigned char a = 255;
+    mpq_class b(a); ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpq_class a('A'); ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpq_class a('z'); ASSERT_ALWAYS(a == 122);
+  }
+
+  // mpq_class(signed int)
+  {
+    signed int a = 0;
+    mpq_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpq_class b(a); ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 4567;
+    mpq_class b(a); ASSERT_ALWAYS(b == 4567);
+  }
+
+  // mpq_class(unsigned int)
+  {
+    unsigned int a = 890;
+    mpq_class b(a); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpq_class(signed short int)
+  {
+    signed short int a = -12345;
+    mpq_class b(a); ASSERT_ALWAYS(b == -12345);
+  }
+
+  // mpq_class(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpq_class b(a); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpq_class(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpq_class b(a); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpq_class(unsigned long int)
+  {
+    unsigned long int a = 1UL << 30;
+    mpq_class b(a); ASSERT_ALWAYS(b == 1073741824L);
+  }
+
+  // mpq_class(float)
+  {
+    float a = 0.625;
+    mpq_class b(a); ASSERT_ALWAYS(b == 0.625);
+  }
+
+  // mpq_class(double)
+  {
+    double a = 1.25;
+    mpq_class b(a); ASSERT_ALWAYS(b == 1.25);
+  }
+
+  // mpq_class(long double)
+  // currently not implemented
+
+  // mpq_class(const char *)
+  {
+    const char *a = "1234567890";
+    mpq_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpq_class(const char *, int)
+  {
+    const char *a = "FFFF";
+    int base = 16;
+    mpq_class b(a, base); ASSERT_ALWAYS(b == 65535u);
+    mpq_class c(0, 1); ASSERT_ALWAYS(c == 0);
+  }
+
+  // mpq_class(const std::string &)
+  {
+    string a("1234567890");
+    mpq_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpq_class(const std::string &, int)
+  {
+    string a("7777");
+    int base = 8;
+    mpq_class b(a, base); ASSERT_ALWAYS(b == 4095);
+  }
+
+  // mpq_class(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpq_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpq_class(const char *, int) with invalid
+  {
+    try {
+      const char *a = "ZZZ";
+      int base = 16;
+      mpq_class b (a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpq_class(const std::string &) with invalid
+  {
+    try {
+      string a("abc");
+      mpq_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpq_class(const std::string &, int) with invalid
+  {
+    try {
+      string a("ZZZ");
+      int base = 8;
+      mpq_class b (a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpq_class(mpq_srcptr)
+  {
+    mpq_t a;
+    mpq_init(a);
+    mpq_set_ui(a, 100, 1);
+    mpq_class b(a); ASSERT_ALWAYS(b == 100);
+    mpq_clear(a);
+  }
+
+  // mpq_class(const mpz_class &, const mpz_class &)
+  {
+    mpz_class a(123), b(4); // tested above, assume it works
+    mpq_class c(a, b); ASSERT_ALWAYS(c == 30.75);
+  }
+  {
+    mpz_class a(-1), b(2);  // tested above, assume it works
+    mpq_class c(a, b); ASSERT_ALWAYS(c == -0.5);
+  }
+  {
+    mpz_class a(5), b(4); // tested above, assume it works
+    mpq_class c(a, b); ASSERT_ALWAYS(c == 1.25);
+  }
+
+  // mpq_class(const mpz_class &)
+  {
+    mpq_class a(12345); // tested above, assume it works
+    mpq_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // no constructor for bool, but it gets casted to int
+  {
+    bool a = true;
+    mpq_class b(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    mpq_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // mpf_class()
+  {
+    mpf_class a; ASSERT_ALWAYS(a == 0);
+  }
+
+  // mpf_class(const mpf_class &)
+  // mpf_class(const mpf_class &, unsigned long int)
+  // see below
+
+  // template <class T, class U> mpf_class(const __gmp_expr<T, U> &)
+  // template <class T, class U> mpf_class(const __gmp_expr<T, U> &,
+  //                                       unsigned long int)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // mpf_class(signed char)
+  {
+    signed char a = -127;
+    mpf_class b(a); ASSERT_ALWAYS(b == -127);
+  }
+
+  // mpf_class(signed char, unsigned long int)
+  {
+    signed char a = -1;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == -1);
+  }
+
+  // mpf_class(unsigned char)
+  {
+    unsigned char a = 255;
+    mpf_class b(a); ASSERT_ALWAYS(b == 255);
+  }
+
+  // mpf_class(unsigned char, unsigned long int)
+  {
+    unsigned char a = 128;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 128);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpf_class a('A'); ASSERT_ALWAYS(a == 65);
+  }
+  {
+    int prec = 256;
+    mpf_class a('z', prec); ASSERT_ALWAYS(a == 122);
+  }
+
+  // mpf_class(signed int)
+  {
+    signed int a = 0;
+    mpf_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpf_class b(a); ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 4567;
+    mpf_class b(a); ASSERT_ALWAYS(b == 4567);
+  }
+
+  // mpf_class(signed int, unsigned long int)
+  {
+    signed int a = -123;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == -123);
+  }
+
+  // mpf_class(unsigned int)
+  {
+    unsigned int a = 890;
+    mpf_class b(a); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpf_class(unsigned int, unsigned long int)
+  {
+    unsigned int a = 890;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpf_class(signed short int)
+  {
+    signed short int a = -12345;
+    mpf_class b(a); ASSERT_ALWAYS(b == -12345);
+  }
+
+  // mpf_class(signed short int, unsigned long int)
+  {
+    signed short int a = 6789;
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 6789);
+  }
+
+  // mpf_class(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpf_class b(a); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpf_class(unsigned short int, unsigned long int)
+  {
+    unsigned short int a = 54321u;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpf_class(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpf_class b(a); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpf_class(signed long int, unsigned long int)
+  {
+    signed long int a = -1234567890L;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpf_class(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpf_class b(a); ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // mpf_class(unsigned long int, unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // mpf_class(float)
+  {
+    float a = 1234.5;
+    mpf_class b(a); ASSERT_ALWAYS(b == 1234.5);
+  }
+
+  // mpf_class(float, unsigned long int)
+  {
+    float a = 1234.5;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234.5);
+  }
+
+  // mpf_class(double)
+  {
+    double a = 12345.0;
+    mpf_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+  {
+    double a = 1.2345e+4;
+    mpf_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+  {
+    double a = 312.5e-2;
+    mpf_class b(a); ASSERT_ALWAYS(b == 3.125);
+  }
+
+  // mpf_class(double, unsigned long int)
+  {
+    double a = 5.4321e+4;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 54321L);
+  }
+
+  // mpf_class(long double)
+  // mpf_class(long double, unsigned long int)
+  // currently not implemented
+
+  // mpf_class(const char *)
+  {
+    const char *a = "1234567890";
+    mpf_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpf_class(const char *, unsigned long int, int = 0)
+  {
+    const char *a = "1234567890";
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+  }
+  {
+    const char *a = "777777";
+    int prec = 64, base = 8;
+    mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 262143L);
+  }
+
+  // mpf_class(const std::string &)
+  {
+    string a("1234567890");
+    mpf_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpf_class(const std::string &, unsigned long int, int = 0)
+  {
+    string a("1234567890");
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+  }
+  {
+    string a("FFFF");
+    int prec = 256, base = 16;
+    mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // mpf_class(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpf_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpf_class(const char *, unsigned long int, int = 0) with invalid
+  {
+    try {
+      const char *a = "def";
+      int prec = 256;
+      mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+  {
+    try {
+      const char *a = "ghi";
+      int prec = 64, base = 8;
+      mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 262143L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpf_class(const std::string &) with invalid
+  {
+    try {
+      string a("abc");
+      mpf_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpf_class(const std::string &, unsigned long int, int = 0) with invalid
+  {
+    try {
+      string a("def");
+      int prec = 128;
+      mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+  {
+    try {
+      string a("ghi");
+      int prec = 256, base = 16;
+      mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 65535u);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument&) {
+    }
+  }
+
+  // mpf_class(mpf_srcptr)
+  {
+    mpf_t a;
+    mpf_init_set_ui(a, 100);
+    mpf_class b(a); ASSERT_ALWAYS(b == 100);
+    mpf_clear(a);
+  }
+
+  // mpf_class(mpf_srcptr, unsigned long int)
+  {
+    mpf_t a;
+    int prec = 64;
+    mpf_init_set_ui(a, 100);
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 100);
+    mpf_clear(a);
+  }
+
+  // mpf_class(const mpf_class &)
+  {
+    mpf_class a(12345); // tested above, assume it works
+    mpf_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // mpf_class(const mpf_class &, unsigned long int)
+  {
+    mpf_class a(12345); // tested above, assume it works
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // no constructors for bool, but it gets casted to int
+  {
+    bool a = true;
+    mpf_class b(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    mpf_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    bool a = true;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 0);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-cxx11.cc b/tests/cxx/t-cxx11.cc
new file mode 100644
index 0000000..8d6fccb
--- /dev/null
+++ b/tests/cxx/t-cxx11.cc
@@ -0,0 +1,232 @@
+/* Test C++11 features
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMPXX_USE_CXX11
+
+#include <utility>
+#include <type_traits>
+
+void check_noexcept ()
+{
+  mpz_class z1, z2;
+  mpq_class q1, q2;
+  mpf_class f1, f2;
+  static_assert(noexcept(z1 = std::move(z2)), "sorry");
+  static_assert(noexcept(q1 = std::move(q2)), "sorry");
+  static_assert(noexcept(f1 = std::move(f2)), "sorry");
+  static_assert(noexcept(q1 = std::move(z1)), "sorry");
+
+  // Only mpz has lazy allocation for now
+  static_assert(std::is_nothrow_default_constructible<mpz_class>::value, "sorry");
+  static_assert(std::is_nothrow_move_constructible<mpz_class>::value, "sorry");
+  static_assert(!std::is_nothrow_default_constructible<mpq_class>::value, "sorry");
+  static_assert(!std::is_nothrow_move_constructible<mpq_class>::value, "sorry");
+  static_assert(!std::is_nothrow_default_constructible<mpf_class>::value, "sorry");
+  static_assert(!std::is_nothrow_move_constructible<mpf_class>::value, "sorry");
+}
+
+void check_common_type ()
+{
+#define CHECK_COMMON_TYPE1(T, Res) \
+  static_assert(std::is_same<std::common_type<T>::type, Res>::value, "sorry")
+#define CHECK_COMMON_TYPE(T, U, Res) \
+  static_assert(std::is_same<std::common_type<T, U>::type, Res>::value, "sorry")
+#define CHECK_COMMON_TYPE_BUILTIN1(T, Res) \
+  CHECK_COMMON_TYPE(  signed char , T, Res); \
+  CHECK_COMMON_TYPE(unsigned char , T, Res); \
+  CHECK_COMMON_TYPE(  signed short, T, Res); \
+  CHECK_COMMON_TYPE(unsigned short, T, Res); \
+  CHECK_COMMON_TYPE(  signed int  , T, Res); \
+  CHECK_COMMON_TYPE(unsigned int  , T, Res); \
+  CHECK_COMMON_TYPE(  signed long , T, Res); \
+  CHECK_COMMON_TYPE(unsigned long , T, Res); \
+  CHECK_COMMON_TYPE(float , T, Res); \
+  CHECK_COMMON_TYPE(double, T, Res)
+#define CHECK_COMMON_TYPE_BUILTIN2(T, Res) \
+  CHECK_COMMON_TYPE(T,   signed char , Res); \
+  CHECK_COMMON_TYPE(T, unsigned char , Res); \
+  CHECK_COMMON_TYPE(T,   signed short, Res); \
+  CHECK_COMMON_TYPE(T, unsigned short, Res); \
+  CHECK_COMMON_TYPE(T,   signed int  , Res); \
+  CHECK_COMMON_TYPE(T, unsigned int  , Res); \
+  CHECK_COMMON_TYPE(T,   signed long , Res); \
+  CHECK_COMMON_TYPE(T, unsigned long , Res); \
+  CHECK_COMMON_TYPE(T, float , Res); \
+  CHECK_COMMON_TYPE(T, double, Res)
+#define CHECK_COMMON_TYPE_BUILTIN(T, Res) \
+  CHECK_COMMON_TYPE_BUILTIN1(T, Res); \
+  CHECK_COMMON_TYPE_BUILTIN2(T, Res)
+  /* These would just work with implicit conversions */
+  CHECK_COMMON_TYPE (mpz_class, mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (mpz_class, mpf_class, mpf_class);
+  CHECK_COMMON_TYPE (mpf_class, mpq_class, mpf_class);
+
+  CHECK_COMMON_TYPE_BUILTIN (mpz_class, mpz_class);
+  CHECK_COMMON_TYPE_BUILTIN (mpq_class, mpq_class);
+  CHECK_COMMON_TYPE_BUILTIN (mpf_class, mpf_class);
+
+  mpz_class z; mpq_class q; mpf_class f;
+
+  CHECK_COMMON_TYPE (decltype(-z), mpz_class, mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpf_class, mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-z), mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-z), mpf_class, mpf_class);
+  CHECK_COMMON_TYPE (decltype(-q), mpf_class, mpf_class);
+
+  /* These require a common_type specialization */
+  CHECK_COMMON_TYPE (decltype(-z), decltype(z+z), mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(q+q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), decltype(f+f), mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-q), mpz_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpz_class, mpf_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpq_class, mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-f), mpf_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(-f), mpf_class);
+
+  /* common_type now decays */
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-z), mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), decltype(-f), mpf_class);
+  CHECK_COMMON_TYPE1 (decltype(-z), mpz_class);
+  CHECK_COMMON_TYPE1 (decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE1 (decltype(-f), mpf_class);
+
+  /* Painful */
+  CHECK_COMMON_TYPE_BUILTIN (decltype(-z), mpz_class);
+  CHECK_COMMON_TYPE_BUILTIN (decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE_BUILTIN (decltype(-f), mpf_class);
+}
+
+template<class T, class U = T>
+void check_move_init ()
+{
+  {
+    // Delete moved-from x1
+    T x1 = 3;
+    U x2 = std::move(x1);
+    ASSERT_ALWAYS (x2 == 3);
+  }
+  {
+    // Assign to moved-from x1
+    T x1 = 2;
+    U x2 = std::move(x1);
+    x1 = -7;
+    ASSERT_ALWAYS (x1 == -7);
+    ASSERT_ALWAYS (x2 == 2);
+  }
+}
+
+template<class T, class U = T>
+void check_move_assign ()
+{
+  {
+    // Delete moved-from x1
+    T x1 = 3; U x2;
+    x2 = std::move(x1);
+    ASSERT_ALWAYS (x2 == 3);
+  }
+  {
+    // Assign to moved-from x1
+    T x1 = 2; U x2;
+    x2 = std::move(x1);
+    x1 = -7;
+    ASSERT_ALWAYS (x1 == -7);
+    ASSERT_ALWAYS (x2 == 2);
+  }
+  {
+    // Self move-assign (not necessary, but it happens to work...)
+    T x = 4;
+    x = std::move(x);
+    ASSERT_ALWAYS (x == 4);
+  }
+}
+
+void check_user_defined_literal ()
+{
+  ASSERT_ALWAYS (123_mpz % 5 == 3);
+  ASSERT_ALWAYS (-11_mpq / 22 == -.5);
+  ASSERT_ALWAYS (112.5e-1_mpf * 4 == 45);
+  {
+    mpz_class ref ( "123456789abcdef0123456789abcdef0123", 16);
+    ASSERT_ALWAYS (0x123456789abcdef0123456789abcdef0123_mpz == ref);
+  }
+}
+
+// Check for explicit conversion to bool
+void implicit_bool(bool);
+int implicit_bool(...);
+
+void check_bool_conversion ()
+{
+  const mpz_class zn = -2;
+  const mpq_class qn = -2;
+  const mpf_class fn = -2;
+  const mpz_class z0 =  0;
+  const mpq_class q0 =  0;
+  const mpf_class f0 =  0;
+  const mpz_class zp = +2;
+  const mpq_class qp = +2;
+  const mpf_class fp = +2;
+  if (zn && qn && fn && zp && qp && fp && !z0 && !q0 && !f0)
+    {
+      if (z0 || q0 || f0) ASSERT_ALWAYS(false);
+    }
+  else ASSERT_ALWAYS(false);
+  decltype(implicit_bool(zn)) zi = 1;
+  decltype(implicit_bool(qn)) qi = 1;
+  decltype(implicit_bool(fn)) fi = 1;
+  (void)(zi+qi+fi);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  check_noexcept();
+  check_common_type();
+  check_move_init<mpz_class>();
+  check_move_init<mpq_class>();
+  check_move_init<mpf_class>();
+  check_move_assign<mpz_class>();
+  check_move_assign<mpq_class>();
+  check_move_assign<mpf_class>();
+  check_move_init<mpz_class,mpq_class>();
+  check_move_assign<mpz_class,mpq_class>();
+  check_user_defined_literal();
+  check_bool_conversion();
+
+  tests_end();
+  return 0;
+}
+
+#else
+int main () { return 0; }
+#endif
diff --git a/tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc b/tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc
new file mode 100644
index 0000000..014eb75
--- /dev/null
+++ b/tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc
@@ -0,0 +1,38 @@
+/* Test if the compiler has working try / throw / catch.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdexcept>
+
+inline void
+throw_expr ()
+{
+  throw std::invalid_argument ("Test");
+}
+
+using namespace std;
+
+int
+main ()
+{
+  try
+  {
+    throw_expr();
+  }
+  catch (invalid_argument&) { }
+}
diff --git a/tests/cxx/t-headers.cc b/tests/cxx/t-headers.cc
new file mode 100644
index 0000000..35f7a25
--- /dev/null
+++ b/tests/cxx/t-headers.cc
@@ -0,0 +1,26 @@
+/* Test that gmpxx.h compiles correctly.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/tests/cxx/t-iostream.cc b/tests/cxx/t-iostream.cc
new file mode 100644
index 0000000..76e280b
--- /dev/null
+++ b/tests/cxx/t-iostream.cc
@@ -0,0 +1,106 @@
+/* Test stream formatted input and output on mp*_class
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <sstream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+// The tests are extremely basic. These functions just forward to the
+// ones tested in t-istream.cc and t-ostream.cc; we rely on those for
+// advanced tests and only check the syntax here.
+
+void
+checki ()
+{
+  {
+    istringstream i("123");
+    mpz_class x;
+    i >> x;
+    ASSERT_ALWAYS (x == 123);
+  }
+  {
+    istringstream i("3/4");
+    mpq_class x;
+    i >> x;
+    ASSERT_ALWAYS (x == .75);
+  }
+  {
+    istringstream i("1.5");
+    mpf_class x;
+    i >> x;
+    ASSERT_ALWAYS (x == 1.5);
+  }
+}
+
+void
+checko ()
+{
+  {
+    ostringstream o;
+    mpz_class x=123;
+    o << x;
+    ASSERT_ALWAYS (o.str() == "123");
+  }
+  {
+    ostringstream o;
+    mpz_class x=123;
+    o << (x+1);
+    ASSERT_ALWAYS (o.str() == "124");
+  }
+  {
+    ostringstream o;
+    mpq_class x(3,4);
+    o << x;
+    ASSERT_ALWAYS (o.str() == "3/4");
+  }
+  {
+    ostringstream o;
+    mpq_class x(3,4);
+    o << (x+1);
+    ASSERT_ALWAYS (o.str() == "7/4");
+  }
+  {
+    ostringstream o;
+    mpf_class x=1.5;
+    o << x;
+    ASSERT_ALWAYS (o.str() == "1.5");
+  }
+  {
+    ostringstream o;
+    mpf_class x=1.5;
+    o << (x+1);
+    ASSERT_ALWAYS (o.str() == "2.5");
+  }
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  checki ();
+  checko ();
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/cxx/t-istream.cc b/tests/cxx/t-istream.cc
new file mode 100644
index 0000000..76bcbab
--- /dev/null
+++ b/tests/cxx/t-istream.cc
@@ -0,0 +1,598 @@
+/* Test istream formatted input.
+
+Copyright 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+// Under option_check_standard, the various test cases for mpz operator>>
+// are put through the standard operator>> for long, and likewise mpf
+// operator>> is put through double.
+//
+// In g++ 3.3 this results in some printouts about the final position
+// indicated for something like ".e123".  Our mpf code stops at the "e"
+// since there's no mantissa digits, but g++ reads the whole thing and only
+// then decides it's bad.
+
+bool option_check_standard = false;
+
+
+// On some versions of g++ 2.96 it's been observed that putback() may leave
+// tellg() unchanged.  We believe this is incorrect and presumably the
+// result of a bug, since for instance it's ok in g++ 2.95 and g++ 3.3.  We
+// detect the problem at runtime and disable affected checks.
+
+bool putback_tellg_works = true;
+
+void
+check_putback_tellg (void)
+{
+  istringstream input ("hello");
+  streampos  old_pos, new_pos;
+  char  c;
+
+  input.get(c);
+  old_pos = input.tellg();
+  input.putback(c);
+  new_pos = input.tellg();
+
+  if (old_pos == new_pos)
+    {
+      cout << "Warning, istringstream has a bug: putback() doesn't update tellg().\n";;
+      cout << "Tests on tellg() will be skipped.\n";
+      putback_tellg_works = false;
+    }
+}
+
+
+#define WRONG(str)                                              \
+  do {                                                          \
+    cout << str ", data[" << i << "]\n";                        \
+    cout << "  input: \"" << data[i].input << "\"\n";           \
+    cout << "  flags: " << hex << input.flags() << dec << "\n"; \
+  } while (0)
+
+void
+check_mpz (void)
+{
+  static const struct {
+    const char     *input;
+    int            want_pos;
+    const char     *want;
+    ios::fmtflags  flags;
+
+  } data[] = {
+
+    { "0",      -1, "0",    (ios::fmtflags) 0 },
+    { "123",    -1, "123",  (ios::fmtflags) 0 },
+    { "0123",   -1, "83",   (ios::fmtflags) 0 },
+    { "0x123",  -1, "291",  (ios::fmtflags) 0 },
+    { "-123",   -1, "-123", (ios::fmtflags) 0 },
+    { "-0123",  -1, "-83",  (ios::fmtflags) 0 },
+    { "-0x123", -1, "-291", (ios::fmtflags) 0 },
+    { "+123",   -1, "123", (ios::fmtflags) 0 },
+    { "+0123",  -1, "83",  (ios::fmtflags) 0 },
+    { "+0x123", -1, "291", (ios::fmtflags) 0 },
+
+    { "0",     -1, "0",    ios::dec },
+    { "1f",     1, "1",    ios::dec },
+    { "011f",   3, "11",   ios::dec },
+    { "123",   -1, "123",  ios::dec },
+    { "-1f",    2, "-1",   ios::dec },
+    { "-011f",  4, "-11",  ios::dec },
+    { "-123",  -1, "-123", ios::dec },
+    { "+1f",    2, "1",    ios::dec },
+    { "+011f",  4, "11",   ios::dec },
+    { "+123",  -1, "123",  ios::dec },
+
+    { "0",    -1, "0",   ios::oct },
+    { "123",  -1, "83",  ios::oct },
+    { "-123", -1, "-83", ios::oct },
+    { "+123", -1, "83",  ios::oct },
+
+    { "0",    -1, "0",    ios::hex },
+    { "123",  -1, "291",  ios::hex },
+    { "ff",   -1, "255",  ios::hex },
+    { "FF",   -1, "255",  ios::hex },
+    { "-123", -1, "-291", ios::hex },
+    { "-ff",  -1, "-255", ios::hex },
+    { "-FF",  -1, "-255", ios::hex },
+    { "+123", -1, "291",  ios::hex },
+    { "+ff",  -1, "255",  ios::hex },
+    { "+FF",  -1, "255",  ios::hex },
+    { "ab",   -1, "171",  ios::hex },
+    { "cd",   -1, "205",  ios::hex },
+    { "ef",   -1, "239",  ios::hex },
+
+    { " 123",  0, NULL,  (ios::fmtflags) 0 },   // not without skipws
+    { " 123", -1, "123", ios::skipws },
+  };
+
+  mpz_t      got, want;
+  bool       got_ok, want_ok;
+  bool       got_eof, want_eof;
+  long       got_si, want_si;
+  streampos  init_tellg, got_pos, want_pos;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (size_t i = 0; i < numberof (data); i++)
+    {
+      size_t input_length = strlen (data[i].input);
+      want_pos = (data[i].want_pos == -1
+                  ? input_length : data[i].want_pos);
+      want_eof = (want_pos == streampos(input_length));
+
+      want_ok = (data[i].want != NULL);
+
+      if (data[i].want != NULL)
+        mpz_set_str_or_abort (want, data[i].want, 0);
+      else
+        mpz_set_ui (want, 0L);
+
+      if (option_check_standard && mpz_fits_slong_p (want))
+        {
+          istringstream  input (data[i].input);
+          input.flags (data[i].flags);
+          init_tellg = input.tellg();
+          want_si = mpz_get_si (want);
+
+          input >> got_si;
+          got_ok = !input.fail();
+          got_eof = input.eof();
+          input.clear();
+          got_pos = input.tellg() - init_tellg;
+
+          if (got_ok != want_ok)
+            {
+              WRONG ("stdc++ operator>> wrong status, check_mpz");
+              cout << "  want_ok: " << want_ok << "\n";
+              cout << "  got_ok:  " << got_ok << "\n";
+            }
+          if (want_ok && got_si != want_si)
+            {
+              WRONG ("stdc++ operator>> wrong result, check_mpz");
+              cout << "  got_si:  " << got_si << "\n";
+              cout << "  want_si: " << want_si << "\n";
+            }
+          if (want_ok && got_eof != want_eof)
+            {
+              WRONG ("stdc++ operator>> wrong EOF state, check_mpz");
+              cout << "  got_eof:  " << got_eof << "\n";
+              cout << "  want_eof: " << want_eof << "\n";
+            }
+          if (putback_tellg_works && got_pos != want_pos)
+            {
+              WRONG ("stdc++ operator>> wrong position, check_mpz");
+              cout << "  want_pos: " << want_pos << "\n";
+              cout << "  got_pos:  " << got_pos << "\n";
+            }
+        }
+
+      {
+        istringstream  input (data[i].input);
+        input.flags (data[i].flags);
+        init_tellg = input.tellg();
+
+        mpz_set_ui (got, 0xDEAD);
+        input >> got;
+        got_ok = !input.fail();
+	got_eof = input.eof();
+        input.clear();
+        got_pos = input.tellg() - init_tellg;
+
+        if (got_ok != want_ok)
+          {
+            WRONG ("mpz operator>> wrong status");
+            cout << "  want_ok: " << want_ok << "\n";
+            cout << "  got_ok:  " << got_ok << "\n";
+            abort ();
+          }
+        if (want_ok && mpz_cmp (got, want) != 0)
+          {
+            WRONG ("mpz operator>> wrong result");
+            mpz_trace ("  got ", got);
+            mpz_trace ("  want", want);
+            abort ();
+          }
+        if (want_ok && got_eof != want_eof)
+          {
+            WRONG ("mpz operator>> wrong EOF state");
+            cout << "  want_eof: " << want_eof << "\n";
+            cout << "  got_eof:  " << got_eof << "\n";
+            abort ();
+          }
+        if (putback_tellg_works && got_pos != want_pos)
+          {
+            WRONG ("mpz operator>> wrong position");
+            cout << "  want_pos: " << want_pos << "\n";
+            cout << "  got_pos:  " << got_pos << "\n";
+            abort ();
+          }
+      }
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+void
+check_mpq (void)
+{
+  static const struct {
+    const char     *input;
+    int            want_pos;
+    const char     *want;
+    ios::fmtflags  flags;
+
+  } data[] = {
+
+    { "0",   -1, "0", (ios::fmtflags) 0 },
+    { "00",  -1, "0", (ios::fmtflags) 0 },
+    { "0x0", -1, "0", (ios::fmtflags) 0 },
+
+    { "123/456",   -1, "123/456", ios::dec },
+    { "0123/456",  -1, "123/456", ios::dec },
+    { "123/0456",  -1, "123/456", ios::dec },
+    { "0123/0456", -1, "123/456", ios::dec },
+
+    { "123/456",   -1, "83/302", ios::oct },
+    { "0123/456",  -1, "83/302", ios::oct },
+    { "123/0456",  -1, "83/302", ios::oct },
+    { "0123/0456", -1, "83/302", ios::oct },
+
+    { "ab",   -1, "171",  ios::hex },
+    { "cd",   -1, "205",  ios::hex },
+    { "ef",   -1, "239",  ios::hex },
+
+    { "0/0",     -1, "0/0", (ios::fmtflags) 0 },
+    { "5/8",     -1, "5/8", (ios::fmtflags) 0 },
+    { "0x5/0x8", -1, "5/8", (ios::fmtflags) 0 },
+
+    { "123/456",   -1, "123/456",  (ios::fmtflags) 0 },
+    { "123/0456",  -1, "123/302",  (ios::fmtflags) 0 },
+    { "123/0x456", -1, "123/1110", (ios::fmtflags) 0 },
+    { "123/0X456", -1, "123/1110", (ios::fmtflags) 0 },
+
+    { "0123/123",   -1, "83/123", (ios::fmtflags) 0 },
+    { "0123/0123",  -1, "83/83",  (ios::fmtflags) 0 },
+    { "0123/0x123", -1, "83/291", (ios::fmtflags) 0 },
+    { "0123/0X123", -1, "83/291", (ios::fmtflags) 0 },
+
+    { "0x123/123",   -1, "291/123", (ios::fmtflags) 0 },
+    { "0X123/0123",  -1, "291/83",  (ios::fmtflags) 0 },
+    { "0x123/0x123", -1, "291/291", (ios::fmtflags) 0 },
+
+    { " 123",  0, NULL,  (ios::fmtflags) 0 },   // not without skipws
+    { " 123", -1, "123", ios::skipws },
+
+    { "123 /456",    3, "123",  (ios::fmtflags) 0 },
+    { "123/ 456",    4,  NULL,  (ios::fmtflags) 0 },
+    { "123/"    ,   -1,  NULL,  (ios::fmtflags) 0 },
+    { "123 /456",    3, "123",  ios::skipws },
+    { "123/ 456",    4,  NULL,  ios::skipws },
+  };
+
+  mpq_t      got, want;
+  bool       got_ok, want_ok;
+  bool       got_eof, want_eof;
+  long       got_si, want_si;
+  streampos  init_tellg, got_pos, want_pos;
+
+  mpq_init (got);
+  mpq_init (want);
+
+  for (size_t i = 0; i < numberof (data); i++)
+    {
+      size_t input_length = strlen (data[i].input);
+      want_pos = (data[i].want_pos == -1
+                  ? input_length : data[i].want_pos);
+      want_eof = (want_pos == streampos(input_length));
+
+      want_ok = (data[i].want != NULL);
+
+      if (data[i].want != NULL)
+        mpq_set_str_or_abort (want, data[i].want, 0);
+      else
+        mpq_set_ui (want, 0L, 1L);
+
+      if (option_check_standard
+          && mpz_fits_slong_p (mpq_numref(want))
+          && mpz_cmp_ui (mpq_denref(want), 1L) == 0
+          && strchr (data[i].input, '/') == NULL)
+        {
+          istringstream  input (data[i].input);
+          input.flags (data[i].flags);
+          init_tellg = input.tellg();
+          want_si = mpz_get_si (mpq_numref(want));
+
+          input >> got_si;
+          got_ok = !input.fail();
+          got_eof = input.eof();
+          input.clear();
+          got_pos = input.tellg() - init_tellg;
+
+          if (got_ok != want_ok)
+            {
+              WRONG ("stdc++ operator>> wrong status, check_mpq");
+              cout << "  want_ok: " << want_ok << "\n";
+              cout << "  got_ok:  " << got_ok << "\n";
+            }
+          if (want_ok && want_si != got_si)
+            {
+              WRONG ("stdc++ operator>> wrong result, check_mpq");
+              cout << "  got_si:  " << got_si << "\n";
+              cout << "  want_si: " << want_si << "\n";
+            }
+          if (want_ok && got_eof != want_eof)
+            {
+              WRONG ("stdc++ operator>> wrong EOF state, check_mpq");
+              cout << "  got_eof:  " << got_eof << "\n";
+              cout << "  want_eof: " << want_eof << "\n";
+            }
+          if (putback_tellg_works && got_pos != want_pos)
+            {
+              WRONG ("stdc++ operator>> wrong position, check_mpq");
+              cout << "  want_pos: " << want_pos << "\n";
+              cout << "  got_pos:  " << got_pos << "\n";
+            }
+        }
+
+      {
+        istringstream  input (data[i].input);
+        input.flags (data[i].flags);
+        init_tellg = input.tellg();
+        mpq_set_si (got, 0xDEAD, 0xBEEF);
+
+        input >> got;
+        got_ok = !input.fail();
+	got_eof = input.eof();
+        input.clear();
+        got_pos = input.tellg() - init_tellg;
+
+        if (got_ok != want_ok)
+          {
+            WRONG ("mpq operator>> wrong status");
+            cout << "  want_ok: " << want_ok << "\n";
+            cout << "  got_ok:  " << got_ok << "\n";
+            abort ();
+          }
+        // don't use mpq_equal, since we allow non-normalized values to be
+        // read, which can trigger ASSERTs in mpq_equal
+        if (want_ok && (mpz_cmp (mpq_numref (got), mpq_numref(want)) != 0
+                        || mpz_cmp (mpq_denref (got), mpq_denref(want)) != 0))
+          {
+            WRONG ("mpq operator>> wrong result");
+            mpq_trace ("  got ", got);
+            mpq_trace ("  want", want);
+            abort ();
+          }
+        if (want_ok && got_eof != want_eof)
+          {
+            WRONG ("mpq operator>> wrong EOF state");
+            cout << "  want_eof: " << want_eof << "\n";
+            cout << "  got_eof:  " << got_eof << "\n";
+            abort ();
+          }
+        if (putback_tellg_works && got_pos != want_pos)
+          {
+            WRONG ("mpq operator>> wrong position");
+            cout << "  want_pos: " << want_pos << "\n";
+            cout << "  got_pos:  " << got_pos << "\n";
+            abort ();
+          }
+      }
+    }
+
+  mpq_clear (got);
+  mpq_clear (want);
+}
+
+
+void
+check_mpf (void)
+{
+  static const struct {
+    const char     *input;
+    int            want_pos;
+    const char     *want;
+    ios::fmtflags  flags;
+
+  } data[] = {
+
+    { "0",      -1, "0", (ios::fmtflags) 0 },
+    { "+0",     -1, "0", (ios::fmtflags) 0 },
+    { "-0",     -1, "0", (ios::fmtflags) 0 },
+    { "0.0",    -1, "0", (ios::fmtflags) 0 },
+    { "0.",     -1, "0", (ios::fmtflags) 0 },
+    { ".0",     -1, "0", (ios::fmtflags) 0 },
+    { "+.0",    -1, "0", (ios::fmtflags) 0 },
+    { "-.0",    -1, "0", (ios::fmtflags) 0 },
+    { "+0.00",  -1, "0", (ios::fmtflags) 0 },
+    { "-0.000", -1, "0", (ios::fmtflags) 0 },
+    { "+0.00",  -1, "0", (ios::fmtflags) 0 },
+    { "-0.000", -1, "0", (ios::fmtflags) 0 },
+    { "0.0e0",  -1, "0", (ios::fmtflags) 0 },
+    { "0.e0",   -1, "0", (ios::fmtflags) 0 },
+    { ".0e0",   -1, "0", (ios::fmtflags) 0 },
+    { "0.0e-0", -1, "0", (ios::fmtflags) 0 },
+    { "0.e-0",  -1, "0", (ios::fmtflags) 0 },
+    { ".0e-0",  -1, "0", (ios::fmtflags) 0 },
+    { "0.0e+0", -1, "0", (ios::fmtflags) 0 },
+    { "0.e+0",  -1, "0", (ios::fmtflags) 0 },
+    { ".0e+0",  -1, "0", (ios::fmtflags) 0 },
+
+    { "1",  -1,  "1", (ios::fmtflags) 0 },
+    { "+1", -1,  "1", (ios::fmtflags) 0 },
+    { "-1", -1, "-1", (ios::fmtflags) 0 },
+
+    { " 0",  0,  NULL, (ios::fmtflags) 0 },  // not without skipws
+    { " 0",  -1, "0", ios::skipws },
+    { " +0", -1, "0", ios::skipws },
+    { " -0", -1, "0", ios::skipws },
+
+    { "+-123", 1, NULL, (ios::fmtflags) 0 },
+    { "-+123", 1, NULL, (ios::fmtflags) 0 },
+    { "1e+-123", 3, NULL, (ios::fmtflags) 0 },
+    { "1e-+123", 3, NULL, (ios::fmtflags) 0 },
+
+    { "e123",   0, NULL, (ios::fmtflags) 0 }, // at least one mantissa digit
+    { ".e123",  1, NULL, (ios::fmtflags) 0 },
+    { "+.e123", 2, NULL, (ios::fmtflags) 0 },
+    { "-.e123", 2, NULL, (ios::fmtflags) 0 },
+
+    { "123e",   4, NULL, (ios::fmtflags) 0 }, // at least one exponent digit
+    { "123e-",  5, NULL, (ios::fmtflags) 0 },
+    { "123e+",  5, NULL, (ios::fmtflags) 0 },
+  };
+
+  mpf_t      got, want;
+  bool       got_ok, want_ok;
+  bool       got_eof, want_eof;
+  double     got_d, want_d;
+  streampos  init_tellg, got_pos, want_pos;
+
+  mpf_init (got);
+  mpf_init (want);
+
+  for (size_t i = 0; i < numberof (data); i++)
+    {
+      size_t input_length = strlen (data[i].input);
+      want_pos = (data[i].want_pos == -1
+                  ? input_length : data[i].want_pos);
+      want_eof = (want_pos == streampos(input_length));
+
+      want_ok = (data[i].want != NULL);
+
+      if (data[i].want != NULL)
+        mpf_set_str_or_abort (want, data[i].want, 0);
+      else
+        mpf_set_ui (want, 0L);
+
+      want_d = mpf_get_d (want);
+      if (option_check_standard && mpf_cmp_d (want, want_d) == 0)
+        {
+          istringstream  input (data[i].input);
+          input.flags (data[i].flags);
+          init_tellg = input.tellg();
+
+          input >> got_d;
+          got_ok = !input.fail();
+          got_eof = input.eof();
+          input.clear();
+          got_pos = input.tellg() - init_tellg;
+
+          if (got_ok != want_ok)
+            {
+              WRONG ("stdc++ operator>> wrong status, check_mpf");
+              cout << "  want_ok: " << want_ok << "\n";
+              cout << "  got_ok:  " << got_ok << "\n";
+            }
+          if (want_ok && want_d != got_d)
+            {
+              WRONG ("stdc++ operator>> wrong result, check_mpf");
+              cout << "  got:   " << got_d << "\n";
+              cout << "  want:  " << want_d << "\n";
+            }
+          if (want_ok && got_eof != want_eof)
+            {
+              WRONG ("stdc++ operator>> wrong EOF state, check_mpf");
+              cout << "  got_eof:  " << got_eof << "\n";
+              cout << "  want_eof: " << want_eof << "\n";
+            }
+          if (putback_tellg_works && got_pos != want_pos)
+            {
+              WRONG ("stdc++ operator>> wrong position, check_mpf");
+              cout << "  want_pos: " << want_pos << "\n";
+              cout << "  got_pos:  " << got_pos << "\n";
+            }
+        }
+
+      {
+        istringstream  input (data[i].input);
+        input.flags (data[i].flags);
+        init_tellg = input.tellg();
+
+        mpf_set_ui (got, 0xDEAD);
+        input >> got;
+        got_ok = !input.fail();
+	got_eof = input.eof();
+        input.clear();
+        got_pos = input.tellg() - init_tellg;
+
+        if (got_ok != want_ok)
+          {
+            WRONG ("mpf operator>> wrong status");
+            cout << "  want_ok: " << want_ok << "\n";
+            cout << "  got_ok:  " << got_ok << "\n";
+            abort ();
+          }
+        if (want_ok && mpf_cmp (got, want) != 0)
+          {
+            WRONG ("mpf operator>> wrong result");
+            mpf_trace ("  got ", got);
+            mpf_trace ("  want", want);
+            abort ();
+          }
+        if (want_ok && got_eof != want_eof)
+          {
+            WRONG ("mpf operator>> wrong EOF state");
+            cout << "  want_eof: " << want_eof << "\n";
+            cout << "  got_eof:  " << got_eof << "\n";
+            abort ();
+          }
+        if (putback_tellg_works && got_pos != want_pos)
+          {
+            WRONG ("mpf operator>> wrong position");
+            cout << "  want_pos: " << want_pos << "\n";
+            cout << "  got_pos:  " << got_pos << "\n";
+            abort ();
+          }
+      }
+    }
+
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_check_standard = true;
+
+  tests_start ();
+
+  check_putback_tellg ();
+  check_mpz ();
+  check_mpq ();
+  check_mpf ();
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/cxx/t-locale.cc b/tests/cxx/t-locale.cc
new file mode 100644
index 0000000..14e95e0
--- /dev/null
+++ b/tests/cxx/t-locale.cc
@@ -0,0 +1,194 @@
+/* Test locale support in C++ functions.
+
+Copyright 2001-2003, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <clocale>
+#include <iostream>
+#include <cstdlib>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+extern "C" {
+  char point_string[2];
+}
+
+#if HAVE_STD__LOCALE
+// Like std::numpunct, but with decimal_point coming from point_string[].
+class my_numpunct : public numpunct<char> {
+ public:
+  explicit my_numpunct (size_t r = 0) : numpunct<char>(r) { }
+ protected:
+  char do_decimal_point() const { return point_string[0]; }
+};
+#endif
+
+void
+set_point (char c)
+{
+  point_string[0] = c;
+
+#if HAVE_STD__LOCALE
+  locale loc (locale::classic(), new my_numpunct ());
+  locale::global (loc);
+#endif
+}
+
+
+void
+check_input (void)
+{
+  static const struct {
+    const char  *str1;
+    const char  *str2;
+    double      want;
+  } data[] = {
+
+    { "1","",   1.0 },
+    { "1","0",  1.0 },
+    { "1","00", 1.0 },
+
+    { "","5",    0.5 },
+    { "0","5",   0.5 },
+    { "00","5",  0.5 },
+    { "00","50", 0.5 },
+
+    { "1","5",    1.5 },
+    { "1","5e1", 15.0 },
+  };
+
+  static char point[] = {
+    '.', ',', 'x', '\xFF'
+  };
+
+  mpf_t  got;
+  mpf_init (got);
+
+  for (size_t i = 0; i < numberof (point); i++)
+    {
+      set_point (point[i]);
+
+      for (int neg = 0; neg <= 1; neg++)
+        {
+          for (size_t j = 0; j < numberof (data); j++)
+            {
+              string str = string(data[j].str1)+point[i]+string(data[j].str2);
+              if (neg)
+                str = "-" + str;
+
+              istringstream is (str.c_str());
+
+              mpf_set_ui (got, 123);   // dummy initial value
+
+              if (! (is >> got))
+                {
+                  cout << "istream mpf_t operator>> error\n";
+                  cout << "  point " << point[i] << "\n";
+                  cout << "  str   \"" << str << "\"\n";
+                  cout << "  localeconv point \""
+                       << GMP_DECIMAL_POINT << "\"\n";
+                  abort ();
+                }
+
+              double want = data[j].want;
+              if (neg)
+                want = -want;
+              if (mpf_cmp_d (got, want) != 0)
+                {
+                  cout << "istream mpf_t operator>> wrong\n";
+                  cout << "  point " << point[i] << "\n";
+                  cout << "  str   \"" << str << "\"\n";
+                  cout << "  got   " << got << "\n";
+                  cout << "  want  " << want << "\n";
+                  cout << "  localeconv point \""
+                       << GMP_DECIMAL_POINT << "\"\n";
+                  abort ();
+                }
+            }
+        }
+    }
+
+  mpf_clear (got);
+}
+
+void
+check_output (void)
+{
+  static char point[] = {
+    '.', ',', 'x', '\xFF'
+  };
+
+  for (size_t i = 0; i < numberof (point); i++)
+    {
+      set_point (point[i]);
+      ostringstream  got;
+
+      mpf_t  f;
+      mpf_init (f);
+      mpf_set_d (f, 1.5);
+      got << f;
+      mpf_clear (f);
+
+      string  want = string("1") + point[i] + string("5");
+
+      if (want.compare (got.str()) != 0)
+        {
+          cout << "ostream mpf_t operator<< doesn't respect locale\n";
+          cout << "  point " << point[i] << "\n";
+          cout << "  got   \"" << got.str() << "\"\n";
+          cout << "  want  \"" << want      << "\"\n";
+          abort ();
+        }
+    }
+}
+
+int
+replacement_works (void)
+{
+  set_point ('x');
+  mpf_t  f;
+  mpf_init (f);
+  mpf_set_d (f, 1.5);
+  ostringstream s;
+  s << f;
+  mpf_clear (f);
+
+  return (s.str().compare("1x5") == 0);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  if (replacement_works())
+    {
+      check_input ();
+      check_output ();
+    }
+  else
+    {
+      cout << "Replacing decimal point didn't work, tests skipped\n";
+    }
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/cxx/t-misc.cc b/tests/cxx/t-misc.cc
new file mode 100644
index 0000000..1143e84
--- /dev/null
+++ b/tests/cxx/t-misc.cc
@@ -0,0 +1,397 @@
+/* Test mp*_class functions.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Note that we don't use <climits> for LONG_MIN, but instead our own
+   definitions in gmp-impl.h.  In g++ 2.95.4 (debian 3.0) under
+   -mcpu=ultrasparc, limits.h sees __sparc_v9__ defined and assumes that
+   means long is 64-bit long, but it's only 32-bits, causing fatal compile
+   errors.  */
+
+#include "config.h"
+
+#include <string>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // mpz_class::fits_sint_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = INT_MIN; fits = z.fits_sint_p(); ASSERT_ALWAYS (fits);
+    z--;         fits = z.fits_sint_p(); ASSERT_ALWAYS (! fits);
+    z = INT_MAX; fits = z.fits_sint_p(); ASSERT_ALWAYS (fits);
+    z++;         fits = z.fits_sint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_uint_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = 0;        fits = z.fits_uint_p(); ASSERT_ALWAYS (fits);
+    z--;          fits = z.fits_uint_p(); ASSERT_ALWAYS (! fits);
+    z = UINT_MAX; fits = z.fits_uint_p(); ASSERT_ALWAYS (fits);
+    z++;          fits = z.fits_uint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_slong_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = LONG_MIN; fits = z.fits_slong_p(); ASSERT_ALWAYS (fits);
+    z--;          fits = z.fits_slong_p(); ASSERT_ALWAYS (! fits);
+    z = LONG_MAX; fits = z.fits_slong_p(); ASSERT_ALWAYS (fits);
+    z++;          fits = z.fits_slong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_ulong_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = 0;         fits = z.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    z--;           fits = z.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+    z = ULONG_MAX; fits = z.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    z++;           fits = z.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_sshort_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = SHRT_MIN; fits = z.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    z--;          fits = z.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+    z = SHRT_MAX; fits = z.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    z++;          fits = z.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_ushort_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = 0;         fits = z.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    z--;           fits = z.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+    z = USHRT_MAX; fits = z.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    z++;           fits = z.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::get_mpz_t
+  {
+    mpz_class  z(0);
+    mpz_ptr    p = z.get_mpz_t();
+    ASSERT_ALWAYS (mpz_cmp_ui (p, 0) == 0);
+  }
+  {
+    mpz_class  z(0);
+    mpz_srcptr p = z.get_mpz_t();
+    ASSERT_ALWAYS (mpz_cmp_ui (p, 0) == 0);
+  }
+
+  // mpz_class::get_d
+  // mpz_class::get_si
+  // mpz_class::get_ui
+  {
+    mpz_class  z(123);
+    { double d = z.get_d();  ASSERT_ALWAYS (d == 123.0); }
+    { long   l = z.get_si(); ASSERT_ALWAYS (l == 123L); }
+    { long   u = z.get_ui(); ASSERT_ALWAYS (u == 123L); }
+  }
+  {
+    mpz_class  z(-123);
+    { double d = z.get_d();  ASSERT_ALWAYS (d == -123.0); }
+    { long   l = z.get_si(); ASSERT_ALWAYS (l == -123L); }
+  }
+
+  // mpz_class::get_str
+  {
+    mpz_class  z(123);
+    string     s;
+    s = z.get_str(); ASSERT_ALWAYS (s == "123");
+    s = z.get_str(16); ASSERT_ALWAYS (s == "7b");
+    s = z.get_str(-16); ASSERT_ALWAYS (s == "7B");
+  }
+
+  // mpz_class::set_str
+  {
+    mpz_class  z;
+    int        ret;
+    ret = z.set_str ("123", 10);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str ("7b",  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str ("7B",  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str ("0x7B", 0);  ASSERT_ALWAYS (ret == 0 && z == 123);
+
+    ret = z.set_str (string("123"), 10);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str (string("7b"),  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str (string("7B"),  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str (string("0x7B"), 0);  ASSERT_ALWAYS (ret == 0 && z == 123);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // mpq_class::canonicalize
+  {
+    mpq_class  q(12,9);
+    q.canonicalize();
+    ASSERT_ALWAYS (q.get_num() == 4);
+    ASSERT_ALWAYS (q.get_den() == 3);
+  }
+
+  // mpq_class::get_d
+  {
+    mpq_class  q(123);
+    { double d = q.get_d();  ASSERT_ALWAYS (d == 123.0); }
+  }
+  {
+    mpq_class  q(-123);
+    { double d = q.get_d();  ASSERT_ALWAYS (d == -123.0); }
+  }
+
+  // mpq_class::get_mpq_t
+  {
+    mpq_class  q(0);
+    mpq_ptr    p = q.get_mpq_t();
+    ASSERT_ALWAYS (mpq_cmp_ui (p, 0, 1) == 0);
+  }
+  {
+    mpq_class  q(0);
+    mpq_srcptr p = q.get_mpq_t();
+    ASSERT_ALWAYS (mpq_cmp_ui (p, 0, 1) == 0);
+  }
+
+  // mpq_class::get_num, mpq_class::get_den
+  {
+    const mpq_class  q(4,5);
+    mpz_class  z;
+    z = q.get_num(); ASSERT_ALWAYS (z == 4);
+    z = q.get_den(); ASSERT_ALWAYS (z == 5);
+  }
+
+  // mpq_class::get_num_mpz_t, mpq_class::get_den_mpz_t
+  {
+    mpq_class  q(4,5);
+    mpz_ptr    p;
+    p = q.get_num_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 4) == 0);
+    p = q.get_den_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 5) == 0);
+  }
+  {
+    const mpq_class  q(4,5);
+    mpz_srcptr p;
+    p = q.get_num_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 4) == 0);
+    p = q.get_den_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 5) == 0);
+  }
+
+  // mpq_class::get_str
+  {
+    mpq_class  q(17,11);
+    string     s;
+    s = q.get_str();    ASSERT_ALWAYS (s == "17/11");
+    s = q.get_str(10);  ASSERT_ALWAYS (s == "17/11");
+    s = q.get_str(16);  ASSERT_ALWAYS (s == "11/b");
+    s = q.get_str(-16); ASSERT_ALWAYS (s == "11/B");
+  }
+
+  // mpq_class::set_str
+  {
+    mpq_class  q;
+    int        ret;
+    ret = q.set_str ("123", 10);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("4/5", 10);     ASSERT_ALWAYS (ret == 0 && q == mpq_class(4,5));
+    ret = q.set_str ("7b",  16);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("7B",  16);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("0x7B", 0);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("0x10/17", 0);  ASSERT_ALWAYS (ret == 0 && q == mpq_class(16,17));
+
+    ret = q.set_str (string("4/5"), 10);  ASSERT_ALWAYS (ret == 0 && q == mpq_class(4,5));
+    ret = q.set_str (string("123"), 10);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("7b"),  16);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("7B"),  16);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("0x7B"), 0);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("0x10/17"), 0);  ASSERT_ALWAYS (ret == 0 && q == mpq_class(16,17));
+  }
+}
+
+void
+check_mpf (void)
+{
+  // mpf_class::fits_sint_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(int));
+    f = INT_MIN; fits = f.fits_sint_p(); ASSERT_ALWAYS (fits);
+    f--;         fits = f.fits_sint_p(); ASSERT_ALWAYS (! fits);
+    f = INT_MAX; fits = f.fits_sint_p(); ASSERT_ALWAYS (fits);
+    f++;         fits = f.fits_sint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_uint_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(int));
+    f = 0;        fits = f.fits_uint_p(); ASSERT_ALWAYS (fits);
+    f--;          fits = f.fits_uint_p(); ASSERT_ALWAYS (! fits);
+    f = UINT_MAX; fits = f.fits_uint_p(); ASSERT_ALWAYS (fits);
+    f++;          fits = f.fits_uint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_slong_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(long));
+    f = LONG_MIN; fits = f.fits_slong_p(); ASSERT_ALWAYS (fits);
+    f--;          fits = f.fits_slong_p(); ASSERT_ALWAYS (! fits);
+    f = LONG_MAX; fits = f.fits_slong_p(); ASSERT_ALWAYS (fits);
+    f++;          fits = f.fits_slong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_ulong_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(long));
+    f = 0;         fits = f.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    f--;           fits = f.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+    f = ULONG_MAX; fits = f.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    f++;           fits = f.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_sshort_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(short));
+    f = SHRT_MIN; fits = f.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    f--;          fits = f.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+    f = SHRT_MAX; fits = f.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    f++;          fits = f.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_ushort_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(short));
+    f = 0;         fits = f.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    f--;           fits = f.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+    f = USHRT_MAX; fits = f.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    f++;           fits = f.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::get_d
+  // mpf_class::get_si
+  // mpf_class::get_ui
+  {
+    mpf_class  f(123);
+    { double d = f.get_d();  ASSERT_ALWAYS (d == 123.0); }
+    { long   l = f.get_si(); ASSERT_ALWAYS (l == 123L); }
+    { long   u = f.get_ui(); ASSERT_ALWAYS (u == 123L); }
+  }
+  {
+    mpf_class  f(-123);
+    { double d = f.get_d();  ASSERT_ALWAYS (d == -123.0); }
+    { long   l = f.get_si(); ASSERT_ALWAYS (l == -123L); }
+  }
+
+  // mpf_class::get_prec
+  {
+    mpf_class  f;
+    ASSERT_ALWAYS (f.get_prec() == mpf_get_default_prec());
+  }
+
+  // mpf_class::get_str
+  {
+    mpf_class  f(123);
+    string     s;
+    mp_exp_t   e;
+    s = f.get_str(e);        ASSERT_ALWAYS (s == "123" && e == 3);
+    s = f.get_str(e,  16);   ASSERT_ALWAYS (s == "7b"  && e == 2);
+    s = f.get_str(e, -16);   ASSERT_ALWAYS (s == "7B"  && e == 2);
+    s = f.get_str(e, 10, 2); ASSERT_ALWAYS (s == "12"  && e == 3);
+    s = f.get_str(e, 10, 1); ASSERT_ALWAYS (s == "1"   && e == 3);
+  }
+
+  // mpf_class::set_str
+  {
+    mpf_class  f;
+    int        ret;
+    ret = f.set_str ("123",     10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("123e1",   10);  ASSERT_ALWAYS (ret == 0 && f == 1230);
+    ret = f.set_str ("1230e-1", 10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("7b",      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("7B",      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("7B@1",    16);  ASSERT_ALWAYS (ret == 0 && f == 1968);
+    ret = f.set_str ("7B0@-1",  16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+
+    ret = f.set_str (string("123"),     10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("123e1"),   10);  ASSERT_ALWAYS (ret == 0 && f == 1230);
+    ret = f.set_str (string("1230e-1"), 10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("7b"),      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("7B"),      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("7B@1"),    16);  ASSERT_ALWAYS (ret == 0 && f == 1968);
+    ret = f.set_str (string("7B0@-1"),  16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+  }
+
+  // mpf_class::set_prec
+  {
+    mpf_class  f;
+    f.set_prec (256);
+    ASSERT_ALWAYS (f.get_prec () >= 256);
+  }
+
+  // mpf_class::set_prec_raw
+  {
+    mpf_class  f (0, 100 * GMP_NUMB_BITS);
+    f.set_prec_raw (5 * GMP_NUMB_BITS);
+    ASSERT_ALWAYS (f.get_prec () >= 5 * GMP_NUMB_BITS);
+    ASSERT_ALWAYS (f.get_prec () < 100 * GMP_NUMB_BITS);
+    f.set_prec_raw (100 * GMP_NUMB_BITS);
+  }
+}
+
+// std::numeric_limits
+void
+check_limits (void)
+{
+  // Check that the content is not private.
+  ASSERT_ALWAYS ( std::numeric_limits<mpz_class>::is_integer);
+  ASSERT_ALWAYS (!std::numeric_limits<mpf_class>::is_integer);
+
+  // Check that symbols are emitted.
+  ASSERT_ALWAYS (&std::numeric_limits<mpz_class>::is_integer
+	      != &std::numeric_limits<mpq_class>::is_integer);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+  check_limits();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-mix.cc b/tests/cxx/t-mix.cc
new file mode 100644
index 0000000..cb6733b
--- /dev/null
+++ b/tests/cxx/t-mix.cc
@@ -0,0 +1,82 @@
+/* Test legality of conversion between the different mp*_class
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+int f_z  (mpz_class){return 0;}
+int f_q  (mpq_class){return 1;}
+int f_f  (mpf_class){return 2;}
+int f_zq (mpz_class){return 0;}
+int f_zq (mpq_class){return 1;}
+int f_zf (mpz_class){return 0;}
+int f_zf (mpf_class){return 2;}
+int f_qf (mpq_class){return 1;}
+int f_qf (mpf_class){return 2;}
+int f_zqf(mpz_class){return 0;}
+int f_zqf(mpq_class){return 1;}
+int f_zqf(mpf_class){return 2;}
+
+void
+check (void)
+{
+  mpz_class z=42;
+  mpq_class q=33;
+  mpf_class f=18;
+
+  ASSERT_ALWAYS(f_z  (z)==0); ASSERT_ALWAYS(f_z  (-z)==0);
+  ASSERT_ALWAYS(f_q  (z)==1); ASSERT_ALWAYS(f_q  (-z)==1);
+  ASSERT_ALWAYS(f_q  (q)==1); ASSERT_ALWAYS(f_q  (-q)==1);
+  ASSERT_ALWAYS(f_f  (z)==2); ASSERT_ALWAYS(f_f  (-z)==2);
+  ASSERT_ALWAYS(f_f  (q)==2); ASSERT_ALWAYS(f_f  (-q)==2);
+  ASSERT_ALWAYS(f_f  (f)==2); ASSERT_ALWAYS(f_f  (-f)==2);
+  ASSERT_ALWAYS(f_zq (z)==0);
+  ASSERT_ALWAYS(f_zq (q)==1); ASSERT_ALWAYS(f_zq (-q)==1);
+  ASSERT_ALWAYS(f_zf (z)==0);
+  ASSERT_ALWAYS(f_zf (f)==2); ASSERT_ALWAYS(f_zf (-f)==2);
+  ASSERT_ALWAYS(f_qf (q)==1);
+  ASSERT_ALWAYS(f_qf (f)==2); ASSERT_ALWAYS(f_qf (-f)==2);
+  ASSERT_ALWAYS(f_zqf(z)==0);
+  ASSERT_ALWAYS(f_zqf(q)==1);
+  ASSERT_ALWAYS(f_zqf(f)==2); ASSERT_ALWAYS(f_zqf(-f)==2);
+
+  ASSERT_ALWAYS(f_zqf(mpz_class(z))==0); ASSERT_ALWAYS(f_zqf(mpz_class(-z))==0);
+  ASSERT_ALWAYS(f_zqf(mpz_class(q))==0); ASSERT_ALWAYS(f_zqf(mpz_class(-q))==0);
+  ASSERT_ALWAYS(f_zqf(mpz_class(f))==0); ASSERT_ALWAYS(f_zqf(mpz_class(-f))==0);
+  ASSERT_ALWAYS(f_zqf(mpq_class(z))==1); ASSERT_ALWAYS(f_zqf(mpq_class(-z))==1);
+  ASSERT_ALWAYS(f_zqf(mpq_class(q))==1); ASSERT_ALWAYS(f_zqf(mpq_class(-q))==1);
+  ASSERT_ALWAYS(f_zqf(mpq_class(f))==1); ASSERT_ALWAYS(f_zqf(mpq_class(-f))==1);
+  ASSERT_ALWAYS(f_zqf(mpf_class(z))==2); ASSERT_ALWAYS(f_zqf(mpf_class(-z))==2);
+  ASSERT_ALWAYS(f_zqf(mpf_class(q))==2); ASSERT_ALWAYS(f_zqf(mpf_class(-q))==2);
+  ASSERT_ALWAYS(f_zqf(mpf_class(f))==2); ASSERT_ALWAYS(f_zqf(mpf_class(-f))==2);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  check();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ops.cc b/tests/cxx/t-ops.cc
new file mode 100644
index 0000000..ecc6bd0
--- /dev/null
+++ b/tests/cxx/t-ops.cc
@@ -0,0 +1,753 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2001-2003, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // unary operators and functions
+
+  // operator+
+  {
+    mpz_class a(1);
+    mpz_class b;
+    b = +a; ASSERT_ALWAYS(b == 1);
+  }
+
+  // operator-
+  {
+    mpz_class a(2);
+    mpz_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // operator~
+  {
+    mpz_class a(3);
+    mpz_class b;
+    b = ~a; ASSERT_ALWAYS(b == -4);
+  }
+
+  // abs
+  {
+    mpz_class a(-123);
+    mpz_class b;
+    b = abs(a); ASSERT_ALWAYS(b == 123);
+    a <<= 300;
+    b = abs(a); ASSERT_ALWAYS(a + b == 0);
+  }
+
+  // sqrt
+  {
+    mpz_class a(25);
+    mpz_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 5);
+  }
+  {
+    mpz_class a(125);
+    mpz_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 11); // round toward zero
+  }
+
+  // sgn
+  {
+    mpz_class a(123);
+    int b = sgn(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpz_class a(0);
+    int b = sgn(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    mpz_class a(-123);
+    int b = sgn(a); ASSERT_ALWAYS(b == -1);
+  }
+
+
+  // binary operators and functions
+
+  // operator+
+  {
+    mpz_class a(1), b(2);
+    mpz_class c;
+    c = a + b; ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpz_class a(3);
+    signed int b = 4;
+    mpz_class c;
+    c = a + b; ASSERT_ALWAYS(c == 7);
+  }
+  {
+    mpz_class a(5);
+    double b = 6.0;
+    mpz_class c;
+    c = b + a; ASSERT_ALWAYS(c == 11);
+  }
+
+  // operator-
+  {
+    mpz_class a(3), b(6);
+    mpz_class c;
+    c = a - b; ASSERT_ALWAYS(c == -3);
+  }
+
+  // operator*
+  {
+    mpz_class a(-2), b(4);
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == -8);
+  }
+  {
+    mpz_class a(2);
+    long b = -4;
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == -8);
+    c = b * a; ASSERT_ALWAYS(c == -8);
+  }
+  {
+    mpz_class a(-2);
+    unsigned long b = 4;
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == -8);
+    c = b * a; ASSERT_ALWAYS(c == -8);
+  }
+
+  // operator/ and operator%
+  {
+    mpz_class a(12), b(4);
+    mpz_class c;
+    c = a / b; ASSERT_ALWAYS(c == 3);
+    c = a % b; ASSERT_ALWAYS(c == 0);
+  }
+  {
+    mpz_class a(7), b(5);
+    mpz_class c;
+    c = a / b; ASSERT_ALWAYS(c == 1);
+    c = a % b; ASSERT_ALWAYS(c == 2);
+  }
+  {
+    mpz_class a(-10);
+    signed int ai = -10;
+    mpz_class b(3);
+    signed int bi = 3;
+    mpz_class c;
+    c = a / b;  ASSERT_ALWAYS(c == -3);
+    c = a % b;  ASSERT_ALWAYS(c == -1);
+    c = a / bi; ASSERT_ALWAYS(c == -3);
+    c = a % bi; ASSERT_ALWAYS(c == -1);
+    c = ai / b; ASSERT_ALWAYS(c == -3);
+    c = ai % b; ASSERT_ALWAYS(c == -1);
+  }
+  {
+    mpz_class a(-10);
+    signed int ai = -10;
+    mpz_class b(-3);
+    signed int bi = -3;
+    mpz_class c;
+    c = a / b;  ASSERT_ALWAYS(c == 3);
+    c = a % b;  ASSERT_ALWAYS(c == -1);
+    c = a / bi; ASSERT_ALWAYS(c == 3);
+    c = a % bi; ASSERT_ALWAYS(c == -1);
+    c = ai / b; ASSERT_ALWAYS(c == 3);
+    c = ai % b; ASSERT_ALWAYS(c == -1);
+  }
+  {
+    mpz_class a (LONG_MIN);
+    signed long ai = LONG_MIN;
+    mpz_class b = - mpz_class (LONG_MIN);
+    mpz_class c;
+    c = a / b;  ASSERT_ALWAYS(c == -1);
+    c = a % b;  ASSERT_ALWAYS(c == 0);
+    c = ai / b; ASSERT_ALWAYS(c == -1);
+    c = ai % b; ASSERT_ALWAYS(c == 0);
+  }
+
+  // operator&
+  // operator|
+  // operator^
+
+  // operator<<
+  {
+    mpz_class a(3);
+    unsigned int b = 4;
+    mpz_class c;
+    c = a << b; ASSERT_ALWAYS(c == 48);
+  }
+
+  // operator>>
+  {
+    mpz_class a(127);
+    unsigned int b = 4;
+    mpz_class c;
+    c = a >> b; ASSERT_ALWAYS(c == 7);
+  }
+
+  // operator==
+  // operator!=
+  // operator<
+  // operator<=
+  // operator>
+  // operator>=
+
+  // cmp
+  {
+    mpz_class a(123), b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpz_class a(123);
+    unsigned long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpz_class a(123);
+    long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpz_class a(123);
+    double b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+
+
+  // ternary operators
+
+  // mpz_addmul
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(3);
+    unsigned int c = 2;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(3);
+    signed int c = 2;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(3);
+    double c = 2.0;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b + c; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(4);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(3), b(4);
+    unsigned int c = 2;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(4);
+    signed int c = 3;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(3), b(4);
+    signed int c = 2;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(4);
+    double c = 3.0;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(3), b(4);
+    double c = 2.0;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 10);
+  }
+
+  // mpz_submul
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(3);
+    unsigned int c = 2;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(3);
+    signed int c = 2;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(3);
+    double c = 2.0;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b - c; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(2), b(4);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(3), b(4);
+    unsigned int c = 2;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(2), b(4);
+    signed int c = 3;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(3), b(4);
+    signed int c = 2;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(2), b(4);
+    double c = 3.0;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(3), b(4);
+    double c = 2.0;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 2);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // unary operators and functions
+
+  // operator+
+  {
+    mpq_class a(1, 2);
+    mpq_class b;
+    b = +a; ASSERT_ALWAYS(b == 0.5);
+  }
+
+  // operator-
+  {
+    mpq_class a(3, 4);
+    mpq_class b;
+    b = -a; ASSERT_ALWAYS(b == -0.75);
+  }
+
+  // abs
+  {
+    mpq_class a(-123);
+    mpq_class b;
+    b = abs(a); ASSERT_ALWAYS(b == 123);
+  }
+
+  // sgn
+  {
+    mpq_class a(123);
+    int b = sgn(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpq_class a(0);
+    int b = sgn(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    mpq_class a(-123);
+    int b = sgn(a); ASSERT_ALWAYS(b == -1);
+  }
+
+
+  // binary operators and functions
+
+  // operator+
+  {
+    mpq_class a(1, 2), b(3, 4);
+    mpq_class c;
+    c = a + b; ASSERT_ALWAYS(c == 1.25);
+  }
+  {
+    mpq_class a(1, 2);
+    signed int b = 2;
+    mpq_class c;
+    c = a + b; ASSERT_ALWAYS(c == 2.5);
+  }
+  {
+    mpq_class a(1, 2);
+    double b = 1.5;
+    mpq_class c;
+    c = b + a; ASSERT_ALWAYS(c == 2);
+  }
+
+  // operator-
+  {
+    mpq_class a(1, 2), b(3, 4);
+    mpq_class c;
+    c = a - b; ASSERT_ALWAYS(c == -0.25);
+  }
+
+  // operator*
+  {
+    mpq_class a(1, 3), b(3, 4);
+    mpq_class c;
+    c = a * b; ASSERT_ALWAYS(c == 0.25);
+    c = b * b; ASSERT_ALWAYS(c == 0.5625);
+  }
+
+  // operator/
+  {
+    mpq_class a(1, 2), b(2, 3);
+    mpq_class c;
+    c = a / b; ASSERT_ALWAYS(c == 0.75);
+  }
+  {
+    mpq_class one = 1;
+    mpq_class x(2, 5);
+    ASSERT_ALWAYS(1 / x == one / x);
+    ASSERT_ALWAYS(1u / x == one / x);
+    x = (-1) / x;
+    ASSERT_ALWAYS(x == -2.5);
+    ASSERT_ALWAYS(0 / x == 0);
+    ASSERT_ALWAYS(0u / x == 0);
+  }
+
+  // operator<<
+  // operator>>
+  // operator==
+  // operator!=
+  // operator<
+  // operator<=
+  // operator>
+  // operator>=
+
+  // cmp
+  {
+    mpq_class a(123), b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    unsigned long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    double b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    mpz_class b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // unary operators and functions
+
+  // operator+
+  {
+    mpf_class a(1);
+    mpf_class b;
+    b = +a; ASSERT_ALWAYS(b == 1);
+  }
+
+  // operator-
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // abs
+  {
+    mpf_class a(-123);
+    mpf_class b;
+    b = abs(a); ASSERT_ALWAYS(b == 123);
+  }
+
+  // trunc
+  {
+    mpf_class a(1.5);
+    mpf_class b;
+    b = trunc(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(-1.5);
+    mpf_class b;
+    b = trunc(a); ASSERT_ALWAYS(b == -1);
+  }
+
+  // floor
+  {
+    mpf_class a(1.9);
+    mpf_class b;
+    b = floor(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(-1.1);
+    mpf_class b;
+    b = floor(a); ASSERT_ALWAYS(b == -2);
+  }
+
+  // ceil
+  {
+    mpf_class a(1.1);
+    mpf_class b;
+    b = ceil(a); ASSERT_ALWAYS(b == 2);
+  }
+  {
+    mpf_class a(-1.9);
+    mpf_class b;
+    b = ceil(a); ASSERT_ALWAYS(b == -1);
+  }
+
+  // sqrt
+  {
+    mpf_class a(25);
+    mpf_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 5);
+  }
+  {
+    mpf_class a(2.25);
+    mpf_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 1.5);
+  }
+
+  // sgn
+  {
+    mpf_class a(123);
+    int b = sgn(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(0);
+    int b = sgn(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    mpf_class a(-123);
+    int b = sgn(a); ASSERT_ALWAYS(b == -1);
+  }
+
+
+  // binary operators and functions
+
+  // operator+
+  {
+    mpf_class a(1), b(2);
+    mpf_class c;
+    c = a + b; ASSERT_ALWAYS(c == 3);
+  }
+
+  // operator-
+  {
+    mpf_class a(3), b(4);
+    mpf_class c;
+    c = a - b; ASSERT_ALWAYS(c == -1);
+  }
+
+  // operator*
+  {
+    mpf_class a(2), b(5);
+    mpf_class c;
+    c = a * b; ASSERT_ALWAYS(c == 10);
+  }
+
+  // operator/
+  {
+    mpf_class a(7), b(4);
+    mpf_class c;
+    c = a / b; ASSERT_ALWAYS(c == 1.75);
+  }
+
+  // operator<<
+  // operator>>
+  // operator==
+  // operator!=
+  // operator<
+  // operator<=
+  // operator>
+  // operator>=
+
+  // hypot
+  {
+    mpf_class a(3), b(4);
+    mpf_class c;
+    c = hypot(a, b); ASSERT_ALWAYS(c == 5);
+  }
+
+  // cmp
+  {
+    mpf_class a(123), b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    unsigned long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    double b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    mpz_class b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    mpq_class b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ops2.h b/tests/cxx/t-ops2.h
new file mode 100644
index 0000000..f8898ee
--- /dev/null
+++ b/tests/cxx/t-ops2.h
@@ -0,0 +1,82 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define CHECK1(Type,a,fun) \
+  ASSERT_ALWAYS(fun((Type)(a))==fun(a))
+#define CHECK(Type1,Type2,a,b,op) \
+  ASSERT_ALWAYS(((Type1)(a) op (Type2)(b))==((a) op (b)))
+#define CHECK_G(Type,a,b,op) \
+  CHECK(Type,Type,a,b,op)
+#define CHECK_UI(Type,a,b,op) \
+  CHECK(Type,unsigned long,a,b,op); \
+  CHECK(unsigned long,Type,a,b,op)
+#define CHECK_SI(Type,a,b,op) \
+  CHECK(Type,long,a,b,op); \
+  CHECK(long,Type,a,b,op)
+#define CHECK_D(Type,a,b,op) \
+  CHECK(Type,double,a,b,op); \
+  CHECK(double,Type,a,b,op)
+#define CHECK_MPZ(Type,a,b,op) \
+  CHECK(Type,mpz_class,a,b,op); \
+  CHECK(mpz_class,Type,a,b,op)
+#define CHECK_MPQ(Type,a,b,op) \
+  CHECK(Type,mpq_class,a,b,op); \
+  CHECK(mpq_class,Type,a,b,op)
+#define CHECK_ALL_SIGNED(Type,a,b,op) \
+  CHECK_G(Type,a,b,op); \
+  CHECK_SI(Type,a,b,op); \
+  CHECK_D(Type,a,b,op)
+#define CHECK_ALL_SIGNS(Type,a,b,op) \
+  CHECK_ALL_SIGNED(Type,a,b,op); \
+  CHECK_ALL_SIGNED(Type,-(a),b,op); \
+  CHECK_ALL_SIGNED(Type,a,-(b),op); \
+  CHECK_ALL_SIGNED(Type,-(a),-(b),op)
+#define CHECK_ALL(Type,a,b,op) \
+  CHECK_ALL_SIGNED(Type,a,b,op); \
+  CHECK_UI(Type,a,b,op)
+#define CHECK_ALL_SIGNED_COMPARISONS(Type,a,b) \
+  CHECK_ALL_SIGNED(Type,a,b,<); \
+  CHECK_ALL_SIGNED(Type,a,b,>); \
+  CHECK_ALL_SIGNED(Type,a,b,<=); \
+  CHECK_ALL_SIGNED(Type,a,b,>=); \
+  CHECK_ALL_SIGNED(Type,a,b,==); \
+  CHECK_ALL_SIGNED(Type,a,b,!=)
+#define CHECK_ALL_SIGNS_COMPARISONS(Type,a,b) \
+  CHECK_ALL_SIGNS(Type,a,b,<); \
+  CHECK_ALL_SIGNS(Type,a,b,>); \
+  CHECK_ALL_SIGNS(Type,a,b,<=); \
+  CHECK_ALL_SIGNS(Type,a,b,>=); \
+  CHECK_ALL_SIGNS(Type,a,b,==); \
+  CHECK_ALL_SIGNS(Type,a,b,!=)
+#define CHECK_ALL_COMPARISONS(Type,a,b) \
+  CHECK_ALL(Type,a,b,<); \
+  CHECK_ALL(Type,a,b,>); \
+  CHECK_ALL(Type,a,b,<=); \
+  CHECK_ALL(Type,a,b,>=); \
+  CHECK_ALL(Type,a,b,==); \
+  CHECK_ALL(Type,a,b,!=)
diff --git a/tests/cxx/t-ops2f.cc b/tests/cxx/t-ops2f.cc
new file mode 100644
index 0000000..71c9e10
--- /dev/null
+++ b/tests/cxx/t-ops2f.cc
@@ -0,0 +1,87 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "t-ops2.h"
+
+void checkf (){
+  ASSERT_ALWAYS(sqrt(mpf_class(7))>2.64);
+  ASSERT_ALWAYS(sqrt(mpf_class(7))<2.65);
+  ASSERT_ALWAYS(sqrt(mpf_class(0))==0);
+  // TODO: add some consistency checks, as described in
+  // https://gmplib.org/list-archives/gmp-bugs/2013-February/002940.html
+  CHECK1(mpf_class,1.9,trunc);
+  CHECK1(mpf_class,1.9,floor);
+  CHECK1(mpf_class,1.9,ceil);
+  CHECK1(mpf_class,4.3,trunc);
+  CHECK1(mpf_class,4.3,floor);
+  CHECK1(mpf_class,4.3,ceil);
+  CHECK1(mpf_class,-7.1,trunc);
+  CHECK1(mpf_class,-7.1,floor);
+  CHECK1(mpf_class,-7.1,ceil);
+  CHECK1(mpf_class,-2.8,trunc);
+  CHECK1(mpf_class,-2.8,floor);
+  CHECK1(mpf_class,-2.8,ceil);
+  CHECK1(mpf_class,-1.5,trunc);
+  CHECK1(mpf_class,-1.5,floor);
+  CHECK1(mpf_class,-1.5,ceil);
+  CHECK1(mpf_class,2.5,trunc);
+  CHECK1(mpf_class,2.5,floor);
+  CHECK1(mpf_class,2.5,ceil);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),mpf_class(4))>4.9);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),mpf_class(4))<5.1);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),4.)>4.9);
+  ASSERT_ALWAYS(hypot(-3.,mpf_class(4))<5.1);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),4l)>4.9);
+  ASSERT_ALWAYS(hypot(-3l,mpf_class(4))<5.1);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),4ul)>4.9);
+  ASSERT_ALWAYS(hypot(3ul,mpf_class(4))<5.1);
+  CHECK(mpf_class,mpq_class,1.5,2.25,+);
+  CHECK(mpf_class,mpq_class,1.5,2.25,-);
+  CHECK(mpf_class,mpq_class,1.5,-2.25,*);
+  CHECK(mpf_class,mpq_class,1.5,-2,/);
+  CHECK_MPQ(mpf_class,-5.5,-2.25,+);
+  CHECK_MPQ(mpf_class,-5.5,-2.25,-);
+  CHECK_MPQ(mpf_class,-5.5,-2.25,*);
+  CHECK_MPQ(mpf_class,-5.25,-0.5,/);
+  CHECK_MPQ(mpf_class,5,-2,<);
+  CHECK_MPQ(mpf_class,5,-2,>);
+  CHECK_MPQ(mpf_class,5,-2,<=);
+  CHECK_MPQ(mpf_class,5,-2,>=);
+  CHECK_MPQ(mpf_class,5,-2,==);
+  CHECK_MPQ(mpf_class,5,-2,!=);
+  CHECK_MPQ(mpf_class,0,0,<);
+  CHECK_MPQ(mpf_class,0,0,>);
+  CHECK_MPQ(mpf_class,0,0,<=);
+  CHECK_MPQ(mpf_class,0,0,>=);
+  CHECK_MPQ(mpf_class,0,0,==);
+  CHECK_MPQ(mpf_class,0,0,!=);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  // Enough precision for 1 + denorm_min
+  mpf_set_default_prec(DBL_MANT_DIG-DBL_MIN_EXP+42);
+  checkf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ops2qf.cc b/tests/cxx/t-ops2qf.cc
new file mode 100644
index 0000000..bd96f61
--- /dev/null
+++ b/tests/cxx/t-ops2qf.cc
@@ -0,0 +1,89 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "t-ops2.h"
+
+template<class T>
+void checkqf (){
+  CHECK_ALL(T,5.,0,+);
+  CHECK_ALL(T,5.,0,-);
+  CHECK_ALL(T,5.,2,+); CHECK_MPZ(T,5.,2,+);
+  CHECK_ALL(T,5.,2,-); CHECK_MPZ(T,5.,2,-);
+  CHECK_ALL(T,5.,2,*); CHECK_MPZ(T,5.,2,*);
+  CHECK_ALL(T,5.,2,/); CHECK_MPZ(T,5.,2,/);
+  CHECK_ALL(T,0.,2,/);
+  CHECK_ALL_SIGNS(T,11.,3,+);
+  CHECK_ALL_SIGNS(T,11.,3,-);
+  CHECK_ALL_SIGNS(T,13.,1,+);
+  CHECK_ALL_SIGNS(T,13.,1,-);
+  CHECK_ALL_SIGNS(T,11.,3,*);
+  CHECK_ALL_SIGNS(T,11.,4,/);
+  CHECK_SI(T,LONG_MIN,1,*);
+  CHECK_SI(T,0,3,*);
+  CHECK_ALL_COMPARISONS(T,5.,2);
+  CHECK_ALL_SIGNS_COMPARISONS(T,11.,3);
+  CHECK_MPZ(T,5,-2,<);
+  CHECK_MPZ(T,5,-2,>);
+  CHECK_MPZ(T,5,-2,<=);
+  CHECK_MPZ(T,5,-2,>=);
+  CHECK_MPZ(T,5,-2,==);
+  CHECK_MPZ(T,5,-2,!=);
+  CHECK_MPZ(T,0,0,<);
+  CHECK_MPZ(T,0,0,>);
+  CHECK_MPZ(T,0,0,<=);
+  CHECK_MPZ(T,0,0,>=);
+  CHECK_MPZ(T,0,0,==);
+  CHECK_MPZ(T,0,0,!=);
+  ASSERT_ALWAYS(T(6)<<2==6.*4);
+  ASSERT_ALWAYS(T(6)>>2==6./4);
+  ASSERT_ALWAYS(T(-13)<<2==-13.*4);
+  ASSERT_ALWAYS(T(-13)>>2==-13./4);
+  ASSERT_ALWAYS(++T(7)==8);
+  ASSERT_ALWAYS(++T(-8)==-7);
+  ASSERT_ALWAYS(--T(8)==7);
+  ASSERT_ALWAYS(--T(-7)==-8);
+  ASSERT_ALWAYS(+T(7)==7);
+  ASSERT_ALWAYS(+T(-8)==-8);
+  ASSERT_ALWAYS(-T(7)==-7);
+  ASSERT_ALWAYS(-T(-8)==8);
+  ASSERT_ALWAYS(abs(T(7))==7);
+  ASSERT_ALWAYS(abs(T(-8))==8);
+  ASSERT_ALWAYS(sgn(T(0))==0);
+  ASSERT_ALWAYS(sgn(T(9))==1);
+  ASSERT_ALWAYS(sgn(T(-17))==-1);
+  ASSERT_ALWAYS(T(1)+DBL_MAX>2);
+  ASSERT_ALWAYS(T(1)+DBL_MIN>1);
+  ASSERT_ALWAYS(T(1)+DBL_MIN<1.001);
+  ASSERT_ALWAYS(T(1)+std::numeric_limits<double>::denorm_min()>1);
+  ASSERT_ALWAYS(T(1)+std::numeric_limits<double>::denorm_min()<1.001);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  // Enough precision for 1 + denorm_min
+  mpf_set_default_prec(DBL_MANT_DIG-DBL_MIN_EXP+42);
+  checkqf<mpq_class>();
+  checkqf<mpf_class>();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ops2z.cc b/tests/cxx/t-ops2z.cc
new file mode 100644
index 0000000..78694b7
--- /dev/null
+++ b/tests/cxx/t-ops2z.cc
@@ -0,0 +1,126 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "t-ops2.h"
+
+void checkz (){
+  CHECK_ALL(mpz_class,5,2,+);
+  CHECK_ALL(mpz_class,5,2,-);
+  CHECK_ALL(mpz_class,5,2,*);
+  CHECK_ALL(mpz_class,5,2,/);
+  CHECK_ALL(mpz_class,5,2,%);
+  CHECK_ALL_COMPARISONS(mpz_class,5,2);
+  CHECK_ALL_SIGNS(mpz_class,11,3,+);
+  CHECK_ALL_SIGNS(mpz_class,11,3,-);
+  CHECK_ALL_SIGNS(mpz_class,11,3,*);
+  CHECK_ALL_SIGNS(mpz_class,11,3,/);
+  CHECK_ALL_SIGNS(mpz_class,11,3,%);
+  CHECK_ALL_SIGNS(mpz_class,17,2,*);
+  CHECK_ALL_SIGNS(mpz_class,17,2,/);
+  CHECK_ALL_SIGNS(mpz_class,17,2,%);
+  CHECK(unsigned long,mpz_class,5,-2,/);
+  CHECK(unsigned long,mpz_class,5,-2,%);
+  ASSERT_ALWAYS(7ul/mpz_class(1e35)==0);
+  ASSERT_ALWAYS(7ul%mpz_class(1e35)==7);
+  ASSERT_ALWAYS(7ul/mpz_class(-1e35)==0);
+  ASSERT_ALWAYS(7ul%mpz_class(-1e35)==7);
+  CHECK_ALL_SIGNS_COMPARISONS(mpz_class,11,3);
+  CHECK_ALL(mpz_class,6,3,&);
+  CHECK_ALL(mpz_class,6,3,|);
+  CHECK_ALL(mpz_class,6,3,^);
+  CHECK(mpz_class,unsigned long,6,2,<<);
+  CHECK(mpz_class,unsigned long,6,2,>>);
+  ASSERT_ALWAYS((mpz_class(-13)<<(unsigned long)2) == (-13)*4);
+  CHECK(mpz_class,unsigned long,-13,2,>>);
+  ASSERT_ALWAYS(++mpz_class(7)==8);
+  ASSERT_ALWAYS(++mpz_class(-8)==-7);
+  ASSERT_ALWAYS(--mpz_class(8)==7);
+  ASSERT_ALWAYS(--mpz_class(-7)==-8);
+  ASSERT_ALWAYS(~mpz_class(7)==-8);
+  ASSERT_ALWAYS(~mpz_class(-8)==7);
+  ASSERT_ALWAYS(+mpz_class(7)==7);
+  ASSERT_ALWAYS(+mpz_class(-8)==-8);
+  ASSERT_ALWAYS(-mpz_class(7)==-7);
+  ASSERT_ALWAYS(-mpz_class(-8)==8);
+  ASSERT_ALWAYS(abs(mpz_class(7))==7);
+  ASSERT_ALWAYS(abs(mpz_class(-8))==8);
+  ASSERT_ALWAYS(sqrt(mpz_class(7))==2);
+  ASSERT_ALWAYS(sqrt(mpz_class(0))==0);
+  ASSERT_ALWAYS(sgn(mpz_class(0))==0);
+  ASSERT_ALWAYS(sgn(mpz_class(9))==1);
+  ASSERT_ALWAYS(sgn(mpz_class(-17))==-1);
+  ASSERT_ALWAYS(mpz_class(1)+DBL_MAX>2);
+  ASSERT_ALWAYS(mpz_class(1)+DBL_MIN<2);
+  ASSERT_ALWAYS(mpz_class(1)+std::numeric_limits<double>::denorm_min()<2);
+  ASSERT_ALWAYS(gcd(mpz_class(6),mpz_class(8))==2);
+  ASSERT_ALWAYS(gcd(-mpz_class(6),mpz_class(8))==2);
+  ASSERT_ALWAYS(gcd(-mpz_class(6),-mpz_class(8))==2);
+  ASSERT_ALWAYS(gcd(mpz_class(6),8.f)==2);
+  ASSERT_ALWAYS(gcd(-mpz_class(6),static_cast<unsigned char>(8))==2);
+  ASSERT_ALWAYS(gcd(static_cast<long>(-6),mpz_class(5)+3)==2);
+  ASSERT_ALWAYS(lcm(mpz_class(6),mpz_class(8))==24);
+  ASSERT_ALWAYS(lcm(-mpz_class(6),mpz_class(8))==24);
+  ASSERT_ALWAYS(lcm(-mpz_class(6),-mpz_class(8))==24);
+  ASSERT_ALWAYS(lcm(mpz_class(6),static_cast<short>(8))==24);
+  ASSERT_ALWAYS(lcm(-mpz_class(6),static_cast<unsigned char>(8))==24);
+  ASSERT_ALWAYS(lcm(-6.,mpz_class(5)+3)==24);
+  ASSERT_ALWAYS(factorial(mpz_class(3))==6);
+  ASSERT_ALWAYS(factorial(mpz_class(5)-1)==24);
+  ASSERT_ALWAYS(mpz_class::factorial(mpz_class(3))==6);
+  ASSERT_ALWAYS(mpz_class::factorial(mpz_class(2)*2)==24);
+  ASSERT_ALWAYS(mpz_class::factorial(3)==6);
+  ASSERT_ALWAYS(mpz_class::factorial(3ul)==6);
+  ASSERT_ALWAYS(mpz_class::factorial(3.f)==6);
+  mpz_class ret;
+  try { ret=factorial(-mpz_class(3)); ASSERT_ALWAYS(0); }
+  catch (std::domain_error&) {}
+  try { ret=mpz_class::factorial(-2); ASSERT_ALWAYS(0); }
+  catch (std::domain_error&) {}
+  try { ret=factorial(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
+  catch (std::bad_alloc&) {}
+  ASSERT_ALWAYS(mpz_class::primorial(mpz_class(3))==6);
+  ASSERT_ALWAYS(mpz_class::primorial(mpz_class(2)*2)==6);
+  ASSERT_ALWAYS(mpz_class::primorial(3)==6);
+  ASSERT_ALWAYS(mpz_class::primorial(3ul)==6);
+  ASSERT_ALWAYS(mpz_class::primorial(3.f)==6);
+  try { ret=primorial(-mpz_class(3)); ASSERT_ALWAYS(0); }
+  catch (std::domain_error&) {}
+  try { ret=mpz_class::primorial(-5); ASSERT_ALWAYS(0); }
+  catch (std::domain_error&) {}
+  try { ret=primorial(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
+  catch (std::bad_alloc&) {}
+  ASSERT_ALWAYS(mpz_class::fibonacci(mpz_class(6))==8);
+  ASSERT_ALWAYS(mpz_class::fibonacci(mpz_class(2)*2)==3);
+  ASSERT_ALWAYS(mpz_class::fibonacci(3)==2);
+  ASSERT_ALWAYS(mpz_class::fibonacci(3ul)==2);
+  ASSERT_ALWAYS(mpz_class::fibonacci(3.f)==2);
+  ASSERT_ALWAYS(fibonacci(-mpz_class(6))==-8);
+  ASSERT_ALWAYS(mpz_class::fibonacci(-3)==2);
+  try { ret=fibonacci(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
+  catch (std::bad_alloc&) {}
+}
+
+int
+main (void)
+{
+  tests_start();
+  checkz();
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ops3.cc b/tests/cxx/t-ops3.cc
new file mode 100644
index 0000000..baf49e1
--- /dev/null
+++ b/tests/cxx/t-ops3.cc
@@ -0,0 +1,132 @@
+/* Test mp*_class assignment operators (+=, -=, etc)
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+#define FOR_ALL_SIGNED_BUILTIN(F) \
+	F(signed char) \
+	F(signed short) \
+	F(signed int) \
+	F(signed long) \
+	F(float) \
+	F(double)
+
+#define FOR_ALL_BUILTIN(F) \
+	FOR_ALL_SIGNED_BUILTIN(F) \
+	F(char) \
+	F(unsigned char) \
+	F(unsigned short) \
+	F(unsigned int) \
+	F(unsigned long)
+
+#define FOR_ALL_GMPXX(F) \
+	F(mpz_class) \
+	F(mpq_class) \
+	F(mpf_class)
+
+template<class T,class U> void f(T t, U u){
+  T a=t;
+  ASSERT_ALWAYS((a+=u)==(t+u)); ASSERT_ALWAYS(a==(t+u));
+  ASSERT_ALWAYS((a-=u)==t); ASSERT_ALWAYS(a==t);
+  ASSERT_ALWAYS((a*=u)==(t*u)); ASSERT_ALWAYS(a==(t*u));
+  ASSERT_ALWAYS((a/=u)==t); ASSERT_ALWAYS(a==t);
+  ASSERT_ALWAYS((a<<=5)==(t<<5)); ASSERT_ALWAYS(a==(t<<5));
+  ASSERT_ALWAYS((a>>=5)==t); ASSERT_ALWAYS(a==t);
+}
+
+template<class T,class U> void g(T t, U u){
+  T a=t;
+  ASSERT_ALWAYS((a%=u)==(t%u)); ASSERT_ALWAYS(a==(t%u));
+  a=t;
+  ASSERT_ALWAYS((a&=u)==(t&u)); ASSERT_ALWAYS(a==(t&u));
+  a=t;
+  ASSERT_ALWAYS((a|=u)==(t|u)); ASSERT_ALWAYS(a==(t|u));
+  a=t;
+  ASSERT_ALWAYS((a^=u)==(t^u)); ASSERT_ALWAYS(a==(t^u));
+}
+
+template<class T> void h(T t){
+  T a=t;
+  ASSERT_ALWAYS((a<<=5)==(t<<5)); ASSERT_ALWAYS(a==(t<<5));
+  ASSERT_ALWAYS((a>>=5)==t); ASSERT_ALWAYS(a==t);
+}
+
+template<class T, class U> void ffs(T t, U u){
+#define F(V) f(t,(V)u);
+	FOR_ALL_SIGNED_BUILTIN(F)
+	FOR_ALL_GMPXX(F)
+#undef F
+#define F(V) f(t,-(V)u);
+	FOR_ALL_GMPXX(F)
+#undef F
+}
+
+template<class T, class U> void ff(T t, U u){
+#define F(V) f(t,(V)u);
+	FOR_ALL_BUILTIN(F)
+	FOR_ALL_GMPXX(F)
+#undef F
+#define F(V) f(t,-(V)u);
+	FOR_ALL_GMPXX(F)
+#undef F
+}
+
+template<class U> void ggs(mpz_class t, U u){
+#define F(V) g(t,(V)u);
+	FOR_ALL_SIGNED_BUILTIN(F)
+#undef F
+	g(t,(mpz_class)u);
+	g(t,-(mpz_class)u);
+}
+
+template<class U> void gg(mpz_class t, U u){
+#define F(V) g(t,(V)u);
+	FOR_ALL_BUILTIN(F)
+#undef F
+	g(t,(mpz_class)u);
+	g(t,-(mpz_class)u);
+}
+
+void check(){
+	mpz_class z=18;
+	mpq_class q(7,2);
+	mpf_class d=3.375;
+	h(z); h(q); h(d);
+	ff(z,13); ff(q,13); ff(d,13);
+	ffs(z,-42); ffs(q,-42); ffs(d,-42);
+	gg(z,33); ggs(z,-22);
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ostream.cc b/tests/cxx/t-ostream.cc
new file mode 100644
index 0000000..8550f67
--- /dev/null
+++ b/tests/cxx/t-ostream.cc
@@ -0,0 +1,449 @@
+/* Test ostream formatted output.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <cstdlib>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+bool option_check_standard = false;
+
+
+#define CALL(expr)							\
+  do {									\
+    got.flags (data[i].flags);						\
+    got.width (data[i].width);						\
+    got.precision (data[i].precision);					\
+    if (data[i].fill == '\0')						\
+      got.fill (' ');							\
+    else								\
+      got.fill (data[i].fill);						\
+									\
+    if (! (expr))							\
+      {									\
+	cout << "\"got\" output error\n";				\
+	abort ();							\
+      }									\
+    if (got.width() != 0)						\
+      {									\
+	cout << "\"got\" width not reset to 0\n";			\
+	abort ();							\
+      }									\
+									\
+  } while (0)
+
+
+#define DUMP()								\
+  do {									\
+    cout << "  want:  |" << data[i].want << "|\n";			\
+    cout << "  got:   |" << got.str() << "|\n";				\
+    cout << "  width: " << data[i].width << "\n";			\
+    cout << "  prec:  " << got.precision() << "\n";			\
+    cout << "  flags: " << hex << (unsigned long) got.flags() << "\n";	\
+  } while (0)
+
+#define ABORT() \
+  do {          \
+    DUMP ();    \
+    abort ();   \
+  } while (0)
+
+void
+check_mpz (void)
+{
+  static const struct {
+    const char     *z;
+    const char     *want;
+    ios::fmtflags  flags;
+    int            width;
+    int            precision;
+    char           fill;
+
+  } data[] = {
+
+    { "0", "0", ios::dec },
+
+    { "0", "0", ios::oct },
+    { "0", "0", ios::oct | ios::showbase },
+
+    { "0", "0", ios::hex },
+    { "0", "0x0", ios::hex | ios::showbase },
+    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
+
+    { "1", "****1", ios::dec, 5, 0, '*' },
+
+    { "-1", "   -1",  ios::dec | ios::right,    5 },
+    { "-1", "-   1",  ios::dec | ios::internal, 5 },
+    { "-1", "-1   ",  ios::dec | ios::left,     5 },
+
+    { "1", "   0x1", ios::hex | ios::showbase | ios::right,    6 },
+    { "1", "0x   1", ios::hex | ios::showbase | ios::internal, 6 },
+    { "1", "0x1   ", ios::hex | ios::showbase | ios::left,     6 },
+
+    { "1", "   +0x1", ios::hex | ios::showbase | ios::showpos | ios::right,
+      7 },
+    { "1", "+0x   1", ios::hex | ios::showbase | ios::showpos | ios::internal,
+      7 },
+    { "1", "+0x1   ", ios::hex | ios::showbase | ios::showpos | ios::left,
+      7 },
+
+    {  "123",    "7b", ios::hex },
+    {  "123",    "7B", ios::hex | ios::uppercase },
+    {  "123",  "0x7b", ios::hex | ios::showbase },
+    {  "123",  "0X7B", ios::hex | ios::showbase | ios::uppercase },
+    { "-123", "-0x7b", ios::hex | ios::showbase },
+    { "-123", "-0X7B", ios::hex | ios::showbase | ios::uppercase },
+
+    {  "123",   "173", ios::oct },
+    {  "123",   "173", ios::oct | ios::uppercase },
+    {  "123",  "0173", ios::oct | ios::showbase },
+    {  "123",  "0173", ios::oct | ios::showbase | ios::uppercase },
+    { "-123", "-0173", ios::oct | ios::showbase },
+    { "-123", "-0173", ios::oct | ios::showbase | ios::uppercase },
+
+  };
+
+  size_t  i;
+  mpz_t   z;
+
+  mpz_init (z);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (z, data[i].z, 0);
+
+      if (option_check_standard
+	  && mpz_fits_slong_p (z)
+
+	  // no negatives or showpos in hex or oct
+	  && (((data[i].flags & ios::basefield) == ios::hex
+	       || (data[i].flags & ios::basefield) == ios::oct)
+	      ? (mpz_sgn (z) >= 0
+		 && ! (data[i].flags & ios::showpos))
+	      : 1)
+	  )
+	{
+	  ostringstream  got;
+	  long  n = mpz_get_si (z);
+	  CALL (got << n);
+	  if (got.str().compare (data[i].want) != 0)
+	    {
+	      cout << "check_mpz data[" << i
+		   << "] doesn't match standard ostream output\n";
+	      cout << "  z:     " << data[i].z << "\n";
+	      cout << "  n:     " << n << "\n";
+	      DUMP ();
+	    }
+	}
+
+      {
+	ostringstream  got;
+	CALL (got << z);
+	if (got.str().compare (data[i].want) != 0)
+	  {
+	    cout << "mpz operator<< wrong, data[" << i << "]\n";
+	    cout << "  z:     " << data[i].z << "\n";
+	    ABORT ();
+	  }
+      }
+    }
+
+  mpz_clear (z);
+}
+
+void
+check_mpq (void)
+{
+  static const struct {
+    const char     *q;
+    const char     *want;
+    ios::fmtflags  flags;
+    int            width;
+    int            precision;
+    char           fill;
+
+  } data[] = {
+
+    { "0", "0", ios::dec },
+    { "0", "0", ios::hex },
+    { "0", "0x0", ios::hex | ios::showbase },
+    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
+
+    { "5/8", "5/8", ios::dec },
+    { "5/8", "0X5/0X8", ios::hex | ios::showbase | ios::uppercase },
+
+    // zero denominator with showbase
+    { "0/0",   "       0/0", ios::oct | ios::showbase, 10 },
+    { "0/0",   "       0/0", ios::dec | ios::showbase, 10 },
+    { "0/0",   "   0x0/0x0", ios::hex | ios::showbase, 10 },
+    { "123/0", "    0173/0", ios::oct | ios::showbase, 10 },
+    { "123/0", "     123/0", ios::dec | ios::showbase, 10 },
+    { "123/0", "  0x7b/0x0", ios::hex | ios::showbase, 10 },
+    { "123/0", "  0X7B/0X0", ios::hex | ios::showbase | ios::uppercase, 10 },
+    { "0/123", "    0/0173", ios::oct | ios::showbase, 10 },
+    { "0/123", "     0/123", ios::dec | ios::showbase, 10 },
+    { "0/123", "  0x0/0x7b", ios::hex | ios::showbase, 10 },
+    { "0/123", "  0X0/0X7B", ios::hex | ios::showbase | ios::uppercase, 10 },
+  };
+
+  size_t  i;
+  mpq_t   q;
+
+  mpq_init (q);
+
+#define mpq_integer_p(q)  (mpz_cmp_ui (mpq_denref(q), 1L) == 0)
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (q, data[i].q, 0);
+      MPZ_CHECK_FORMAT (mpq_numref (q));
+      MPZ_CHECK_FORMAT (mpq_denref (q));
+
+      if (option_check_standard
+	  && mpz_fits_slong_p (mpq_numref(q))
+	  && mpq_integer_p (q))
+	{
+	  ostringstream  got;
+	  long  n = mpz_get_si (mpq_numref(q));
+	  CALL (got << n);
+	  if (got.str().compare (data[i].want) != 0)
+	    {
+	      cout << "check_mpq data[" << i
+		   << "] doesn't match standard ostream output\n";
+	      cout << "  q:     " << data[i].q << "\n";
+	      cout << "  n:     " << n << "\n";
+	      DUMP ();
+	    }
+	}
+
+      {
+	ostringstream  got;
+	CALL (got << q);
+	if (got.str().compare (data[i].want) != 0)
+	  {
+	    cout << "mpq operator<< wrong, data[" << i << "]\n";
+	    cout << "  q:     " << data[i].q << "\n";
+	    ABORT ();
+	  }
+      }
+    }
+
+  mpq_clear (q);
+}
+
+
+void
+check_mpf (void)
+{
+  static const struct {
+    const char     *f;
+    const char     *want;
+    ios::fmtflags  flags;
+    int            width;
+    int            precision;
+    char           fill;
+
+  } data[] = {
+
+    { "0", "0",            ios::dec },
+    { "0", "+0",           ios::dec | ios::showpos },
+    { "0", "0.00000",      ios::dec | ios::showpoint },
+    { "0", "0",            ios::dec | ios::fixed },
+    { "0", "0.",           ios::dec | ios::fixed | ios::showpoint },
+    { "0", "0.000000e+00", ios::dec | ios::scientific },
+    { "0", "0.000000e+00", ios::dec | ios::scientific | ios::showpoint },
+
+    { "0", "0",          ios::dec, 0, 4 },
+    { "0", "0.000",      ios::dec | ios::showpoint, 0, 4 },
+    { "0", "0.0000",     ios::dec | ios::fixed, 0, 4 },
+    { "0", "0.0000",     ios::dec | ios::fixed | ios::showpoint, 0, 4 },
+    { "0", "0.0000e+00", ios::dec | ios::scientific, 0, 4 },
+    { "0", "0.0000e+00", ios::dec | ios::scientific | ios::showpoint, 0, 4 },
+
+    { "1", "1",       ios::dec },
+    { "1", "+1",      ios::dec | ios::showpos },
+    { "1", "1.00000", ios::dec | ios::showpoint },
+    { "1", "1",       ios::dec | ios::fixed },
+    { "1", "1.",      ios::dec | ios::fixed | ios::showpoint },
+    { "1", "1.000000e+00",   ios::dec | ios::scientific },
+    { "1", "1.000000e+00",  ios::dec | ios::scientific | ios::showpoint },
+
+    { "1", "1",          ios::dec,                   0, 4 },
+    { "1", "1.000",      ios::dec | ios::showpoint,  0, 4 },
+    { "1", "1.0000",     ios::dec | ios::fixed,      0, 4 },
+    { "1", "1.0000",     ios::dec | ios::fixed | ios::showpoint, 0, 4 },
+    { "1", "1.0000e+00", ios::dec | ios::scientific, 0, 4 },
+    { "1", "1.0000e+00", ios::dec | ios::scientific | ios::showpoint, 0, 4 },
+
+    { "-1", "-1",        ios::dec | ios::showpos },
+
+    { "-1", "  -1",      ios::dec, 4 },
+    { "-1", "-  1",      ios::dec | ios::internal, 4 },
+    { "-1", "-1  ",      ios::dec | ios::left, 4 },
+
+    { "-1", "  -0x1",    ios::hex | ios::showbase, 6 },
+    { "-1", "-0x  1",    ios::hex | ios::showbase | ios::internal, 6 },
+    { "-1", "-0x1  ",    ios::hex | ios::showbase | ios::left, 6 },
+
+    {    "1", "*********1", ios::dec, 10, 4, '*' },
+    { "1234", "******1234", ios::dec, 10, 4, '*' },
+    { "1234", "*****1234.", ios::dec | ios::showpoint, 10, 4, '*' },
+
+    { "12345", "1.23e+04", ios::dec, 0, 3 },
+
+    { "12345", "12345.", ios::dec | ios::fixed | ios::showpoint },
+
+    { "1.9999999",    "2",     ios::dec, 0, 1 },
+    { "1.0009999999", "1.001", ios::dec, 0, 4 },
+    { "1.0001",       "1",     ios::dec, 0, 4 },
+    { "1.0004",       "1",     ios::dec, 0, 4 },
+    { "1.000555",     "1.001", ios::dec, 0, 4 },
+
+    { "1.0002",       "1.000", ios::dec | ios::fixed, 0, 3 },
+    { "1.0008",       "1.001", ios::dec | ios::fixed, 0, 3 },
+
+    { "0", "0", ios::hex },
+    { "0", "0x0", ios::hex | ios::showbase },
+    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
+    { "123",   "7b", ios::hex },
+    { "123", "0x7b", ios::hex | ios::showbase },
+    { "123", "0X7B", ios::hex | ios::showbase | ios::uppercase },
+
+    { "0", "0.000@+00", ios::hex | ios::scientific, 0, 3 },
+    { "256", "1.000@+02", ios::hex | ios::scientific, 0, 3 },
+
+    { "123",   "7.b@+01", ios::hex | ios::scientific, 0, 1 },
+    { "123",   "7.B@+01", ios::hex | ios::scientific | ios::uppercase, 0, 1 },
+    { "123", "0x7.b@+01", ios::hex | ios::scientific | ios::showbase, 0, 1 },
+    { "123", "0X7.B@+01",
+      ios::hex | ios::scientific | ios::showbase | ios::uppercase, 0, 1 },
+
+    { "1099511627776", "1.0@+10", ios::hex | ios::scientific, 0, 1 },
+    { "1099511627776", "1.0@+10",
+      ios::hex | ios::scientific | ios::uppercase, 0, 1 },
+
+    { "0.0625", "1.00@-01", ios::hex | ios::scientific, 0, 2 },
+
+    { "0", "0", ios::oct },
+    { "123",  "173", ios::oct },
+    { "123", "0173", ios::oct | ios::showbase },
+
+    // octal showbase suppressed for 0
+    { "0", "0", ios::oct | ios::showbase },
+    { ".125",    "00.1",  ios::oct | ios::showbase, 0, 1 },
+    { ".015625", "00.01", ios::oct | ios::showbase, 0, 2 },
+    { ".125",    "00.1",  ios::fixed | ios::oct | ios::showbase, 0, 1 },
+    { ".015625", "0.0",   ios::fixed | ios::oct | ios::showbase, 0, 1 },
+    { ".015625", "00.01", ios::fixed | ios::oct | ios::showbase, 0, 2 },
+
+    {  "0.125",  "1.000000e-01", ios::oct | ios::scientific },
+    {  "0.125", "+1.000000e-01", ios::oct | ios::scientific | ios::showpos },
+    { "-0.125", "-1.000000e-01", ios::oct | ios::scientific },
+    { "-0.125", "-1.000000e-01", ios::oct | ios::scientific | ios::showpos },
+
+    { "0", "0.000e+00", ios::oct | ios::scientific, 0, 3 },
+    { "256",  "4.000e+02", ios::oct | ios::scientific, 0, 3 },
+    { "256", "04.000e+02", ios::oct | ios::scientific | ios::showbase, 0, 3 },
+    { "256",  "4.000E+02", ios::oct | ios::scientific | ios::uppercase, 0, 3 },
+    { "256", "04.000E+02",
+      ios::oct | ios::scientific | ios::showbase | ios::uppercase, 0, 3 },
+
+    { "16777216",    "1.000000e+08", ios::oct | ios::scientific },
+    { "16777216",    "1.000000E+08",
+      ios::oct | ios::scientific | ios::uppercase },
+    { "16777216",   "01.000000e+08",
+      ios::oct | ios::scientific | ios::showbase },
+    { "16777216",   "01.000000E+08",
+      ios::oct | ios::scientific | ios::showbase | ios::uppercase },
+    { "16777216",  "+01.000000e+08",
+      ios::oct | ios::scientific | ios::showbase | ios::showpos },
+    { "16777216",  "+01.000000E+08", ios::oct | ios::scientific
+      | ios::showbase | ios::showpos | ios::uppercase },
+    { "-16777216", "-01.000000e+08",
+      ios::oct | ios::scientific | ios::showbase | ios::showpos },
+    { "-16777216", "-01.000000E+08", ios::oct | ios::scientific
+      | ios::showbase | ios::showpos | ios::uppercase },
+
+  };
+
+  size_t  i;
+  mpf_t   f, f2;
+  double  d;
+
+  mpf_init (f);
+  mpf_init (f2);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (f, data[i].f, 0);
+
+      d = mpf_get_d (f);
+      mpf_set_d (f2, d);
+      if (option_check_standard && mpf_cmp (f, f2) == 0
+	  && ! (data[i].flags & (ios::hex | ios::oct | ios::showbase)))
+	{
+	  ostringstream  got;
+	  CALL (got << d);
+	  if (got.str().compare (data[i].want) != 0)
+	    {
+	      cout << "check_mpf data[" << i
+		   << "] doesn't match standard ostream output\n";
+	      cout << "  f:     " << data[i].f << "\n";
+	      cout << "  d:     " << d << "\n";
+	      DUMP ();
+	    }
+	}
+
+      {
+	ostringstream  got;
+	CALL (got << f);
+	if (got.str().compare (data[i].want) != 0)
+	  {
+	    cout << "mpf operator<< wrong, data[" << i << "]\n";
+	    cout << "  f:     " << data[i].f << "\n";
+	    ABORT ();
+	  }
+      }
+    }
+
+  mpf_clear (f);
+  mpf_clear (f2);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_check_standard = true;
+
+  tests_start ();
+
+  check_mpz ();
+  check_mpq ();
+  check_mpf ();
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/cxx/t-prec.cc b/tests/cxx/t-prec.cc
new file mode 100644
index 0000000..72fca72
--- /dev/null
+++ b/tests/cxx/t-prec.cc
@@ -0,0 +1,216 @@
+/* Test precision of mpf_class expressions.
+
+Copyright 2001-2003, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+const int
+small_prec = 64, medium_prec = 128, large_prec = 192, very_large_prec = 256;
+
+#define ASSERT_ALWAYS_PREC(a, s, prec) \
+{                                      \
+  mpf_srcptr _a = a.get_mpf_t();       \
+  mpf_class _b(s, prec);               \
+  mpf_srcptr _c = _b.get_mpf_t();      \
+  ASSERT_ALWAYS(mpf_eq(_a, _c, prec)); \
+}
+
+
+
+void
+check_mpf (void)
+{
+  mpf_set_default_prec(medium_prec);
+
+  // simple expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(1 / f, very_large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "0.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "     33333 33333 33333 33333 33333 333", very_large_prec);
+  }
+  {
+    mpf_class f(9.0, medium_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = 1 / f;
+    ASSERT_ALWAYS_PREC
+      (g, "0.11111 11111 11111 11111 11111 11111 11111 11111 11111 11111"
+       "     11111 11111 11111 11111 11111 111", very_large_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = 1 / f;
+    ASSERT_ALWAYS_PREC
+      (g, "0.06666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 667", very_large_prec);
+  }
+
+  // compound expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(-(-(-1 / f)), very_large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "-0.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33333 33333 33333 33333 333", very_large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec);
+    mpf_class h(0.0, very_large_prec);
+    h = 1/f + 1/g;
+    ASSERT_ALWAYS_PREC
+      (h, "0.44444 44444 44444 44444 44444 44444 44444 44444 44444 44444"
+       "     44444 44444 44444 44444 44444 444", very_large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec), h(15.0, large_prec);
+    mpf_class i(0.0, very_large_prec);
+    i = f / g + h;
+    ASSERT_ALWAYS_PREC
+      (i, "15.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33333 33333 33333 33333 3", very_large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(-(1 + f) / 3, very_large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "-1.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33333 33333 33333 33333 33", very_large_prec);
+  }
+  {
+    mpf_class f(9.0, medium_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = sqrt(1 / f);
+    ASSERT_ALWAYS_PREC
+      (g, "0.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "     33333 33333 33333 33333 33333 333", very_large_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = hypot(1 + 5 / f, 1.0);
+    ASSERT_ALWAYS_PREC
+      (g, "1.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 67", very_large_prec);
+  }
+
+  // compound assignments
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec);
+    mpf_class h(1.0, very_large_prec);
+    h -= f / g;
+    ASSERT_ALWAYS_PREC
+      (h, "0.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 667", very_large_prec);
+  }
+
+  // construction from expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(1 / f);
+    ASSERT_ALWAYS_PREC(g, "0.33333 33333 33333 33333", small_prec);
+  }
+  {
+    mpf_class f(9.0, medium_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(1 / f);
+    ASSERT_ALWAYS_PREC
+      (g, "0.11111 11111 11111 11111 11111 11111 11111 1111", medium_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(1 / f);
+    ASSERT_ALWAYS_PREC
+      (g, "0.06666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 6667", large_prec);
+  }
+
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec);
+    mpf_class h(0.0, very_large_prec);
+    h = mpf_class(f / g + 1, large_prec);
+    ASSERT_ALWAYS_PREC
+      (h, "1.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "     33333 333",
+       large_prec);
+  }
+
+  // mixed mpf/mpq expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = f - q;
+    ASSERT_ALWAYS_PREC
+      (g, "2.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 67", very_large_prec);
+  }
+
+  {
+    mpf_class f(3.0, small_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(f - q, large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "2.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 667",
+       large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(f - q);
+    ASSERT_ALWAYS_PREC
+      (g, "2.66666 66666 66666 66666 66666 66666 66666 667", medium_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(f + q);
+    ASSERT_ALWAYS_PREC
+      (g, "15.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33",
+       large_prec);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-rand.cc b/tests/cxx/t-rand.cc
new file mode 100644
index 0000000..d336d08
--- /dev/null
+++ b/tests/cxx/t-rand.cc
@@ -0,0 +1,148 @@
+/* Test gmp_randclass.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+/* all flavours of initialization */
+void
+check_randinit (void)
+{
+  {
+    gmp_randclass r(gmp_randinit_default);
+  }
+
+  {
+    mpz_class a(0);
+    unsigned long c = 0, m2exp = 8;
+    gmp_randclass r(gmp_randinit_lc_2exp, a, c, m2exp);
+  }
+
+  {
+    unsigned long m2exp = 64;
+    gmp_randclass r(gmp_randinit_lc_2exp_size, m2exp);
+  }
+
+  /* gmp_randinit_lc_2exp_size, with excessive size */
+  {
+    try {
+      unsigned long m2exp = ULONG_MAX;
+      gmp_randclass r(gmp_randinit_lc_2exp_size, m2exp);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (length_error&) {
+    }
+  }
+
+  {
+    gmp_randclass r(gmp_randinit_mt);
+  }
+
+  /* obsolete, but still available */
+  {
+    gmp_randalg_t alg = GMP_RAND_ALG_LC;
+    unsigned long m2exp = 64;
+    gmp_randclass r(alg, m2exp);
+  }
+  {
+    gmp_randalg_t alg = GMP_RAND_ALG_DEFAULT;
+    unsigned long m2exp = 64;
+    gmp_randclass r(alg, m2exp);
+  }
+  {
+    gmp_randalg_t alg = (gmp_randalg_t) 0;
+    unsigned long m2exp = 64;
+    gmp_randclass r(alg, m2exp);
+  }
+}
+
+void
+check_mpz (void)
+{
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(123);
+    unsigned int b = 256;
+    mpz_class c;
+    r.seed(a);
+    c = r.get_z_bits(b);
+  }
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(256);
+    unsigned long b = 123;
+    mpz_class c;
+    r.seed(b);
+    c = r.get_z_bits(a);
+  }
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(123), b(256);
+    mpz_class c;
+    r.seed(a);
+    c = r.get_z_range(b);
+  }
+}
+
+void
+check_mpf (void)
+{
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(123);
+    r.seed(a);
+    mpf_class b;
+    b = r.get_f();
+    mpf_class c(r.get_f());
+    ASSERT_ALWAYS (c.get_prec() == mpf_get_default_prec());
+    mpf_class d(r.get_f(),212);
+    ASSERT_ALWAYS (d.get_prec() >= 212);
+  }
+  {
+    gmp_randclass r(gmp_randinit_default);
+    int a = 123, b = 198;
+    r.seed(a);
+    mpf_class c;
+    c = r.get_f(b);
+    ASSERT_ALWAYS (c.get_prec() == mpf_get_default_prec());
+    mpf_class d(r.get_f(b));
+    ASSERT_ALWAYS (d.get_prec() >= 198);
+    mpf_class e(r.get_f(b)-r.get_f());
+    ASSERT_ALWAYS (e.get_prec() >= 198);
+    mpf_class f(r.get_f(60),300);
+    ASSERT_ALWAYS (f.get_prec() >= 300);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_randinit();
+  check_mpz();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-ternary.cc b/tests/cxx/t-ternary.cc
new file mode 100644
index 0000000..8d087fb
--- /dev/null
+++ b/tests/cxx/t-ternary.cc
@@ -0,0 +1,734 @@
+/* Test mp*_class ternary expressions.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+/* The various test cases are broken up into separate functions to keep down
+   compiler memory use.  They're static so that any mistakenly omitted from
+   main() will provoke warnings (under gcc -Wall at least).  */
+
+static void
+check_mpz_1 (void)
+{
+  // template<class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+}
+
+static void
+check_mpz_2 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, T, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+}
+
+static void
+check_mpz_3 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<T, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+}
+
+static void
+check_mpz_4 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr<mpz_t, T>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0;
+    mpz_class e;
+    e = a + b * (c + d); ASSERT_ALWAYS(e == 15);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0;
+    mpz_class e;
+    e = a - b * (c + d); ASSERT_ALWAYS(e == -13);
+  }
+}
+
+static void
+check_mpz_5 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4;
+    mpz_class e;
+    e = a + (b - d) * c; ASSERT_ALWAYS(e == -5);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4;
+    mpz_class e;
+    e = a - (b - d) * c; ASSERT_ALWAYS(e == 7);
+  }
+}
+
+static void
+check_mpz_6 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, U, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4;
+    mpz_class e;
+    e = a + (b + c) * d; ASSERT_ALWAYS(e == 21);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4;
+    mpz_class e;
+    e = a - (b + c) * d; ASSERT_ALWAYS(e == -19);
+  }
+}
+
+static void
+check_mpz_7 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<T, __gmp_expr<mpz_t, U>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = a + c * (b + d); ASSERT_ALWAYS(e == 19);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = a - c * (b + d); ASSERT_ALWAYS(e == -17);
+  }
+}
+
+static void
+check_mpz_8 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr<mpz_t, U>,
+  // Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4, e = 5;
+    mpz_class f;
+    f = a + (b - d) * (c + e); ASSERT_ALWAYS(f == -15);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4, e = 5;
+    mpz_class f;
+    f = a - (b - d) * (c + e); ASSERT_ALWAYS(f == 17);
+  }
+}
+
+static void
+check_mpz_9 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>,
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4;
+    mpz_class e;
+    e = (a + d) + b * c; ASSERT_ALWAYS(e == 11);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4;
+    mpz_class e;
+    e = (a + d) - b * c; ASSERT_ALWAYS(e == -1);
+  }
+}
+
+static void
+check_mpz_10 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>,
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, U, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = (a - c) + b * d; ASSERT_ALWAYS(e == 6);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = (a - c) - b * d; ASSERT_ALWAYS(e == -10);
+  }
+}
+
+static void
+check_mpz_11 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>,
+  // __gmp_expr<mpz_t, __gmp_binary_expr<U, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4;
+    mpz_class e;
+    e = (a - c) + d * b; ASSERT_ALWAYS(e == 6);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4;
+    mpz_class e;
+    e = (a - c) - d * b; ASSERT_ALWAYS(e == -10);
+  }
+}
+
+static void
+check_mpz_12 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr<mpz_t, U>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4, e = 5;
+    mpz_class f;
+    f = (a + d) + b * (c - e); ASSERT_ALWAYS(f == 1);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4, e = 5;
+    mpz_class f;
+    f = (a + d) - b * (c - e); ASSERT_ALWAYS(f == 9);
+  }
+}
+
+static void
+check_mpz_13 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, U>, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0;
+    mpz_class f;
+    f = (a - d) + (b + e) * c; ASSERT_ALWAYS(f == 18);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0;
+    mpz_class f;
+    f = (a - d) - (b + e) * c; ASSERT_ALWAYS(f == -24);
+  }
+
+}
+
+static void
+check_mpz_14 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, U>, V, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a + c) + (b + d) * e; ASSERT_ALWAYS(f == 34);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a + c) - (b + d) * e; ASSERT_ALWAYS(f == -26);
+  }
+}
+
+static void
+check_mpz_15 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<U, __gmp_expr<mpz_t, V>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a - c) + d * (b - e); ASSERT_ALWAYS(f == -14);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a - c) - d * (b - e); ASSERT_ALWAYS(f == 10);
+  }
+
+}
+
+static void
+check_mpz_16 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, U>, __gmp_expr<mpz_t, V>,
+  // Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0, f = 6.0;
+    mpz_class g;
+    g = (a + d) + (b - e) * (c + f); ASSERT_ALWAYS(g == -22);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0, f = 6.0;
+    mpz_class g;
+    g = (a + d) - (b - e) * (c + f); ASSERT_ALWAYS(g == 32);
+  }
+}
+
+static void
+check_mpz_17 (void)
+{
+  // template <class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, mpz_class, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b + c; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b - c; ASSERT_ALWAYS(d == 2);
+  }
+}
+
+static void
+check_mpz_18 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, T, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 11);
+  }
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 5);
+  }
+
+}
+
+static void
+check_mpz_19 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr
+  // <mpz_t, __gmp_binary_expr<T, mpz_class, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 11);
+  }
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 5);
+  }
+}
+
+static void
+check_mpz_20 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, __gmp_expr<mpz_t, T>, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0;
+    mpz_class e;
+    e = a * (b + d) + c; ASSERT_ALWAYS(e == 20);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0;
+    mpz_class e;
+    e = a * (b + d) - c; ASSERT_ALWAYS(e == 12);
+  }
+}
+
+static void
+check_mpz_21 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, mpz_class, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5;
+    mpz_class e;
+    e = (a - d) * b + c; ASSERT_ALWAYS(e == -5);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5;
+    mpz_class e;
+    e = (a - d) * b - c; ASSERT_ALWAYS(e == -13);
+  }
+}
+
+static void
+check_mpz_22 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, U, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5;
+    mpz_class e;
+    e = (a + c) * d + b; ASSERT_ALWAYS(e == 33);
+  }
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5;
+    mpz_class e;
+    e = (a + c) * d - b; ASSERT_ALWAYS(e == 27);
+  }
+}
+
+static void
+check_mpz_23 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <T, __gmp_expr<mpz_t, U>, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = c * (a + d) + b; ASSERT_ALWAYS(e == 31);
+  }
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = c * (a + d) - b; ASSERT_ALWAYS(e == 25);
+  }
+
+}
+
+static void
+check_mpz_24 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, __gmp_expr<mpz_t, U>, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5, e = 6;
+    mpz_class f;
+    f = (a - d) * (b + e) + c; ASSERT_ALWAYS(f == -23);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5, e = 6;
+    mpz_class f;
+    f = (a - d) * (b + e) - c; ASSERT_ALWAYS(f == -31);
+  }
+}
+
+static void
+check_mpz_25 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, mpz_class, Op1> >, __gmp_expr<mpz_t, T>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5;
+    mpz_class e;
+    e = a * b + (c - d); ASSERT_ALWAYS(e == 5);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5;
+    mpz_class e;
+    e = a * b - (c - d); ASSERT_ALWAYS(e == 7);
+  }
+}
+
+static void
+check_mpz_26 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, T, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = a * c + (b + d); ASSERT_ALWAYS(e == 16);
+  }
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = a * c - (b + d); ASSERT_ALWAYS(e == 0);
+  }
+}
+
+static void
+check_mpz_27 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <T, mpz_class, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5;
+    mpz_class e;
+    e = c * a + (b - d); ASSERT_ALWAYS(e == 6);
+  }
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5;
+    mpz_class e;
+    e = c * a - (b - d); ASSERT_ALWAYS(e == 10);
+  }
+}
+
+static void
+check_mpz_28 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, __gmp_expr<mpz_t, T>, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5, e = 6;
+    mpz_class f;
+    f = a * (b - d) + (c + e); ASSERT_ALWAYS(f == 6);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5, e = 6;
+    mpz_class f;
+    f = a * (b - d) - (c + e); ASSERT_ALWAYS(f == -14);
+  }
+}
+
+static void
+check_mpz_29 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, mpz_class, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0;
+    mpz_class f;
+    f = (a + d) * b + (c - e); ASSERT_ALWAYS(f == 19);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0;
+    mpz_class f;
+    f = (a + d) * b - (c - e); ASSERT_ALWAYS(f == 23);
+  }
+}
+
+static void
+check_mpz_30 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, U, Op1> >, __gmp_expr<mpz_t, V>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = (a + c) * d + (b + e); ASSERT_ALWAYS(f == 39);
+  }
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = (a + c) * d - (b + e); ASSERT_ALWAYS(f == 21);
+  }
+}
+
+static void
+check_mpz_31 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <T, __gmp_expr<mpz_t, U>, Op1> >, __gmp_expr<mpz_t, V>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = c * (a + d) + (b - e); ASSERT_ALWAYS(f == 25);
+  }
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = c * (a + d) - (b - e); ASSERT_ALWAYS(f == 31);
+  }
+}
+
+static void
+check_mpz_32 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, __gmp_expr<mpz_t, U>, Op1> >,
+  // __gmp_expr<mpz_t, V>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0, f = 7.0;
+    mpz_class g;
+    g = (a + d) * (b - e) + (c + f); ASSERT_ALWAYS(g == -10);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0, f = 7.0;
+    mpz_class g;
+    g = (a + d) * (b - e) - (c + f); ASSERT_ALWAYS(g == -32);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // currently there's no ternary mpq operation
+}
+
+void
+check_mpf (void)
+{
+  // currently there's no ternary mpf operation
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz_1 ();
+  check_mpz_2 ();
+  check_mpz_3 ();
+  check_mpz_4 ();
+  check_mpz_5 ();
+  check_mpz_6 ();
+  check_mpz_7 ();
+  check_mpz_8 ();
+  check_mpz_9 ();
+  check_mpz_10 ();
+  check_mpz_11 ();
+  check_mpz_12 ();
+  check_mpz_13 ();
+  check_mpz_14 ();
+  check_mpz_15 ();
+  check_mpz_16 ();
+  check_mpz_17 ();
+  check_mpz_18 ();
+  check_mpz_19 ();
+  check_mpz_20 ();
+  check_mpz_21 ();
+  check_mpz_22 ();
+  check_mpz_23 ();
+  check_mpz_24 ();
+  check_mpz_25 ();
+  check_mpz_26 ();
+  check_mpz_27 ();
+  check_mpz_28 ();
+  check_mpz_29 ();
+  check_mpz_30 ();
+  check_mpz_31 ();
+  check_mpz_32 ();
+
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/cxx/t-unary.cc b/tests/cxx/t-unary.cc
new file mode 100644
index 0000000..c7d8bf6
--- /dev/null
+++ b/tests/cxx/t-unary.cc
@@ -0,0 +1,132 @@
+/* Test mp*_class unary expressions.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(1);
+    mpz_class b(+a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpz_class a(2);
+    mpz_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+  {
+    mpz_class a(3);
+    mpz_class b;
+    b = ~a; ASSERT_ALWAYS(b == -4);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+  {
+    mpz_class a(1);
+    mpz_class b(-(-a)); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpz_class a(2);
+    mpz_class b;
+    b = -(-(-a)); ASSERT_ALWAYS(b == -2);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(1);
+    mpq_class b(+a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpq_class a(2);
+    mpq_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+  {
+    mpq_class a(1);
+    mpq_class b(-(-a)); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpq_class a(2);
+    mpq_class b;
+    b = -(-(-a)); ASSERT_ALWAYS(b == -2);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(1);
+    mpf_class b(+a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+  {
+    mpf_class a(1);
+    mpf_class b(-(-a)); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = -(-(-a)); ASSERT_ALWAYS(b == -2);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/tests/devel/gen-test-longlong_h.c b/tests/devel/gen-test-longlong_h.c
new file mode 100644
index 0000000..939c3f2
--- /dev/null
+++ b/tests/devel/gen-test-longlong_h.c
@@ -0,0 +1,140 @@
+/*
+Copyright 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+typedef unsigned long mp_limb_t; /* neat */
+
+void
+one (const char *op, size_t ind, mp_limb_t m0, mp_limb_t s0)
+{
+  printf ("static void f%zu(mp_limb_t*r1p,mp_limb_t*r0p){", ind);
+  printf ("mp_limb_t r1,r0;");
+  printf ("%s(r1,r0,0,%ld,0,%ld);", op, (long) m0, (long) s0);
+  printf ("*r1p=r1;*r0p=r0;");
+  printf ("}\n");
+}
+
+mp_limb_t ops[1000];
+
+enum what_t {ADD, SUB};
+
+int
+main (int argc, char **argv)
+{
+  size_t n_operands = 0;
+  size_t n_functions = 0;
+  const char *op;
+  enum what_t what;
+
+  if (argc == 2 && strcmp (argv[1], "add") == 0)
+    {
+      op = "add_ssaaaa";
+      what = ADD;
+    }
+  else if (argc == 2 && strcmp (argv[1], "sub") == 0)
+    {
+      op = "sub_ddmmss";
+      what = SUB;
+    }
+  else
+    {
+      fprintf (stderr, "what do yuo want me to do?\n");
+      exit (1);
+    }
+
+  for (int i = 0; i < 16; i++)
+    {
+      ops[n_operands++] = 1 << i;
+      ops[n_operands++] = -(1 << i);
+      ops[n_operands++] = (1 << i) - 1;
+      ops[n_operands++] = -(1 << i) - 1;
+    }
+
+  printf ("#include <stdlib.h>\n");
+  printf ("#include <stdio.h>\n");
+  printf ("#include \"gmp-impl.h\"\n");
+  printf ("#include \"longlong.h\"\n");
+
+  /* Print out ops[] definition.  */
+  printf ("static const int ops[%zu] = {\n", n_operands);
+  for (int i = 0; i < n_operands; i++)
+    {
+      printf ("%ld,", (long) ops[i]);
+      if ((i + 1) % 4 == 0)
+	puts ("");
+    }
+  printf ("};\n");
+
+  /* Generate functions and print them.  */
+  for (int i = 0; i < n_operands; i++)
+    {
+      for (int j = 0; j < n_operands; j++)
+	{
+	  one (op, n_functions++, ops[i], ops[j]);
+	}
+    }
+
+  /* Print out function pointer table.  */
+  printf ("typedef void (*func_t) (mp_limb_t*, mp_limb_t*);\n");
+  printf ("static const func_t funcs[%zu] = {\n", n_functions);
+  for (size_t i = 0; i < n_functions; i++)
+    {
+      printf ("f%zu,", i);
+      if ((i + 1) % 16 == 0)
+	puts ("");
+    }
+  printf ("};\n");
+
+  /* Print out table of reference results.  */
+  printf ("static const int ref[%zu][2] = {\n", n_functions);
+  for (int i = 0; i < n_operands; i++)
+    {
+      for (int j = 0; j < n_operands; j++)
+	{
+	  if (what == ADD)
+	    printf ("{%6ld,%2ld},", (long) ( ops[i] + ops[j]), (long) ((mp_limb_t) ((ops[i] + ops[j]) < ops[i])));
+	  else     /* SUB */
+	    printf ("{%6ld,%2ld},", (long) ( ops[i] - ops[j]), (long) (-(mp_limb_t) (ops[i] < ops[j])));
+	  if ((i * n_operands + j) % 8 == 0)
+	    puts ("");
+	}
+    }
+  printf ("};\n");
+
+  printf ("int main ()\n{\n");
+  printf ("  mp_limb_t r1, r0;\n");
+  printf ("  int err = 0;\n");
+  printf ("  size_t ind = 0;\n");
+  printf ("  for (size_t i = 0; i < %zu; i++)\n", n_functions);
+  printf ("    {\n");
+  printf ("      int ii = i / %zu, jj = i %% %zu;\n", n_operands, n_operands);
+  printf ("      funcs[i](&r1, &r0);\n");
+  printf ("      if (r0 != (mp_limb_signed_t) ref[ind][0] || r1 != (mp_limb_signed_t) ref[ind][1]) {\n");
+  printf ("         printf (\"error for f%%zu(%%d,%%d): want (%%d,%%d) got (%%d,%%d)\\n\", i, (int) ops[ii], (int) ops[jj], ref[ind][1], ref[ind][0], (int) r1, (int) r0);\n");
+  printf ("         err++;\n");
+  printf ("       }\n");
+  printf ("      ind++;\n");
+  printf ("    }\n");
+
+  printf ("  return err != 0;\n");
+  printf ("}\n");
+  return 0;
+}
diff --git a/tests/devel/primes.c b/tests/devel/primes.c
new file mode 100644
index 0000000..8e58962
--- /dev/null
+++ b/tests/devel/primes.c
@@ -0,0 +1,424 @@
+/*
+Copyright 2018-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Usage:
+
+   ./primes [p|c] [n0] <nMax>
+
+     Checks mpz_probab_prime_p(n, r) exhaustively, starting from n=n0
+     up to nMax.
+     If n0 * n0 > nMax, the intervall is sieved piecewise, else the
+     full intervall [0..nMax] is sieved at once.
+     With the parameter "p" (or nothing), tests all numbers. With "c"
+     only composites are tested.
+
+   ./primes n|N [n0] <nMax>
+
+     Checks mpz_nextprime() exhaustively, starting from n=n0 up to
+     nMax. With "n", only the sequence of primes is checked, with "N"
+     the function is tested on every number in the interval.
+
+     WARNING: The full intervall [0..nMax] is sieved at once, even if
+     only a piece is needed. This may require a lot of memory!
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+#define STOP(x) return (x)
+/* #define STOP(x) x */
+#define REPS 10
+/* #define TRACE(x,n) if ((n)>1) {x;} */
+#define TRACE(x,n)
+
+/* The full primesieve.c is included, just for block_resieve, that
+   is not exported ... */
+#undef gmp_primesieve
+#include "../../primesieve.c"
+
+#ifndef BLOCK_SIZE
+#define BLOCK_SIZE 2048
+#endif
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_fto_bit(n) / GMP_LIMB_BITS + 1; }
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if ((*__sieve & __mask) == 0)				\
+	{							\
+	  mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, *__sieve, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __sieve = (sieve) + __i / GMP_LIMB_BITS;			\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __sieve += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+mpz_t g;
+
+int something_wrong (mpz_t er, int exp)
+{
+  fprintf (stderr, "value = %lu , expected = %i\n", mpz_get_ui (er), exp);
+  return -1;
+}
+
+int
+check_pprime (unsigned long begin, unsigned long end, int composites)
+{
+  begin = (begin / 6U) * 6U;
+  for (;(begin < 2) & (begin <= end); ++begin)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("-%li ", begin),1);
+      if (mpz_probab_prime_p (g, REPS))
+	STOP (something_wrong (g, 0));
+    }
+  for (;(begin < 4) & (begin <= end); ++begin)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("+%li ", begin),2);
+      if (!composites && !mpz_probab_prime_p (g, REPS))
+	STOP (something_wrong (g, 1));
+    }
+  if (end > 4) {
+    if ((end > 10000) && (begin > end / begin))
+      {
+	mp_limb_t *sieve, *primes;
+	mp_size_t size_s, size_p, off;
+	unsigned long start;
+
+	mpz_set_ui (g, end);
+	mpz_sqrt (g, g);
+	start = mpz_get_ui (g) + GMP_LIMB_BITS;
+	size_p = primesieve_size (start);
+
+	primes = __GMP_ALLOCATE_FUNC_LIMBS (size_p);
+	gmp_primesieve (primes, start);
+
+	size_s = BLOCK_SIZE * 2;
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size_s);
+	off = n_cto_bit(begin);
+
+	do {
+	  TRACE (printf ("off =%li\n", off),3);
+	  block_resieve (sieve, BLOCK_SIZE, off, primes);
+	  TRACE (printf ("LOOP =%li - %li\n", id_to_n (off+1), id_to_n (off + BLOCK_SIZE * GMP_LIMB_BITS)),3);
+	  LOOP_ON_SIEVE_BEGIN (prime, off, off + BLOCK_SIZE * GMP_LIMB_BITS - 1,
+			       off, sieve);
+
+	  do {
+	    *(g->_mp_d) = begin;
+	    TRACE(printf ("-%li ", begin),1);
+	    if (mpz_probab_prime_p (g, REPS))
+	      STOP (something_wrong (g, 0));
+	    if ((begin & 0xff) == 0)
+	      {
+		spinner();
+		if ((begin & 0xfffffff) == 0)
+		  printf ("%li (0x%lx)\n", begin, begin);
+	      }
+	  } while (++begin < prime);
+
+	  *(g->_mp_d) = begin;
+	  TRACE(printf ("+%li ", begin),2);
+	  if (!composites && ! mpz_probab_prime_p (g, REPS))
+	    STOP (something_wrong (g, 1));
+	  ++begin;
+
+	  LOOP_ON_SIEVE_END;
+	  off += BLOCK_SIZE * GMP_LIMB_BITS;
+	} while (begin < end);
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size_s);
+	__GMP_FREE_FUNC_LIMBS (primes, size_p);
+      }
+    else
+      {
+	mp_limb_t *sieve;
+	mp_size_t size;
+	unsigned long start;
+
+	size = primesieve_size (end);
+
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
+	gmp_primesieve (sieve, end);
+	start = MAX (begin, 5) | 1;
+	LOOP_ON_SIEVE_BEGIN (prime, n_cto_bit(start),
+			     n_fto_bit (end), 0, sieve);
+
+	do {
+	  *(g->_mp_d) = begin;
+	  TRACE(printf ("-%li ", begin),1);
+	  if (mpz_probab_prime_p (g, REPS))
+	    STOP (something_wrong (g, 0));
+	  if ((begin & 0xff) == 0)
+	    {
+	      spinner();
+	      if ((begin & 0xfffffff) == 0)
+		printf ("%li (0x%lx)\n", begin, begin);
+	    }
+	} while (++begin < prime);
+
+	*(g->_mp_d) = begin;
+	TRACE(printf ("+%li ", begin),2);
+	if (!composites && ! mpz_probab_prime_p (g, REPS))
+	  STOP (something_wrong (g, 1));
+	++begin;
+
+	LOOP_ON_SIEVE_END;
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size);
+      }
+  }
+
+  for (;begin < end; ++begin)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("-%li ", begin),1);
+      if (mpz_probab_prime_p (g, REPS))
+	STOP (something_wrong (g, 0));
+    }
+
+  gmp_printf ("%Zd\n", g);
+  return 0;
+}
+
+int
+check_nprime (unsigned long begin, unsigned long end)
+{
+  if (begin < 2)
+    {
+      *(g->_mp_d) = begin;
+      g->_mp_size = begin;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, 2) != 0)
+	STOP (something_wrong (g, 2));
+      begin = mpz_get_ui (g);
+    }
+  if (begin < 3)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, 3) != 0)
+	STOP (something_wrong (g, 3));
+      begin = mpz_get_ui (g);
+    }
+  if (end > 4)
+      {
+	mp_limb_t *sieve;
+	mp_size_t size;
+	unsigned long start;
+
+	size = primesieve_size (end);
+
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
+	gmp_primesieve (sieve, end);
+	start = MAX (begin, 5) | 1;
+	*(g->_mp_d) = begin;
+	LOOP_ON_SIEVE_BEGIN (prime, n_cto_bit(start),
+			     n_fto_bit (end), 0, sieve);
+
+	mpz_nextprime (g, g);
+	if (mpz_cmp_ui (g, prime) != 0)
+	  STOP (something_wrong (g, prime));
+
+	if (prime - start > 200)
+	  {
+	    start = prime;
+	    spinner();
+	    if (prime - begin > 0xfffffff)
+	      {
+		begin = prime;
+		printf ("%li (0x%lx)\n", begin, begin);
+	      }
+	  }
+
+	LOOP_ON_SIEVE_END;
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size);
+      }
+
+  if (mpz_cmp_ui (g, end) < 0)
+    {
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, end) <= 0)
+	STOP (something_wrong (g, -1));
+    }
+
+  gmp_printf ("%Zd\n", g);
+  return 0;
+}
+
+int
+check_Nprime (unsigned long begin, unsigned long end)
+{
+  mpz_t op;
+  mpz_init_set_ui (op, end);
+
+  for (;begin < 2; ++begin)
+    {
+      *(op->_mp_d) = begin;
+      op->_mp_size = begin;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, op);
+      if (mpz_cmp_ui (g, 2) != 0)
+	STOP (something_wrong (g, 2));
+    }
+  if (begin < 3)
+    {
+      *(op->_mp_d) = begin;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, op);
+      if (mpz_cmp_ui (g, 3) != 0)
+	STOP (something_wrong (g, 3));
+      begin = 3;
+    }
+  if (end > 4)
+      {
+	mp_limb_t *sieve;
+	mp_size_t size;
+	unsigned long start;
+	unsigned long opl;
+
+	size = primesieve_size (end);
+
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
+	gmp_primesieve (sieve, end);
+	start = MAX (begin, 5) | 1;
+	opl = begin;
+	LOOP_ON_SIEVE_BEGIN (prime, n_cto_bit(start),
+			     n_fto_bit (end), 0, sieve);
+
+	do {
+	  *(op->_mp_d) = opl;
+	  mpz_nextprime (g, op);
+	  if (mpz_cmp_ui (g, prime) != 0)
+	    STOP (something_wrong (g, prime));
+	  ++opl;
+	} while (opl < prime);
+
+	if (prime - start > 200)
+	  {
+	    start = prime;
+	    spinner();
+	    if (prime - begin > 0xfffffff)
+	      {
+		begin = prime;
+		printf ("%li (0x%lx)\n", begin, begin);
+	      }
+	  }
+
+	LOOP_ON_SIEVE_END;
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size);
+      }
+
+  if (mpz_cmp_ui (g, end) < 0)
+    {
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, end) <= 0)
+	STOP (something_wrong (g, -1));
+    }
+
+  gmp_printf ("%Zd\n", g);
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int ret, mode = 0;
+  unsigned long begin = 0, end = 0;
+
+  for (;argc > 1;--argc,++argv)
+    switch (*argv[1]) {
+    case 'p':
+      mode = 0;
+      break;
+    case 'c':
+      mode = 2;
+      break;
+    case 'n':
+      mode = 1;
+      break;
+    case 'N':
+      mode = 3;
+      break;
+    default:
+      begin = end;
+      end = atol (argv[1]);
+    }
+
+  if (begin >= end)
+    {
+      fprintf (stderr, "usage: primes [N|n|p|c] [n0] <nMax>\n");
+      exit (1);
+    }
+
+  mpz_init_set_ui (g, ULONG_MAX);
+
+  switch (mode) {
+  case 1:
+    ret = check_nprime (begin, end);
+    break;
+  case 3:
+    ret = check_Nprime (begin, end);
+    break;
+  default:
+    ret = check_pprime (begin, end, mode);
+  }
+
+  mpz_clear (g);
+
+  if (ret == 0)
+    printf ("Prime tests checked in [%lu - %lu] [0x%lx - 0x%lx].\n", begin, end, begin, end);
+  return ret;
+}
diff --git a/tests/devel/sqrtrem_1_2.c b/tests/devel/sqrtrem_1_2.c
new file mode 100644
index 0000000..3951191
--- /dev/null
+++ b/tests/devel/sqrtrem_1_2.c
@@ -0,0 +1,401 @@
+/*
+Copyright 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Usage:
+
+   ./sqrtrem_1_2 x
+
+     Checks mpn_sqrtrem() exhaustively, starting from 0, incrementing
+     the operand by a single unit, until all values handled by
+     mpn_sqrtrem{1,2} are tested. SLOW.
+
+   ./sqrtrem_1_2 s 1
+
+     Checks some special cases for mpn_sqrtrem(). I.e. values of the form
+     2^k*i and 2^k*(i+1)-1, with k=2^n and 0<i<2^k, until all such values,
+     handled by mpn_sqrtrem{1,2}, are tested.
+     Currently supports only the test of values that fits in one limb.
+     Less slow than the exhaustive test.
+
+   ./sqrtrem_1_2 c
+
+     Checks all corner cases for mpn_sqrtrem(). I.e. values of the form
+     i*i and (i+1)*(i+1)-1, for each value of i, until all such values,
+     handled by mpn_sqrtrem{1,2}, are tested.
+     Slightly faster than the special cases test.
+
+   For larger values, use
+   ./try mpn_sqrtrem
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+#define STOP(x) return (x)
+/* #define STOP(x) x */
+#define SPINNER(v)					\
+  do {							\
+    MPN_SIZEINBASE_2EXP (spinner_count, q, v, 1);	\
+    --spinner_count;					\
+    spinner();						\
+  } while (0)
+
+int something_wrong (mp_limb_t er, mp_limb_t ec, mp_limb_t es)
+{
+  fprintf (stderr, "root = %lu , rem = {%lu , %lu}\n", (long unsigned) es,(long unsigned) ec,(long unsigned) er);
+  return -1;
+}
+
+int
+check_all_values (int justone, int quick)
+{
+  mp_limb_t es, mer, er, s[1], r[2], q[2];
+  mp_size_t x;
+  unsigned bits;
+
+  es=1;
+  if (quick) {
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+    es <<= GMP_NUMB_BITS / 2 - 1;
+  }
+  er=0;
+  mer= es << 1;
+  *q = es * es;
+  printf ("All values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 1);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (UNLIKELY (er == mer)) {
+      ++es;
+      if (UNLIKELY ((es & 0xff) == 0))
+	SPINNER(1);
+      mer +=2; /* mer = es * 2 */
+      er = 0;
+    } else
+      ++er;
+    ++*q;
+  } while (*q != 0);
+  q[1] = 1;
+  SPINNER(2);
+  printf ("\nValues of a single limb, tested.\n");
+  if (justone) return 0;
+  printf ("All values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (UNLIKELY (er == mer)) {
+      ++es;
+      if (UNLIKELY ((es & 0x7f) == 0))
+	SPINNER(2);
+      mer +=2; /* mer = es * 2 */
+      if (UNLIKELY (mer == 0))
+	break;
+      er = 0;
+    } else
+      ++er;
+    q[1] += (++*q == 0);
+  } while (1);
+  SPINNER(2);
+  printf ("\nValues with at most a limb for reminder, tested.\n");
+  printf ("Testing more values not supported, jet.\n");
+  return 0;
+}
+
+mp_limb_t
+upd (mp_limb_t *s, mp_limb_t k)
+{
+  mp_limb_t _s = *s;
+
+  while (k > _s * 2)
+    {
+      k -= _s * 2 + 1;
+      ++_s;
+    }
+  *s = _s;
+  return k;
+}
+
+mp_limb_t
+upd1 (mp_limb_t *s, mp_limb_t k)
+{
+  mp_limb_t _s = *s;
+
+  if (LIKELY (k < _s * 2)) return k + 1;
+  *s = _s + 1;
+  return k - _s * 2;
+}
+
+int
+check_some_values (int justone, int quick)
+{
+  mp_limb_t es, her, er, k, s[1], r[2], q[2];
+  mp_size_t x;
+  unsigned bits;
+
+  es = 1 << 1;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 4 - 1;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS / 2);
+  }
+  er = 0;
+  *q = es * es;
+  printf ("High-half values tested, up to bits:\n");
+  do {
+    k  = *q - 1;
+    do {
+      x = mpn_sqrtrem (s, r, q, 1);
+      if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	  || UNLIKELY ((x == 1) && (er != *r)))
+	STOP (something_wrong (er, 0, es));
+
+      if (UNLIKELY ((es & 0xffff) == 0))
+	SPINNER(1);
+      if ((*q & k) == 0) {
+	*q |= k;
+	er = upd (&es, k + er);
+      } else {
+	++*q;
+	er = upd1 (&es, er);
+      }
+    } while (es & k);
+  } while (*q != 0);
+  q[1] = 1;
+  SPINNER(2);
+  printf ("\nValues of a single limb, tested.\n");
+  if (justone) return 0;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 2 - 1;
+    q[1] <<= GMP_NUMB_BITS - 2;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+  }
+  printf ("High-half values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (*q == 0) {
+      *q = GMP_NUMB_MAX;
+      if (UNLIKELY ((es & 0xffff) == 0)) {
+	if (UNLIKELY (es == GMP_NUMB_HIGHBIT))
+	  break;
+	SPINNER(2);
+      }
+      /* er = er + GMP_NUMB_MAX - 1 - es*2 // postponed */
+      ++es;
+      /* er = er + GMP_NUMB_MAX - 1 - 2*(es-1) =
+            = er +(GMP_NUMB_MAX + 1)- 2* es = er - 2*es */
+      er = upd (&es, er - 2 * es);
+    } else {
+      *q = 0;
+      ++q[1];
+      er = upd1 (&es, er);
+    }
+  } while (1);
+  SPINNER(2);
+  printf ("\nValues with at most a limb for reminder, tested.\n");
+  er = GMP_NUMB_MAX; her = 0;
+
+  printf ("High-half values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (her?2:(er != 0))) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x != 0) && ((er != *r) || ((x == 2) && (r[1] != 1)))))
+      STOP (something_wrong (er, her, es));
+
+    if (*q == 0) {
+      *q = GMP_NUMB_MAX;
+      if (UNLIKELY ((es & 0xffff) == 0)) {
+	SPINNER(2);
+      }
+      if (her) {
+	++es;
+	her = 0;
+	er = er - 2 * es;
+      } else {
+	her = --er != GMP_NUMB_MAX;
+	if (her & (er > es * 2)) {
+	  er -= es * 2 + 1;
+	  her = 0;
+	  ++es;
+	}
+      }
+    } else {
+      *q = 0;
+      if (++q[1] == 0) break;
+      if ((her == 0) | (er < es * 2)) {
+	her += ++er == 0;
+      }	else {
+	  er -= es * 2;
+	  her = 0;
+	  ++es;
+      }
+    }
+  } while (1);
+  printf ("| %u\nValues of at most two limbs, tested.\n", GMP_NUMB_BITS*2);
+  return 0;
+}
+
+int
+check_corner_cases (int justone, int quick)
+{
+  mp_limb_t es, er, s[1], r[2], q[2];
+  mp_size_t x;
+  unsigned bits;
+
+  es = 1;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 2 - 1;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+  }
+  er = 0;
+  *q = es*es;
+  printf ("Corner cases tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 1);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (er != 0) {
+      ++es;
+      if (UNLIKELY ((es & 0xffff) == 0))
+	SPINNER(1);
+      er = 0;
+      ++*q;
+    } else {
+      er = es * 2;
+      *q += er;
+    }
+  } while (*q != 0);
+  q[1] = 1;
+  SPINNER(2);
+  printf ("\nValues of a single limb, tested.\n");
+  if (justone) return 0;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 2 - 1;
+    q[1] <<= GMP_NUMB_BITS - 2;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+    --es;
+    --q[1];
+    q[0] -= es*2+1;
+  }
+  printf ("Corner cases tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (er != 0) {
+      ++es;
+      if (UNLIKELY ((es & 0xff) == 0))
+	SPINNER(2);
+      er = 0;
+      q[1] += (++*q == 0);
+      if (UNLIKELY (es == GMP_NUMB_HIGHBIT))
+	break;
+    } else {
+      er = es * 2;
+      add_ssaaaa (q[1], *q, q[1], *q, 0, er);
+    }
+  } while (1);
+  SPINNER(2);
+  printf ("\nValues with at most a limb for reminder, tested.\nCorner cases tested, up to bits:\n");
+  x = mpn_sqrtrem (s, r, q, 2);
+  if ((*s != es) || (x != 0))
+    STOP (something_wrong (0, 0, es));
+  q[1] += 1;
+  x = mpn_sqrtrem (s, r, q, 2);
+  if ((*s != es) || (x != 2) || (*r != 0) || (r[1] != 1))
+    STOP (something_wrong (0, 1, es));
+  ++es;
+  q[1] += (++*q == 0);
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0) * 2) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 2) && ((er != *r) || (r[1] != 1))))
+      STOP (something_wrong (er, er != 0, es));
+
+    if (er != 0) {
+      ++es;
+      if (UNLIKELY (es == 0))
+	break;
+      if (UNLIKELY ((es & 0xff) == 0))
+	SPINNER(2);
+      er = 0;
+      q[1] += (++*q == 0);
+    } else {
+      er = es * 2;
+      add_ssaaaa (q[1], *q, q[1], *q, 1, er);
+    }
+  } while (1);
+  printf ("| %u\nValues of at most two limbs, tested.\n", GMP_NUMB_BITS*2);
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int mode = 0;
+  int justone = 0;
+  int quick = 0;
+
+  for (;argc > 1;--argc,++argv)
+    switch (*argv[1]) {
+    default:
+      fprintf (stderr, "usage: sqrtrem_1_2 [x|c|s] [1|2] [q]\n");
+      exit (1);
+    case 'x':
+      mode = 0;
+      break;
+    case 'c':
+      mode = 1;
+      break;
+    case 's':
+      mode = 2;
+      break;
+    case 'q':
+      quick = 1;
+      break;
+    case '1':
+      justone = 1;
+      break;
+    case '2':
+      justone = 0;
+    }
+
+  switch (mode) {
+  default:
+    return check_all_values (justone, quick);
+  case 1:
+    return check_corner_cases (justone, quick);
+  case 2:
+    return check_some_values (justone, quick);
+  }
+}
diff --git a/tests/devel/test-add_ssaaaa.c b/tests/devel/test-add_ssaaaa.c
new file mode 100644
index 0000000..b5714f2
--- /dev/null
+++ b/tests/devel/test-add_ssaaaa.c
@@ -0,0 +1,4908 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+static const int ops[64] = {
+1,-1,0,-2,
+2,-2,1,-3,
+4,-4,3,-5,
+8,-8,7,-9,
+16,-16,15,-17,
+32,-32,31,-33,
+64,-64,63,-65,
+128,-128,127,-129,
+256,-256,255,-257,
+512,-512,511,-513,
+1024,-1024,1023,-1025,
+2048,-2048,2047,-2049,
+4096,-4096,4095,-4097,
+8192,-8192,8191,-8193,
+16384,-16384,16383,-16385,
+32768,-32768,32767,-32769,
+};
+static void f0(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f1(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-1);*r1p=r1;*r0p=r0;}
+static void f2(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,0);*r1p=r1;*r0p=r0;}
+static void f3(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f4(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,2);*r1p=r1;*r0p=r0;}
+static void f5(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f6(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f7(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-3);*r1p=r1;*r0p=r0;}
+static void f8(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,4);*r1p=r1;*r0p=r0;}
+static void f9(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-4);*r1p=r1;*r0p=r0;}
+static void f10(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,3);*r1p=r1;*r0p=r0;}
+static void f11(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-5);*r1p=r1;*r0p=r0;}
+static void f12(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,8);*r1p=r1;*r0p=r0;}
+static void f13(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-8);*r1p=r1;*r0p=r0;}
+static void f14(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,7);*r1p=r1;*r0p=r0;}
+static void f15(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-9);*r1p=r1;*r0p=r0;}
+static void f16(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,16);*r1p=r1;*r0p=r0;}
+static void f17(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-16);*r1p=r1;*r0p=r0;}
+static void f18(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,15);*r1p=r1;*r0p=r0;}
+static void f19(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-17);*r1p=r1;*r0p=r0;}
+static void f20(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,32);*r1p=r1;*r0p=r0;}
+static void f21(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-32);*r1p=r1;*r0p=r0;}
+static void f22(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,31);*r1p=r1;*r0p=r0;}
+static void f23(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-33);*r1p=r1;*r0p=r0;}
+static void f24(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,64);*r1p=r1;*r0p=r0;}
+static void f25(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-64);*r1p=r1;*r0p=r0;}
+static void f26(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,63);*r1p=r1;*r0p=r0;}
+static void f27(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-65);*r1p=r1;*r0p=r0;}
+static void f28(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,128);*r1p=r1;*r0p=r0;}
+static void f29(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-128);*r1p=r1;*r0p=r0;}
+static void f30(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,127);*r1p=r1;*r0p=r0;}
+static void f31(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-129);*r1p=r1;*r0p=r0;}
+static void f32(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,256);*r1p=r1;*r0p=r0;}
+static void f33(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-256);*r1p=r1;*r0p=r0;}
+static void f34(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,255);*r1p=r1;*r0p=r0;}
+static void f35(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-257);*r1p=r1;*r0p=r0;}
+static void f36(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,512);*r1p=r1;*r0p=r0;}
+static void f37(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-512);*r1p=r1;*r0p=r0;}
+static void f38(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,511);*r1p=r1;*r0p=r0;}
+static void f39(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-513);*r1p=r1;*r0p=r0;}
+static void f40(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1024);*r1p=r1;*r0p=r0;}
+static void f41(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-1024);*r1p=r1;*r0p=r0;}
+static void f42(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1023);*r1p=r1;*r0p=r0;}
+static void f43(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-1025);*r1p=r1;*r0p=r0;}
+static void f44(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,2048);*r1p=r1;*r0p=r0;}
+static void f45(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2048);*r1p=r1;*r0p=r0;}
+static void f46(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,2047);*r1p=r1;*r0p=r0;}
+static void f47(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2049);*r1p=r1;*r0p=r0;}
+static void f48(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,4096);*r1p=r1;*r0p=r0;}
+static void f49(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-4096);*r1p=r1;*r0p=r0;}
+static void f50(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,4095);*r1p=r1;*r0p=r0;}
+static void f51(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-4097);*r1p=r1;*r0p=r0;}
+static void f52(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,8192);*r1p=r1;*r0p=r0;}
+static void f53(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-8192);*r1p=r1;*r0p=r0;}
+static void f54(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,8191);*r1p=r1;*r0p=r0;}
+static void f55(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-8193);*r1p=r1;*r0p=r0;}
+static void f56(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,16384);*r1p=r1;*r0p=r0;}
+static void f57(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-16384);*r1p=r1;*r0p=r0;}
+static void f58(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,16383);*r1p=r1;*r0p=r0;}
+static void f59(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-16385);*r1p=r1;*r0p=r0;}
+static void f60(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,32768);*r1p=r1;*r0p=r0;}
+static void f61(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-32768);*r1p=r1;*r0p=r0;}
+static void f62(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,32767);*r1p=r1;*r0p=r0;}
+static void f63(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-32769);*r1p=r1;*r0p=r0;}
+static void f64(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,1);*r1p=r1;*r0p=r0;}
+static void f65(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-1);*r1p=r1;*r0p=r0;}
+static void f66(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,0);*r1p=r1;*r0p=r0;}
+static void f67(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-2);*r1p=r1;*r0p=r0;}
+static void f68(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,2);*r1p=r1;*r0p=r0;}
+static void f69(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-2);*r1p=r1;*r0p=r0;}
+static void f70(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,1);*r1p=r1;*r0p=r0;}
+static void f71(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-3);*r1p=r1;*r0p=r0;}
+static void f72(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,4);*r1p=r1;*r0p=r0;}
+static void f73(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-4);*r1p=r1;*r0p=r0;}
+static void f74(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,3);*r1p=r1;*r0p=r0;}
+static void f75(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-5);*r1p=r1;*r0p=r0;}
+static void f76(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,8);*r1p=r1;*r0p=r0;}
+static void f77(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-8);*r1p=r1;*r0p=r0;}
+static void f78(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,7);*r1p=r1;*r0p=r0;}
+static void f79(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-9);*r1p=r1;*r0p=r0;}
+static void f80(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,16);*r1p=r1;*r0p=r0;}
+static void f81(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-16);*r1p=r1;*r0p=r0;}
+static void f82(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,15);*r1p=r1;*r0p=r0;}
+static void f83(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-17);*r1p=r1;*r0p=r0;}
+static void f84(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,32);*r1p=r1;*r0p=r0;}
+static void f85(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-32);*r1p=r1;*r0p=r0;}
+static void f86(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,31);*r1p=r1;*r0p=r0;}
+static void f87(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-33);*r1p=r1;*r0p=r0;}
+static void f88(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,64);*r1p=r1;*r0p=r0;}
+static void f89(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-64);*r1p=r1;*r0p=r0;}
+static void f90(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,63);*r1p=r1;*r0p=r0;}
+static void f91(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-65);*r1p=r1;*r0p=r0;}
+static void f92(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,128);*r1p=r1;*r0p=r0;}
+static void f93(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-128);*r1p=r1;*r0p=r0;}
+static void f94(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,127);*r1p=r1;*r0p=r0;}
+static void f95(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-129);*r1p=r1;*r0p=r0;}
+static void f96(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,256);*r1p=r1;*r0p=r0;}
+static void f97(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-256);*r1p=r1;*r0p=r0;}
+static void f98(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,255);*r1p=r1;*r0p=r0;}
+static void f99(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-257);*r1p=r1;*r0p=r0;}
+static void f100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,512);*r1p=r1;*r0p=r0;}
+static void f101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-512);*r1p=r1;*r0p=r0;}
+static void f102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,511);*r1p=r1;*r0p=r0;}
+static void f103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-513);*r1p=r1;*r0p=r0;}
+static void f104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,1024);*r1p=r1;*r0p=r0;}
+static void f105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-1024);*r1p=r1;*r0p=r0;}
+static void f106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,1023);*r1p=r1;*r0p=r0;}
+static void f107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-1025);*r1p=r1;*r0p=r0;}
+static void f108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,2048);*r1p=r1;*r0p=r0;}
+static void f109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-2048);*r1p=r1;*r0p=r0;}
+static void f110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,2047);*r1p=r1;*r0p=r0;}
+static void f111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-2049);*r1p=r1;*r0p=r0;}
+static void f112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,4096);*r1p=r1;*r0p=r0;}
+static void f113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-4096);*r1p=r1;*r0p=r0;}
+static void f114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,4095);*r1p=r1;*r0p=r0;}
+static void f115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-4097);*r1p=r1;*r0p=r0;}
+static void f116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,8192);*r1p=r1;*r0p=r0;}
+static void f117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-8192);*r1p=r1;*r0p=r0;}
+static void f118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,8191);*r1p=r1;*r0p=r0;}
+static void f119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-8193);*r1p=r1;*r0p=r0;}
+static void f120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,16384);*r1p=r1;*r0p=r0;}
+static void f121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-16384);*r1p=r1;*r0p=r0;}
+static void f122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,16383);*r1p=r1;*r0p=r0;}
+static void f123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-16385);*r1p=r1;*r0p=r0;}
+static void f124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,32768);*r1p=r1;*r0p=r0;}
+static void f125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-32768);*r1p=r1;*r0p=r0;}
+static void f126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,32767);*r1p=r1;*r0p=r0;}
+static void f127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1,0,-32769);*r1p=r1;*r0p=r0;}
+static void f128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,1);*r1p=r1;*r0p=r0;}
+static void f129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-1);*r1p=r1;*r0p=r0;}
+static void f130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,0);*r1p=r1;*r0p=r0;}
+static void f131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-2);*r1p=r1;*r0p=r0;}
+static void f132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,2);*r1p=r1;*r0p=r0;}
+static void f133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-2);*r1p=r1;*r0p=r0;}
+static void f134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,1);*r1p=r1;*r0p=r0;}
+static void f135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-3);*r1p=r1;*r0p=r0;}
+static void f136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,4);*r1p=r1;*r0p=r0;}
+static void f137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-4);*r1p=r1;*r0p=r0;}
+static void f138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,3);*r1p=r1;*r0p=r0;}
+static void f139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-5);*r1p=r1;*r0p=r0;}
+static void f140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,8);*r1p=r1;*r0p=r0;}
+static void f141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-8);*r1p=r1;*r0p=r0;}
+static void f142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,7);*r1p=r1;*r0p=r0;}
+static void f143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-9);*r1p=r1;*r0p=r0;}
+static void f144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,16);*r1p=r1;*r0p=r0;}
+static void f145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-16);*r1p=r1;*r0p=r0;}
+static void f146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,15);*r1p=r1;*r0p=r0;}
+static void f147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-17);*r1p=r1;*r0p=r0;}
+static void f148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,32);*r1p=r1;*r0p=r0;}
+static void f149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-32);*r1p=r1;*r0p=r0;}
+static void f150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,31);*r1p=r1;*r0p=r0;}
+static void f151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-33);*r1p=r1;*r0p=r0;}
+static void f152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,64);*r1p=r1;*r0p=r0;}
+static void f153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-64);*r1p=r1;*r0p=r0;}
+static void f154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,63);*r1p=r1;*r0p=r0;}
+static void f155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-65);*r1p=r1;*r0p=r0;}
+static void f156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,128);*r1p=r1;*r0p=r0;}
+static void f157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-128);*r1p=r1;*r0p=r0;}
+static void f158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,127);*r1p=r1;*r0p=r0;}
+static void f159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-129);*r1p=r1;*r0p=r0;}
+static void f160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,256);*r1p=r1;*r0p=r0;}
+static void f161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-256);*r1p=r1;*r0p=r0;}
+static void f162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,255);*r1p=r1;*r0p=r0;}
+static void f163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-257);*r1p=r1;*r0p=r0;}
+static void f164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,512);*r1p=r1;*r0p=r0;}
+static void f165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-512);*r1p=r1;*r0p=r0;}
+static void f166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,511);*r1p=r1;*r0p=r0;}
+static void f167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-513);*r1p=r1;*r0p=r0;}
+static void f168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,1024);*r1p=r1;*r0p=r0;}
+static void f169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-1024);*r1p=r1;*r0p=r0;}
+static void f170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,1023);*r1p=r1;*r0p=r0;}
+static void f171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-1025);*r1p=r1;*r0p=r0;}
+static void f172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,2048);*r1p=r1;*r0p=r0;}
+static void f173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-2048);*r1p=r1;*r0p=r0;}
+static void f174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,2047);*r1p=r1;*r0p=r0;}
+static void f175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-2049);*r1p=r1;*r0p=r0;}
+static void f176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,4096);*r1p=r1;*r0p=r0;}
+static void f177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-4096);*r1p=r1;*r0p=r0;}
+static void f178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,4095);*r1p=r1;*r0p=r0;}
+static void f179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-4097);*r1p=r1;*r0p=r0;}
+static void f180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,8192);*r1p=r1;*r0p=r0;}
+static void f181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-8192);*r1p=r1;*r0p=r0;}
+static void f182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,8191);*r1p=r1;*r0p=r0;}
+static void f183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-8193);*r1p=r1;*r0p=r0;}
+static void f184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,16384);*r1p=r1;*r0p=r0;}
+static void f185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-16384);*r1p=r1;*r0p=r0;}
+static void f186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,16383);*r1p=r1;*r0p=r0;}
+static void f187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-16385);*r1p=r1;*r0p=r0;}
+static void f188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,32768);*r1p=r1;*r0p=r0;}
+static void f189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-32768);*r1p=r1;*r0p=r0;}
+static void f190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,32767);*r1p=r1;*r0p=r0;}
+static void f191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,0,0,-32769);*r1p=r1;*r0p=r0;}
+static void f192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-1);*r1p=r1;*r0p=r0;}
+static void f194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,0);*r1p=r1;*r0p=r0;}
+static void f195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,2);*r1p=r1;*r0p=r0;}
+static void f197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-3);*r1p=r1;*r0p=r0;}
+static void f200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,4);*r1p=r1;*r0p=r0;}
+static void f201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-4);*r1p=r1;*r0p=r0;}
+static void f202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,3);*r1p=r1;*r0p=r0;}
+static void f203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-5);*r1p=r1;*r0p=r0;}
+static void f204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,8);*r1p=r1;*r0p=r0;}
+static void f205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-8);*r1p=r1;*r0p=r0;}
+static void f206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,7);*r1p=r1;*r0p=r0;}
+static void f207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-9);*r1p=r1;*r0p=r0;}
+static void f208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,16);*r1p=r1;*r0p=r0;}
+static void f209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-16);*r1p=r1;*r0p=r0;}
+static void f210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,15);*r1p=r1;*r0p=r0;}
+static void f211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-17);*r1p=r1;*r0p=r0;}
+static void f212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,32);*r1p=r1;*r0p=r0;}
+static void f213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-32);*r1p=r1;*r0p=r0;}
+static void f214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,31);*r1p=r1;*r0p=r0;}
+static void f215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-33);*r1p=r1;*r0p=r0;}
+static void f216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,64);*r1p=r1;*r0p=r0;}
+static void f217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-64);*r1p=r1;*r0p=r0;}
+static void f218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,63);*r1p=r1;*r0p=r0;}
+static void f219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-65);*r1p=r1;*r0p=r0;}
+static void f220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,128);*r1p=r1;*r0p=r0;}
+static void f221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-128);*r1p=r1;*r0p=r0;}
+static void f222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,127);*r1p=r1;*r0p=r0;}
+static void f223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-129);*r1p=r1;*r0p=r0;}
+static void f224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,256);*r1p=r1;*r0p=r0;}
+static void f225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-256);*r1p=r1;*r0p=r0;}
+static void f226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,255);*r1p=r1;*r0p=r0;}
+static void f227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-257);*r1p=r1;*r0p=r0;}
+static void f228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,512);*r1p=r1;*r0p=r0;}
+static void f229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-512);*r1p=r1;*r0p=r0;}
+static void f230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,511);*r1p=r1;*r0p=r0;}
+static void f231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-513);*r1p=r1;*r0p=r0;}
+static void f232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1024);*r1p=r1;*r0p=r0;}
+static void f233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-1024);*r1p=r1;*r0p=r0;}
+static void f234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1023);*r1p=r1;*r0p=r0;}
+static void f235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-1025);*r1p=r1;*r0p=r0;}
+static void f236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,2048);*r1p=r1;*r0p=r0;}
+static void f237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2048);*r1p=r1;*r0p=r0;}
+static void f238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,2047);*r1p=r1;*r0p=r0;}
+static void f239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2049);*r1p=r1;*r0p=r0;}
+static void f240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,4096);*r1p=r1;*r0p=r0;}
+static void f241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-4096);*r1p=r1;*r0p=r0;}
+static void f242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,4095);*r1p=r1;*r0p=r0;}
+static void f243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-4097);*r1p=r1;*r0p=r0;}
+static void f244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,8192);*r1p=r1;*r0p=r0;}
+static void f245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-8192);*r1p=r1;*r0p=r0;}
+static void f246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,8191);*r1p=r1;*r0p=r0;}
+static void f247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-8193);*r1p=r1;*r0p=r0;}
+static void f248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,16384);*r1p=r1;*r0p=r0;}
+static void f249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-16384);*r1p=r1;*r0p=r0;}
+static void f250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,16383);*r1p=r1;*r0p=r0;}
+static void f251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-16385);*r1p=r1;*r0p=r0;}
+static void f252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,32768);*r1p=r1;*r0p=r0;}
+static void f253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-32768);*r1p=r1;*r0p=r0;}
+static void f254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,32767);*r1p=r1;*r0p=r0;}
+static void f255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-32769);*r1p=r1;*r0p=r0;}
+static void f256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,1);*r1p=r1;*r0p=r0;}
+static void f257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-1);*r1p=r1;*r0p=r0;}
+static void f258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,0);*r1p=r1;*r0p=r0;}
+static void f259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-2);*r1p=r1;*r0p=r0;}
+static void f260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,2);*r1p=r1;*r0p=r0;}
+static void f261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-2);*r1p=r1;*r0p=r0;}
+static void f262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,1);*r1p=r1;*r0p=r0;}
+static void f263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-3);*r1p=r1;*r0p=r0;}
+static void f264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,4);*r1p=r1;*r0p=r0;}
+static void f265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-4);*r1p=r1;*r0p=r0;}
+static void f266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,3);*r1p=r1;*r0p=r0;}
+static void f267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-5);*r1p=r1;*r0p=r0;}
+static void f268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,8);*r1p=r1;*r0p=r0;}
+static void f269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-8);*r1p=r1;*r0p=r0;}
+static void f270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,7);*r1p=r1;*r0p=r0;}
+static void f271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-9);*r1p=r1;*r0p=r0;}
+static void f272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,16);*r1p=r1;*r0p=r0;}
+static void f273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-16);*r1p=r1;*r0p=r0;}
+static void f274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,15);*r1p=r1;*r0p=r0;}
+static void f275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-17);*r1p=r1;*r0p=r0;}
+static void f276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,32);*r1p=r1;*r0p=r0;}
+static void f277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-32);*r1p=r1;*r0p=r0;}
+static void f278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,31);*r1p=r1;*r0p=r0;}
+static void f279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-33);*r1p=r1;*r0p=r0;}
+static void f280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,64);*r1p=r1;*r0p=r0;}
+static void f281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-64);*r1p=r1;*r0p=r0;}
+static void f282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,63);*r1p=r1;*r0p=r0;}
+static void f283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-65);*r1p=r1;*r0p=r0;}
+static void f284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,128);*r1p=r1;*r0p=r0;}
+static void f285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-128);*r1p=r1;*r0p=r0;}
+static void f286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,127);*r1p=r1;*r0p=r0;}
+static void f287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-129);*r1p=r1;*r0p=r0;}
+static void f288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,256);*r1p=r1;*r0p=r0;}
+static void f289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-256);*r1p=r1;*r0p=r0;}
+static void f290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,255);*r1p=r1;*r0p=r0;}
+static void f291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-257);*r1p=r1;*r0p=r0;}
+static void f292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,512);*r1p=r1;*r0p=r0;}
+static void f293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-512);*r1p=r1;*r0p=r0;}
+static void f294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,511);*r1p=r1;*r0p=r0;}
+static void f295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-513);*r1p=r1;*r0p=r0;}
+static void f296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,1024);*r1p=r1;*r0p=r0;}
+static void f297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-1024);*r1p=r1;*r0p=r0;}
+static void f298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,1023);*r1p=r1;*r0p=r0;}
+static void f299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-1025);*r1p=r1;*r0p=r0;}
+static void f300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,2048);*r1p=r1;*r0p=r0;}
+static void f301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-2048);*r1p=r1;*r0p=r0;}
+static void f302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,2047);*r1p=r1;*r0p=r0;}
+static void f303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-2049);*r1p=r1;*r0p=r0;}
+static void f304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,4096);*r1p=r1;*r0p=r0;}
+static void f305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-4096);*r1p=r1;*r0p=r0;}
+static void f306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,4095);*r1p=r1;*r0p=r0;}
+static void f307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-4097);*r1p=r1;*r0p=r0;}
+static void f308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,8192);*r1p=r1;*r0p=r0;}
+static void f309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-8192);*r1p=r1;*r0p=r0;}
+static void f310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,8191);*r1p=r1;*r0p=r0;}
+static void f311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-8193);*r1p=r1;*r0p=r0;}
+static void f312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,16384);*r1p=r1;*r0p=r0;}
+static void f313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-16384);*r1p=r1;*r0p=r0;}
+static void f314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,16383);*r1p=r1;*r0p=r0;}
+static void f315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-16385);*r1p=r1;*r0p=r0;}
+static void f316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,32768);*r1p=r1;*r0p=r0;}
+static void f317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-32768);*r1p=r1;*r0p=r0;}
+static void f318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,32767);*r1p=r1;*r0p=r0;}
+static void f319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2,0,-32769);*r1p=r1;*r0p=r0;}
+static void f320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-1);*r1p=r1;*r0p=r0;}
+static void f322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,0);*r1p=r1;*r0p=r0;}
+static void f323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,2);*r1p=r1;*r0p=r0;}
+static void f325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-3);*r1p=r1;*r0p=r0;}
+static void f328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,4);*r1p=r1;*r0p=r0;}
+static void f329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-4);*r1p=r1;*r0p=r0;}
+static void f330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,3);*r1p=r1;*r0p=r0;}
+static void f331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-5);*r1p=r1;*r0p=r0;}
+static void f332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,8);*r1p=r1;*r0p=r0;}
+static void f333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-8);*r1p=r1;*r0p=r0;}
+static void f334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,7);*r1p=r1;*r0p=r0;}
+static void f335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-9);*r1p=r1;*r0p=r0;}
+static void f336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,16);*r1p=r1;*r0p=r0;}
+static void f337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-16);*r1p=r1;*r0p=r0;}
+static void f338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,15);*r1p=r1;*r0p=r0;}
+static void f339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-17);*r1p=r1;*r0p=r0;}
+static void f340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,32);*r1p=r1;*r0p=r0;}
+static void f341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-32);*r1p=r1;*r0p=r0;}
+static void f342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,31);*r1p=r1;*r0p=r0;}
+static void f343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-33);*r1p=r1;*r0p=r0;}
+static void f344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,64);*r1p=r1;*r0p=r0;}
+static void f345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-64);*r1p=r1;*r0p=r0;}
+static void f346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,63);*r1p=r1;*r0p=r0;}
+static void f347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-65);*r1p=r1;*r0p=r0;}
+static void f348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,128);*r1p=r1;*r0p=r0;}
+static void f349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-128);*r1p=r1;*r0p=r0;}
+static void f350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,127);*r1p=r1;*r0p=r0;}
+static void f351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-129);*r1p=r1;*r0p=r0;}
+static void f352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,256);*r1p=r1;*r0p=r0;}
+static void f353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-256);*r1p=r1;*r0p=r0;}
+static void f354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,255);*r1p=r1;*r0p=r0;}
+static void f355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-257);*r1p=r1;*r0p=r0;}
+static void f356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,512);*r1p=r1;*r0p=r0;}
+static void f357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-512);*r1p=r1;*r0p=r0;}
+static void f358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,511);*r1p=r1;*r0p=r0;}
+static void f359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-513);*r1p=r1;*r0p=r0;}
+static void f360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1024);*r1p=r1;*r0p=r0;}
+static void f361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-1024);*r1p=r1;*r0p=r0;}
+static void f362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,1023);*r1p=r1;*r0p=r0;}
+static void f363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-1025);*r1p=r1;*r0p=r0;}
+static void f364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,2048);*r1p=r1;*r0p=r0;}
+static void f365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2048);*r1p=r1;*r0p=r0;}
+static void f366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,2047);*r1p=r1;*r0p=r0;}
+static void f367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-2049);*r1p=r1;*r0p=r0;}
+static void f368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,4096);*r1p=r1;*r0p=r0;}
+static void f369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-4096);*r1p=r1;*r0p=r0;}
+static void f370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,4095);*r1p=r1;*r0p=r0;}
+static void f371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-4097);*r1p=r1;*r0p=r0;}
+static void f372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,8192);*r1p=r1;*r0p=r0;}
+static void f373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-8192);*r1p=r1;*r0p=r0;}
+static void f374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,8191);*r1p=r1;*r0p=r0;}
+static void f375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-8193);*r1p=r1;*r0p=r0;}
+static void f376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,16384);*r1p=r1;*r0p=r0;}
+static void f377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-16384);*r1p=r1;*r0p=r0;}
+static void f378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,16383);*r1p=r1;*r0p=r0;}
+static void f379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-16385);*r1p=r1;*r0p=r0;}
+static void f380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,32768);*r1p=r1;*r0p=r0;}
+static void f381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-32768);*r1p=r1;*r0p=r0;}
+static void f382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,32767);*r1p=r1;*r0p=r0;}
+static void f383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2,0,-32769);*r1p=r1;*r0p=r0;}
+static void f384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-1);*r1p=r1;*r0p=r0;}
+static void f386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,0);*r1p=r1;*r0p=r0;}
+static void f387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,2);*r1p=r1;*r0p=r0;}
+static void f389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-3);*r1p=r1;*r0p=r0;}
+static void f392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,4);*r1p=r1;*r0p=r0;}
+static void f393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-4);*r1p=r1;*r0p=r0;}
+static void f394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,3);*r1p=r1;*r0p=r0;}
+static void f395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-5);*r1p=r1;*r0p=r0;}
+static void f396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,8);*r1p=r1;*r0p=r0;}
+static void f397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-8);*r1p=r1;*r0p=r0;}
+static void f398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,7);*r1p=r1;*r0p=r0;}
+static void f399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-9);*r1p=r1;*r0p=r0;}
+static void f400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,16);*r1p=r1;*r0p=r0;}
+static void f401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-16);*r1p=r1;*r0p=r0;}
+static void f402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,15);*r1p=r1;*r0p=r0;}
+static void f403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-17);*r1p=r1;*r0p=r0;}
+static void f404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,32);*r1p=r1;*r0p=r0;}
+static void f405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-32);*r1p=r1;*r0p=r0;}
+static void f406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,31);*r1p=r1;*r0p=r0;}
+static void f407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-33);*r1p=r1;*r0p=r0;}
+static void f408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,64);*r1p=r1;*r0p=r0;}
+static void f409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-64);*r1p=r1;*r0p=r0;}
+static void f410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,63);*r1p=r1;*r0p=r0;}
+static void f411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-65);*r1p=r1;*r0p=r0;}
+static void f412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,128);*r1p=r1;*r0p=r0;}
+static void f413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-128);*r1p=r1;*r0p=r0;}
+static void f414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,127);*r1p=r1;*r0p=r0;}
+static void f415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-129);*r1p=r1;*r0p=r0;}
+static void f416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,256);*r1p=r1;*r0p=r0;}
+static void f417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-256);*r1p=r1;*r0p=r0;}
+static void f418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,255);*r1p=r1;*r0p=r0;}
+static void f419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-257);*r1p=r1;*r0p=r0;}
+static void f420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,512);*r1p=r1;*r0p=r0;}
+static void f421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-512);*r1p=r1;*r0p=r0;}
+static void f422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,511);*r1p=r1;*r0p=r0;}
+static void f423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-513);*r1p=r1;*r0p=r0;}
+static void f424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1024);*r1p=r1;*r0p=r0;}
+static void f425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-1024);*r1p=r1;*r0p=r0;}
+static void f426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,1023);*r1p=r1;*r0p=r0;}
+static void f427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-1025);*r1p=r1;*r0p=r0;}
+static void f428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,2048);*r1p=r1;*r0p=r0;}
+static void f429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2048);*r1p=r1;*r0p=r0;}
+static void f430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,2047);*r1p=r1;*r0p=r0;}
+static void f431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-2049);*r1p=r1;*r0p=r0;}
+static void f432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,4096);*r1p=r1;*r0p=r0;}
+static void f433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-4096);*r1p=r1;*r0p=r0;}
+static void f434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,4095);*r1p=r1;*r0p=r0;}
+static void f435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-4097);*r1p=r1;*r0p=r0;}
+static void f436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,8192);*r1p=r1;*r0p=r0;}
+static void f437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-8192);*r1p=r1;*r0p=r0;}
+static void f438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,8191);*r1p=r1;*r0p=r0;}
+static void f439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-8193);*r1p=r1;*r0p=r0;}
+static void f440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,16384);*r1p=r1;*r0p=r0;}
+static void f441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-16384);*r1p=r1;*r0p=r0;}
+static void f442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,16383);*r1p=r1;*r0p=r0;}
+static void f443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-16385);*r1p=r1;*r0p=r0;}
+static void f444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,32768);*r1p=r1;*r0p=r0;}
+static void f445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-32768);*r1p=r1;*r0p=r0;}
+static void f446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,32767);*r1p=r1;*r0p=r0;}
+static void f447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1,0,-32769);*r1p=r1;*r0p=r0;}
+static void f448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,1);*r1p=r1;*r0p=r0;}
+static void f449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-1);*r1p=r1;*r0p=r0;}
+static void f450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,0);*r1p=r1;*r0p=r0;}
+static void f451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-2);*r1p=r1;*r0p=r0;}
+static void f452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,2);*r1p=r1;*r0p=r0;}
+static void f453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-2);*r1p=r1;*r0p=r0;}
+static void f454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,1);*r1p=r1;*r0p=r0;}
+static void f455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-3);*r1p=r1;*r0p=r0;}
+static void f456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,4);*r1p=r1;*r0p=r0;}
+static void f457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-4);*r1p=r1;*r0p=r0;}
+static void f458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,3);*r1p=r1;*r0p=r0;}
+static void f459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-5);*r1p=r1;*r0p=r0;}
+static void f460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,8);*r1p=r1;*r0p=r0;}
+static void f461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-8);*r1p=r1;*r0p=r0;}
+static void f462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,7);*r1p=r1;*r0p=r0;}
+static void f463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-9);*r1p=r1;*r0p=r0;}
+static void f464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,16);*r1p=r1;*r0p=r0;}
+static void f465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-16);*r1p=r1;*r0p=r0;}
+static void f466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,15);*r1p=r1;*r0p=r0;}
+static void f467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-17);*r1p=r1;*r0p=r0;}
+static void f468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,32);*r1p=r1;*r0p=r0;}
+static void f469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-32);*r1p=r1;*r0p=r0;}
+static void f470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,31);*r1p=r1;*r0p=r0;}
+static void f471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-33);*r1p=r1;*r0p=r0;}
+static void f472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,64);*r1p=r1;*r0p=r0;}
+static void f473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-64);*r1p=r1;*r0p=r0;}
+static void f474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,63);*r1p=r1;*r0p=r0;}
+static void f475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-65);*r1p=r1;*r0p=r0;}
+static void f476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,128);*r1p=r1;*r0p=r0;}
+static void f477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-128);*r1p=r1;*r0p=r0;}
+static void f478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,127);*r1p=r1;*r0p=r0;}
+static void f479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-129);*r1p=r1;*r0p=r0;}
+static void f480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,256);*r1p=r1;*r0p=r0;}
+static void f481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-256);*r1p=r1;*r0p=r0;}
+static void f482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,255);*r1p=r1;*r0p=r0;}
+static void f483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-257);*r1p=r1;*r0p=r0;}
+static void f484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,512);*r1p=r1;*r0p=r0;}
+static void f485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-512);*r1p=r1;*r0p=r0;}
+static void f486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,511);*r1p=r1;*r0p=r0;}
+static void f487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-513);*r1p=r1;*r0p=r0;}
+static void f488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,1024);*r1p=r1;*r0p=r0;}
+static void f489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-1024);*r1p=r1;*r0p=r0;}
+static void f490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,1023);*r1p=r1;*r0p=r0;}
+static void f491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-1025);*r1p=r1;*r0p=r0;}
+static void f492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,2048);*r1p=r1;*r0p=r0;}
+static void f493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-2048);*r1p=r1;*r0p=r0;}
+static void f494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,2047);*r1p=r1;*r0p=r0;}
+static void f495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-2049);*r1p=r1;*r0p=r0;}
+static void f496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,4096);*r1p=r1;*r0p=r0;}
+static void f497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-4096);*r1p=r1;*r0p=r0;}
+static void f498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,4095);*r1p=r1;*r0p=r0;}
+static void f499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-4097);*r1p=r1;*r0p=r0;}
+static void f500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,8192);*r1p=r1;*r0p=r0;}
+static void f501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-8192);*r1p=r1;*r0p=r0;}
+static void f502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,8191);*r1p=r1;*r0p=r0;}
+static void f503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-8193);*r1p=r1;*r0p=r0;}
+static void f504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,16384);*r1p=r1;*r0p=r0;}
+static void f505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-16384);*r1p=r1;*r0p=r0;}
+static void f506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,16383);*r1p=r1;*r0p=r0;}
+static void f507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-16385);*r1p=r1;*r0p=r0;}
+static void f508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,32768);*r1p=r1;*r0p=r0;}
+static void f509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-32768);*r1p=r1;*r0p=r0;}
+static void f510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,32767);*r1p=r1;*r0p=r0;}
+static void f511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-3,0,-32769);*r1p=r1;*r0p=r0;}
+static void f512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,1);*r1p=r1;*r0p=r0;}
+static void f513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-1);*r1p=r1;*r0p=r0;}
+static void f514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,0);*r1p=r1;*r0p=r0;}
+static void f515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-2);*r1p=r1;*r0p=r0;}
+static void f516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,2);*r1p=r1;*r0p=r0;}
+static void f517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-2);*r1p=r1;*r0p=r0;}
+static void f518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,1);*r1p=r1;*r0p=r0;}
+static void f519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-3);*r1p=r1;*r0p=r0;}
+static void f520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,4);*r1p=r1;*r0p=r0;}
+static void f521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-4);*r1p=r1;*r0p=r0;}
+static void f522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,3);*r1p=r1;*r0p=r0;}
+static void f523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-5);*r1p=r1;*r0p=r0;}
+static void f524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,8);*r1p=r1;*r0p=r0;}
+static void f525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-8);*r1p=r1;*r0p=r0;}
+static void f526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,7);*r1p=r1;*r0p=r0;}
+static void f527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-9);*r1p=r1;*r0p=r0;}
+static void f528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,16);*r1p=r1;*r0p=r0;}
+static void f529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-16);*r1p=r1;*r0p=r0;}
+static void f530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,15);*r1p=r1;*r0p=r0;}
+static void f531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-17);*r1p=r1;*r0p=r0;}
+static void f532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,32);*r1p=r1;*r0p=r0;}
+static void f533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-32);*r1p=r1;*r0p=r0;}
+static void f534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,31);*r1p=r1;*r0p=r0;}
+static void f535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-33);*r1p=r1;*r0p=r0;}
+static void f536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,64);*r1p=r1;*r0p=r0;}
+static void f537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-64);*r1p=r1;*r0p=r0;}
+static void f538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,63);*r1p=r1;*r0p=r0;}
+static void f539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-65);*r1p=r1;*r0p=r0;}
+static void f540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,128);*r1p=r1;*r0p=r0;}
+static void f541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-128);*r1p=r1;*r0p=r0;}
+static void f542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,127);*r1p=r1;*r0p=r0;}
+static void f543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-129);*r1p=r1;*r0p=r0;}
+static void f544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,256);*r1p=r1;*r0p=r0;}
+static void f545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-256);*r1p=r1;*r0p=r0;}
+static void f546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,255);*r1p=r1;*r0p=r0;}
+static void f547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-257);*r1p=r1;*r0p=r0;}
+static void f548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,512);*r1p=r1;*r0p=r0;}
+static void f549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-512);*r1p=r1;*r0p=r0;}
+static void f550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,511);*r1p=r1;*r0p=r0;}
+static void f551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-513);*r1p=r1;*r0p=r0;}
+static void f552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,1024);*r1p=r1;*r0p=r0;}
+static void f553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-1024);*r1p=r1;*r0p=r0;}
+static void f554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,1023);*r1p=r1;*r0p=r0;}
+static void f555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-1025);*r1p=r1;*r0p=r0;}
+static void f556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,2048);*r1p=r1;*r0p=r0;}
+static void f557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-2048);*r1p=r1;*r0p=r0;}
+static void f558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,2047);*r1p=r1;*r0p=r0;}
+static void f559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-2049);*r1p=r1;*r0p=r0;}
+static void f560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,4096);*r1p=r1;*r0p=r0;}
+static void f561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-4096);*r1p=r1;*r0p=r0;}
+static void f562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,4095);*r1p=r1;*r0p=r0;}
+static void f563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-4097);*r1p=r1;*r0p=r0;}
+static void f564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,8192);*r1p=r1;*r0p=r0;}
+static void f565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-8192);*r1p=r1;*r0p=r0;}
+static void f566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,8191);*r1p=r1;*r0p=r0;}
+static void f567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-8193);*r1p=r1;*r0p=r0;}
+static void f568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,16384);*r1p=r1;*r0p=r0;}
+static void f569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-16384);*r1p=r1;*r0p=r0;}
+static void f570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,16383);*r1p=r1;*r0p=r0;}
+static void f571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-16385);*r1p=r1;*r0p=r0;}
+static void f572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,32768);*r1p=r1;*r0p=r0;}
+static void f573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-32768);*r1p=r1;*r0p=r0;}
+static void f574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,32767);*r1p=r1;*r0p=r0;}
+static void f575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4,0,-32769);*r1p=r1;*r0p=r0;}
+static void f576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,1);*r1p=r1;*r0p=r0;}
+static void f577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-1);*r1p=r1;*r0p=r0;}
+static void f578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,0);*r1p=r1;*r0p=r0;}
+static void f579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-2);*r1p=r1;*r0p=r0;}
+static void f580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,2);*r1p=r1;*r0p=r0;}
+static void f581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-2);*r1p=r1;*r0p=r0;}
+static void f582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,1);*r1p=r1;*r0p=r0;}
+static void f583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-3);*r1p=r1;*r0p=r0;}
+static void f584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,4);*r1p=r1;*r0p=r0;}
+static void f585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-4);*r1p=r1;*r0p=r0;}
+static void f586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,3);*r1p=r1;*r0p=r0;}
+static void f587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-5);*r1p=r1;*r0p=r0;}
+static void f588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,8);*r1p=r1;*r0p=r0;}
+static void f589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-8);*r1p=r1;*r0p=r0;}
+static void f590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,7);*r1p=r1;*r0p=r0;}
+static void f591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-9);*r1p=r1;*r0p=r0;}
+static void f592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,16);*r1p=r1;*r0p=r0;}
+static void f593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-16);*r1p=r1;*r0p=r0;}
+static void f594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,15);*r1p=r1;*r0p=r0;}
+static void f595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-17);*r1p=r1;*r0p=r0;}
+static void f596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,32);*r1p=r1;*r0p=r0;}
+static void f597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-32);*r1p=r1;*r0p=r0;}
+static void f598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,31);*r1p=r1;*r0p=r0;}
+static void f599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-33);*r1p=r1;*r0p=r0;}
+static void f600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,64);*r1p=r1;*r0p=r0;}
+static void f601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-64);*r1p=r1;*r0p=r0;}
+static void f602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,63);*r1p=r1;*r0p=r0;}
+static void f603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-65);*r1p=r1;*r0p=r0;}
+static void f604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,128);*r1p=r1;*r0p=r0;}
+static void f605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-128);*r1p=r1;*r0p=r0;}
+static void f606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,127);*r1p=r1;*r0p=r0;}
+static void f607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-129);*r1p=r1;*r0p=r0;}
+static void f608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,256);*r1p=r1;*r0p=r0;}
+static void f609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-256);*r1p=r1;*r0p=r0;}
+static void f610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,255);*r1p=r1;*r0p=r0;}
+static void f611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-257);*r1p=r1;*r0p=r0;}
+static void f612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,512);*r1p=r1;*r0p=r0;}
+static void f613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-512);*r1p=r1;*r0p=r0;}
+static void f614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,511);*r1p=r1;*r0p=r0;}
+static void f615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-513);*r1p=r1;*r0p=r0;}
+static void f616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,1024);*r1p=r1;*r0p=r0;}
+static void f617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-1024);*r1p=r1;*r0p=r0;}
+static void f618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,1023);*r1p=r1;*r0p=r0;}
+static void f619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-1025);*r1p=r1;*r0p=r0;}
+static void f620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,2048);*r1p=r1;*r0p=r0;}
+static void f621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-2048);*r1p=r1;*r0p=r0;}
+static void f622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,2047);*r1p=r1;*r0p=r0;}
+static void f623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-2049);*r1p=r1;*r0p=r0;}
+static void f624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,4096);*r1p=r1;*r0p=r0;}
+static void f625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-4096);*r1p=r1;*r0p=r0;}
+static void f626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,4095);*r1p=r1;*r0p=r0;}
+static void f627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-4097);*r1p=r1;*r0p=r0;}
+static void f628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,8192);*r1p=r1;*r0p=r0;}
+static void f629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-8192);*r1p=r1;*r0p=r0;}
+static void f630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,8191);*r1p=r1;*r0p=r0;}
+static void f631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-8193);*r1p=r1;*r0p=r0;}
+static void f632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,16384);*r1p=r1;*r0p=r0;}
+static void f633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-16384);*r1p=r1;*r0p=r0;}
+static void f634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,16383);*r1p=r1;*r0p=r0;}
+static void f635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-16385);*r1p=r1;*r0p=r0;}
+static void f636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,32768);*r1p=r1;*r0p=r0;}
+static void f637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-32768);*r1p=r1;*r0p=r0;}
+static void f638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,32767);*r1p=r1;*r0p=r0;}
+static void f639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4,0,-32769);*r1p=r1;*r0p=r0;}
+static void f640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,1);*r1p=r1;*r0p=r0;}
+static void f641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-1);*r1p=r1;*r0p=r0;}
+static void f642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,0);*r1p=r1;*r0p=r0;}
+static void f643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-2);*r1p=r1;*r0p=r0;}
+static void f644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,2);*r1p=r1;*r0p=r0;}
+static void f645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-2);*r1p=r1;*r0p=r0;}
+static void f646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,1);*r1p=r1;*r0p=r0;}
+static void f647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-3);*r1p=r1;*r0p=r0;}
+static void f648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,4);*r1p=r1;*r0p=r0;}
+static void f649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-4);*r1p=r1;*r0p=r0;}
+static void f650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,3);*r1p=r1;*r0p=r0;}
+static void f651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-5);*r1p=r1;*r0p=r0;}
+static void f652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,8);*r1p=r1;*r0p=r0;}
+static void f653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-8);*r1p=r1;*r0p=r0;}
+static void f654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,7);*r1p=r1;*r0p=r0;}
+static void f655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-9);*r1p=r1;*r0p=r0;}
+static void f656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,16);*r1p=r1;*r0p=r0;}
+static void f657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-16);*r1p=r1;*r0p=r0;}
+static void f658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,15);*r1p=r1;*r0p=r0;}
+static void f659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-17);*r1p=r1;*r0p=r0;}
+static void f660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,32);*r1p=r1;*r0p=r0;}
+static void f661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-32);*r1p=r1;*r0p=r0;}
+static void f662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,31);*r1p=r1;*r0p=r0;}
+static void f663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-33);*r1p=r1;*r0p=r0;}
+static void f664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,64);*r1p=r1;*r0p=r0;}
+static void f665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-64);*r1p=r1;*r0p=r0;}
+static void f666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,63);*r1p=r1;*r0p=r0;}
+static void f667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-65);*r1p=r1;*r0p=r0;}
+static void f668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,128);*r1p=r1;*r0p=r0;}
+static void f669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-128);*r1p=r1;*r0p=r0;}
+static void f670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,127);*r1p=r1;*r0p=r0;}
+static void f671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-129);*r1p=r1;*r0p=r0;}
+static void f672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,256);*r1p=r1;*r0p=r0;}
+static void f673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-256);*r1p=r1;*r0p=r0;}
+static void f674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,255);*r1p=r1;*r0p=r0;}
+static void f675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-257);*r1p=r1;*r0p=r0;}
+static void f676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,512);*r1p=r1;*r0p=r0;}
+static void f677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-512);*r1p=r1;*r0p=r0;}
+static void f678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,511);*r1p=r1;*r0p=r0;}
+static void f679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-513);*r1p=r1;*r0p=r0;}
+static void f680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,1024);*r1p=r1;*r0p=r0;}
+static void f681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-1024);*r1p=r1;*r0p=r0;}
+static void f682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,1023);*r1p=r1;*r0p=r0;}
+static void f683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-1025);*r1p=r1;*r0p=r0;}
+static void f684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,2048);*r1p=r1;*r0p=r0;}
+static void f685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-2048);*r1p=r1;*r0p=r0;}
+static void f686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,2047);*r1p=r1;*r0p=r0;}
+static void f687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-2049);*r1p=r1;*r0p=r0;}
+static void f688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,4096);*r1p=r1;*r0p=r0;}
+static void f689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-4096);*r1p=r1;*r0p=r0;}
+static void f690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,4095);*r1p=r1;*r0p=r0;}
+static void f691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-4097);*r1p=r1;*r0p=r0;}
+static void f692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,8192);*r1p=r1;*r0p=r0;}
+static void f693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-8192);*r1p=r1;*r0p=r0;}
+static void f694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,8191);*r1p=r1;*r0p=r0;}
+static void f695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-8193);*r1p=r1;*r0p=r0;}
+static void f696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,16384);*r1p=r1;*r0p=r0;}
+static void f697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-16384);*r1p=r1;*r0p=r0;}
+static void f698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,16383);*r1p=r1;*r0p=r0;}
+static void f699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-16385);*r1p=r1;*r0p=r0;}
+static void f700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,32768);*r1p=r1;*r0p=r0;}
+static void f701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-32768);*r1p=r1;*r0p=r0;}
+static void f702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,32767);*r1p=r1;*r0p=r0;}
+static void f703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,3,0,-32769);*r1p=r1;*r0p=r0;}
+static void f704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,1);*r1p=r1;*r0p=r0;}
+static void f705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-1);*r1p=r1;*r0p=r0;}
+static void f706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,0);*r1p=r1;*r0p=r0;}
+static void f707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-2);*r1p=r1;*r0p=r0;}
+static void f708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,2);*r1p=r1;*r0p=r0;}
+static void f709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-2);*r1p=r1;*r0p=r0;}
+static void f710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,1);*r1p=r1;*r0p=r0;}
+static void f711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-3);*r1p=r1;*r0p=r0;}
+static void f712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,4);*r1p=r1;*r0p=r0;}
+static void f713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-4);*r1p=r1;*r0p=r0;}
+static void f714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,3);*r1p=r1;*r0p=r0;}
+static void f715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-5);*r1p=r1;*r0p=r0;}
+static void f716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,8);*r1p=r1;*r0p=r0;}
+static void f717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-8);*r1p=r1;*r0p=r0;}
+static void f718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,7);*r1p=r1;*r0p=r0;}
+static void f719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-9);*r1p=r1;*r0p=r0;}
+static void f720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,16);*r1p=r1;*r0p=r0;}
+static void f721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-16);*r1p=r1;*r0p=r0;}
+static void f722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,15);*r1p=r1;*r0p=r0;}
+static void f723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-17);*r1p=r1;*r0p=r0;}
+static void f724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,32);*r1p=r1;*r0p=r0;}
+static void f725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-32);*r1p=r1;*r0p=r0;}
+static void f726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,31);*r1p=r1;*r0p=r0;}
+static void f727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-33);*r1p=r1;*r0p=r0;}
+static void f728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,64);*r1p=r1;*r0p=r0;}
+static void f729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-64);*r1p=r1;*r0p=r0;}
+static void f730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,63);*r1p=r1;*r0p=r0;}
+static void f731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-65);*r1p=r1;*r0p=r0;}
+static void f732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,128);*r1p=r1;*r0p=r0;}
+static void f733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-128);*r1p=r1;*r0p=r0;}
+static void f734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,127);*r1p=r1;*r0p=r0;}
+static void f735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-129);*r1p=r1;*r0p=r0;}
+static void f736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,256);*r1p=r1;*r0p=r0;}
+static void f737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-256);*r1p=r1;*r0p=r0;}
+static void f738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,255);*r1p=r1;*r0p=r0;}
+static void f739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-257);*r1p=r1;*r0p=r0;}
+static void f740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,512);*r1p=r1;*r0p=r0;}
+static void f741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-512);*r1p=r1;*r0p=r0;}
+static void f742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,511);*r1p=r1;*r0p=r0;}
+static void f743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-513);*r1p=r1;*r0p=r0;}
+static void f744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,1024);*r1p=r1;*r0p=r0;}
+static void f745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-1024);*r1p=r1;*r0p=r0;}
+static void f746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,1023);*r1p=r1;*r0p=r0;}
+static void f747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-1025);*r1p=r1;*r0p=r0;}
+static void f748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,2048);*r1p=r1;*r0p=r0;}
+static void f749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-2048);*r1p=r1;*r0p=r0;}
+static void f750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,2047);*r1p=r1;*r0p=r0;}
+static void f751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-2049);*r1p=r1;*r0p=r0;}
+static void f752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,4096);*r1p=r1;*r0p=r0;}
+static void f753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-4096);*r1p=r1;*r0p=r0;}
+static void f754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,4095);*r1p=r1;*r0p=r0;}
+static void f755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-4097);*r1p=r1;*r0p=r0;}
+static void f756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,8192);*r1p=r1;*r0p=r0;}
+static void f757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-8192);*r1p=r1;*r0p=r0;}
+static void f758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,8191);*r1p=r1;*r0p=r0;}
+static void f759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-8193);*r1p=r1;*r0p=r0;}
+static void f760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,16384);*r1p=r1;*r0p=r0;}
+static void f761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-16384);*r1p=r1;*r0p=r0;}
+static void f762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,16383);*r1p=r1;*r0p=r0;}
+static void f763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-16385);*r1p=r1;*r0p=r0;}
+static void f764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,32768);*r1p=r1;*r0p=r0;}
+static void f765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-32768);*r1p=r1;*r0p=r0;}
+static void f766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,32767);*r1p=r1;*r0p=r0;}
+static void f767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-5,0,-32769);*r1p=r1;*r0p=r0;}
+static void f768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,1);*r1p=r1;*r0p=r0;}
+static void f769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-1);*r1p=r1;*r0p=r0;}
+static void f770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,0);*r1p=r1;*r0p=r0;}
+static void f771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-2);*r1p=r1;*r0p=r0;}
+static void f772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,2);*r1p=r1;*r0p=r0;}
+static void f773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-2);*r1p=r1;*r0p=r0;}
+static void f774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,1);*r1p=r1;*r0p=r0;}
+static void f775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-3);*r1p=r1;*r0p=r0;}
+static void f776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,4);*r1p=r1;*r0p=r0;}
+static void f777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-4);*r1p=r1;*r0p=r0;}
+static void f778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,3);*r1p=r1;*r0p=r0;}
+static void f779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-5);*r1p=r1;*r0p=r0;}
+static void f780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,8);*r1p=r1;*r0p=r0;}
+static void f781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-8);*r1p=r1;*r0p=r0;}
+static void f782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,7);*r1p=r1;*r0p=r0;}
+static void f783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-9);*r1p=r1;*r0p=r0;}
+static void f784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,16);*r1p=r1;*r0p=r0;}
+static void f785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-16);*r1p=r1;*r0p=r0;}
+static void f786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,15);*r1p=r1;*r0p=r0;}
+static void f787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-17);*r1p=r1;*r0p=r0;}
+static void f788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,32);*r1p=r1;*r0p=r0;}
+static void f789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-32);*r1p=r1;*r0p=r0;}
+static void f790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,31);*r1p=r1;*r0p=r0;}
+static void f791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-33);*r1p=r1;*r0p=r0;}
+static void f792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,64);*r1p=r1;*r0p=r0;}
+static void f793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-64);*r1p=r1;*r0p=r0;}
+static void f794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,63);*r1p=r1;*r0p=r0;}
+static void f795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-65);*r1p=r1;*r0p=r0;}
+static void f796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,128);*r1p=r1;*r0p=r0;}
+static void f797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-128);*r1p=r1;*r0p=r0;}
+static void f798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,127);*r1p=r1;*r0p=r0;}
+static void f799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-129);*r1p=r1;*r0p=r0;}
+static void f800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,256);*r1p=r1;*r0p=r0;}
+static void f801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-256);*r1p=r1;*r0p=r0;}
+static void f802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,255);*r1p=r1;*r0p=r0;}
+static void f803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-257);*r1p=r1;*r0p=r0;}
+static void f804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,512);*r1p=r1;*r0p=r0;}
+static void f805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-512);*r1p=r1;*r0p=r0;}
+static void f806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,511);*r1p=r1;*r0p=r0;}
+static void f807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-513);*r1p=r1;*r0p=r0;}
+static void f808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,1024);*r1p=r1;*r0p=r0;}
+static void f809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-1024);*r1p=r1;*r0p=r0;}
+static void f810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,1023);*r1p=r1;*r0p=r0;}
+static void f811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-1025);*r1p=r1;*r0p=r0;}
+static void f812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,2048);*r1p=r1;*r0p=r0;}
+static void f813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-2048);*r1p=r1;*r0p=r0;}
+static void f814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,2047);*r1p=r1;*r0p=r0;}
+static void f815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-2049);*r1p=r1;*r0p=r0;}
+static void f816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,4096);*r1p=r1;*r0p=r0;}
+static void f817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-4096);*r1p=r1;*r0p=r0;}
+static void f818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,4095);*r1p=r1;*r0p=r0;}
+static void f819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-4097);*r1p=r1;*r0p=r0;}
+static void f820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,8192);*r1p=r1;*r0p=r0;}
+static void f821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-8192);*r1p=r1;*r0p=r0;}
+static void f822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,8191);*r1p=r1;*r0p=r0;}
+static void f823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-8193);*r1p=r1;*r0p=r0;}
+static void f824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,16384);*r1p=r1;*r0p=r0;}
+static void f825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-16384);*r1p=r1;*r0p=r0;}
+static void f826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,16383);*r1p=r1;*r0p=r0;}
+static void f827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-16385);*r1p=r1;*r0p=r0;}
+static void f828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,32768);*r1p=r1;*r0p=r0;}
+static void f829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-32768);*r1p=r1;*r0p=r0;}
+static void f830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,32767);*r1p=r1;*r0p=r0;}
+static void f831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8,0,-32769);*r1p=r1;*r0p=r0;}
+static void f832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,1);*r1p=r1;*r0p=r0;}
+static void f833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-1);*r1p=r1;*r0p=r0;}
+static void f834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,0);*r1p=r1;*r0p=r0;}
+static void f835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-2);*r1p=r1;*r0p=r0;}
+static void f836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,2);*r1p=r1;*r0p=r0;}
+static void f837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-2);*r1p=r1;*r0p=r0;}
+static void f838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,1);*r1p=r1;*r0p=r0;}
+static void f839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-3);*r1p=r1;*r0p=r0;}
+static void f840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,4);*r1p=r1;*r0p=r0;}
+static void f841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-4);*r1p=r1;*r0p=r0;}
+static void f842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,3);*r1p=r1;*r0p=r0;}
+static void f843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-5);*r1p=r1;*r0p=r0;}
+static void f844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,8);*r1p=r1;*r0p=r0;}
+static void f845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-8);*r1p=r1;*r0p=r0;}
+static void f846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,7);*r1p=r1;*r0p=r0;}
+static void f847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-9);*r1p=r1;*r0p=r0;}
+static void f848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,16);*r1p=r1;*r0p=r0;}
+static void f849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-16);*r1p=r1;*r0p=r0;}
+static void f850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,15);*r1p=r1;*r0p=r0;}
+static void f851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-17);*r1p=r1;*r0p=r0;}
+static void f852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,32);*r1p=r1;*r0p=r0;}
+static void f853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-32);*r1p=r1;*r0p=r0;}
+static void f854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,31);*r1p=r1;*r0p=r0;}
+static void f855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-33);*r1p=r1;*r0p=r0;}
+static void f856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,64);*r1p=r1;*r0p=r0;}
+static void f857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-64);*r1p=r1;*r0p=r0;}
+static void f858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,63);*r1p=r1;*r0p=r0;}
+static void f859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-65);*r1p=r1;*r0p=r0;}
+static void f860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,128);*r1p=r1;*r0p=r0;}
+static void f861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-128);*r1p=r1;*r0p=r0;}
+static void f862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,127);*r1p=r1;*r0p=r0;}
+static void f863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-129);*r1p=r1;*r0p=r0;}
+static void f864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,256);*r1p=r1;*r0p=r0;}
+static void f865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-256);*r1p=r1;*r0p=r0;}
+static void f866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,255);*r1p=r1;*r0p=r0;}
+static void f867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-257);*r1p=r1;*r0p=r0;}
+static void f868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,512);*r1p=r1;*r0p=r0;}
+static void f869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-512);*r1p=r1;*r0p=r0;}
+static void f870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,511);*r1p=r1;*r0p=r0;}
+static void f871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-513);*r1p=r1;*r0p=r0;}
+static void f872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,1024);*r1p=r1;*r0p=r0;}
+static void f873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-1024);*r1p=r1;*r0p=r0;}
+static void f874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,1023);*r1p=r1;*r0p=r0;}
+static void f875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-1025);*r1p=r1;*r0p=r0;}
+static void f876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,2048);*r1p=r1;*r0p=r0;}
+static void f877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-2048);*r1p=r1;*r0p=r0;}
+static void f878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,2047);*r1p=r1;*r0p=r0;}
+static void f879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-2049);*r1p=r1;*r0p=r0;}
+static void f880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,4096);*r1p=r1;*r0p=r0;}
+static void f881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-4096);*r1p=r1;*r0p=r0;}
+static void f882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,4095);*r1p=r1;*r0p=r0;}
+static void f883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-4097);*r1p=r1;*r0p=r0;}
+static void f884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,8192);*r1p=r1;*r0p=r0;}
+static void f885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-8192);*r1p=r1;*r0p=r0;}
+static void f886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,8191);*r1p=r1;*r0p=r0;}
+static void f887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-8193);*r1p=r1;*r0p=r0;}
+static void f888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,16384);*r1p=r1;*r0p=r0;}
+static void f889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-16384);*r1p=r1;*r0p=r0;}
+static void f890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,16383);*r1p=r1;*r0p=r0;}
+static void f891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-16385);*r1p=r1;*r0p=r0;}
+static void f892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,32768);*r1p=r1;*r0p=r0;}
+static void f893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-32768);*r1p=r1;*r0p=r0;}
+static void f894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,32767);*r1p=r1;*r0p=r0;}
+static void f895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8,0,-32769);*r1p=r1;*r0p=r0;}
+static void f896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,1);*r1p=r1;*r0p=r0;}
+static void f897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-1);*r1p=r1;*r0p=r0;}
+static void f898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,0);*r1p=r1;*r0p=r0;}
+static void f899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-2);*r1p=r1;*r0p=r0;}
+static void f900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,2);*r1p=r1;*r0p=r0;}
+static void f901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-2);*r1p=r1;*r0p=r0;}
+static void f902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,1);*r1p=r1;*r0p=r0;}
+static void f903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-3);*r1p=r1;*r0p=r0;}
+static void f904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,4);*r1p=r1;*r0p=r0;}
+static void f905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-4);*r1p=r1;*r0p=r0;}
+static void f906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,3);*r1p=r1;*r0p=r0;}
+static void f907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-5);*r1p=r1;*r0p=r0;}
+static void f908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,8);*r1p=r1;*r0p=r0;}
+static void f909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-8);*r1p=r1;*r0p=r0;}
+static void f910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,7);*r1p=r1;*r0p=r0;}
+static void f911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-9);*r1p=r1;*r0p=r0;}
+static void f912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,16);*r1p=r1;*r0p=r0;}
+static void f913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-16);*r1p=r1;*r0p=r0;}
+static void f914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,15);*r1p=r1;*r0p=r0;}
+static void f915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-17);*r1p=r1;*r0p=r0;}
+static void f916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,32);*r1p=r1;*r0p=r0;}
+static void f917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-32);*r1p=r1;*r0p=r0;}
+static void f918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,31);*r1p=r1;*r0p=r0;}
+static void f919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-33);*r1p=r1;*r0p=r0;}
+static void f920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,64);*r1p=r1;*r0p=r0;}
+static void f921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-64);*r1p=r1;*r0p=r0;}
+static void f922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,63);*r1p=r1;*r0p=r0;}
+static void f923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-65);*r1p=r1;*r0p=r0;}
+static void f924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,128);*r1p=r1;*r0p=r0;}
+static void f925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-128);*r1p=r1;*r0p=r0;}
+static void f926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,127);*r1p=r1;*r0p=r0;}
+static void f927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-129);*r1p=r1;*r0p=r0;}
+static void f928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,256);*r1p=r1;*r0p=r0;}
+static void f929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-256);*r1p=r1;*r0p=r0;}
+static void f930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,255);*r1p=r1;*r0p=r0;}
+static void f931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-257);*r1p=r1;*r0p=r0;}
+static void f932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,512);*r1p=r1;*r0p=r0;}
+static void f933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-512);*r1p=r1;*r0p=r0;}
+static void f934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,511);*r1p=r1;*r0p=r0;}
+static void f935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-513);*r1p=r1;*r0p=r0;}
+static void f936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,1024);*r1p=r1;*r0p=r0;}
+static void f937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-1024);*r1p=r1;*r0p=r0;}
+static void f938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,1023);*r1p=r1;*r0p=r0;}
+static void f939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-1025);*r1p=r1;*r0p=r0;}
+static void f940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,2048);*r1p=r1;*r0p=r0;}
+static void f941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-2048);*r1p=r1;*r0p=r0;}
+static void f942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,2047);*r1p=r1;*r0p=r0;}
+static void f943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-2049);*r1p=r1;*r0p=r0;}
+static void f944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,4096);*r1p=r1;*r0p=r0;}
+static void f945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-4096);*r1p=r1;*r0p=r0;}
+static void f946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,4095);*r1p=r1;*r0p=r0;}
+static void f947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-4097);*r1p=r1;*r0p=r0;}
+static void f948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,8192);*r1p=r1;*r0p=r0;}
+static void f949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-8192);*r1p=r1;*r0p=r0;}
+static void f950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,8191);*r1p=r1;*r0p=r0;}
+static void f951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-8193);*r1p=r1;*r0p=r0;}
+static void f952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,16384);*r1p=r1;*r0p=r0;}
+static void f953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-16384);*r1p=r1;*r0p=r0;}
+static void f954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,16383);*r1p=r1;*r0p=r0;}
+static void f955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-16385);*r1p=r1;*r0p=r0;}
+static void f956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,32768);*r1p=r1;*r0p=r0;}
+static void f957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-32768);*r1p=r1;*r0p=r0;}
+static void f958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,32767);*r1p=r1;*r0p=r0;}
+static void f959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,7,0,-32769);*r1p=r1;*r0p=r0;}
+static void f960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,1);*r1p=r1;*r0p=r0;}
+static void f961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-1);*r1p=r1;*r0p=r0;}
+static void f962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,0);*r1p=r1;*r0p=r0;}
+static void f963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-2);*r1p=r1;*r0p=r0;}
+static void f964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,2);*r1p=r1;*r0p=r0;}
+static void f965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-2);*r1p=r1;*r0p=r0;}
+static void f966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,1);*r1p=r1;*r0p=r0;}
+static void f967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-3);*r1p=r1;*r0p=r0;}
+static void f968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,4);*r1p=r1;*r0p=r0;}
+static void f969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-4);*r1p=r1;*r0p=r0;}
+static void f970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,3);*r1p=r1;*r0p=r0;}
+static void f971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-5);*r1p=r1;*r0p=r0;}
+static void f972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,8);*r1p=r1;*r0p=r0;}
+static void f973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-8);*r1p=r1;*r0p=r0;}
+static void f974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,7);*r1p=r1;*r0p=r0;}
+static void f975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-9);*r1p=r1;*r0p=r0;}
+static void f976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,16);*r1p=r1;*r0p=r0;}
+static void f977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-16);*r1p=r1;*r0p=r0;}
+static void f978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,15);*r1p=r1;*r0p=r0;}
+static void f979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-17);*r1p=r1;*r0p=r0;}
+static void f980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,32);*r1p=r1;*r0p=r0;}
+static void f981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-32);*r1p=r1;*r0p=r0;}
+static void f982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,31);*r1p=r1;*r0p=r0;}
+static void f983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-33);*r1p=r1;*r0p=r0;}
+static void f984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,64);*r1p=r1;*r0p=r0;}
+static void f985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-64);*r1p=r1;*r0p=r0;}
+static void f986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,63);*r1p=r1;*r0p=r0;}
+static void f987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-65);*r1p=r1;*r0p=r0;}
+static void f988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,128);*r1p=r1;*r0p=r0;}
+static void f989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-128);*r1p=r1;*r0p=r0;}
+static void f990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,127);*r1p=r1;*r0p=r0;}
+static void f991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-129);*r1p=r1;*r0p=r0;}
+static void f992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,256);*r1p=r1;*r0p=r0;}
+static void f993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-256);*r1p=r1;*r0p=r0;}
+static void f994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,255);*r1p=r1;*r0p=r0;}
+static void f995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-257);*r1p=r1;*r0p=r0;}
+static void f996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,512);*r1p=r1;*r0p=r0;}
+static void f997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-512);*r1p=r1;*r0p=r0;}
+static void f998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,511);*r1p=r1;*r0p=r0;}
+static void f999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-513);*r1p=r1;*r0p=r0;}
+static void f1000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,1024);*r1p=r1;*r0p=r0;}
+static void f1001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,1023);*r1p=r1;*r0p=r0;}
+static void f1003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,2048);*r1p=r1;*r0p=r0;}
+static void f1005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,2047);*r1p=r1;*r0p=r0;}
+static void f1007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,4096);*r1p=r1;*r0p=r0;}
+static void f1009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,4095);*r1p=r1;*r0p=r0;}
+static void f1011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,8192);*r1p=r1;*r0p=r0;}
+static void f1013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,8191);*r1p=r1;*r0p=r0;}
+static void f1015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,16384);*r1p=r1;*r0p=r0;}
+static void f1017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,16383);*r1p=r1;*r0p=r0;}
+static void f1019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,32768);*r1p=r1;*r0p=r0;}
+static void f1021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,32767);*r1p=r1;*r0p=r0;}
+static void f1023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-9,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,1);*r1p=r1;*r0p=r0;}
+static void f1025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-1);*r1p=r1;*r0p=r0;}
+static void f1026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,0);*r1p=r1;*r0p=r0;}
+static void f1027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,2);*r1p=r1;*r0p=r0;}
+static void f1029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,1);*r1p=r1;*r0p=r0;}
+static void f1031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-3);*r1p=r1;*r0p=r0;}
+static void f1032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,4);*r1p=r1;*r0p=r0;}
+static void f1033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-4);*r1p=r1;*r0p=r0;}
+static void f1034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,3);*r1p=r1;*r0p=r0;}
+static void f1035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-5);*r1p=r1;*r0p=r0;}
+static void f1036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,8);*r1p=r1;*r0p=r0;}
+static void f1037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-8);*r1p=r1;*r0p=r0;}
+static void f1038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,7);*r1p=r1;*r0p=r0;}
+static void f1039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-9);*r1p=r1;*r0p=r0;}
+static void f1040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,16);*r1p=r1;*r0p=r0;}
+static void f1041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-16);*r1p=r1;*r0p=r0;}
+static void f1042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,15);*r1p=r1;*r0p=r0;}
+static void f1043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-17);*r1p=r1;*r0p=r0;}
+static void f1044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,32);*r1p=r1;*r0p=r0;}
+static void f1045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-32);*r1p=r1;*r0p=r0;}
+static void f1046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,31);*r1p=r1;*r0p=r0;}
+static void f1047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-33);*r1p=r1;*r0p=r0;}
+static void f1048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,64);*r1p=r1;*r0p=r0;}
+static void f1049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-64);*r1p=r1;*r0p=r0;}
+static void f1050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,63);*r1p=r1;*r0p=r0;}
+static void f1051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-65);*r1p=r1;*r0p=r0;}
+static void f1052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,128);*r1p=r1;*r0p=r0;}
+static void f1053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-128);*r1p=r1;*r0p=r0;}
+static void f1054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,127);*r1p=r1;*r0p=r0;}
+static void f1055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-129);*r1p=r1;*r0p=r0;}
+static void f1056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,256);*r1p=r1;*r0p=r0;}
+static void f1057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-256);*r1p=r1;*r0p=r0;}
+static void f1058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,255);*r1p=r1;*r0p=r0;}
+static void f1059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-257);*r1p=r1;*r0p=r0;}
+static void f1060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,512);*r1p=r1;*r0p=r0;}
+static void f1061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-512);*r1p=r1;*r0p=r0;}
+static void f1062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,511);*r1p=r1;*r0p=r0;}
+static void f1063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-513);*r1p=r1;*r0p=r0;}
+static void f1064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,1024);*r1p=r1;*r0p=r0;}
+static void f1065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,1023);*r1p=r1;*r0p=r0;}
+static void f1067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,2048);*r1p=r1;*r0p=r0;}
+static void f1069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,2047);*r1p=r1;*r0p=r0;}
+static void f1071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,4096);*r1p=r1;*r0p=r0;}
+static void f1073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,4095);*r1p=r1;*r0p=r0;}
+static void f1075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,8192);*r1p=r1;*r0p=r0;}
+static void f1077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,8191);*r1p=r1;*r0p=r0;}
+static void f1079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,16384);*r1p=r1;*r0p=r0;}
+static void f1081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,16383);*r1p=r1;*r0p=r0;}
+static void f1083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,32768);*r1p=r1;*r0p=r0;}
+static void f1085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,32767);*r1p=r1;*r0p=r0;}
+static void f1087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,1);*r1p=r1;*r0p=r0;}
+static void f1089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-1);*r1p=r1;*r0p=r0;}
+static void f1090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,0);*r1p=r1;*r0p=r0;}
+static void f1091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,2);*r1p=r1;*r0p=r0;}
+static void f1093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,1);*r1p=r1;*r0p=r0;}
+static void f1095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-3);*r1p=r1;*r0p=r0;}
+static void f1096(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,4);*r1p=r1;*r0p=r0;}
+static void f1097(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-4);*r1p=r1;*r0p=r0;}
+static void f1098(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,3);*r1p=r1;*r0p=r0;}
+static void f1099(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-5);*r1p=r1;*r0p=r0;}
+static void f1100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,8);*r1p=r1;*r0p=r0;}
+static void f1101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-8);*r1p=r1;*r0p=r0;}
+static void f1102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,7);*r1p=r1;*r0p=r0;}
+static void f1103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-9);*r1p=r1;*r0p=r0;}
+static void f1104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,16);*r1p=r1;*r0p=r0;}
+static void f1105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-16);*r1p=r1;*r0p=r0;}
+static void f1106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,15);*r1p=r1;*r0p=r0;}
+static void f1107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-17);*r1p=r1;*r0p=r0;}
+static void f1108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,32);*r1p=r1;*r0p=r0;}
+static void f1109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-32);*r1p=r1;*r0p=r0;}
+static void f1110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,31);*r1p=r1;*r0p=r0;}
+static void f1111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-33);*r1p=r1;*r0p=r0;}
+static void f1112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,64);*r1p=r1;*r0p=r0;}
+static void f1113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-64);*r1p=r1;*r0p=r0;}
+static void f1114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,63);*r1p=r1;*r0p=r0;}
+static void f1115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-65);*r1p=r1;*r0p=r0;}
+static void f1116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,128);*r1p=r1;*r0p=r0;}
+static void f1117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-128);*r1p=r1;*r0p=r0;}
+static void f1118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,127);*r1p=r1;*r0p=r0;}
+static void f1119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-129);*r1p=r1;*r0p=r0;}
+static void f1120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,256);*r1p=r1;*r0p=r0;}
+static void f1121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-256);*r1p=r1;*r0p=r0;}
+static void f1122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,255);*r1p=r1;*r0p=r0;}
+static void f1123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-257);*r1p=r1;*r0p=r0;}
+static void f1124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,512);*r1p=r1;*r0p=r0;}
+static void f1125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-512);*r1p=r1;*r0p=r0;}
+static void f1126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,511);*r1p=r1;*r0p=r0;}
+static void f1127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-513);*r1p=r1;*r0p=r0;}
+static void f1128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,1024);*r1p=r1;*r0p=r0;}
+static void f1129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,1023);*r1p=r1;*r0p=r0;}
+static void f1131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,2048);*r1p=r1;*r0p=r0;}
+static void f1133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,2047);*r1p=r1;*r0p=r0;}
+static void f1135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,4096);*r1p=r1;*r0p=r0;}
+static void f1137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,4095);*r1p=r1;*r0p=r0;}
+static void f1139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,8192);*r1p=r1;*r0p=r0;}
+static void f1141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,8191);*r1p=r1;*r0p=r0;}
+static void f1143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,16384);*r1p=r1;*r0p=r0;}
+static void f1145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,16383);*r1p=r1;*r0p=r0;}
+static void f1147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,32768);*r1p=r1;*r0p=r0;}
+static void f1149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,32767);*r1p=r1;*r0p=r0;}
+static void f1151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,1);*r1p=r1;*r0p=r0;}
+static void f1153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-1);*r1p=r1;*r0p=r0;}
+static void f1154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,0);*r1p=r1;*r0p=r0;}
+static void f1155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-2);*r1p=r1;*r0p=r0;}
+static void f1156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,2);*r1p=r1;*r0p=r0;}
+static void f1157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-2);*r1p=r1;*r0p=r0;}
+static void f1158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,1);*r1p=r1;*r0p=r0;}
+static void f1159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-3);*r1p=r1;*r0p=r0;}
+static void f1160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,4);*r1p=r1;*r0p=r0;}
+static void f1161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-4);*r1p=r1;*r0p=r0;}
+static void f1162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,3);*r1p=r1;*r0p=r0;}
+static void f1163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-5);*r1p=r1;*r0p=r0;}
+static void f1164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,8);*r1p=r1;*r0p=r0;}
+static void f1165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-8);*r1p=r1;*r0p=r0;}
+static void f1166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,7);*r1p=r1;*r0p=r0;}
+static void f1167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-9);*r1p=r1;*r0p=r0;}
+static void f1168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,16);*r1p=r1;*r0p=r0;}
+static void f1169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-16);*r1p=r1;*r0p=r0;}
+static void f1170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,15);*r1p=r1;*r0p=r0;}
+static void f1171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-17);*r1p=r1;*r0p=r0;}
+static void f1172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,32);*r1p=r1;*r0p=r0;}
+static void f1173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-32);*r1p=r1;*r0p=r0;}
+static void f1174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,31);*r1p=r1;*r0p=r0;}
+static void f1175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-33);*r1p=r1;*r0p=r0;}
+static void f1176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,64);*r1p=r1;*r0p=r0;}
+static void f1177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-64);*r1p=r1;*r0p=r0;}
+static void f1178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,63);*r1p=r1;*r0p=r0;}
+static void f1179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-65);*r1p=r1;*r0p=r0;}
+static void f1180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,128);*r1p=r1;*r0p=r0;}
+static void f1181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-128);*r1p=r1;*r0p=r0;}
+static void f1182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,127);*r1p=r1;*r0p=r0;}
+static void f1183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-129);*r1p=r1;*r0p=r0;}
+static void f1184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,256);*r1p=r1;*r0p=r0;}
+static void f1185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-256);*r1p=r1;*r0p=r0;}
+static void f1186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,255);*r1p=r1;*r0p=r0;}
+static void f1187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-257);*r1p=r1;*r0p=r0;}
+static void f1188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,512);*r1p=r1;*r0p=r0;}
+static void f1189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-512);*r1p=r1;*r0p=r0;}
+static void f1190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,511);*r1p=r1;*r0p=r0;}
+static void f1191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-513);*r1p=r1;*r0p=r0;}
+static void f1192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,1024);*r1p=r1;*r0p=r0;}
+static void f1193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,1023);*r1p=r1;*r0p=r0;}
+static void f1195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,2048);*r1p=r1;*r0p=r0;}
+static void f1197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,2047);*r1p=r1;*r0p=r0;}
+static void f1199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,4096);*r1p=r1;*r0p=r0;}
+static void f1201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,4095);*r1p=r1;*r0p=r0;}
+static void f1203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,8192);*r1p=r1;*r0p=r0;}
+static void f1205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,8191);*r1p=r1;*r0p=r0;}
+static void f1207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,16384);*r1p=r1;*r0p=r0;}
+static void f1209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,16383);*r1p=r1;*r0p=r0;}
+static void f1211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,32768);*r1p=r1;*r0p=r0;}
+static void f1213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,32767);*r1p=r1;*r0p=r0;}
+static void f1215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,15,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,1);*r1p=r1;*r0p=r0;}
+static void f1217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-1);*r1p=r1;*r0p=r0;}
+static void f1218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,0);*r1p=r1;*r0p=r0;}
+static void f1219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-2);*r1p=r1;*r0p=r0;}
+static void f1220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,2);*r1p=r1;*r0p=r0;}
+static void f1221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-2);*r1p=r1;*r0p=r0;}
+static void f1222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,1);*r1p=r1;*r0p=r0;}
+static void f1223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-3);*r1p=r1;*r0p=r0;}
+static void f1224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,4);*r1p=r1;*r0p=r0;}
+static void f1225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-4);*r1p=r1;*r0p=r0;}
+static void f1226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,3);*r1p=r1;*r0p=r0;}
+static void f1227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-5);*r1p=r1;*r0p=r0;}
+static void f1228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,8);*r1p=r1;*r0p=r0;}
+static void f1229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-8);*r1p=r1;*r0p=r0;}
+static void f1230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,7);*r1p=r1;*r0p=r0;}
+static void f1231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-9);*r1p=r1;*r0p=r0;}
+static void f1232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,16);*r1p=r1;*r0p=r0;}
+static void f1233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-16);*r1p=r1;*r0p=r0;}
+static void f1234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,15);*r1p=r1;*r0p=r0;}
+static void f1235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-17);*r1p=r1;*r0p=r0;}
+static void f1236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,32);*r1p=r1;*r0p=r0;}
+static void f1237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-32);*r1p=r1;*r0p=r0;}
+static void f1238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,31);*r1p=r1;*r0p=r0;}
+static void f1239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-33);*r1p=r1;*r0p=r0;}
+static void f1240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,64);*r1p=r1;*r0p=r0;}
+static void f1241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-64);*r1p=r1;*r0p=r0;}
+static void f1242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,63);*r1p=r1;*r0p=r0;}
+static void f1243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-65);*r1p=r1;*r0p=r0;}
+static void f1244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,128);*r1p=r1;*r0p=r0;}
+static void f1245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-128);*r1p=r1;*r0p=r0;}
+static void f1246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,127);*r1p=r1;*r0p=r0;}
+static void f1247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-129);*r1p=r1;*r0p=r0;}
+static void f1248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,256);*r1p=r1;*r0p=r0;}
+static void f1249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-256);*r1p=r1;*r0p=r0;}
+static void f1250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,255);*r1p=r1;*r0p=r0;}
+static void f1251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-257);*r1p=r1;*r0p=r0;}
+static void f1252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,512);*r1p=r1;*r0p=r0;}
+static void f1253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-512);*r1p=r1;*r0p=r0;}
+static void f1254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,511);*r1p=r1;*r0p=r0;}
+static void f1255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-513);*r1p=r1;*r0p=r0;}
+static void f1256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,1024);*r1p=r1;*r0p=r0;}
+static void f1257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,1023);*r1p=r1;*r0p=r0;}
+static void f1259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,2048);*r1p=r1;*r0p=r0;}
+static void f1261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,2047);*r1p=r1;*r0p=r0;}
+static void f1263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,4096);*r1p=r1;*r0p=r0;}
+static void f1265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,4095);*r1p=r1;*r0p=r0;}
+static void f1267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,8192);*r1p=r1;*r0p=r0;}
+static void f1269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,8191);*r1p=r1;*r0p=r0;}
+static void f1271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,16384);*r1p=r1;*r0p=r0;}
+static void f1273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,16383);*r1p=r1;*r0p=r0;}
+static void f1275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,32768);*r1p=r1;*r0p=r0;}
+static void f1277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,32767);*r1p=r1;*r0p=r0;}
+static void f1279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-17,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,1);*r1p=r1;*r0p=r0;}
+static void f1281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-1);*r1p=r1;*r0p=r0;}
+static void f1282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,0);*r1p=r1;*r0p=r0;}
+static void f1283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,2);*r1p=r1;*r0p=r0;}
+static void f1285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,1);*r1p=r1;*r0p=r0;}
+static void f1287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-3);*r1p=r1;*r0p=r0;}
+static void f1288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,4);*r1p=r1;*r0p=r0;}
+static void f1289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-4);*r1p=r1;*r0p=r0;}
+static void f1290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,3);*r1p=r1;*r0p=r0;}
+static void f1291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-5);*r1p=r1;*r0p=r0;}
+static void f1292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,8);*r1p=r1;*r0p=r0;}
+static void f1293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-8);*r1p=r1;*r0p=r0;}
+static void f1294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,7);*r1p=r1;*r0p=r0;}
+static void f1295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-9);*r1p=r1;*r0p=r0;}
+static void f1296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,16);*r1p=r1;*r0p=r0;}
+static void f1297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-16);*r1p=r1;*r0p=r0;}
+static void f1298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,15);*r1p=r1;*r0p=r0;}
+static void f1299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-17);*r1p=r1;*r0p=r0;}
+static void f1300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,32);*r1p=r1;*r0p=r0;}
+static void f1301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-32);*r1p=r1;*r0p=r0;}
+static void f1302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,31);*r1p=r1;*r0p=r0;}
+static void f1303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-33);*r1p=r1;*r0p=r0;}
+static void f1304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,64);*r1p=r1;*r0p=r0;}
+static void f1305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-64);*r1p=r1;*r0p=r0;}
+static void f1306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,63);*r1p=r1;*r0p=r0;}
+static void f1307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-65);*r1p=r1;*r0p=r0;}
+static void f1308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,128);*r1p=r1;*r0p=r0;}
+static void f1309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-128);*r1p=r1;*r0p=r0;}
+static void f1310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,127);*r1p=r1;*r0p=r0;}
+static void f1311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-129);*r1p=r1;*r0p=r0;}
+static void f1312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,256);*r1p=r1;*r0p=r0;}
+static void f1313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-256);*r1p=r1;*r0p=r0;}
+static void f1314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,255);*r1p=r1;*r0p=r0;}
+static void f1315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-257);*r1p=r1;*r0p=r0;}
+static void f1316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,512);*r1p=r1;*r0p=r0;}
+static void f1317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-512);*r1p=r1;*r0p=r0;}
+static void f1318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,511);*r1p=r1;*r0p=r0;}
+static void f1319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-513);*r1p=r1;*r0p=r0;}
+static void f1320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,1024);*r1p=r1;*r0p=r0;}
+static void f1321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,1023);*r1p=r1;*r0p=r0;}
+static void f1323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,2048);*r1p=r1;*r0p=r0;}
+static void f1325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,2047);*r1p=r1;*r0p=r0;}
+static void f1327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,4096);*r1p=r1;*r0p=r0;}
+static void f1329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,4095);*r1p=r1;*r0p=r0;}
+static void f1331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,8192);*r1p=r1;*r0p=r0;}
+static void f1333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,8191);*r1p=r1;*r0p=r0;}
+static void f1335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,16384);*r1p=r1;*r0p=r0;}
+static void f1337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,16383);*r1p=r1;*r0p=r0;}
+static void f1339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,32768);*r1p=r1;*r0p=r0;}
+static void f1341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,32767);*r1p=r1;*r0p=r0;}
+static void f1343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,1);*r1p=r1;*r0p=r0;}
+static void f1345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-1);*r1p=r1;*r0p=r0;}
+static void f1346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,0);*r1p=r1;*r0p=r0;}
+static void f1347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,2);*r1p=r1;*r0p=r0;}
+static void f1349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,1);*r1p=r1;*r0p=r0;}
+static void f1351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-3);*r1p=r1;*r0p=r0;}
+static void f1352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,4);*r1p=r1;*r0p=r0;}
+static void f1353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-4);*r1p=r1;*r0p=r0;}
+static void f1354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,3);*r1p=r1;*r0p=r0;}
+static void f1355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-5);*r1p=r1;*r0p=r0;}
+static void f1356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,8);*r1p=r1;*r0p=r0;}
+static void f1357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-8);*r1p=r1;*r0p=r0;}
+static void f1358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,7);*r1p=r1;*r0p=r0;}
+static void f1359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-9);*r1p=r1;*r0p=r0;}
+static void f1360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,16);*r1p=r1;*r0p=r0;}
+static void f1361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-16);*r1p=r1;*r0p=r0;}
+static void f1362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,15);*r1p=r1;*r0p=r0;}
+static void f1363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-17);*r1p=r1;*r0p=r0;}
+static void f1364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,32);*r1p=r1;*r0p=r0;}
+static void f1365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-32);*r1p=r1;*r0p=r0;}
+static void f1366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,31);*r1p=r1;*r0p=r0;}
+static void f1367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-33);*r1p=r1;*r0p=r0;}
+static void f1368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,64);*r1p=r1;*r0p=r0;}
+static void f1369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-64);*r1p=r1;*r0p=r0;}
+static void f1370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,63);*r1p=r1;*r0p=r0;}
+static void f1371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-65);*r1p=r1;*r0p=r0;}
+static void f1372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,128);*r1p=r1;*r0p=r0;}
+static void f1373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-128);*r1p=r1;*r0p=r0;}
+static void f1374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,127);*r1p=r1;*r0p=r0;}
+static void f1375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-129);*r1p=r1;*r0p=r0;}
+static void f1376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,256);*r1p=r1;*r0p=r0;}
+static void f1377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-256);*r1p=r1;*r0p=r0;}
+static void f1378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,255);*r1p=r1;*r0p=r0;}
+static void f1379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-257);*r1p=r1;*r0p=r0;}
+static void f1380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,512);*r1p=r1;*r0p=r0;}
+static void f1381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-512);*r1p=r1;*r0p=r0;}
+static void f1382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,511);*r1p=r1;*r0p=r0;}
+static void f1383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-513);*r1p=r1;*r0p=r0;}
+static void f1384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,1024);*r1p=r1;*r0p=r0;}
+static void f1385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,1023);*r1p=r1;*r0p=r0;}
+static void f1387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,2048);*r1p=r1;*r0p=r0;}
+static void f1389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,2047);*r1p=r1;*r0p=r0;}
+static void f1391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,4096);*r1p=r1;*r0p=r0;}
+static void f1393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,4095);*r1p=r1;*r0p=r0;}
+static void f1395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,8192);*r1p=r1;*r0p=r0;}
+static void f1397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,8191);*r1p=r1;*r0p=r0;}
+static void f1399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,16384);*r1p=r1;*r0p=r0;}
+static void f1401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,16383);*r1p=r1;*r0p=r0;}
+static void f1403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,32768);*r1p=r1;*r0p=r0;}
+static void f1405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,32767);*r1p=r1;*r0p=r0;}
+static void f1407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,1);*r1p=r1;*r0p=r0;}
+static void f1409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-1);*r1p=r1;*r0p=r0;}
+static void f1410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,0);*r1p=r1;*r0p=r0;}
+static void f1411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-2);*r1p=r1;*r0p=r0;}
+static void f1412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,2);*r1p=r1;*r0p=r0;}
+static void f1413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-2);*r1p=r1;*r0p=r0;}
+static void f1414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,1);*r1p=r1;*r0p=r0;}
+static void f1415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-3);*r1p=r1;*r0p=r0;}
+static void f1416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,4);*r1p=r1;*r0p=r0;}
+static void f1417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-4);*r1p=r1;*r0p=r0;}
+static void f1418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,3);*r1p=r1;*r0p=r0;}
+static void f1419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-5);*r1p=r1;*r0p=r0;}
+static void f1420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,8);*r1p=r1;*r0p=r0;}
+static void f1421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-8);*r1p=r1;*r0p=r0;}
+static void f1422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,7);*r1p=r1;*r0p=r0;}
+static void f1423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-9);*r1p=r1;*r0p=r0;}
+static void f1424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,16);*r1p=r1;*r0p=r0;}
+static void f1425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-16);*r1p=r1;*r0p=r0;}
+static void f1426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,15);*r1p=r1;*r0p=r0;}
+static void f1427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-17);*r1p=r1;*r0p=r0;}
+static void f1428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,32);*r1p=r1;*r0p=r0;}
+static void f1429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-32);*r1p=r1;*r0p=r0;}
+static void f1430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,31);*r1p=r1;*r0p=r0;}
+static void f1431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-33);*r1p=r1;*r0p=r0;}
+static void f1432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,64);*r1p=r1;*r0p=r0;}
+static void f1433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-64);*r1p=r1;*r0p=r0;}
+static void f1434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,63);*r1p=r1;*r0p=r0;}
+static void f1435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-65);*r1p=r1;*r0p=r0;}
+static void f1436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,128);*r1p=r1;*r0p=r0;}
+static void f1437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-128);*r1p=r1;*r0p=r0;}
+static void f1438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,127);*r1p=r1;*r0p=r0;}
+static void f1439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-129);*r1p=r1;*r0p=r0;}
+static void f1440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,256);*r1p=r1;*r0p=r0;}
+static void f1441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-256);*r1p=r1;*r0p=r0;}
+static void f1442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,255);*r1p=r1;*r0p=r0;}
+static void f1443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-257);*r1p=r1;*r0p=r0;}
+static void f1444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,512);*r1p=r1;*r0p=r0;}
+static void f1445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-512);*r1p=r1;*r0p=r0;}
+static void f1446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,511);*r1p=r1;*r0p=r0;}
+static void f1447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-513);*r1p=r1;*r0p=r0;}
+static void f1448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,1024);*r1p=r1;*r0p=r0;}
+static void f1449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,1023);*r1p=r1;*r0p=r0;}
+static void f1451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,2048);*r1p=r1;*r0p=r0;}
+static void f1453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,2047);*r1p=r1;*r0p=r0;}
+static void f1455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,4096);*r1p=r1;*r0p=r0;}
+static void f1457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,4095);*r1p=r1;*r0p=r0;}
+static void f1459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,8192);*r1p=r1;*r0p=r0;}
+static void f1461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,8191);*r1p=r1;*r0p=r0;}
+static void f1463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,16384);*r1p=r1;*r0p=r0;}
+static void f1465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,16383);*r1p=r1;*r0p=r0;}
+static void f1467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,32768);*r1p=r1;*r0p=r0;}
+static void f1469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,32767);*r1p=r1;*r0p=r0;}
+static void f1471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,31,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,1);*r1p=r1;*r0p=r0;}
+static void f1473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-1);*r1p=r1;*r0p=r0;}
+static void f1474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,0);*r1p=r1;*r0p=r0;}
+static void f1475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-2);*r1p=r1;*r0p=r0;}
+static void f1476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,2);*r1p=r1;*r0p=r0;}
+static void f1477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-2);*r1p=r1;*r0p=r0;}
+static void f1478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,1);*r1p=r1;*r0p=r0;}
+static void f1479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-3);*r1p=r1;*r0p=r0;}
+static void f1480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,4);*r1p=r1;*r0p=r0;}
+static void f1481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-4);*r1p=r1;*r0p=r0;}
+static void f1482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,3);*r1p=r1;*r0p=r0;}
+static void f1483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-5);*r1p=r1;*r0p=r0;}
+static void f1484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,8);*r1p=r1;*r0p=r0;}
+static void f1485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-8);*r1p=r1;*r0p=r0;}
+static void f1486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,7);*r1p=r1;*r0p=r0;}
+static void f1487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-9);*r1p=r1;*r0p=r0;}
+static void f1488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,16);*r1p=r1;*r0p=r0;}
+static void f1489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-16);*r1p=r1;*r0p=r0;}
+static void f1490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,15);*r1p=r1;*r0p=r0;}
+static void f1491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-17);*r1p=r1;*r0p=r0;}
+static void f1492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,32);*r1p=r1;*r0p=r0;}
+static void f1493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-32);*r1p=r1;*r0p=r0;}
+static void f1494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,31);*r1p=r1;*r0p=r0;}
+static void f1495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-33);*r1p=r1;*r0p=r0;}
+static void f1496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,64);*r1p=r1;*r0p=r0;}
+static void f1497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-64);*r1p=r1;*r0p=r0;}
+static void f1498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,63);*r1p=r1;*r0p=r0;}
+static void f1499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-65);*r1p=r1;*r0p=r0;}
+static void f1500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,128);*r1p=r1;*r0p=r0;}
+static void f1501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-128);*r1p=r1;*r0p=r0;}
+static void f1502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,127);*r1p=r1;*r0p=r0;}
+static void f1503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-129);*r1p=r1;*r0p=r0;}
+static void f1504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,256);*r1p=r1;*r0p=r0;}
+static void f1505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-256);*r1p=r1;*r0p=r0;}
+static void f1506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,255);*r1p=r1;*r0p=r0;}
+static void f1507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-257);*r1p=r1;*r0p=r0;}
+static void f1508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,512);*r1p=r1;*r0p=r0;}
+static void f1509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-512);*r1p=r1;*r0p=r0;}
+static void f1510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,511);*r1p=r1;*r0p=r0;}
+static void f1511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-513);*r1p=r1;*r0p=r0;}
+static void f1512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,1024);*r1p=r1;*r0p=r0;}
+static void f1513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,1023);*r1p=r1;*r0p=r0;}
+static void f1515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,2048);*r1p=r1;*r0p=r0;}
+static void f1517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,2047);*r1p=r1;*r0p=r0;}
+static void f1519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,4096);*r1p=r1;*r0p=r0;}
+static void f1521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,4095);*r1p=r1;*r0p=r0;}
+static void f1523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,8192);*r1p=r1;*r0p=r0;}
+static void f1525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,8191);*r1p=r1;*r0p=r0;}
+static void f1527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,16384);*r1p=r1;*r0p=r0;}
+static void f1529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,16383);*r1p=r1;*r0p=r0;}
+static void f1531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,32768);*r1p=r1;*r0p=r0;}
+static void f1533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,32767);*r1p=r1;*r0p=r0;}
+static void f1535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-33,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,1);*r1p=r1;*r0p=r0;}
+static void f1537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-1);*r1p=r1;*r0p=r0;}
+static void f1538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,0);*r1p=r1;*r0p=r0;}
+static void f1539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,2);*r1p=r1;*r0p=r0;}
+static void f1541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,1);*r1p=r1;*r0p=r0;}
+static void f1543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-3);*r1p=r1;*r0p=r0;}
+static void f1544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,4);*r1p=r1;*r0p=r0;}
+static void f1545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-4);*r1p=r1;*r0p=r0;}
+static void f1546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,3);*r1p=r1;*r0p=r0;}
+static void f1547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-5);*r1p=r1;*r0p=r0;}
+static void f1548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,8);*r1p=r1;*r0p=r0;}
+static void f1549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-8);*r1p=r1;*r0p=r0;}
+static void f1550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,7);*r1p=r1;*r0p=r0;}
+static void f1551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-9);*r1p=r1;*r0p=r0;}
+static void f1552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,16);*r1p=r1;*r0p=r0;}
+static void f1553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-16);*r1p=r1;*r0p=r0;}
+static void f1554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,15);*r1p=r1;*r0p=r0;}
+static void f1555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-17);*r1p=r1;*r0p=r0;}
+static void f1556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,32);*r1p=r1;*r0p=r0;}
+static void f1557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-32);*r1p=r1;*r0p=r0;}
+static void f1558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,31);*r1p=r1;*r0p=r0;}
+static void f1559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-33);*r1p=r1;*r0p=r0;}
+static void f1560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,64);*r1p=r1;*r0p=r0;}
+static void f1561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-64);*r1p=r1;*r0p=r0;}
+static void f1562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,63);*r1p=r1;*r0p=r0;}
+static void f1563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-65);*r1p=r1;*r0p=r0;}
+static void f1564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,128);*r1p=r1;*r0p=r0;}
+static void f1565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-128);*r1p=r1;*r0p=r0;}
+static void f1566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,127);*r1p=r1;*r0p=r0;}
+static void f1567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-129);*r1p=r1;*r0p=r0;}
+static void f1568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,256);*r1p=r1;*r0p=r0;}
+static void f1569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-256);*r1p=r1;*r0p=r0;}
+static void f1570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,255);*r1p=r1;*r0p=r0;}
+static void f1571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-257);*r1p=r1;*r0p=r0;}
+static void f1572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,512);*r1p=r1;*r0p=r0;}
+static void f1573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-512);*r1p=r1;*r0p=r0;}
+static void f1574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,511);*r1p=r1;*r0p=r0;}
+static void f1575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-513);*r1p=r1;*r0p=r0;}
+static void f1576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,1024);*r1p=r1;*r0p=r0;}
+static void f1577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,1023);*r1p=r1;*r0p=r0;}
+static void f1579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,2048);*r1p=r1;*r0p=r0;}
+static void f1581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,2047);*r1p=r1;*r0p=r0;}
+static void f1583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,4096);*r1p=r1;*r0p=r0;}
+static void f1585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,4095);*r1p=r1;*r0p=r0;}
+static void f1587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,8192);*r1p=r1;*r0p=r0;}
+static void f1589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,8191);*r1p=r1;*r0p=r0;}
+static void f1591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,16384);*r1p=r1;*r0p=r0;}
+static void f1593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,16383);*r1p=r1;*r0p=r0;}
+static void f1595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,32768);*r1p=r1;*r0p=r0;}
+static void f1597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,32767);*r1p=r1;*r0p=r0;}
+static void f1599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,64,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,1);*r1p=r1;*r0p=r0;}
+static void f1601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-1);*r1p=r1;*r0p=r0;}
+static void f1602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,0);*r1p=r1;*r0p=r0;}
+static void f1603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,2);*r1p=r1;*r0p=r0;}
+static void f1605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,1);*r1p=r1;*r0p=r0;}
+static void f1607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-3);*r1p=r1;*r0p=r0;}
+static void f1608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,4);*r1p=r1;*r0p=r0;}
+static void f1609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-4);*r1p=r1;*r0p=r0;}
+static void f1610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,3);*r1p=r1;*r0p=r0;}
+static void f1611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-5);*r1p=r1;*r0p=r0;}
+static void f1612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,8);*r1p=r1;*r0p=r0;}
+static void f1613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-8);*r1p=r1;*r0p=r0;}
+static void f1614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,7);*r1p=r1;*r0p=r0;}
+static void f1615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-9);*r1p=r1;*r0p=r0;}
+static void f1616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,16);*r1p=r1;*r0p=r0;}
+static void f1617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-16);*r1p=r1;*r0p=r0;}
+static void f1618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,15);*r1p=r1;*r0p=r0;}
+static void f1619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-17);*r1p=r1;*r0p=r0;}
+static void f1620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,32);*r1p=r1;*r0p=r0;}
+static void f1621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-32);*r1p=r1;*r0p=r0;}
+static void f1622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,31);*r1p=r1;*r0p=r0;}
+static void f1623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-33);*r1p=r1;*r0p=r0;}
+static void f1624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,64);*r1p=r1;*r0p=r0;}
+static void f1625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-64);*r1p=r1;*r0p=r0;}
+static void f1626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,63);*r1p=r1;*r0p=r0;}
+static void f1627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-65);*r1p=r1;*r0p=r0;}
+static void f1628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,128);*r1p=r1;*r0p=r0;}
+static void f1629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-128);*r1p=r1;*r0p=r0;}
+static void f1630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,127);*r1p=r1;*r0p=r0;}
+static void f1631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-129);*r1p=r1;*r0p=r0;}
+static void f1632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,256);*r1p=r1;*r0p=r0;}
+static void f1633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-256);*r1p=r1;*r0p=r0;}
+static void f1634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,255);*r1p=r1;*r0p=r0;}
+static void f1635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-257);*r1p=r1;*r0p=r0;}
+static void f1636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,512);*r1p=r1;*r0p=r0;}
+static void f1637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-512);*r1p=r1;*r0p=r0;}
+static void f1638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,511);*r1p=r1;*r0p=r0;}
+static void f1639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-513);*r1p=r1;*r0p=r0;}
+static void f1640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,1024);*r1p=r1;*r0p=r0;}
+static void f1641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,1023);*r1p=r1;*r0p=r0;}
+static void f1643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,2048);*r1p=r1;*r0p=r0;}
+static void f1645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,2047);*r1p=r1;*r0p=r0;}
+static void f1647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,4096);*r1p=r1;*r0p=r0;}
+static void f1649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,4095);*r1p=r1;*r0p=r0;}
+static void f1651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,8192);*r1p=r1;*r0p=r0;}
+static void f1653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,8191);*r1p=r1;*r0p=r0;}
+static void f1655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,16384);*r1p=r1;*r0p=r0;}
+static void f1657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,16383);*r1p=r1;*r0p=r0;}
+static void f1659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,32768);*r1p=r1;*r0p=r0;}
+static void f1661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,32767);*r1p=r1;*r0p=r0;}
+static void f1663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-64,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,1);*r1p=r1;*r0p=r0;}
+static void f1665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-1);*r1p=r1;*r0p=r0;}
+static void f1666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,0);*r1p=r1;*r0p=r0;}
+static void f1667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-2);*r1p=r1;*r0p=r0;}
+static void f1668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,2);*r1p=r1;*r0p=r0;}
+static void f1669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-2);*r1p=r1;*r0p=r0;}
+static void f1670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,1);*r1p=r1;*r0p=r0;}
+static void f1671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-3);*r1p=r1;*r0p=r0;}
+static void f1672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,4);*r1p=r1;*r0p=r0;}
+static void f1673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-4);*r1p=r1;*r0p=r0;}
+static void f1674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,3);*r1p=r1;*r0p=r0;}
+static void f1675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-5);*r1p=r1;*r0p=r0;}
+static void f1676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,8);*r1p=r1;*r0p=r0;}
+static void f1677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-8);*r1p=r1;*r0p=r0;}
+static void f1678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,7);*r1p=r1;*r0p=r0;}
+static void f1679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-9);*r1p=r1;*r0p=r0;}
+static void f1680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,16);*r1p=r1;*r0p=r0;}
+static void f1681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-16);*r1p=r1;*r0p=r0;}
+static void f1682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,15);*r1p=r1;*r0p=r0;}
+static void f1683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-17);*r1p=r1;*r0p=r0;}
+static void f1684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,32);*r1p=r1;*r0p=r0;}
+static void f1685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-32);*r1p=r1;*r0p=r0;}
+static void f1686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,31);*r1p=r1;*r0p=r0;}
+static void f1687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-33);*r1p=r1;*r0p=r0;}
+static void f1688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,64);*r1p=r1;*r0p=r0;}
+static void f1689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-64);*r1p=r1;*r0p=r0;}
+static void f1690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,63);*r1p=r1;*r0p=r0;}
+static void f1691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-65);*r1p=r1;*r0p=r0;}
+static void f1692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,128);*r1p=r1;*r0p=r0;}
+static void f1693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-128);*r1p=r1;*r0p=r0;}
+static void f1694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,127);*r1p=r1;*r0p=r0;}
+static void f1695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-129);*r1p=r1;*r0p=r0;}
+static void f1696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,256);*r1p=r1;*r0p=r0;}
+static void f1697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-256);*r1p=r1;*r0p=r0;}
+static void f1698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,255);*r1p=r1;*r0p=r0;}
+static void f1699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-257);*r1p=r1;*r0p=r0;}
+static void f1700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,512);*r1p=r1;*r0p=r0;}
+static void f1701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-512);*r1p=r1;*r0p=r0;}
+static void f1702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,511);*r1p=r1;*r0p=r0;}
+static void f1703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-513);*r1p=r1;*r0p=r0;}
+static void f1704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,1024);*r1p=r1;*r0p=r0;}
+static void f1705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,1023);*r1p=r1;*r0p=r0;}
+static void f1707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,2048);*r1p=r1;*r0p=r0;}
+static void f1709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,2047);*r1p=r1;*r0p=r0;}
+static void f1711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,4096);*r1p=r1;*r0p=r0;}
+static void f1713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,4095);*r1p=r1;*r0p=r0;}
+static void f1715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,8192);*r1p=r1;*r0p=r0;}
+static void f1717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,8191);*r1p=r1;*r0p=r0;}
+static void f1719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,16384);*r1p=r1;*r0p=r0;}
+static void f1721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,16383);*r1p=r1;*r0p=r0;}
+static void f1723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,32768);*r1p=r1;*r0p=r0;}
+static void f1725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,32767);*r1p=r1;*r0p=r0;}
+static void f1727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,63,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,1);*r1p=r1;*r0p=r0;}
+static void f1729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-1);*r1p=r1;*r0p=r0;}
+static void f1730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,0);*r1p=r1;*r0p=r0;}
+static void f1731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-2);*r1p=r1;*r0p=r0;}
+static void f1732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,2);*r1p=r1;*r0p=r0;}
+static void f1733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-2);*r1p=r1;*r0p=r0;}
+static void f1734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,1);*r1p=r1;*r0p=r0;}
+static void f1735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-3);*r1p=r1;*r0p=r0;}
+static void f1736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,4);*r1p=r1;*r0p=r0;}
+static void f1737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-4);*r1p=r1;*r0p=r0;}
+static void f1738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,3);*r1p=r1;*r0p=r0;}
+static void f1739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-5);*r1p=r1;*r0p=r0;}
+static void f1740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,8);*r1p=r1;*r0p=r0;}
+static void f1741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-8);*r1p=r1;*r0p=r0;}
+static void f1742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,7);*r1p=r1;*r0p=r0;}
+static void f1743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-9);*r1p=r1;*r0p=r0;}
+static void f1744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,16);*r1p=r1;*r0p=r0;}
+static void f1745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-16);*r1p=r1;*r0p=r0;}
+static void f1746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,15);*r1p=r1;*r0p=r0;}
+static void f1747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-17);*r1p=r1;*r0p=r0;}
+static void f1748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,32);*r1p=r1;*r0p=r0;}
+static void f1749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-32);*r1p=r1;*r0p=r0;}
+static void f1750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,31);*r1p=r1;*r0p=r0;}
+static void f1751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-33);*r1p=r1;*r0p=r0;}
+static void f1752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,64);*r1p=r1;*r0p=r0;}
+static void f1753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-64);*r1p=r1;*r0p=r0;}
+static void f1754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,63);*r1p=r1;*r0p=r0;}
+static void f1755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-65);*r1p=r1;*r0p=r0;}
+static void f1756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,128);*r1p=r1;*r0p=r0;}
+static void f1757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-128);*r1p=r1;*r0p=r0;}
+static void f1758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,127);*r1p=r1;*r0p=r0;}
+static void f1759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-129);*r1p=r1;*r0p=r0;}
+static void f1760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,256);*r1p=r1;*r0p=r0;}
+static void f1761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-256);*r1p=r1;*r0p=r0;}
+static void f1762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,255);*r1p=r1;*r0p=r0;}
+static void f1763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-257);*r1p=r1;*r0p=r0;}
+static void f1764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,512);*r1p=r1;*r0p=r0;}
+static void f1765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-512);*r1p=r1;*r0p=r0;}
+static void f1766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,511);*r1p=r1;*r0p=r0;}
+static void f1767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-513);*r1p=r1;*r0p=r0;}
+static void f1768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,1024);*r1p=r1;*r0p=r0;}
+static void f1769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,1023);*r1p=r1;*r0p=r0;}
+static void f1771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,2048);*r1p=r1;*r0p=r0;}
+static void f1773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,2047);*r1p=r1;*r0p=r0;}
+static void f1775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,4096);*r1p=r1;*r0p=r0;}
+static void f1777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,4095);*r1p=r1;*r0p=r0;}
+static void f1779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,8192);*r1p=r1;*r0p=r0;}
+static void f1781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,8191);*r1p=r1;*r0p=r0;}
+static void f1783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,16384);*r1p=r1;*r0p=r0;}
+static void f1785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,16383);*r1p=r1;*r0p=r0;}
+static void f1787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,32768);*r1p=r1;*r0p=r0;}
+static void f1789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,32767);*r1p=r1;*r0p=r0;}
+static void f1791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-65,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,1);*r1p=r1;*r0p=r0;}
+static void f1793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-1);*r1p=r1;*r0p=r0;}
+static void f1794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,0);*r1p=r1;*r0p=r0;}
+static void f1795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,2);*r1p=r1;*r0p=r0;}
+static void f1797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,1);*r1p=r1;*r0p=r0;}
+static void f1799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-3);*r1p=r1;*r0p=r0;}
+static void f1800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,4);*r1p=r1;*r0p=r0;}
+static void f1801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-4);*r1p=r1;*r0p=r0;}
+static void f1802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,3);*r1p=r1;*r0p=r0;}
+static void f1803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-5);*r1p=r1;*r0p=r0;}
+static void f1804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,8);*r1p=r1;*r0p=r0;}
+static void f1805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-8);*r1p=r1;*r0p=r0;}
+static void f1806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,7);*r1p=r1;*r0p=r0;}
+static void f1807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-9);*r1p=r1;*r0p=r0;}
+static void f1808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,16);*r1p=r1;*r0p=r0;}
+static void f1809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-16);*r1p=r1;*r0p=r0;}
+static void f1810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,15);*r1p=r1;*r0p=r0;}
+static void f1811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-17);*r1p=r1;*r0p=r0;}
+static void f1812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,32);*r1p=r1;*r0p=r0;}
+static void f1813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-32);*r1p=r1;*r0p=r0;}
+static void f1814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,31);*r1p=r1;*r0p=r0;}
+static void f1815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-33);*r1p=r1;*r0p=r0;}
+static void f1816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,64);*r1p=r1;*r0p=r0;}
+static void f1817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-64);*r1p=r1;*r0p=r0;}
+static void f1818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,63);*r1p=r1;*r0p=r0;}
+static void f1819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-65);*r1p=r1;*r0p=r0;}
+static void f1820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,128);*r1p=r1;*r0p=r0;}
+static void f1821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-128);*r1p=r1;*r0p=r0;}
+static void f1822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,127);*r1p=r1;*r0p=r0;}
+static void f1823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-129);*r1p=r1;*r0p=r0;}
+static void f1824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,256);*r1p=r1;*r0p=r0;}
+static void f1825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-256);*r1p=r1;*r0p=r0;}
+static void f1826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,255);*r1p=r1;*r0p=r0;}
+static void f1827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-257);*r1p=r1;*r0p=r0;}
+static void f1828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,512);*r1p=r1;*r0p=r0;}
+static void f1829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-512);*r1p=r1;*r0p=r0;}
+static void f1830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,511);*r1p=r1;*r0p=r0;}
+static void f1831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-513);*r1p=r1;*r0p=r0;}
+static void f1832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,1024);*r1p=r1;*r0p=r0;}
+static void f1833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,1023);*r1p=r1;*r0p=r0;}
+static void f1835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,2048);*r1p=r1;*r0p=r0;}
+static void f1837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,2047);*r1p=r1;*r0p=r0;}
+static void f1839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,4096);*r1p=r1;*r0p=r0;}
+static void f1841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,4095);*r1p=r1;*r0p=r0;}
+static void f1843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,8192);*r1p=r1;*r0p=r0;}
+static void f1845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,8191);*r1p=r1;*r0p=r0;}
+static void f1847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,16384);*r1p=r1;*r0p=r0;}
+static void f1849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,16383);*r1p=r1;*r0p=r0;}
+static void f1851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,32768);*r1p=r1;*r0p=r0;}
+static void f1853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,32767);*r1p=r1;*r0p=r0;}
+static void f1855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,128,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,1);*r1p=r1;*r0p=r0;}
+static void f1857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-1);*r1p=r1;*r0p=r0;}
+static void f1858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,0);*r1p=r1;*r0p=r0;}
+static void f1859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,2);*r1p=r1;*r0p=r0;}
+static void f1861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,1);*r1p=r1;*r0p=r0;}
+static void f1863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-3);*r1p=r1;*r0p=r0;}
+static void f1864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,4);*r1p=r1;*r0p=r0;}
+static void f1865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-4);*r1p=r1;*r0p=r0;}
+static void f1866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,3);*r1p=r1;*r0p=r0;}
+static void f1867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-5);*r1p=r1;*r0p=r0;}
+static void f1868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,8);*r1p=r1;*r0p=r0;}
+static void f1869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-8);*r1p=r1;*r0p=r0;}
+static void f1870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,7);*r1p=r1;*r0p=r0;}
+static void f1871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-9);*r1p=r1;*r0p=r0;}
+static void f1872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,16);*r1p=r1;*r0p=r0;}
+static void f1873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-16);*r1p=r1;*r0p=r0;}
+static void f1874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,15);*r1p=r1;*r0p=r0;}
+static void f1875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-17);*r1p=r1;*r0p=r0;}
+static void f1876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,32);*r1p=r1;*r0p=r0;}
+static void f1877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-32);*r1p=r1;*r0p=r0;}
+static void f1878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,31);*r1p=r1;*r0p=r0;}
+static void f1879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-33);*r1p=r1;*r0p=r0;}
+static void f1880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,64);*r1p=r1;*r0p=r0;}
+static void f1881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-64);*r1p=r1;*r0p=r0;}
+static void f1882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,63);*r1p=r1;*r0p=r0;}
+static void f1883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-65);*r1p=r1;*r0p=r0;}
+static void f1884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,128);*r1p=r1;*r0p=r0;}
+static void f1885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-128);*r1p=r1;*r0p=r0;}
+static void f1886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,127);*r1p=r1;*r0p=r0;}
+static void f1887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-129);*r1p=r1;*r0p=r0;}
+static void f1888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,256);*r1p=r1;*r0p=r0;}
+static void f1889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-256);*r1p=r1;*r0p=r0;}
+static void f1890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,255);*r1p=r1;*r0p=r0;}
+static void f1891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-257);*r1p=r1;*r0p=r0;}
+static void f1892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,512);*r1p=r1;*r0p=r0;}
+static void f1893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-512);*r1p=r1;*r0p=r0;}
+static void f1894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,511);*r1p=r1;*r0p=r0;}
+static void f1895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-513);*r1p=r1;*r0p=r0;}
+static void f1896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,1024);*r1p=r1;*r0p=r0;}
+static void f1897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,1023);*r1p=r1;*r0p=r0;}
+static void f1899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,2048);*r1p=r1;*r0p=r0;}
+static void f1901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,2047);*r1p=r1;*r0p=r0;}
+static void f1903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,4096);*r1p=r1;*r0p=r0;}
+static void f1905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,4095);*r1p=r1;*r0p=r0;}
+static void f1907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,8192);*r1p=r1;*r0p=r0;}
+static void f1909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,8191);*r1p=r1;*r0p=r0;}
+static void f1911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,16384);*r1p=r1;*r0p=r0;}
+static void f1913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,16383);*r1p=r1;*r0p=r0;}
+static void f1915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,32768);*r1p=r1;*r0p=r0;}
+static void f1917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,32767);*r1p=r1;*r0p=r0;}
+static void f1919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-128,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,1);*r1p=r1;*r0p=r0;}
+static void f1921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-1);*r1p=r1;*r0p=r0;}
+static void f1922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,0);*r1p=r1;*r0p=r0;}
+static void f1923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-2);*r1p=r1;*r0p=r0;}
+static void f1924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,2);*r1p=r1;*r0p=r0;}
+static void f1925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-2);*r1p=r1;*r0p=r0;}
+static void f1926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,1);*r1p=r1;*r0p=r0;}
+static void f1927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-3);*r1p=r1;*r0p=r0;}
+static void f1928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,4);*r1p=r1;*r0p=r0;}
+static void f1929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-4);*r1p=r1;*r0p=r0;}
+static void f1930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,3);*r1p=r1;*r0p=r0;}
+static void f1931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-5);*r1p=r1;*r0p=r0;}
+static void f1932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,8);*r1p=r1;*r0p=r0;}
+static void f1933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-8);*r1p=r1;*r0p=r0;}
+static void f1934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,7);*r1p=r1;*r0p=r0;}
+static void f1935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-9);*r1p=r1;*r0p=r0;}
+static void f1936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,16);*r1p=r1;*r0p=r0;}
+static void f1937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-16);*r1p=r1;*r0p=r0;}
+static void f1938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,15);*r1p=r1;*r0p=r0;}
+static void f1939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-17);*r1p=r1;*r0p=r0;}
+static void f1940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,32);*r1p=r1;*r0p=r0;}
+static void f1941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-32);*r1p=r1;*r0p=r0;}
+static void f1942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,31);*r1p=r1;*r0p=r0;}
+static void f1943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-33);*r1p=r1;*r0p=r0;}
+static void f1944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,64);*r1p=r1;*r0p=r0;}
+static void f1945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-64);*r1p=r1;*r0p=r0;}
+static void f1946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,63);*r1p=r1;*r0p=r0;}
+static void f1947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-65);*r1p=r1;*r0p=r0;}
+static void f1948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,128);*r1p=r1;*r0p=r0;}
+static void f1949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-128);*r1p=r1;*r0p=r0;}
+static void f1950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,127);*r1p=r1;*r0p=r0;}
+static void f1951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-129);*r1p=r1;*r0p=r0;}
+static void f1952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,256);*r1p=r1;*r0p=r0;}
+static void f1953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-256);*r1p=r1;*r0p=r0;}
+static void f1954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,255);*r1p=r1;*r0p=r0;}
+static void f1955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-257);*r1p=r1;*r0p=r0;}
+static void f1956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,512);*r1p=r1;*r0p=r0;}
+static void f1957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-512);*r1p=r1;*r0p=r0;}
+static void f1958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,511);*r1p=r1;*r0p=r0;}
+static void f1959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-513);*r1p=r1;*r0p=r0;}
+static void f1960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,1024);*r1p=r1;*r0p=r0;}
+static void f1961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,1023);*r1p=r1;*r0p=r0;}
+static void f1963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,2048);*r1p=r1;*r0p=r0;}
+static void f1965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,2047);*r1p=r1;*r0p=r0;}
+static void f1967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,4096);*r1p=r1;*r0p=r0;}
+static void f1969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,4095);*r1p=r1;*r0p=r0;}
+static void f1971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,8192);*r1p=r1;*r0p=r0;}
+static void f1973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,8191);*r1p=r1;*r0p=r0;}
+static void f1975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,16384);*r1p=r1;*r0p=r0;}
+static void f1977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,16383);*r1p=r1;*r0p=r0;}
+static void f1979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,32768);*r1p=r1;*r0p=r0;}
+static void f1981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,32767);*r1p=r1;*r0p=r0;}
+static void f1983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,127,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,1);*r1p=r1;*r0p=r0;}
+static void f1985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-1);*r1p=r1;*r0p=r0;}
+static void f1986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,0);*r1p=r1;*r0p=r0;}
+static void f1987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-2);*r1p=r1;*r0p=r0;}
+static void f1988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,2);*r1p=r1;*r0p=r0;}
+static void f1989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-2);*r1p=r1;*r0p=r0;}
+static void f1990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,1);*r1p=r1;*r0p=r0;}
+static void f1991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-3);*r1p=r1;*r0p=r0;}
+static void f1992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,4);*r1p=r1;*r0p=r0;}
+static void f1993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-4);*r1p=r1;*r0p=r0;}
+static void f1994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,3);*r1p=r1;*r0p=r0;}
+static void f1995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-5);*r1p=r1;*r0p=r0;}
+static void f1996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,8);*r1p=r1;*r0p=r0;}
+static void f1997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-8);*r1p=r1;*r0p=r0;}
+static void f1998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,7);*r1p=r1;*r0p=r0;}
+static void f1999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-9);*r1p=r1;*r0p=r0;}
+static void f2000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,16);*r1p=r1;*r0p=r0;}
+static void f2001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-16);*r1p=r1;*r0p=r0;}
+static void f2002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,15);*r1p=r1;*r0p=r0;}
+static void f2003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-17);*r1p=r1;*r0p=r0;}
+static void f2004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,32);*r1p=r1;*r0p=r0;}
+static void f2005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-32);*r1p=r1;*r0p=r0;}
+static void f2006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,31);*r1p=r1;*r0p=r0;}
+static void f2007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-33);*r1p=r1;*r0p=r0;}
+static void f2008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,64);*r1p=r1;*r0p=r0;}
+static void f2009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-64);*r1p=r1;*r0p=r0;}
+static void f2010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,63);*r1p=r1;*r0p=r0;}
+static void f2011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-65);*r1p=r1;*r0p=r0;}
+static void f2012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,128);*r1p=r1;*r0p=r0;}
+static void f2013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-128);*r1p=r1;*r0p=r0;}
+static void f2014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,127);*r1p=r1;*r0p=r0;}
+static void f2015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-129);*r1p=r1;*r0p=r0;}
+static void f2016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,256);*r1p=r1;*r0p=r0;}
+static void f2017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-256);*r1p=r1;*r0p=r0;}
+static void f2018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,255);*r1p=r1;*r0p=r0;}
+static void f2019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-257);*r1p=r1;*r0p=r0;}
+static void f2020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,512);*r1p=r1;*r0p=r0;}
+static void f2021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-512);*r1p=r1;*r0p=r0;}
+static void f2022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,511);*r1p=r1;*r0p=r0;}
+static void f2023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-513);*r1p=r1;*r0p=r0;}
+static void f2024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,1024);*r1p=r1;*r0p=r0;}
+static void f2025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,1023);*r1p=r1;*r0p=r0;}
+static void f2027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,2048);*r1p=r1;*r0p=r0;}
+static void f2029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,2047);*r1p=r1;*r0p=r0;}
+static void f2031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,4096);*r1p=r1;*r0p=r0;}
+static void f2033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,4095);*r1p=r1;*r0p=r0;}
+static void f2035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,8192);*r1p=r1;*r0p=r0;}
+static void f2037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,8191);*r1p=r1;*r0p=r0;}
+static void f2039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,16384);*r1p=r1;*r0p=r0;}
+static void f2041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,16383);*r1p=r1;*r0p=r0;}
+static void f2043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,32768);*r1p=r1;*r0p=r0;}
+static void f2045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,32767);*r1p=r1;*r0p=r0;}
+static void f2047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-129,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,1);*r1p=r1;*r0p=r0;}
+static void f2049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-1);*r1p=r1;*r0p=r0;}
+static void f2050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,0);*r1p=r1;*r0p=r0;}
+static void f2051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,2);*r1p=r1;*r0p=r0;}
+static void f2053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,1);*r1p=r1;*r0p=r0;}
+static void f2055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-3);*r1p=r1;*r0p=r0;}
+static void f2056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,4);*r1p=r1;*r0p=r0;}
+static void f2057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-4);*r1p=r1;*r0p=r0;}
+static void f2058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,3);*r1p=r1;*r0p=r0;}
+static void f2059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-5);*r1p=r1;*r0p=r0;}
+static void f2060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,8);*r1p=r1;*r0p=r0;}
+static void f2061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-8);*r1p=r1;*r0p=r0;}
+static void f2062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,7);*r1p=r1;*r0p=r0;}
+static void f2063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-9);*r1p=r1;*r0p=r0;}
+static void f2064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,16);*r1p=r1;*r0p=r0;}
+static void f2065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-16);*r1p=r1;*r0p=r0;}
+static void f2066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,15);*r1p=r1;*r0p=r0;}
+static void f2067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-17);*r1p=r1;*r0p=r0;}
+static void f2068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,32);*r1p=r1;*r0p=r0;}
+static void f2069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-32);*r1p=r1;*r0p=r0;}
+static void f2070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,31);*r1p=r1;*r0p=r0;}
+static void f2071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-33);*r1p=r1;*r0p=r0;}
+static void f2072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,64);*r1p=r1;*r0p=r0;}
+static void f2073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-64);*r1p=r1;*r0p=r0;}
+static void f2074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,63);*r1p=r1;*r0p=r0;}
+static void f2075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-65);*r1p=r1;*r0p=r0;}
+static void f2076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,128);*r1p=r1;*r0p=r0;}
+static void f2077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-128);*r1p=r1;*r0p=r0;}
+static void f2078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,127);*r1p=r1;*r0p=r0;}
+static void f2079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-129);*r1p=r1;*r0p=r0;}
+static void f2080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,256);*r1p=r1;*r0p=r0;}
+static void f2081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-256);*r1p=r1;*r0p=r0;}
+static void f2082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,255);*r1p=r1;*r0p=r0;}
+static void f2083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-257);*r1p=r1;*r0p=r0;}
+static void f2084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,512);*r1p=r1;*r0p=r0;}
+static void f2085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-512);*r1p=r1;*r0p=r0;}
+static void f2086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,511);*r1p=r1;*r0p=r0;}
+static void f2087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-513);*r1p=r1;*r0p=r0;}
+static void f2088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,1024);*r1p=r1;*r0p=r0;}
+static void f2089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,1023);*r1p=r1;*r0p=r0;}
+static void f2091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,2048);*r1p=r1;*r0p=r0;}
+static void f2093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,2047);*r1p=r1;*r0p=r0;}
+static void f2095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2096(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,4096);*r1p=r1;*r0p=r0;}
+static void f2097(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2098(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,4095);*r1p=r1;*r0p=r0;}
+static void f2099(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,8192);*r1p=r1;*r0p=r0;}
+static void f2101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,8191);*r1p=r1;*r0p=r0;}
+static void f2103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,16384);*r1p=r1;*r0p=r0;}
+static void f2105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,16383);*r1p=r1;*r0p=r0;}
+static void f2107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,32768);*r1p=r1;*r0p=r0;}
+static void f2109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,32767);*r1p=r1;*r0p=r0;}
+static void f2111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,256,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,1);*r1p=r1;*r0p=r0;}
+static void f2113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-1);*r1p=r1;*r0p=r0;}
+static void f2114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,0);*r1p=r1;*r0p=r0;}
+static void f2115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,2);*r1p=r1;*r0p=r0;}
+static void f2117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,1);*r1p=r1;*r0p=r0;}
+static void f2119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-3);*r1p=r1;*r0p=r0;}
+static void f2120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,4);*r1p=r1;*r0p=r0;}
+static void f2121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-4);*r1p=r1;*r0p=r0;}
+static void f2122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,3);*r1p=r1;*r0p=r0;}
+static void f2123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-5);*r1p=r1;*r0p=r0;}
+static void f2124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,8);*r1p=r1;*r0p=r0;}
+static void f2125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-8);*r1p=r1;*r0p=r0;}
+static void f2126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,7);*r1p=r1;*r0p=r0;}
+static void f2127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-9);*r1p=r1;*r0p=r0;}
+static void f2128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,16);*r1p=r1;*r0p=r0;}
+static void f2129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-16);*r1p=r1;*r0p=r0;}
+static void f2130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,15);*r1p=r1;*r0p=r0;}
+static void f2131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-17);*r1p=r1;*r0p=r0;}
+static void f2132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,32);*r1p=r1;*r0p=r0;}
+static void f2133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-32);*r1p=r1;*r0p=r0;}
+static void f2134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,31);*r1p=r1;*r0p=r0;}
+static void f2135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-33);*r1p=r1;*r0p=r0;}
+static void f2136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,64);*r1p=r1;*r0p=r0;}
+static void f2137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-64);*r1p=r1;*r0p=r0;}
+static void f2138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,63);*r1p=r1;*r0p=r0;}
+static void f2139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-65);*r1p=r1;*r0p=r0;}
+static void f2140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,128);*r1p=r1;*r0p=r0;}
+static void f2141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-128);*r1p=r1;*r0p=r0;}
+static void f2142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,127);*r1p=r1;*r0p=r0;}
+static void f2143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-129);*r1p=r1;*r0p=r0;}
+static void f2144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,256);*r1p=r1;*r0p=r0;}
+static void f2145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-256);*r1p=r1;*r0p=r0;}
+static void f2146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,255);*r1p=r1;*r0p=r0;}
+static void f2147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-257);*r1p=r1;*r0p=r0;}
+static void f2148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,512);*r1p=r1;*r0p=r0;}
+static void f2149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-512);*r1p=r1;*r0p=r0;}
+static void f2150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,511);*r1p=r1;*r0p=r0;}
+static void f2151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-513);*r1p=r1;*r0p=r0;}
+static void f2152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,1024);*r1p=r1;*r0p=r0;}
+static void f2153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,1023);*r1p=r1;*r0p=r0;}
+static void f2155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,2048);*r1p=r1;*r0p=r0;}
+static void f2157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,2047);*r1p=r1;*r0p=r0;}
+static void f2159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,4096);*r1p=r1;*r0p=r0;}
+static void f2161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,4095);*r1p=r1;*r0p=r0;}
+static void f2163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,8192);*r1p=r1;*r0p=r0;}
+static void f2165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,8191);*r1p=r1;*r0p=r0;}
+static void f2167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,16384);*r1p=r1;*r0p=r0;}
+static void f2169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,16383);*r1p=r1;*r0p=r0;}
+static void f2171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,32768);*r1p=r1;*r0p=r0;}
+static void f2173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,32767);*r1p=r1;*r0p=r0;}
+static void f2175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-256,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,1);*r1p=r1;*r0p=r0;}
+static void f2177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-1);*r1p=r1;*r0p=r0;}
+static void f2178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,0);*r1p=r1;*r0p=r0;}
+static void f2179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-2);*r1p=r1;*r0p=r0;}
+static void f2180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,2);*r1p=r1;*r0p=r0;}
+static void f2181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-2);*r1p=r1;*r0p=r0;}
+static void f2182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,1);*r1p=r1;*r0p=r0;}
+static void f2183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-3);*r1p=r1;*r0p=r0;}
+static void f2184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,4);*r1p=r1;*r0p=r0;}
+static void f2185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-4);*r1p=r1;*r0p=r0;}
+static void f2186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,3);*r1p=r1;*r0p=r0;}
+static void f2187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-5);*r1p=r1;*r0p=r0;}
+static void f2188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,8);*r1p=r1;*r0p=r0;}
+static void f2189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-8);*r1p=r1;*r0p=r0;}
+static void f2190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,7);*r1p=r1;*r0p=r0;}
+static void f2191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-9);*r1p=r1;*r0p=r0;}
+static void f2192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,16);*r1p=r1;*r0p=r0;}
+static void f2193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-16);*r1p=r1;*r0p=r0;}
+static void f2194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,15);*r1p=r1;*r0p=r0;}
+static void f2195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-17);*r1p=r1;*r0p=r0;}
+static void f2196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,32);*r1p=r1;*r0p=r0;}
+static void f2197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-32);*r1p=r1;*r0p=r0;}
+static void f2198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,31);*r1p=r1;*r0p=r0;}
+static void f2199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-33);*r1p=r1;*r0p=r0;}
+static void f2200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,64);*r1p=r1;*r0p=r0;}
+static void f2201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-64);*r1p=r1;*r0p=r0;}
+static void f2202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,63);*r1p=r1;*r0p=r0;}
+static void f2203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-65);*r1p=r1;*r0p=r0;}
+static void f2204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,128);*r1p=r1;*r0p=r0;}
+static void f2205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-128);*r1p=r1;*r0p=r0;}
+static void f2206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,127);*r1p=r1;*r0p=r0;}
+static void f2207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-129);*r1p=r1;*r0p=r0;}
+static void f2208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,256);*r1p=r1;*r0p=r0;}
+static void f2209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-256);*r1p=r1;*r0p=r0;}
+static void f2210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,255);*r1p=r1;*r0p=r0;}
+static void f2211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-257);*r1p=r1;*r0p=r0;}
+static void f2212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,512);*r1p=r1;*r0p=r0;}
+static void f2213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-512);*r1p=r1;*r0p=r0;}
+static void f2214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,511);*r1p=r1;*r0p=r0;}
+static void f2215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-513);*r1p=r1;*r0p=r0;}
+static void f2216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,1024);*r1p=r1;*r0p=r0;}
+static void f2217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,1023);*r1p=r1;*r0p=r0;}
+static void f2219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,2048);*r1p=r1;*r0p=r0;}
+static void f2221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,2047);*r1p=r1;*r0p=r0;}
+static void f2223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,4096);*r1p=r1;*r0p=r0;}
+static void f2225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,4095);*r1p=r1;*r0p=r0;}
+static void f2227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,8192);*r1p=r1;*r0p=r0;}
+static void f2229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,8191);*r1p=r1;*r0p=r0;}
+static void f2231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,16384);*r1p=r1;*r0p=r0;}
+static void f2233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,16383);*r1p=r1;*r0p=r0;}
+static void f2235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,32768);*r1p=r1;*r0p=r0;}
+static void f2237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,32767);*r1p=r1;*r0p=r0;}
+static void f2239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,255,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,1);*r1p=r1;*r0p=r0;}
+static void f2241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-1);*r1p=r1;*r0p=r0;}
+static void f2242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,0);*r1p=r1;*r0p=r0;}
+static void f2243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-2);*r1p=r1;*r0p=r0;}
+static void f2244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,2);*r1p=r1;*r0p=r0;}
+static void f2245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-2);*r1p=r1;*r0p=r0;}
+static void f2246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,1);*r1p=r1;*r0p=r0;}
+static void f2247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-3);*r1p=r1;*r0p=r0;}
+static void f2248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,4);*r1p=r1;*r0p=r0;}
+static void f2249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-4);*r1p=r1;*r0p=r0;}
+static void f2250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,3);*r1p=r1;*r0p=r0;}
+static void f2251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-5);*r1p=r1;*r0p=r0;}
+static void f2252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,8);*r1p=r1;*r0p=r0;}
+static void f2253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-8);*r1p=r1;*r0p=r0;}
+static void f2254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,7);*r1p=r1;*r0p=r0;}
+static void f2255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-9);*r1p=r1;*r0p=r0;}
+static void f2256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,16);*r1p=r1;*r0p=r0;}
+static void f2257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-16);*r1p=r1;*r0p=r0;}
+static void f2258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,15);*r1p=r1;*r0p=r0;}
+static void f2259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-17);*r1p=r1;*r0p=r0;}
+static void f2260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,32);*r1p=r1;*r0p=r0;}
+static void f2261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-32);*r1p=r1;*r0p=r0;}
+static void f2262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,31);*r1p=r1;*r0p=r0;}
+static void f2263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-33);*r1p=r1;*r0p=r0;}
+static void f2264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,64);*r1p=r1;*r0p=r0;}
+static void f2265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-64);*r1p=r1;*r0p=r0;}
+static void f2266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,63);*r1p=r1;*r0p=r0;}
+static void f2267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-65);*r1p=r1;*r0p=r0;}
+static void f2268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,128);*r1p=r1;*r0p=r0;}
+static void f2269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-128);*r1p=r1;*r0p=r0;}
+static void f2270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,127);*r1p=r1;*r0p=r0;}
+static void f2271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-129);*r1p=r1;*r0p=r0;}
+static void f2272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,256);*r1p=r1;*r0p=r0;}
+static void f2273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-256);*r1p=r1;*r0p=r0;}
+static void f2274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,255);*r1p=r1;*r0p=r0;}
+static void f2275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-257);*r1p=r1;*r0p=r0;}
+static void f2276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,512);*r1p=r1;*r0p=r0;}
+static void f2277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-512);*r1p=r1;*r0p=r0;}
+static void f2278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,511);*r1p=r1;*r0p=r0;}
+static void f2279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-513);*r1p=r1;*r0p=r0;}
+static void f2280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,1024);*r1p=r1;*r0p=r0;}
+static void f2281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,1023);*r1p=r1;*r0p=r0;}
+static void f2283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,2048);*r1p=r1;*r0p=r0;}
+static void f2285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,2047);*r1p=r1;*r0p=r0;}
+static void f2287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,4096);*r1p=r1;*r0p=r0;}
+static void f2289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,4095);*r1p=r1;*r0p=r0;}
+static void f2291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,8192);*r1p=r1;*r0p=r0;}
+static void f2293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,8191);*r1p=r1;*r0p=r0;}
+static void f2295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,16384);*r1p=r1;*r0p=r0;}
+static void f2297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,16383);*r1p=r1;*r0p=r0;}
+static void f2299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,32768);*r1p=r1;*r0p=r0;}
+static void f2301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,32767);*r1p=r1;*r0p=r0;}
+static void f2303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-257,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,1);*r1p=r1;*r0p=r0;}
+static void f2305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-1);*r1p=r1;*r0p=r0;}
+static void f2306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,0);*r1p=r1;*r0p=r0;}
+static void f2307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,2);*r1p=r1;*r0p=r0;}
+static void f2309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,1);*r1p=r1;*r0p=r0;}
+static void f2311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-3);*r1p=r1;*r0p=r0;}
+static void f2312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,4);*r1p=r1;*r0p=r0;}
+static void f2313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-4);*r1p=r1;*r0p=r0;}
+static void f2314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,3);*r1p=r1;*r0p=r0;}
+static void f2315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-5);*r1p=r1;*r0p=r0;}
+static void f2316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,8);*r1p=r1;*r0p=r0;}
+static void f2317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-8);*r1p=r1;*r0p=r0;}
+static void f2318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,7);*r1p=r1;*r0p=r0;}
+static void f2319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-9);*r1p=r1;*r0p=r0;}
+static void f2320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,16);*r1p=r1;*r0p=r0;}
+static void f2321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-16);*r1p=r1;*r0p=r0;}
+static void f2322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,15);*r1p=r1;*r0p=r0;}
+static void f2323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-17);*r1p=r1;*r0p=r0;}
+static void f2324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,32);*r1p=r1;*r0p=r0;}
+static void f2325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-32);*r1p=r1;*r0p=r0;}
+static void f2326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,31);*r1p=r1;*r0p=r0;}
+static void f2327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-33);*r1p=r1;*r0p=r0;}
+static void f2328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,64);*r1p=r1;*r0p=r0;}
+static void f2329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-64);*r1p=r1;*r0p=r0;}
+static void f2330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,63);*r1p=r1;*r0p=r0;}
+static void f2331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-65);*r1p=r1;*r0p=r0;}
+static void f2332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,128);*r1p=r1;*r0p=r0;}
+static void f2333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-128);*r1p=r1;*r0p=r0;}
+static void f2334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,127);*r1p=r1;*r0p=r0;}
+static void f2335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-129);*r1p=r1;*r0p=r0;}
+static void f2336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,256);*r1p=r1;*r0p=r0;}
+static void f2337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-256);*r1p=r1;*r0p=r0;}
+static void f2338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,255);*r1p=r1;*r0p=r0;}
+static void f2339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-257);*r1p=r1;*r0p=r0;}
+static void f2340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,512);*r1p=r1;*r0p=r0;}
+static void f2341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-512);*r1p=r1;*r0p=r0;}
+static void f2342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,511);*r1p=r1;*r0p=r0;}
+static void f2343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-513);*r1p=r1;*r0p=r0;}
+static void f2344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,1024);*r1p=r1;*r0p=r0;}
+static void f2345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,1023);*r1p=r1;*r0p=r0;}
+static void f2347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,2048);*r1p=r1;*r0p=r0;}
+static void f2349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,2047);*r1p=r1;*r0p=r0;}
+static void f2351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,4096);*r1p=r1;*r0p=r0;}
+static void f2353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,4095);*r1p=r1;*r0p=r0;}
+static void f2355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,8192);*r1p=r1;*r0p=r0;}
+static void f2357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,8191);*r1p=r1;*r0p=r0;}
+static void f2359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,16384);*r1p=r1;*r0p=r0;}
+static void f2361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,16383);*r1p=r1;*r0p=r0;}
+static void f2363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,32768);*r1p=r1;*r0p=r0;}
+static void f2365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,32767);*r1p=r1;*r0p=r0;}
+static void f2367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,512,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,1);*r1p=r1;*r0p=r0;}
+static void f2369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-1);*r1p=r1;*r0p=r0;}
+static void f2370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,0);*r1p=r1;*r0p=r0;}
+static void f2371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,2);*r1p=r1;*r0p=r0;}
+static void f2373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,1);*r1p=r1;*r0p=r0;}
+static void f2375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-3);*r1p=r1;*r0p=r0;}
+static void f2376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,4);*r1p=r1;*r0p=r0;}
+static void f2377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-4);*r1p=r1;*r0p=r0;}
+static void f2378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,3);*r1p=r1;*r0p=r0;}
+static void f2379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-5);*r1p=r1;*r0p=r0;}
+static void f2380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,8);*r1p=r1;*r0p=r0;}
+static void f2381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-8);*r1p=r1;*r0p=r0;}
+static void f2382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,7);*r1p=r1;*r0p=r0;}
+static void f2383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-9);*r1p=r1;*r0p=r0;}
+static void f2384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,16);*r1p=r1;*r0p=r0;}
+static void f2385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-16);*r1p=r1;*r0p=r0;}
+static void f2386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,15);*r1p=r1;*r0p=r0;}
+static void f2387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-17);*r1p=r1;*r0p=r0;}
+static void f2388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,32);*r1p=r1;*r0p=r0;}
+static void f2389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-32);*r1p=r1;*r0p=r0;}
+static void f2390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,31);*r1p=r1;*r0p=r0;}
+static void f2391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-33);*r1p=r1;*r0p=r0;}
+static void f2392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,64);*r1p=r1;*r0p=r0;}
+static void f2393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-64);*r1p=r1;*r0p=r0;}
+static void f2394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,63);*r1p=r1;*r0p=r0;}
+static void f2395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-65);*r1p=r1;*r0p=r0;}
+static void f2396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,128);*r1p=r1;*r0p=r0;}
+static void f2397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-128);*r1p=r1;*r0p=r0;}
+static void f2398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,127);*r1p=r1;*r0p=r0;}
+static void f2399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-129);*r1p=r1;*r0p=r0;}
+static void f2400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,256);*r1p=r1;*r0p=r0;}
+static void f2401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-256);*r1p=r1;*r0p=r0;}
+static void f2402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,255);*r1p=r1;*r0p=r0;}
+static void f2403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-257);*r1p=r1;*r0p=r0;}
+static void f2404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,512);*r1p=r1;*r0p=r0;}
+static void f2405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-512);*r1p=r1;*r0p=r0;}
+static void f2406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,511);*r1p=r1;*r0p=r0;}
+static void f2407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-513);*r1p=r1;*r0p=r0;}
+static void f2408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,1024);*r1p=r1;*r0p=r0;}
+static void f2409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,1023);*r1p=r1;*r0p=r0;}
+static void f2411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,2048);*r1p=r1;*r0p=r0;}
+static void f2413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,2047);*r1p=r1;*r0p=r0;}
+static void f2415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,4096);*r1p=r1;*r0p=r0;}
+static void f2417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,4095);*r1p=r1;*r0p=r0;}
+static void f2419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,8192);*r1p=r1;*r0p=r0;}
+static void f2421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,8191);*r1p=r1;*r0p=r0;}
+static void f2423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,16384);*r1p=r1;*r0p=r0;}
+static void f2425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,16383);*r1p=r1;*r0p=r0;}
+static void f2427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,32768);*r1p=r1;*r0p=r0;}
+static void f2429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,32767);*r1p=r1;*r0p=r0;}
+static void f2431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-512,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,1);*r1p=r1;*r0p=r0;}
+static void f2433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-1);*r1p=r1;*r0p=r0;}
+static void f2434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,0);*r1p=r1;*r0p=r0;}
+static void f2435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-2);*r1p=r1;*r0p=r0;}
+static void f2436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,2);*r1p=r1;*r0p=r0;}
+static void f2437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-2);*r1p=r1;*r0p=r0;}
+static void f2438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,1);*r1p=r1;*r0p=r0;}
+static void f2439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-3);*r1p=r1;*r0p=r0;}
+static void f2440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,4);*r1p=r1;*r0p=r0;}
+static void f2441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-4);*r1p=r1;*r0p=r0;}
+static void f2442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,3);*r1p=r1;*r0p=r0;}
+static void f2443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-5);*r1p=r1;*r0p=r0;}
+static void f2444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,8);*r1p=r1;*r0p=r0;}
+static void f2445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-8);*r1p=r1;*r0p=r0;}
+static void f2446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,7);*r1p=r1;*r0p=r0;}
+static void f2447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-9);*r1p=r1;*r0p=r0;}
+static void f2448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,16);*r1p=r1;*r0p=r0;}
+static void f2449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-16);*r1p=r1;*r0p=r0;}
+static void f2450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,15);*r1p=r1;*r0p=r0;}
+static void f2451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-17);*r1p=r1;*r0p=r0;}
+static void f2452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,32);*r1p=r1;*r0p=r0;}
+static void f2453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-32);*r1p=r1;*r0p=r0;}
+static void f2454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,31);*r1p=r1;*r0p=r0;}
+static void f2455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-33);*r1p=r1;*r0p=r0;}
+static void f2456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,64);*r1p=r1;*r0p=r0;}
+static void f2457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-64);*r1p=r1;*r0p=r0;}
+static void f2458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,63);*r1p=r1;*r0p=r0;}
+static void f2459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-65);*r1p=r1;*r0p=r0;}
+static void f2460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,128);*r1p=r1;*r0p=r0;}
+static void f2461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-128);*r1p=r1;*r0p=r0;}
+static void f2462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,127);*r1p=r1;*r0p=r0;}
+static void f2463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-129);*r1p=r1;*r0p=r0;}
+static void f2464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,256);*r1p=r1;*r0p=r0;}
+static void f2465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-256);*r1p=r1;*r0p=r0;}
+static void f2466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,255);*r1p=r1;*r0p=r0;}
+static void f2467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-257);*r1p=r1;*r0p=r0;}
+static void f2468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,512);*r1p=r1;*r0p=r0;}
+static void f2469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-512);*r1p=r1;*r0p=r0;}
+static void f2470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,511);*r1p=r1;*r0p=r0;}
+static void f2471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-513);*r1p=r1;*r0p=r0;}
+static void f2472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,1024);*r1p=r1;*r0p=r0;}
+static void f2473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,1023);*r1p=r1;*r0p=r0;}
+static void f2475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,2048);*r1p=r1;*r0p=r0;}
+static void f2477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,2047);*r1p=r1;*r0p=r0;}
+static void f2479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,4096);*r1p=r1;*r0p=r0;}
+static void f2481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,4095);*r1p=r1;*r0p=r0;}
+static void f2483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,8192);*r1p=r1;*r0p=r0;}
+static void f2485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,8191);*r1p=r1;*r0p=r0;}
+static void f2487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,16384);*r1p=r1;*r0p=r0;}
+static void f2489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,16383);*r1p=r1;*r0p=r0;}
+static void f2491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,32768);*r1p=r1;*r0p=r0;}
+static void f2493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,32767);*r1p=r1;*r0p=r0;}
+static void f2495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,511,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,1);*r1p=r1;*r0p=r0;}
+static void f2497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-1);*r1p=r1;*r0p=r0;}
+static void f2498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,0);*r1p=r1;*r0p=r0;}
+static void f2499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-2);*r1p=r1;*r0p=r0;}
+static void f2500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,2);*r1p=r1;*r0p=r0;}
+static void f2501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-2);*r1p=r1;*r0p=r0;}
+static void f2502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,1);*r1p=r1;*r0p=r0;}
+static void f2503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-3);*r1p=r1;*r0p=r0;}
+static void f2504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,4);*r1p=r1;*r0p=r0;}
+static void f2505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-4);*r1p=r1;*r0p=r0;}
+static void f2506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,3);*r1p=r1;*r0p=r0;}
+static void f2507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-5);*r1p=r1;*r0p=r0;}
+static void f2508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,8);*r1p=r1;*r0p=r0;}
+static void f2509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-8);*r1p=r1;*r0p=r0;}
+static void f2510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,7);*r1p=r1;*r0p=r0;}
+static void f2511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-9);*r1p=r1;*r0p=r0;}
+static void f2512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,16);*r1p=r1;*r0p=r0;}
+static void f2513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-16);*r1p=r1;*r0p=r0;}
+static void f2514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,15);*r1p=r1;*r0p=r0;}
+static void f2515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-17);*r1p=r1;*r0p=r0;}
+static void f2516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,32);*r1p=r1;*r0p=r0;}
+static void f2517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-32);*r1p=r1;*r0p=r0;}
+static void f2518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,31);*r1p=r1;*r0p=r0;}
+static void f2519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-33);*r1p=r1;*r0p=r0;}
+static void f2520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,64);*r1p=r1;*r0p=r0;}
+static void f2521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-64);*r1p=r1;*r0p=r0;}
+static void f2522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,63);*r1p=r1;*r0p=r0;}
+static void f2523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-65);*r1p=r1;*r0p=r0;}
+static void f2524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,128);*r1p=r1;*r0p=r0;}
+static void f2525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-128);*r1p=r1;*r0p=r0;}
+static void f2526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,127);*r1p=r1;*r0p=r0;}
+static void f2527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-129);*r1p=r1;*r0p=r0;}
+static void f2528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,256);*r1p=r1;*r0p=r0;}
+static void f2529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-256);*r1p=r1;*r0p=r0;}
+static void f2530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,255);*r1p=r1;*r0p=r0;}
+static void f2531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-257);*r1p=r1;*r0p=r0;}
+static void f2532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,512);*r1p=r1;*r0p=r0;}
+static void f2533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-512);*r1p=r1;*r0p=r0;}
+static void f2534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,511);*r1p=r1;*r0p=r0;}
+static void f2535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-513);*r1p=r1;*r0p=r0;}
+static void f2536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,1024);*r1p=r1;*r0p=r0;}
+static void f2537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,1023);*r1p=r1;*r0p=r0;}
+static void f2539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,2048);*r1p=r1;*r0p=r0;}
+static void f2541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,2047);*r1p=r1;*r0p=r0;}
+static void f2543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,4096);*r1p=r1;*r0p=r0;}
+static void f2545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,4095);*r1p=r1;*r0p=r0;}
+static void f2547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,8192);*r1p=r1;*r0p=r0;}
+static void f2549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,8191);*r1p=r1;*r0p=r0;}
+static void f2551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,16384);*r1p=r1;*r0p=r0;}
+static void f2553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,16383);*r1p=r1;*r0p=r0;}
+static void f2555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,32768);*r1p=r1;*r0p=r0;}
+static void f2557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,32767);*r1p=r1;*r0p=r0;}
+static void f2559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-513,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-1);*r1p=r1;*r0p=r0;}
+static void f2562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,0);*r1p=r1;*r0p=r0;}
+static void f2563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,2);*r1p=r1;*r0p=r0;}
+static void f2565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-3);*r1p=r1;*r0p=r0;}
+static void f2568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,4);*r1p=r1;*r0p=r0;}
+static void f2569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-4);*r1p=r1;*r0p=r0;}
+static void f2570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,3);*r1p=r1;*r0p=r0;}
+static void f2571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-5);*r1p=r1;*r0p=r0;}
+static void f2572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,8);*r1p=r1;*r0p=r0;}
+static void f2573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-8);*r1p=r1;*r0p=r0;}
+static void f2574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,7);*r1p=r1;*r0p=r0;}
+static void f2575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-9);*r1p=r1;*r0p=r0;}
+static void f2576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,16);*r1p=r1;*r0p=r0;}
+static void f2577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-16);*r1p=r1;*r0p=r0;}
+static void f2578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,15);*r1p=r1;*r0p=r0;}
+static void f2579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-17);*r1p=r1;*r0p=r0;}
+static void f2580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,32);*r1p=r1;*r0p=r0;}
+static void f2581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-32);*r1p=r1;*r0p=r0;}
+static void f2582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,31);*r1p=r1;*r0p=r0;}
+static void f2583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-33);*r1p=r1;*r0p=r0;}
+static void f2584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,64);*r1p=r1;*r0p=r0;}
+static void f2585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-64);*r1p=r1;*r0p=r0;}
+static void f2586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,63);*r1p=r1;*r0p=r0;}
+static void f2587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-65);*r1p=r1;*r0p=r0;}
+static void f2588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,128);*r1p=r1;*r0p=r0;}
+static void f2589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-128);*r1p=r1;*r0p=r0;}
+static void f2590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,127);*r1p=r1;*r0p=r0;}
+static void f2591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-129);*r1p=r1;*r0p=r0;}
+static void f2592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,256);*r1p=r1;*r0p=r0;}
+static void f2593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-256);*r1p=r1;*r0p=r0;}
+static void f2594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,255);*r1p=r1;*r0p=r0;}
+static void f2595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-257);*r1p=r1;*r0p=r0;}
+static void f2596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,512);*r1p=r1;*r0p=r0;}
+static void f2597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-512);*r1p=r1;*r0p=r0;}
+static void f2598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,511);*r1p=r1;*r0p=r0;}
+static void f2599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-513);*r1p=r1;*r0p=r0;}
+static void f2600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,1024);*r1p=r1;*r0p=r0;}
+static void f2601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,1023);*r1p=r1;*r0p=r0;}
+static void f2603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,2048);*r1p=r1;*r0p=r0;}
+static void f2605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,2047);*r1p=r1;*r0p=r0;}
+static void f2607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,4096);*r1p=r1;*r0p=r0;}
+static void f2609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,4095);*r1p=r1;*r0p=r0;}
+static void f2611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,8192);*r1p=r1;*r0p=r0;}
+static void f2613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,8191);*r1p=r1;*r0p=r0;}
+static void f2615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,16384);*r1p=r1;*r0p=r0;}
+static void f2617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,16383);*r1p=r1;*r0p=r0;}
+static void f2619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,32768);*r1p=r1;*r0p=r0;}
+static void f2621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,32767);*r1p=r1;*r0p=r0;}
+static void f2623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1024,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-1);*r1p=r1;*r0p=r0;}
+static void f2626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,0);*r1p=r1;*r0p=r0;}
+static void f2627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,2);*r1p=r1;*r0p=r0;}
+static void f2629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-3);*r1p=r1;*r0p=r0;}
+static void f2632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,4);*r1p=r1;*r0p=r0;}
+static void f2633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-4);*r1p=r1;*r0p=r0;}
+static void f2634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,3);*r1p=r1;*r0p=r0;}
+static void f2635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-5);*r1p=r1;*r0p=r0;}
+static void f2636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,8);*r1p=r1;*r0p=r0;}
+static void f2637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-8);*r1p=r1;*r0p=r0;}
+static void f2638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,7);*r1p=r1;*r0p=r0;}
+static void f2639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-9);*r1p=r1;*r0p=r0;}
+static void f2640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,16);*r1p=r1;*r0p=r0;}
+static void f2641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-16);*r1p=r1;*r0p=r0;}
+static void f2642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,15);*r1p=r1;*r0p=r0;}
+static void f2643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-17);*r1p=r1;*r0p=r0;}
+static void f2644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,32);*r1p=r1;*r0p=r0;}
+static void f2645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-32);*r1p=r1;*r0p=r0;}
+static void f2646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,31);*r1p=r1;*r0p=r0;}
+static void f2647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-33);*r1p=r1;*r0p=r0;}
+static void f2648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,64);*r1p=r1;*r0p=r0;}
+static void f2649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-64);*r1p=r1;*r0p=r0;}
+static void f2650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,63);*r1p=r1;*r0p=r0;}
+static void f2651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-65);*r1p=r1;*r0p=r0;}
+static void f2652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,128);*r1p=r1;*r0p=r0;}
+static void f2653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-128);*r1p=r1;*r0p=r0;}
+static void f2654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,127);*r1p=r1;*r0p=r0;}
+static void f2655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-129);*r1p=r1;*r0p=r0;}
+static void f2656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,256);*r1p=r1;*r0p=r0;}
+static void f2657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-256);*r1p=r1;*r0p=r0;}
+static void f2658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,255);*r1p=r1;*r0p=r0;}
+static void f2659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-257);*r1p=r1;*r0p=r0;}
+static void f2660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,512);*r1p=r1;*r0p=r0;}
+static void f2661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-512);*r1p=r1;*r0p=r0;}
+static void f2662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,511);*r1p=r1;*r0p=r0;}
+static void f2663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-513);*r1p=r1;*r0p=r0;}
+static void f2664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,1024);*r1p=r1;*r0p=r0;}
+static void f2665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,1023);*r1p=r1;*r0p=r0;}
+static void f2667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,2048);*r1p=r1;*r0p=r0;}
+static void f2669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,2047);*r1p=r1;*r0p=r0;}
+static void f2671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,4096);*r1p=r1;*r0p=r0;}
+static void f2673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,4095);*r1p=r1;*r0p=r0;}
+static void f2675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,8192);*r1p=r1;*r0p=r0;}
+static void f2677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,8191);*r1p=r1;*r0p=r0;}
+static void f2679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,16384);*r1p=r1;*r0p=r0;}
+static void f2681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,16383);*r1p=r1;*r0p=r0;}
+static void f2683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,32768);*r1p=r1;*r0p=r0;}
+static void f2685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,32767);*r1p=r1;*r0p=r0;}
+static void f2687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1024,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,1);*r1p=r1;*r0p=r0;}
+static void f2689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-1);*r1p=r1;*r0p=r0;}
+static void f2690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,0);*r1p=r1;*r0p=r0;}
+static void f2691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-2);*r1p=r1;*r0p=r0;}
+static void f2692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,2);*r1p=r1;*r0p=r0;}
+static void f2693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-2);*r1p=r1;*r0p=r0;}
+static void f2694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,1);*r1p=r1;*r0p=r0;}
+static void f2695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-3);*r1p=r1;*r0p=r0;}
+static void f2696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,4);*r1p=r1;*r0p=r0;}
+static void f2697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-4);*r1p=r1;*r0p=r0;}
+static void f2698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,3);*r1p=r1;*r0p=r0;}
+static void f2699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-5);*r1p=r1;*r0p=r0;}
+static void f2700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,8);*r1p=r1;*r0p=r0;}
+static void f2701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-8);*r1p=r1;*r0p=r0;}
+static void f2702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,7);*r1p=r1;*r0p=r0;}
+static void f2703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-9);*r1p=r1;*r0p=r0;}
+static void f2704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,16);*r1p=r1;*r0p=r0;}
+static void f2705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-16);*r1p=r1;*r0p=r0;}
+static void f2706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,15);*r1p=r1;*r0p=r0;}
+static void f2707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-17);*r1p=r1;*r0p=r0;}
+static void f2708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,32);*r1p=r1;*r0p=r0;}
+static void f2709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-32);*r1p=r1;*r0p=r0;}
+static void f2710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,31);*r1p=r1;*r0p=r0;}
+static void f2711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-33);*r1p=r1;*r0p=r0;}
+static void f2712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,64);*r1p=r1;*r0p=r0;}
+static void f2713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-64);*r1p=r1;*r0p=r0;}
+static void f2714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,63);*r1p=r1;*r0p=r0;}
+static void f2715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-65);*r1p=r1;*r0p=r0;}
+static void f2716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,128);*r1p=r1;*r0p=r0;}
+static void f2717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-128);*r1p=r1;*r0p=r0;}
+static void f2718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,127);*r1p=r1;*r0p=r0;}
+static void f2719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-129);*r1p=r1;*r0p=r0;}
+static void f2720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,256);*r1p=r1;*r0p=r0;}
+static void f2721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-256);*r1p=r1;*r0p=r0;}
+static void f2722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,255);*r1p=r1;*r0p=r0;}
+static void f2723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-257);*r1p=r1;*r0p=r0;}
+static void f2724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,512);*r1p=r1;*r0p=r0;}
+static void f2725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-512);*r1p=r1;*r0p=r0;}
+static void f2726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,511);*r1p=r1;*r0p=r0;}
+static void f2727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-513);*r1p=r1;*r0p=r0;}
+static void f2728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,1024);*r1p=r1;*r0p=r0;}
+static void f2729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,1023);*r1p=r1;*r0p=r0;}
+static void f2731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,2048);*r1p=r1;*r0p=r0;}
+static void f2733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,2047);*r1p=r1;*r0p=r0;}
+static void f2735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,4096);*r1p=r1;*r0p=r0;}
+static void f2737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,4095);*r1p=r1;*r0p=r0;}
+static void f2739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,8192);*r1p=r1;*r0p=r0;}
+static void f2741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,8191);*r1p=r1;*r0p=r0;}
+static void f2743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,16384);*r1p=r1;*r0p=r0;}
+static void f2745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,16383);*r1p=r1;*r0p=r0;}
+static void f2747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,32768);*r1p=r1;*r0p=r0;}
+static void f2749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,32767);*r1p=r1;*r0p=r0;}
+static void f2751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,1023,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,1);*r1p=r1;*r0p=r0;}
+static void f2753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-1);*r1p=r1;*r0p=r0;}
+static void f2754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,0);*r1p=r1;*r0p=r0;}
+static void f2755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-2);*r1p=r1;*r0p=r0;}
+static void f2756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,2);*r1p=r1;*r0p=r0;}
+static void f2757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-2);*r1p=r1;*r0p=r0;}
+static void f2758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,1);*r1p=r1;*r0p=r0;}
+static void f2759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-3);*r1p=r1;*r0p=r0;}
+static void f2760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,4);*r1p=r1;*r0p=r0;}
+static void f2761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-4);*r1p=r1;*r0p=r0;}
+static void f2762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,3);*r1p=r1;*r0p=r0;}
+static void f2763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-5);*r1p=r1;*r0p=r0;}
+static void f2764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,8);*r1p=r1;*r0p=r0;}
+static void f2765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-8);*r1p=r1;*r0p=r0;}
+static void f2766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,7);*r1p=r1;*r0p=r0;}
+static void f2767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-9);*r1p=r1;*r0p=r0;}
+static void f2768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,16);*r1p=r1;*r0p=r0;}
+static void f2769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-16);*r1p=r1;*r0p=r0;}
+static void f2770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,15);*r1p=r1;*r0p=r0;}
+static void f2771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-17);*r1p=r1;*r0p=r0;}
+static void f2772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,32);*r1p=r1;*r0p=r0;}
+static void f2773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-32);*r1p=r1;*r0p=r0;}
+static void f2774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,31);*r1p=r1;*r0p=r0;}
+static void f2775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-33);*r1p=r1;*r0p=r0;}
+static void f2776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,64);*r1p=r1;*r0p=r0;}
+static void f2777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-64);*r1p=r1;*r0p=r0;}
+static void f2778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,63);*r1p=r1;*r0p=r0;}
+static void f2779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-65);*r1p=r1;*r0p=r0;}
+static void f2780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,128);*r1p=r1;*r0p=r0;}
+static void f2781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-128);*r1p=r1;*r0p=r0;}
+static void f2782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,127);*r1p=r1;*r0p=r0;}
+static void f2783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-129);*r1p=r1;*r0p=r0;}
+static void f2784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,256);*r1p=r1;*r0p=r0;}
+static void f2785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-256);*r1p=r1;*r0p=r0;}
+static void f2786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,255);*r1p=r1;*r0p=r0;}
+static void f2787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-257);*r1p=r1;*r0p=r0;}
+static void f2788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,512);*r1p=r1;*r0p=r0;}
+static void f2789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-512);*r1p=r1;*r0p=r0;}
+static void f2790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,511);*r1p=r1;*r0p=r0;}
+static void f2791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-513);*r1p=r1;*r0p=r0;}
+static void f2792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,1024);*r1p=r1;*r0p=r0;}
+static void f2793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,1023);*r1p=r1;*r0p=r0;}
+static void f2795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,2048);*r1p=r1;*r0p=r0;}
+static void f2797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,2047);*r1p=r1;*r0p=r0;}
+static void f2799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,4096);*r1p=r1;*r0p=r0;}
+static void f2801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,4095);*r1p=r1;*r0p=r0;}
+static void f2803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,8192);*r1p=r1;*r0p=r0;}
+static void f2805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,8191);*r1p=r1;*r0p=r0;}
+static void f2807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,16384);*r1p=r1;*r0p=r0;}
+static void f2809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,16383);*r1p=r1;*r0p=r0;}
+static void f2811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,32768);*r1p=r1;*r0p=r0;}
+static void f2813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,32767);*r1p=r1;*r0p=r0;}
+static void f2815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-1025,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-1);*r1p=r1;*r0p=r0;}
+static void f2818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,0);*r1p=r1;*r0p=r0;}
+static void f2819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,2);*r1p=r1;*r0p=r0;}
+static void f2821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-3);*r1p=r1;*r0p=r0;}
+static void f2824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,4);*r1p=r1;*r0p=r0;}
+static void f2825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-4);*r1p=r1;*r0p=r0;}
+static void f2826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,3);*r1p=r1;*r0p=r0;}
+static void f2827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-5);*r1p=r1;*r0p=r0;}
+static void f2828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,8);*r1p=r1;*r0p=r0;}
+static void f2829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-8);*r1p=r1;*r0p=r0;}
+static void f2830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,7);*r1p=r1;*r0p=r0;}
+static void f2831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-9);*r1p=r1;*r0p=r0;}
+static void f2832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,16);*r1p=r1;*r0p=r0;}
+static void f2833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-16);*r1p=r1;*r0p=r0;}
+static void f2834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,15);*r1p=r1;*r0p=r0;}
+static void f2835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-17);*r1p=r1;*r0p=r0;}
+static void f2836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,32);*r1p=r1;*r0p=r0;}
+static void f2837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-32);*r1p=r1;*r0p=r0;}
+static void f2838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,31);*r1p=r1;*r0p=r0;}
+static void f2839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-33);*r1p=r1;*r0p=r0;}
+static void f2840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,64);*r1p=r1;*r0p=r0;}
+static void f2841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-64);*r1p=r1;*r0p=r0;}
+static void f2842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,63);*r1p=r1;*r0p=r0;}
+static void f2843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-65);*r1p=r1;*r0p=r0;}
+static void f2844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,128);*r1p=r1;*r0p=r0;}
+static void f2845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-128);*r1p=r1;*r0p=r0;}
+static void f2846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,127);*r1p=r1;*r0p=r0;}
+static void f2847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-129);*r1p=r1;*r0p=r0;}
+static void f2848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,256);*r1p=r1;*r0p=r0;}
+static void f2849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-256);*r1p=r1;*r0p=r0;}
+static void f2850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,255);*r1p=r1;*r0p=r0;}
+static void f2851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-257);*r1p=r1;*r0p=r0;}
+static void f2852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,512);*r1p=r1;*r0p=r0;}
+static void f2853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-512);*r1p=r1;*r0p=r0;}
+static void f2854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,511);*r1p=r1;*r0p=r0;}
+static void f2855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-513);*r1p=r1;*r0p=r0;}
+static void f2856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,1024);*r1p=r1;*r0p=r0;}
+static void f2857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,1023);*r1p=r1;*r0p=r0;}
+static void f2859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,2048);*r1p=r1;*r0p=r0;}
+static void f2861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,2047);*r1p=r1;*r0p=r0;}
+static void f2863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,4096);*r1p=r1;*r0p=r0;}
+static void f2865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,4095);*r1p=r1;*r0p=r0;}
+static void f2867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,8192);*r1p=r1;*r0p=r0;}
+static void f2869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,8191);*r1p=r1;*r0p=r0;}
+static void f2871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,16384);*r1p=r1;*r0p=r0;}
+static void f2873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,16383);*r1p=r1;*r0p=r0;}
+static void f2875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,32768);*r1p=r1;*r0p=r0;}
+static void f2877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,32767);*r1p=r1;*r0p=r0;}
+static void f2879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2048,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-1);*r1p=r1;*r0p=r0;}
+static void f2882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,0);*r1p=r1;*r0p=r0;}
+static void f2883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,2);*r1p=r1;*r0p=r0;}
+static void f2885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-3);*r1p=r1;*r0p=r0;}
+static void f2888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,4);*r1p=r1;*r0p=r0;}
+static void f2889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-4);*r1p=r1;*r0p=r0;}
+static void f2890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,3);*r1p=r1;*r0p=r0;}
+static void f2891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-5);*r1p=r1;*r0p=r0;}
+static void f2892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,8);*r1p=r1;*r0p=r0;}
+static void f2893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-8);*r1p=r1;*r0p=r0;}
+static void f2894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,7);*r1p=r1;*r0p=r0;}
+static void f2895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-9);*r1p=r1;*r0p=r0;}
+static void f2896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,16);*r1p=r1;*r0p=r0;}
+static void f2897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-16);*r1p=r1;*r0p=r0;}
+static void f2898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,15);*r1p=r1;*r0p=r0;}
+static void f2899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-17);*r1p=r1;*r0p=r0;}
+static void f2900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,32);*r1p=r1;*r0p=r0;}
+static void f2901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-32);*r1p=r1;*r0p=r0;}
+static void f2902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,31);*r1p=r1;*r0p=r0;}
+static void f2903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-33);*r1p=r1;*r0p=r0;}
+static void f2904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,64);*r1p=r1;*r0p=r0;}
+static void f2905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-64);*r1p=r1;*r0p=r0;}
+static void f2906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,63);*r1p=r1;*r0p=r0;}
+static void f2907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-65);*r1p=r1;*r0p=r0;}
+static void f2908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,128);*r1p=r1;*r0p=r0;}
+static void f2909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-128);*r1p=r1;*r0p=r0;}
+static void f2910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,127);*r1p=r1;*r0p=r0;}
+static void f2911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-129);*r1p=r1;*r0p=r0;}
+static void f2912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,256);*r1p=r1;*r0p=r0;}
+static void f2913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-256);*r1p=r1;*r0p=r0;}
+static void f2914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,255);*r1p=r1;*r0p=r0;}
+static void f2915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-257);*r1p=r1;*r0p=r0;}
+static void f2916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,512);*r1p=r1;*r0p=r0;}
+static void f2917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-512);*r1p=r1;*r0p=r0;}
+static void f2918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,511);*r1p=r1;*r0p=r0;}
+static void f2919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-513);*r1p=r1;*r0p=r0;}
+static void f2920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,1024);*r1p=r1;*r0p=r0;}
+static void f2921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,1023);*r1p=r1;*r0p=r0;}
+static void f2923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,2048);*r1p=r1;*r0p=r0;}
+static void f2925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,2047);*r1p=r1;*r0p=r0;}
+static void f2927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,4096);*r1p=r1;*r0p=r0;}
+static void f2929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,4095);*r1p=r1;*r0p=r0;}
+static void f2931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,8192);*r1p=r1;*r0p=r0;}
+static void f2933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,8191);*r1p=r1;*r0p=r0;}
+static void f2935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,16384);*r1p=r1;*r0p=r0;}
+static void f2937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,16383);*r1p=r1;*r0p=r0;}
+static void f2939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,32768);*r1p=r1;*r0p=r0;}
+static void f2941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,32767);*r1p=r1;*r0p=r0;}
+static void f2943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2048,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,1);*r1p=r1;*r0p=r0;}
+static void f2945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-1);*r1p=r1;*r0p=r0;}
+static void f2946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,0);*r1p=r1;*r0p=r0;}
+static void f2947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-2);*r1p=r1;*r0p=r0;}
+static void f2948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,2);*r1p=r1;*r0p=r0;}
+static void f2949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-2);*r1p=r1;*r0p=r0;}
+static void f2950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,1);*r1p=r1;*r0p=r0;}
+static void f2951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-3);*r1p=r1;*r0p=r0;}
+static void f2952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,4);*r1p=r1;*r0p=r0;}
+static void f2953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-4);*r1p=r1;*r0p=r0;}
+static void f2954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,3);*r1p=r1;*r0p=r0;}
+static void f2955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-5);*r1p=r1;*r0p=r0;}
+static void f2956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,8);*r1p=r1;*r0p=r0;}
+static void f2957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-8);*r1p=r1;*r0p=r0;}
+static void f2958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,7);*r1p=r1;*r0p=r0;}
+static void f2959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-9);*r1p=r1;*r0p=r0;}
+static void f2960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,16);*r1p=r1;*r0p=r0;}
+static void f2961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-16);*r1p=r1;*r0p=r0;}
+static void f2962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,15);*r1p=r1;*r0p=r0;}
+static void f2963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-17);*r1p=r1;*r0p=r0;}
+static void f2964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,32);*r1p=r1;*r0p=r0;}
+static void f2965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-32);*r1p=r1;*r0p=r0;}
+static void f2966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,31);*r1p=r1;*r0p=r0;}
+static void f2967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-33);*r1p=r1;*r0p=r0;}
+static void f2968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,64);*r1p=r1;*r0p=r0;}
+static void f2969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-64);*r1p=r1;*r0p=r0;}
+static void f2970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,63);*r1p=r1;*r0p=r0;}
+static void f2971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-65);*r1p=r1;*r0p=r0;}
+static void f2972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,128);*r1p=r1;*r0p=r0;}
+static void f2973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-128);*r1p=r1;*r0p=r0;}
+static void f2974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,127);*r1p=r1;*r0p=r0;}
+static void f2975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-129);*r1p=r1;*r0p=r0;}
+static void f2976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,256);*r1p=r1;*r0p=r0;}
+static void f2977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-256);*r1p=r1;*r0p=r0;}
+static void f2978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,255);*r1p=r1;*r0p=r0;}
+static void f2979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-257);*r1p=r1;*r0p=r0;}
+static void f2980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,512);*r1p=r1;*r0p=r0;}
+static void f2981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-512);*r1p=r1;*r0p=r0;}
+static void f2982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,511);*r1p=r1;*r0p=r0;}
+static void f2983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-513);*r1p=r1;*r0p=r0;}
+static void f2984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,1024);*r1p=r1;*r0p=r0;}
+static void f2985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,1023);*r1p=r1;*r0p=r0;}
+static void f2987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,2048);*r1p=r1;*r0p=r0;}
+static void f2989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,2047);*r1p=r1;*r0p=r0;}
+static void f2991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,4096);*r1p=r1;*r0p=r0;}
+static void f2993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,4095);*r1p=r1;*r0p=r0;}
+static void f2995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,8192);*r1p=r1;*r0p=r0;}
+static void f2997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,8191);*r1p=r1;*r0p=r0;}
+static void f2999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,16384);*r1p=r1;*r0p=r0;}
+static void f3001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,16383);*r1p=r1;*r0p=r0;}
+static void f3003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,32768);*r1p=r1;*r0p=r0;}
+static void f3005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,32767);*r1p=r1;*r0p=r0;}
+static void f3007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,2047,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,1);*r1p=r1;*r0p=r0;}
+static void f3009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-1);*r1p=r1;*r0p=r0;}
+static void f3010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,0);*r1p=r1;*r0p=r0;}
+static void f3011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-2);*r1p=r1;*r0p=r0;}
+static void f3012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,2);*r1p=r1;*r0p=r0;}
+static void f3013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-2);*r1p=r1;*r0p=r0;}
+static void f3014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,1);*r1p=r1;*r0p=r0;}
+static void f3015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-3);*r1p=r1;*r0p=r0;}
+static void f3016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,4);*r1p=r1;*r0p=r0;}
+static void f3017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-4);*r1p=r1;*r0p=r0;}
+static void f3018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,3);*r1p=r1;*r0p=r0;}
+static void f3019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-5);*r1p=r1;*r0p=r0;}
+static void f3020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,8);*r1p=r1;*r0p=r0;}
+static void f3021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-8);*r1p=r1;*r0p=r0;}
+static void f3022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,7);*r1p=r1;*r0p=r0;}
+static void f3023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-9);*r1p=r1;*r0p=r0;}
+static void f3024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,16);*r1p=r1;*r0p=r0;}
+static void f3025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-16);*r1p=r1;*r0p=r0;}
+static void f3026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,15);*r1p=r1;*r0p=r0;}
+static void f3027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-17);*r1p=r1;*r0p=r0;}
+static void f3028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,32);*r1p=r1;*r0p=r0;}
+static void f3029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-32);*r1p=r1;*r0p=r0;}
+static void f3030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,31);*r1p=r1;*r0p=r0;}
+static void f3031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-33);*r1p=r1;*r0p=r0;}
+static void f3032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,64);*r1p=r1;*r0p=r0;}
+static void f3033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-64);*r1p=r1;*r0p=r0;}
+static void f3034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,63);*r1p=r1;*r0p=r0;}
+static void f3035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-65);*r1p=r1;*r0p=r0;}
+static void f3036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,128);*r1p=r1;*r0p=r0;}
+static void f3037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-128);*r1p=r1;*r0p=r0;}
+static void f3038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,127);*r1p=r1;*r0p=r0;}
+static void f3039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-129);*r1p=r1;*r0p=r0;}
+static void f3040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,256);*r1p=r1;*r0p=r0;}
+static void f3041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-256);*r1p=r1;*r0p=r0;}
+static void f3042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,255);*r1p=r1;*r0p=r0;}
+static void f3043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-257);*r1p=r1;*r0p=r0;}
+static void f3044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,512);*r1p=r1;*r0p=r0;}
+static void f3045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-512);*r1p=r1;*r0p=r0;}
+static void f3046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,511);*r1p=r1;*r0p=r0;}
+static void f3047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-513);*r1p=r1;*r0p=r0;}
+static void f3048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,1024);*r1p=r1;*r0p=r0;}
+static void f3049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,1023);*r1p=r1;*r0p=r0;}
+static void f3051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,2048);*r1p=r1;*r0p=r0;}
+static void f3053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,2047);*r1p=r1;*r0p=r0;}
+static void f3055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,4096);*r1p=r1;*r0p=r0;}
+static void f3057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,4095);*r1p=r1;*r0p=r0;}
+static void f3059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,8192);*r1p=r1;*r0p=r0;}
+static void f3061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,8191);*r1p=r1;*r0p=r0;}
+static void f3063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,16384);*r1p=r1;*r0p=r0;}
+static void f3065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,16383);*r1p=r1;*r0p=r0;}
+static void f3067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,32768);*r1p=r1;*r0p=r0;}
+static void f3069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,32767);*r1p=r1;*r0p=r0;}
+static void f3071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-2049,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-1);*r1p=r1;*r0p=r0;}
+static void f3074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,0);*r1p=r1;*r0p=r0;}
+static void f3075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,2);*r1p=r1;*r0p=r0;}
+static void f3077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-3);*r1p=r1;*r0p=r0;}
+static void f3080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,4);*r1p=r1;*r0p=r0;}
+static void f3081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-4);*r1p=r1;*r0p=r0;}
+static void f3082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,3);*r1p=r1;*r0p=r0;}
+static void f3083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-5);*r1p=r1;*r0p=r0;}
+static void f3084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,8);*r1p=r1;*r0p=r0;}
+static void f3085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-8);*r1p=r1;*r0p=r0;}
+static void f3086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,7);*r1p=r1;*r0p=r0;}
+static void f3087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-9);*r1p=r1;*r0p=r0;}
+static void f3088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,16);*r1p=r1;*r0p=r0;}
+static void f3089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-16);*r1p=r1;*r0p=r0;}
+static void f3090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,15);*r1p=r1;*r0p=r0;}
+static void f3091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-17);*r1p=r1;*r0p=r0;}
+static void f3092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,32);*r1p=r1;*r0p=r0;}
+static void f3093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-32);*r1p=r1;*r0p=r0;}
+static void f3094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,31);*r1p=r1;*r0p=r0;}
+static void f3095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-33);*r1p=r1;*r0p=r0;}
+static void f3096(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,64);*r1p=r1;*r0p=r0;}
+static void f3097(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-64);*r1p=r1;*r0p=r0;}
+static void f3098(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,63);*r1p=r1;*r0p=r0;}
+static void f3099(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-65);*r1p=r1;*r0p=r0;}
+static void f3100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,128);*r1p=r1;*r0p=r0;}
+static void f3101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-128);*r1p=r1;*r0p=r0;}
+static void f3102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,127);*r1p=r1;*r0p=r0;}
+static void f3103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-129);*r1p=r1;*r0p=r0;}
+static void f3104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,256);*r1p=r1;*r0p=r0;}
+static void f3105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-256);*r1p=r1;*r0p=r0;}
+static void f3106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,255);*r1p=r1;*r0p=r0;}
+static void f3107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-257);*r1p=r1;*r0p=r0;}
+static void f3108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,512);*r1p=r1;*r0p=r0;}
+static void f3109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-512);*r1p=r1;*r0p=r0;}
+static void f3110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,511);*r1p=r1;*r0p=r0;}
+static void f3111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-513);*r1p=r1;*r0p=r0;}
+static void f3112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,1024);*r1p=r1;*r0p=r0;}
+static void f3113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,1023);*r1p=r1;*r0p=r0;}
+static void f3115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,2048);*r1p=r1;*r0p=r0;}
+static void f3117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,2047);*r1p=r1;*r0p=r0;}
+static void f3119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,4096);*r1p=r1;*r0p=r0;}
+static void f3121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,4095);*r1p=r1;*r0p=r0;}
+static void f3123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,8192);*r1p=r1;*r0p=r0;}
+static void f3125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,8191);*r1p=r1;*r0p=r0;}
+static void f3127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,16384);*r1p=r1;*r0p=r0;}
+static void f3129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,16383);*r1p=r1;*r0p=r0;}
+static void f3131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,32768);*r1p=r1;*r0p=r0;}
+static void f3133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,32767);*r1p=r1;*r0p=r0;}
+static void f3135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4096,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-1);*r1p=r1;*r0p=r0;}
+static void f3138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,0);*r1p=r1;*r0p=r0;}
+static void f3139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,2);*r1p=r1;*r0p=r0;}
+static void f3141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-3);*r1p=r1;*r0p=r0;}
+static void f3144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,4);*r1p=r1;*r0p=r0;}
+static void f3145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-4);*r1p=r1;*r0p=r0;}
+static void f3146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,3);*r1p=r1;*r0p=r0;}
+static void f3147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-5);*r1p=r1;*r0p=r0;}
+static void f3148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,8);*r1p=r1;*r0p=r0;}
+static void f3149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-8);*r1p=r1;*r0p=r0;}
+static void f3150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,7);*r1p=r1;*r0p=r0;}
+static void f3151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-9);*r1p=r1;*r0p=r0;}
+static void f3152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,16);*r1p=r1;*r0p=r0;}
+static void f3153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-16);*r1p=r1;*r0p=r0;}
+static void f3154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,15);*r1p=r1;*r0p=r0;}
+static void f3155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-17);*r1p=r1;*r0p=r0;}
+static void f3156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,32);*r1p=r1;*r0p=r0;}
+static void f3157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-32);*r1p=r1;*r0p=r0;}
+static void f3158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,31);*r1p=r1;*r0p=r0;}
+static void f3159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-33);*r1p=r1;*r0p=r0;}
+static void f3160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,64);*r1p=r1;*r0p=r0;}
+static void f3161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-64);*r1p=r1;*r0p=r0;}
+static void f3162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,63);*r1p=r1;*r0p=r0;}
+static void f3163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-65);*r1p=r1;*r0p=r0;}
+static void f3164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,128);*r1p=r1;*r0p=r0;}
+static void f3165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-128);*r1p=r1;*r0p=r0;}
+static void f3166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,127);*r1p=r1;*r0p=r0;}
+static void f3167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-129);*r1p=r1;*r0p=r0;}
+static void f3168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,256);*r1p=r1;*r0p=r0;}
+static void f3169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-256);*r1p=r1;*r0p=r0;}
+static void f3170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,255);*r1p=r1;*r0p=r0;}
+static void f3171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-257);*r1p=r1;*r0p=r0;}
+static void f3172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,512);*r1p=r1;*r0p=r0;}
+static void f3173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-512);*r1p=r1;*r0p=r0;}
+static void f3174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,511);*r1p=r1;*r0p=r0;}
+static void f3175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-513);*r1p=r1;*r0p=r0;}
+static void f3176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,1024);*r1p=r1;*r0p=r0;}
+static void f3177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,1023);*r1p=r1;*r0p=r0;}
+static void f3179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,2048);*r1p=r1;*r0p=r0;}
+static void f3181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,2047);*r1p=r1;*r0p=r0;}
+static void f3183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,4096);*r1p=r1;*r0p=r0;}
+static void f3185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,4095);*r1p=r1;*r0p=r0;}
+static void f3187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,8192);*r1p=r1;*r0p=r0;}
+static void f3189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,8191);*r1p=r1;*r0p=r0;}
+static void f3191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,16384);*r1p=r1;*r0p=r0;}
+static void f3193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,16383);*r1p=r1;*r0p=r0;}
+static void f3195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,32768);*r1p=r1;*r0p=r0;}
+static void f3197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,32767);*r1p=r1;*r0p=r0;}
+static void f3199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4096,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,1);*r1p=r1;*r0p=r0;}
+static void f3201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-1);*r1p=r1;*r0p=r0;}
+static void f3202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,0);*r1p=r1;*r0p=r0;}
+static void f3203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-2);*r1p=r1;*r0p=r0;}
+static void f3204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,2);*r1p=r1;*r0p=r0;}
+static void f3205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-2);*r1p=r1;*r0p=r0;}
+static void f3206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,1);*r1p=r1;*r0p=r0;}
+static void f3207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-3);*r1p=r1;*r0p=r0;}
+static void f3208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,4);*r1p=r1;*r0p=r0;}
+static void f3209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-4);*r1p=r1;*r0p=r0;}
+static void f3210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,3);*r1p=r1;*r0p=r0;}
+static void f3211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-5);*r1p=r1;*r0p=r0;}
+static void f3212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,8);*r1p=r1;*r0p=r0;}
+static void f3213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-8);*r1p=r1;*r0p=r0;}
+static void f3214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,7);*r1p=r1;*r0p=r0;}
+static void f3215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-9);*r1p=r1;*r0p=r0;}
+static void f3216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,16);*r1p=r1;*r0p=r0;}
+static void f3217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-16);*r1p=r1;*r0p=r0;}
+static void f3218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,15);*r1p=r1;*r0p=r0;}
+static void f3219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-17);*r1p=r1;*r0p=r0;}
+static void f3220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,32);*r1p=r1;*r0p=r0;}
+static void f3221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-32);*r1p=r1;*r0p=r0;}
+static void f3222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,31);*r1p=r1;*r0p=r0;}
+static void f3223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-33);*r1p=r1;*r0p=r0;}
+static void f3224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,64);*r1p=r1;*r0p=r0;}
+static void f3225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-64);*r1p=r1;*r0p=r0;}
+static void f3226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,63);*r1p=r1;*r0p=r0;}
+static void f3227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-65);*r1p=r1;*r0p=r0;}
+static void f3228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,128);*r1p=r1;*r0p=r0;}
+static void f3229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-128);*r1p=r1;*r0p=r0;}
+static void f3230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,127);*r1p=r1;*r0p=r0;}
+static void f3231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-129);*r1p=r1;*r0p=r0;}
+static void f3232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,256);*r1p=r1;*r0p=r0;}
+static void f3233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-256);*r1p=r1;*r0p=r0;}
+static void f3234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,255);*r1p=r1;*r0p=r0;}
+static void f3235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-257);*r1p=r1;*r0p=r0;}
+static void f3236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,512);*r1p=r1;*r0p=r0;}
+static void f3237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-512);*r1p=r1;*r0p=r0;}
+static void f3238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,511);*r1p=r1;*r0p=r0;}
+static void f3239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-513);*r1p=r1;*r0p=r0;}
+static void f3240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,1024);*r1p=r1;*r0p=r0;}
+static void f3241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,1023);*r1p=r1;*r0p=r0;}
+static void f3243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,2048);*r1p=r1;*r0p=r0;}
+static void f3245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,2047);*r1p=r1;*r0p=r0;}
+static void f3247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,4096);*r1p=r1;*r0p=r0;}
+static void f3249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,4095);*r1p=r1;*r0p=r0;}
+static void f3251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,8192);*r1p=r1;*r0p=r0;}
+static void f3253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,8191);*r1p=r1;*r0p=r0;}
+static void f3255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,16384);*r1p=r1;*r0p=r0;}
+static void f3257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,16383);*r1p=r1;*r0p=r0;}
+static void f3259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,32768);*r1p=r1;*r0p=r0;}
+static void f3261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,32767);*r1p=r1;*r0p=r0;}
+static void f3263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,4095,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,1);*r1p=r1;*r0p=r0;}
+static void f3265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-1);*r1p=r1;*r0p=r0;}
+static void f3266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,0);*r1p=r1;*r0p=r0;}
+static void f3267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-2);*r1p=r1;*r0p=r0;}
+static void f3268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,2);*r1p=r1;*r0p=r0;}
+static void f3269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-2);*r1p=r1;*r0p=r0;}
+static void f3270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,1);*r1p=r1;*r0p=r0;}
+static void f3271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-3);*r1p=r1;*r0p=r0;}
+static void f3272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,4);*r1p=r1;*r0p=r0;}
+static void f3273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-4);*r1p=r1;*r0p=r0;}
+static void f3274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,3);*r1p=r1;*r0p=r0;}
+static void f3275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-5);*r1p=r1;*r0p=r0;}
+static void f3276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,8);*r1p=r1;*r0p=r0;}
+static void f3277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-8);*r1p=r1;*r0p=r0;}
+static void f3278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,7);*r1p=r1;*r0p=r0;}
+static void f3279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-9);*r1p=r1;*r0p=r0;}
+static void f3280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,16);*r1p=r1;*r0p=r0;}
+static void f3281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-16);*r1p=r1;*r0p=r0;}
+static void f3282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,15);*r1p=r1;*r0p=r0;}
+static void f3283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-17);*r1p=r1;*r0p=r0;}
+static void f3284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,32);*r1p=r1;*r0p=r0;}
+static void f3285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-32);*r1p=r1;*r0p=r0;}
+static void f3286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,31);*r1p=r1;*r0p=r0;}
+static void f3287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-33);*r1p=r1;*r0p=r0;}
+static void f3288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,64);*r1p=r1;*r0p=r0;}
+static void f3289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-64);*r1p=r1;*r0p=r0;}
+static void f3290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,63);*r1p=r1;*r0p=r0;}
+static void f3291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-65);*r1p=r1;*r0p=r0;}
+static void f3292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,128);*r1p=r1;*r0p=r0;}
+static void f3293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-128);*r1p=r1;*r0p=r0;}
+static void f3294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,127);*r1p=r1;*r0p=r0;}
+static void f3295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-129);*r1p=r1;*r0p=r0;}
+static void f3296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,256);*r1p=r1;*r0p=r0;}
+static void f3297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-256);*r1p=r1;*r0p=r0;}
+static void f3298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,255);*r1p=r1;*r0p=r0;}
+static void f3299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-257);*r1p=r1;*r0p=r0;}
+static void f3300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,512);*r1p=r1;*r0p=r0;}
+static void f3301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-512);*r1p=r1;*r0p=r0;}
+static void f3302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,511);*r1p=r1;*r0p=r0;}
+static void f3303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-513);*r1p=r1;*r0p=r0;}
+static void f3304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,1024);*r1p=r1;*r0p=r0;}
+static void f3305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,1023);*r1p=r1;*r0p=r0;}
+static void f3307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,2048);*r1p=r1;*r0p=r0;}
+static void f3309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,2047);*r1p=r1;*r0p=r0;}
+static void f3311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,4096);*r1p=r1;*r0p=r0;}
+static void f3313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,4095);*r1p=r1;*r0p=r0;}
+static void f3315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,8192);*r1p=r1;*r0p=r0;}
+static void f3317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,8191);*r1p=r1;*r0p=r0;}
+static void f3319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,16384);*r1p=r1;*r0p=r0;}
+static void f3321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,16383);*r1p=r1;*r0p=r0;}
+static void f3323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,32768);*r1p=r1;*r0p=r0;}
+static void f3325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,32767);*r1p=r1;*r0p=r0;}
+static void f3327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-4097,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-1);*r1p=r1;*r0p=r0;}
+static void f3330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,0);*r1p=r1;*r0p=r0;}
+static void f3331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,2);*r1p=r1;*r0p=r0;}
+static void f3333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-3);*r1p=r1;*r0p=r0;}
+static void f3336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,4);*r1p=r1;*r0p=r0;}
+static void f3337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-4);*r1p=r1;*r0p=r0;}
+static void f3338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,3);*r1p=r1;*r0p=r0;}
+static void f3339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-5);*r1p=r1;*r0p=r0;}
+static void f3340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,8);*r1p=r1;*r0p=r0;}
+static void f3341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-8);*r1p=r1;*r0p=r0;}
+static void f3342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,7);*r1p=r1;*r0p=r0;}
+static void f3343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-9);*r1p=r1;*r0p=r0;}
+static void f3344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,16);*r1p=r1;*r0p=r0;}
+static void f3345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-16);*r1p=r1;*r0p=r0;}
+static void f3346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,15);*r1p=r1;*r0p=r0;}
+static void f3347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-17);*r1p=r1;*r0p=r0;}
+static void f3348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,32);*r1p=r1;*r0p=r0;}
+static void f3349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-32);*r1p=r1;*r0p=r0;}
+static void f3350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,31);*r1p=r1;*r0p=r0;}
+static void f3351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-33);*r1p=r1;*r0p=r0;}
+static void f3352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,64);*r1p=r1;*r0p=r0;}
+static void f3353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-64);*r1p=r1;*r0p=r0;}
+static void f3354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,63);*r1p=r1;*r0p=r0;}
+static void f3355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-65);*r1p=r1;*r0p=r0;}
+static void f3356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,128);*r1p=r1;*r0p=r0;}
+static void f3357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-128);*r1p=r1;*r0p=r0;}
+static void f3358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,127);*r1p=r1;*r0p=r0;}
+static void f3359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-129);*r1p=r1;*r0p=r0;}
+static void f3360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,256);*r1p=r1;*r0p=r0;}
+static void f3361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-256);*r1p=r1;*r0p=r0;}
+static void f3362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,255);*r1p=r1;*r0p=r0;}
+static void f3363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-257);*r1p=r1;*r0p=r0;}
+static void f3364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,512);*r1p=r1;*r0p=r0;}
+static void f3365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-512);*r1p=r1;*r0p=r0;}
+static void f3366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,511);*r1p=r1;*r0p=r0;}
+static void f3367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-513);*r1p=r1;*r0p=r0;}
+static void f3368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,1024);*r1p=r1;*r0p=r0;}
+static void f3369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,1023);*r1p=r1;*r0p=r0;}
+static void f3371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,2048);*r1p=r1;*r0p=r0;}
+static void f3373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,2047);*r1p=r1;*r0p=r0;}
+static void f3375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,4096);*r1p=r1;*r0p=r0;}
+static void f3377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,4095);*r1p=r1;*r0p=r0;}
+static void f3379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,8192);*r1p=r1;*r0p=r0;}
+static void f3381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,8191);*r1p=r1;*r0p=r0;}
+static void f3383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,16384);*r1p=r1;*r0p=r0;}
+static void f3385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,16383);*r1p=r1;*r0p=r0;}
+static void f3387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,32768);*r1p=r1;*r0p=r0;}
+static void f3389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,32767);*r1p=r1;*r0p=r0;}
+static void f3391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8192,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-1);*r1p=r1;*r0p=r0;}
+static void f3394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,0);*r1p=r1;*r0p=r0;}
+static void f3395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,2);*r1p=r1;*r0p=r0;}
+static void f3397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-3);*r1p=r1;*r0p=r0;}
+static void f3400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,4);*r1p=r1;*r0p=r0;}
+static void f3401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-4);*r1p=r1;*r0p=r0;}
+static void f3402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,3);*r1p=r1;*r0p=r0;}
+static void f3403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-5);*r1p=r1;*r0p=r0;}
+static void f3404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,8);*r1p=r1;*r0p=r0;}
+static void f3405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-8);*r1p=r1;*r0p=r0;}
+static void f3406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,7);*r1p=r1;*r0p=r0;}
+static void f3407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-9);*r1p=r1;*r0p=r0;}
+static void f3408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,16);*r1p=r1;*r0p=r0;}
+static void f3409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-16);*r1p=r1;*r0p=r0;}
+static void f3410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,15);*r1p=r1;*r0p=r0;}
+static void f3411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-17);*r1p=r1;*r0p=r0;}
+static void f3412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,32);*r1p=r1;*r0p=r0;}
+static void f3413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-32);*r1p=r1;*r0p=r0;}
+static void f3414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,31);*r1p=r1;*r0p=r0;}
+static void f3415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-33);*r1p=r1;*r0p=r0;}
+static void f3416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,64);*r1p=r1;*r0p=r0;}
+static void f3417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-64);*r1p=r1;*r0p=r0;}
+static void f3418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,63);*r1p=r1;*r0p=r0;}
+static void f3419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-65);*r1p=r1;*r0p=r0;}
+static void f3420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,128);*r1p=r1;*r0p=r0;}
+static void f3421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-128);*r1p=r1;*r0p=r0;}
+static void f3422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,127);*r1p=r1;*r0p=r0;}
+static void f3423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-129);*r1p=r1;*r0p=r0;}
+static void f3424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,256);*r1p=r1;*r0p=r0;}
+static void f3425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-256);*r1p=r1;*r0p=r0;}
+static void f3426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,255);*r1p=r1;*r0p=r0;}
+static void f3427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-257);*r1p=r1;*r0p=r0;}
+static void f3428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,512);*r1p=r1;*r0p=r0;}
+static void f3429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-512);*r1p=r1;*r0p=r0;}
+static void f3430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,511);*r1p=r1;*r0p=r0;}
+static void f3431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-513);*r1p=r1;*r0p=r0;}
+static void f3432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,1024);*r1p=r1;*r0p=r0;}
+static void f3433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,1023);*r1p=r1;*r0p=r0;}
+static void f3435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,2048);*r1p=r1;*r0p=r0;}
+static void f3437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,2047);*r1p=r1;*r0p=r0;}
+static void f3439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,4096);*r1p=r1;*r0p=r0;}
+static void f3441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,4095);*r1p=r1;*r0p=r0;}
+static void f3443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,8192);*r1p=r1;*r0p=r0;}
+static void f3445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,8191);*r1p=r1;*r0p=r0;}
+static void f3447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,16384);*r1p=r1;*r0p=r0;}
+static void f3449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,16383);*r1p=r1;*r0p=r0;}
+static void f3451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,32768);*r1p=r1;*r0p=r0;}
+static void f3453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,32767);*r1p=r1;*r0p=r0;}
+static void f3455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8192,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,1);*r1p=r1;*r0p=r0;}
+static void f3457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-1);*r1p=r1;*r0p=r0;}
+static void f3458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,0);*r1p=r1;*r0p=r0;}
+static void f3459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-2);*r1p=r1;*r0p=r0;}
+static void f3460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,2);*r1p=r1;*r0p=r0;}
+static void f3461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-2);*r1p=r1;*r0p=r0;}
+static void f3462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,1);*r1p=r1;*r0p=r0;}
+static void f3463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-3);*r1p=r1;*r0p=r0;}
+static void f3464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,4);*r1p=r1;*r0p=r0;}
+static void f3465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-4);*r1p=r1;*r0p=r0;}
+static void f3466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,3);*r1p=r1;*r0p=r0;}
+static void f3467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-5);*r1p=r1;*r0p=r0;}
+static void f3468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,8);*r1p=r1;*r0p=r0;}
+static void f3469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-8);*r1p=r1;*r0p=r0;}
+static void f3470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,7);*r1p=r1;*r0p=r0;}
+static void f3471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-9);*r1p=r1;*r0p=r0;}
+static void f3472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,16);*r1p=r1;*r0p=r0;}
+static void f3473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-16);*r1p=r1;*r0p=r0;}
+static void f3474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,15);*r1p=r1;*r0p=r0;}
+static void f3475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-17);*r1p=r1;*r0p=r0;}
+static void f3476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,32);*r1p=r1;*r0p=r0;}
+static void f3477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-32);*r1p=r1;*r0p=r0;}
+static void f3478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,31);*r1p=r1;*r0p=r0;}
+static void f3479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-33);*r1p=r1;*r0p=r0;}
+static void f3480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,64);*r1p=r1;*r0p=r0;}
+static void f3481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-64);*r1p=r1;*r0p=r0;}
+static void f3482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,63);*r1p=r1;*r0p=r0;}
+static void f3483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-65);*r1p=r1;*r0p=r0;}
+static void f3484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,128);*r1p=r1;*r0p=r0;}
+static void f3485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-128);*r1p=r1;*r0p=r0;}
+static void f3486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,127);*r1p=r1;*r0p=r0;}
+static void f3487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-129);*r1p=r1;*r0p=r0;}
+static void f3488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,256);*r1p=r1;*r0p=r0;}
+static void f3489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-256);*r1p=r1;*r0p=r0;}
+static void f3490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,255);*r1p=r1;*r0p=r0;}
+static void f3491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-257);*r1p=r1;*r0p=r0;}
+static void f3492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,512);*r1p=r1;*r0p=r0;}
+static void f3493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-512);*r1p=r1;*r0p=r0;}
+static void f3494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,511);*r1p=r1;*r0p=r0;}
+static void f3495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-513);*r1p=r1;*r0p=r0;}
+static void f3496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,1024);*r1p=r1;*r0p=r0;}
+static void f3497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,1023);*r1p=r1;*r0p=r0;}
+static void f3499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,2048);*r1p=r1;*r0p=r0;}
+static void f3501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,2047);*r1p=r1;*r0p=r0;}
+static void f3503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,4096);*r1p=r1;*r0p=r0;}
+static void f3505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,4095);*r1p=r1;*r0p=r0;}
+static void f3507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,8192);*r1p=r1;*r0p=r0;}
+static void f3509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,8191);*r1p=r1;*r0p=r0;}
+static void f3511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,16384);*r1p=r1;*r0p=r0;}
+static void f3513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,16383);*r1p=r1;*r0p=r0;}
+static void f3515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,32768);*r1p=r1;*r0p=r0;}
+static void f3517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,32767);*r1p=r1;*r0p=r0;}
+static void f3519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,8191,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,1);*r1p=r1;*r0p=r0;}
+static void f3521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-1);*r1p=r1;*r0p=r0;}
+static void f3522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,0);*r1p=r1;*r0p=r0;}
+static void f3523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-2);*r1p=r1;*r0p=r0;}
+static void f3524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,2);*r1p=r1;*r0p=r0;}
+static void f3525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-2);*r1p=r1;*r0p=r0;}
+static void f3526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,1);*r1p=r1;*r0p=r0;}
+static void f3527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-3);*r1p=r1;*r0p=r0;}
+static void f3528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,4);*r1p=r1;*r0p=r0;}
+static void f3529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-4);*r1p=r1;*r0p=r0;}
+static void f3530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,3);*r1p=r1;*r0p=r0;}
+static void f3531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-5);*r1p=r1;*r0p=r0;}
+static void f3532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,8);*r1p=r1;*r0p=r0;}
+static void f3533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-8);*r1p=r1;*r0p=r0;}
+static void f3534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,7);*r1p=r1;*r0p=r0;}
+static void f3535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-9);*r1p=r1;*r0p=r0;}
+static void f3536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,16);*r1p=r1;*r0p=r0;}
+static void f3537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-16);*r1p=r1;*r0p=r0;}
+static void f3538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,15);*r1p=r1;*r0p=r0;}
+static void f3539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-17);*r1p=r1;*r0p=r0;}
+static void f3540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,32);*r1p=r1;*r0p=r0;}
+static void f3541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-32);*r1p=r1;*r0p=r0;}
+static void f3542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,31);*r1p=r1;*r0p=r0;}
+static void f3543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-33);*r1p=r1;*r0p=r0;}
+static void f3544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,64);*r1p=r1;*r0p=r0;}
+static void f3545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-64);*r1p=r1;*r0p=r0;}
+static void f3546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,63);*r1p=r1;*r0p=r0;}
+static void f3547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-65);*r1p=r1;*r0p=r0;}
+static void f3548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,128);*r1p=r1;*r0p=r0;}
+static void f3549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-128);*r1p=r1;*r0p=r0;}
+static void f3550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,127);*r1p=r1;*r0p=r0;}
+static void f3551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-129);*r1p=r1;*r0p=r0;}
+static void f3552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,256);*r1p=r1;*r0p=r0;}
+static void f3553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-256);*r1p=r1;*r0p=r0;}
+static void f3554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,255);*r1p=r1;*r0p=r0;}
+static void f3555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-257);*r1p=r1;*r0p=r0;}
+static void f3556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,512);*r1p=r1;*r0p=r0;}
+static void f3557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-512);*r1p=r1;*r0p=r0;}
+static void f3558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,511);*r1p=r1;*r0p=r0;}
+static void f3559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-513);*r1p=r1;*r0p=r0;}
+static void f3560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,1024);*r1p=r1;*r0p=r0;}
+static void f3561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,1023);*r1p=r1;*r0p=r0;}
+static void f3563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,2048);*r1p=r1;*r0p=r0;}
+static void f3565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,2047);*r1p=r1;*r0p=r0;}
+static void f3567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,4096);*r1p=r1;*r0p=r0;}
+static void f3569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,4095);*r1p=r1;*r0p=r0;}
+static void f3571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,8192);*r1p=r1;*r0p=r0;}
+static void f3573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,8191);*r1p=r1;*r0p=r0;}
+static void f3575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,16384);*r1p=r1;*r0p=r0;}
+static void f3577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,16383);*r1p=r1;*r0p=r0;}
+static void f3579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,32768);*r1p=r1;*r0p=r0;}
+static void f3581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,32767);*r1p=r1;*r0p=r0;}
+static void f3583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-8193,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-1);*r1p=r1;*r0p=r0;}
+static void f3586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,0);*r1p=r1;*r0p=r0;}
+static void f3587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,2);*r1p=r1;*r0p=r0;}
+static void f3589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-3);*r1p=r1;*r0p=r0;}
+static void f3592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,4);*r1p=r1;*r0p=r0;}
+static void f3593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-4);*r1p=r1;*r0p=r0;}
+static void f3594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,3);*r1p=r1;*r0p=r0;}
+static void f3595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-5);*r1p=r1;*r0p=r0;}
+static void f3596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,8);*r1p=r1;*r0p=r0;}
+static void f3597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-8);*r1p=r1;*r0p=r0;}
+static void f3598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,7);*r1p=r1;*r0p=r0;}
+static void f3599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-9);*r1p=r1;*r0p=r0;}
+static void f3600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,16);*r1p=r1;*r0p=r0;}
+static void f3601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-16);*r1p=r1;*r0p=r0;}
+static void f3602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,15);*r1p=r1;*r0p=r0;}
+static void f3603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-17);*r1p=r1;*r0p=r0;}
+static void f3604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,32);*r1p=r1;*r0p=r0;}
+static void f3605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-32);*r1p=r1;*r0p=r0;}
+static void f3606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,31);*r1p=r1;*r0p=r0;}
+static void f3607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-33);*r1p=r1;*r0p=r0;}
+static void f3608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,64);*r1p=r1;*r0p=r0;}
+static void f3609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-64);*r1p=r1;*r0p=r0;}
+static void f3610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,63);*r1p=r1;*r0p=r0;}
+static void f3611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-65);*r1p=r1;*r0p=r0;}
+static void f3612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,128);*r1p=r1;*r0p=r0;}
+static void f3613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-128);*r1p=r1;*r0p=r0;}
+static void f3614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,127);*r1p=r1;*r0p=r0;}
+static void f3615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-129);*r1p=r1;*r0p=r0;}
+static void f3616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,256);*r1p=r1;*r0p=r0;}
+static void f3617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-256);*r1p=r1;*r0p=r0;}
+static void f3618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,255);*r1p=r1;*r0p=r0;}
+static void f3619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-257);*r1p=r1;*r0p=r0;}
+static void f3620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,512);*r1p=r1;*r0p=r0;}
+static void f3621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-512);*r1p=r1;*r0p=r0;}
+static void f3622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,511);*r1p=r1;*r0p=r0;}
+static void f3623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-513);*r1p=r1;*r0p=r0;}
+static void f3624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,1024);*r1p=r1;*r0p=r0;}
+static void f3625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,1023);*r1p=r1;*r0p=r0;}
+static void f3627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,2048);*r1p=r1;*r0p=r0;}
+static void f3629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,2047);*r1p=r1;*r0p=r0;}
+static void f3631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,4096);*r1p=r1;*r0p=r0;}
+static void f3633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,4095);*r1p=r1;*r0p=r0;}
+static void f3635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,8192);*r1p=r1;*r0p=r0;}
+static void f3637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,8191);*r1p=r1;*r0p=r0;}
+static void f3639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,16384);*r1p=r1;*r0p=r0;}
+static void f3641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,16383);*r1p=r1;*r0p=r0;}
+static void f3643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,32768);*r1p=r1;*r0p=r0;}
+static void f3645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,32767);*r1p=r1;*r0p=r0;}
+static void f3647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16384,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-1);*r1p=r1;*r0p=r0;}
+static void f3650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,0);*r1p=r1;*r0p=r0;}
+static void f3651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,2);*r1p=r1;*r0p=r0;}
+static void f3653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-3);*r1p=r1;*r0p=r0;}
+static void f3656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,4);*r1p=r1;*r0p=r0;}
+static void f3657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-4);*r1p=r1;*r0p=r0;}
+static void f3658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,3);*r1p=r1;*r0p=r0;}
+static void f3659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-5);*r1p=r1;*r0p=r0;}
+static void f3660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,8);*r1p=r1;*r0p=r0;}
+static void f3661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-8);*r1p=r1;*r0p=r0;}
+static void f3662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,7);*r1p=r1;*r0p=r0;}
+static void f3663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-9);*r1p=r1;*r0p=r0;}
+static void f3664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,16);*r1p=r1;*r0p=r0;}
+static void f3665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-16);*r1p=r1;*r0p=r0;}
+static void f3666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,15);*r1p=r1;*r0p=r0;}
+static void f3667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-17);*r1p=r1;*r0p=r0;}
+static void f3668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,32);*r1p=r1;*r0p=r0;}
+static void f3669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-32);*r1p=r1;*r0p=r0;}
+static void f3670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,31);*r1p=r1;*r0p=r0;}
+static void f3671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-33);*r1p=r1;*r0p=r0;}
+static void f3672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,64);*r1p=r1;*r0p=r0;}
+static void f3673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-64);*r1p=r1;*r0p=r0;}
+static void f3674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,63);*r1p=r1;*r0p=r0;}
+static void f3675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-65);*r1p=r1;*r0p=r0;}
+static void f3676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,128);*r1p=r1;*r0p=r0;}
+static void f3677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-128);*r1p=r1;*r0p=r0;}
+static void f3678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,127);*r1p=r1;*r0p=r0;}
+static void f3679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-129);*r1p=r1;*r0p=r0;}
+static void f3680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,256);*r1p=r1;*r0p=r0;}
+static void f3681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-256);*r1p=r1;*r0p=r0;}
+static void f3682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,255);*r1p=r1;*r0p=r0;}
+static void f3683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-257);*r1p=r1;*r0p=r0;}
+static void f3684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,512);*r1p=r1;*r0p=r0;}
+static void f3685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-512);*r1p=r1;*r0p=r0;}
+static void f3686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,511);*r1p=r1;*r0p=r0;}
+static void f3687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-513);*r1p=r1;*r0p=r0;}
+static void f3688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,1024);*r1p=r1;*r0p=r0;}
+static void f3689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,1023);*r1p=r1;*r0p=r0;}
+static void f3691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,2048);*r1p=r1;*r0p=r0;}
+static void f3693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,2047);*r1p=r1;*r0p=r0;}
+static void f3695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,4096);*r1p=r1;*r0p=r0;}
+static void f3697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,4095);*r1p=r1;*r0p=r0;}
+static void f3699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,8192);*r1p=r1;*r0p=r0;}
+static void f3701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,8191);*r1p=r1;*r0p=r0;}
+static void f3703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,16384);*r1p=r1;*r0p=r0;}
+static void f3705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,16383);*r1p=r1;*r0p=r0;}
+static void f3707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,32768);*r1p=r1;*r0p=r0;}
+static void f3709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,32767);*r1p=r1;*r0p=r0;}
+static void f3711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16384,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,1);*r1p=r1;*r0p=r0;}
+static void f3713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-1);*r1p=r1;*r0p=r0;}
+static void f3714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,0);*r1p=r1;*r0p=r0;}
+static void f3715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-2);*r1p=r1;*r0p=r0;}
+static void f3716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,2);*r1p=r1;*r0p=r0;}
+static void f3717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-2);*r1p=r1;*r0p=r0;}
+static void f3718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,1);*r1p=r1;*r0p=r0;}
+static void f3719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-3);*r1p=r1;*r0p=r0;}
+static void f3720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,4);*r1p=r1;*r0p=r0;}
+static void f3721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-4);*r1p=r1;*r0p=r0;}
+static void f3722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,3);*r1p=r1;*r0p=r0;}
+static void f3723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-5);*r1p=r1;*r0p=r0;}
+static void f3724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,8);*r1p=r1;*r0p=r0;}
+static void f3725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-8);*r1p=r1;*r0p=r0;}
+static void f3726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,7);*r1p=r1;*r0p=r0;}
+static void f3727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-9);*r1p=r1;*r0p=r0;}
+static void f3728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,16);*r1p=r1;*r0p=r0;}
+static void f3729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-16);*r1p=r1;*r0p=r0;}
+static void f3730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,15);*r1p=r1;*r0p=r0;}
+static void f3731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-17);*r1p=r1;*r0p=r0;}
+static void f3732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,32);*r1p=r1;*r0p=r0;}
+static void f3733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-32);*r1p=r1;*r0p=r0;}
+static void f3734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,31);*r1p=r1;*r0p=r0;}
+static void f3735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-33);*r1p=r1;*r0p=r0;}
+static void f3736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,64);*r1p=r1;*r0p=r0;}
+static void f3737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-64);*r1p=r1;*r0p=r0;}
+static void f3738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,63);*r1p=r1;*r0p=r0;}
+static void f3739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-65);*r1p=r1;*r0p=r0;}
+static void f3740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,128);*r1p=r1;*r0p=r0;}
+static void f3741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-128);*r1p=r1;*r0p=r0;}
+static void f3742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,127);*r1p=r1;*r0p=r0;}
+static void f3743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-129);*r1p=r1;*r0p=r0;}
+static void f3744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,256);*r1p=r1;*r0p=r0;}
+static void f3745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-256);*r1p=r1;*r0p=r0;}
+static void f3746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,255);*r1p=r1;*r0p=r0;}
+static void f3747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-257);*r1p=r1;*r0p=r0;}
+static void f3748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,512);*r1p=r1;*r0p=r0;}
+static void f3749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-512);*r1p=r1;*r0p=r0;}
+static void f3750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,511);*r1p=r1;*r0p=r0;}
+static void f3751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-513);*r1p=r1;*r0p=r0;}
+static void f3752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,1024);*r1p=r1;*r0p=r0;}
+static void f3753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,1023);*r1p=r1;*r0p=r0;}
+static void f3755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,2048);*r1p=r1;*r0p=r0;}
+static void f3757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,2047);*r1p=r1;*r0p=r0;}
+static void f3759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,4096);*r1p=r1;*r0p=r0;}
+static void f3761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,4095);*r1p=r1;*r0p=r0;}
+static void f3763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,8192);*r1p=r1;*r0p=r0;}
+static void f3765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,8191);*r1p=r1;*r0p=r0;}
+static void f3767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,16384);*r1p=r1;*r0p=r0;}
+static void f3769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,16383);*r1p=r1;*r0p=r0;}
+static void f3771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,32768);*r1p=r1;*r0p=r0;}
+static void f3773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,32767);*r1p=r1;*r0p=r0;}
+static void f3775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,16383,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,1);*r1p=r1;*r0p=r0;}
+static void f3777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-1);*r1p=r1;*r0p=r0;}
+static void f3778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,0);*r1p=r1;*r0p=r0;}
+static void f3779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-2);*r1p=r1;*r0p=r0;}
+static void f3780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,2);*r1p=r1;*r0p=r0;}
+static void f3781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-2);*r1p=r1;*r0p=r0;}
+static void f3782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,1);*r1p=r1;*r0p=r0;}
+static void f3783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-3);*r1p=r1;*r0p=r0;}
+static void f3784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,4);*r1p=r1;*r0p=r0;}
+static void f3785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-4);*r1p=r1;*r0p=r0;}
+static void f3786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,3);*r1p=r1;*r0p=r0;}
+static void f3787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-5);*r1p=r1;*r0p=r0;}
+static void f3788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,8);*r1p=r1;*r0p=r0;}
+static void f3789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-8);*r1p=r1;*r0p=r0;}
+static void f3790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,7);*r1p=r1;*r0p=r0;}
+static void f3791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-9);*r1p=r1;*r0p=r0;}
+static void f3792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,16);*r1p=r1;*r0p=r0;}
+static void f3793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-16);*r1p=r1;*r0p=r0;}
+static void f3794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,15);*r1p=r1;*r0p=r0;}
+static void f3795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-17);*r1p=r1;*r0p=r0;}
+static void f3796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,32);*r1p=r1;*r0p=r0;}
+static void f3797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-32);*r1p=r1;*r0p=r0;}
+static void f3798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,31);*r1p=r1;*r0p=r0;}
+static void f3799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-33);*r1p=r1;*r0p=r0;}
+static void f3800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,64);*r1p=r1;*r0p=r0;}
+static void f3801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-64);*r1p=r1;*r0p=r0;}
+static void f3802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,63);*r1p=r1;*r0p=r0;}
+static void f3803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-65);*r1p=r1;*r0p=r0;}
+static void f3804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,128);*r1p=r1;*r0p=r0;}
+static void f3805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-128);*r1p=r1;*r0p=r0;}
+static void f3806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,127);*r1p=r1;*r0p=r0;}
+static void f3807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-129);*r1p=r1;*r0p=r0;}
+static void f3808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,256);*r1p=r1;*r0p=r0;}
+static void f3809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-256);*r1p=r1;*r0p=r0;}
+static void f3810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,255);*r1p=r1;*r0p=r0;}
+static void f3811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-257);*r1p=r1;*r0p=r0;}
+static void f3812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,512);*r1p=r1;*r0p=r0;}
+static void f3813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-512);*r1p=r1;*r0p=r0;}
+static void f3814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,511);*r1p=r1;*r0p=r0;}
+static void f3815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-513);*r1p=r1;*r0p=r0;}
+static void f3816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,1024);*r1p=r1;*r0p=r0;}
+static void f3817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,1023);*r1p=r1;*r0p=r0;}
+static void f3819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,2048);*r1p=r1;*r0p=r0;}
+static void f3821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,2047);*r1p=r1;*r0p=r0;}
+static void f3823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,4096);*r1p=r1;*r0p=r0;}
+static void f3825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,4095);*r1p=r1;*r0p=r0;}
+static void f3827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,8192);*r1p=r1;*r0p=r0;}
+static void f3829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,8191);*r1p=r1;*r0p=r0;}
+static void f3831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,16384);*r1p=r1;*r0p=r0;}
+static void f3833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,16383);*r1p=r1;*r0p=r0;}
+static void f3835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,32768);*r1p=r1;*r0p=r0;}
+static void f3837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,32767);*r1p=r1;*r0p=r0;}
+static void f3839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-16385,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-1);*r1p=r1;*r0p=r0;}
+static void f3842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,0);*r1p=r1;*r0p=r0;}
+static void f3843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,2);*r1p=r1;*r0p=r0;}
+static void f3845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-3);*r1p=r1;*r0p=r0;}
+static void f3848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,4);*r1p=r1;*r0p=r0;}
+static void f3849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-4);*r1p=r1;*r0p=r0;}
+static void f3850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,3);*r1p=r1;*r0p=r0;}
+static void f3851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-5);*r1p=r1;*r0p=r0;}
+static void f3852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,8);*r1p=r1;*r0p=r0;}
+static void f3853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-8);*r1p=r1;*r0p=r0;}
+static void f3854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,7);*r1p=r1;*r0p=r0;}
+static void f3855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-9);*r1p=r1;*r0p=r0;}
+static void f3856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,16);*r1p=r1;*r0p=r0;}
+static void f3857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-16);*r1p=r1;*r0p=r0;}
+static void f3858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,15);*r1p=r1;*r0p=r0;}
+static void f3859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-17);*r1p=r1;*r0p=r0;}
+static void f3860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,32);*r1p=r1;*r0p=r0;}
+static void f3861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-32);*r1p=r1;*r0p=r0;}
+static void f3862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,31);*r1p=r1;*r0p=r0;}
+static void f3863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-33);*r1p=r1;*r0p=r0;}
+static void f3864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,64);*r1p=r1;*r0p=r0;}
+static void f3865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-64);*r1p=r1;*r0p=r0;}
+static void f3866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,63);*r1p=r1;*r0p=r0;}
+static void f3867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-65);*r1p=r1;*r0p=r0;}
+static void f3868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,128);*r1p=r1;*r0p=r0;}
+static void f3869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-128);*r1p=r1;*r0p=r0;}
+static void f3870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,127);*r1p=r1;*r0p=r0;}
+static void f3871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-129);*r1p=r1;*r0p=r0;}
+static void f3872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,256);*r1p=r1;*r0p=r0;}
+static void f3873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-256);*r1p=r1;*r0p=r0;}
+static void f3874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,255);*r1p=r1;*r0p=r0;}
+static void f3875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-257);*r1p=r1;*r0p=r0;}
+static void f3876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,512);*r1p=r1;*r0p=r0;}
+static void f3877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-512);*r1p=r1;*r0p=r0;}
+static void f3878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,511);*r1p=r1;*r0p=r0;}
+static void f3879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-513);*r1p=r1;*r0p=r0;}
+static void f3880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,1024);*r1p=r1;*r0p=r0;}
+static void f3881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,1023);*r1p=r1;*r0p=r0;}
+static void f3883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,2048);*r1p=r1;*r0p=r0;}
+static void f3885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,2047);*r1p=r1;*r0p=r0;}
+static void f3887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,4096);*r1p=r1;*r0p=r0;}
+static void f3889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,4095);*r1p=r1;*r0p=r0;}
+static void f3891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,8192);*r1p=r1;*r0p=r0;}
+static void f3893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,8191);*r1p=r1;*r0p=r0;}
+static void f3895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,16384);*r1p=r1;*r0p=r0;}
+static void f3897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,16383);*r1p=r1;*r0p=r0;}
+static void f3899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,32768);*r1p=r1;*r0p=r0;}
+static void f3901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,32767);*r1p=r1;*r0p=r0;}
+static void f3903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32768,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-1);*r1p=r1;*r0p=r0;}
+static void f3906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,0);*r1p=r1;*r0p=r0;}
+static void f3907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,2);*r1p=r1;*r0p=r0;}
+static void f3909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-3);*r1p=r1;*r0p=r0;}
+static void f3912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,4);*r1p=r1;*r0p=r0;}
+static void f3913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-4);*r1p=r1;*r0p=r0;}
+static void f3914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,3);*r1p=r1;*r0p=r0;}
+static void f3915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-5);*r1p=r1;*r0p=r0;}
+static void f3916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,8);*r1p=r1;*r0p=r0;}
+static void f3917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-8);*r1p=r1;*r0p=r0;}
+static void f3918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,7);*r1p=r1;*r0p=r0;}
+static void f3919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-9);*r1p=r1;*r0p=r0;}
+static void f3920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,16);*r1p=r1;*r0p=r0;}
+static void f3921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-16);*r1p=r1;*r0p=r0;}
+static void f3922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,15);*r1p=r1;*r0p=r0;}
+static void f3923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-17);*r1p=r1;*r0p=r0;}
+static void f3924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,32);*r1p=r1;*r0p=r0;}
+static void f3925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-32);*r1p=r1;*r0p=r0;}
+static void f3926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,31);*r1p=r1;*r0p=r0;}
+static void f3927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-33);*r1p=r1;*r0p=r0;}
+static void f3928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,64);*r1p=r1;*r0p=r0;}
+static void f3929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-64);*r1p=r1;*r0p=r0;}
+static void f3930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,63);*r1p=r1;*r0p=r0;}
+static void f3931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-65);*r1p=r1;*r0p=r0;}
+static void f3932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,128);*r1p=r1;*r0p=r0;}
+static void f3933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-128);*r1p=r1;*r0p=r0;}
+static void f3934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,127);*r1p=r1;*r0p=r0;}
+static void f3935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-129);*r1p=r1;*r0p=r0;}
+static void f3936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,256);*r1p=r1;*r0p=r0;}
+static void f3937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-256);*r1p=r1;*r0p=r0;}
+static void f3938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,255);*r1p=r1;*r0p=r0;}
+static void f3939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-257);*r1p=r1;*r0p=r0;}
+static void f3940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,512);*r1p=r1;*r0p=r0;}
+static void f3941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-512);*r1p=r1;*r0p=r0;}
+static void f3942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,511);*r1p=r1;*r0p=r0;}
+static void f3943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-513);*r1p=r1;*r0p=r0;}
+static void f3944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,1024);*r1p=r1;*r0p=r0;}
+static void f3945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,1023);*r1p=r1;*r0p=r0;}
+static void f3947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,2048);*r1p=r1;*r0p=r0;}
+static void f3949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,2047);*r1p=r1;*r0p=r0;}
+static void f3951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,4096);*r1p=r1;*r0p=r0;}
+static void f3953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,4095);*r1p=r1;*r0p=r0;}
+static void f3955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,8192);*r1p=r1;*r0p=r0;}
+static void f3957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,8191);*r1p=r1;*r0p=r0;}
+static void f3959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,16384);*r1p=r1;*r0p=r0;}
+static void f3961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,16383);*r1p=r1;*r0p=r0;}
+static void f3963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,32768);*r1p=r1;*r0p=r0;}
+static void f3965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,32767);*r1p=r1;*r0p=r0;}
+static void f3967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32768,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,1);*r1p=r1;*r0p=r0;}
+static void f3969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-1);*r1p=r1;*r0p=r0;}
+static void f3970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,0);*r1p=r1;*r0p=r0;}
+static void f3971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-2);*r1p=r1;*r0p=r0;}
+static void f3972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,2);*r1p=r1;*r0p=r0;}
+static void f3973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-2);*r1p=r1;*r0p=r0;}
+static void f3974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,1);*r1p=r1;*r0p=r0;}
+static void f3975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-3);*r1p=r1;*r0p=r0;}
+static void f3976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,4);*r1p=r1;*r0p=r0;}
+static void f3977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-4);*r1p=r1;*r0p=r0;}
+static void f3978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,3);*r1p=r1;*r0p=r0;}
+static void f3979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-5);*r1p=r1;*r0p=r0;}
+static void f3980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,8);*r1p=r1;*r0p=r0;}
+static void f3981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-8);*r1p=r1;*r0p=r0;}
+static void f3982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,7);*r1p=r1;*r0p=r0;}
+static void f3983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-9);*r1p=r1;*r0p=r0;}
+static void f3984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,16);*r1p=r1;*r0p=r0;}
+static void f3985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-16);*r1p=r1;*r0p=r0;}
+static void f3986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,15);*r1p=r1;*r0p=r0;}
+static void f3987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-17);*r1p=r1;*r0p=r0;}
+static void f3988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,32);*r1p=r1;*r0p=r0;}
+static void f3989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-32);*r1p=r1;*r0p=r0;}
+static void f3990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,31);*r1p=r1;*r0p=r0;}
+static void f3991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-33);*r1p=r1;*r0p=r0;}
+static void f3992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,64);*r1p=r1;*r0p=r0;}
+static void f3993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-64);*r1p=r1;*r0p=r0;}
+static void f3994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,63);*r1p=r1;*r0p=r0;}
+static void f3995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-65);*r1p=r1;*r0p=r0;}
+static void f3996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,128);*r1p=r1;*r0p=r0;}
+static void f3997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-128);*r1p=r1;*r0p=r0;}
+static void f3998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,127);*r1p=r1;*r0p=r0;}
+static void f3999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-129);*r1p=r1;*r0p=r0;}
+static void f4000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,256);*r1p=r1;*r0p=r0;}
+static void f4001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-256);*r1p=r1;*r0p=r0;}
+static void f4002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,255);*r1p=r1;*r0p=r0;}
+static void f4003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-257);*r1p=r1;*r0p=r0;}
+static void f4004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,512);*r1p=r1;*r0p=r0;}
+static void f4005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-512);*r1p=r1;*r0p=r0;}
+static void f4006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,511);*r1p=r1;*r0p=r0;}
+static void f4007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-513);*r1p=r1;*r0p=r0;}
+static void f4008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,1024);*r1p=r1;*r0p=r0;}
+static void f4009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-1024);*r1p=r1;*r0p=r0;}
+static void f4010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,1023);*r1p=r1;*r0p=r0;}
+static void f4011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-1025);*r1p=r1;*r0p=r0;}
+static void f4012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,2048);*r1p=r1;*r0p=r0;}
+static void f4013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-2048);*r1p=r1;*r0p=r0;}
+static void f4014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,2047);*r1p=r1;*r0p=r0;}
+static void f4015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-2049);*r1p=r1;*r0p=r0;}
+static void f4016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,4096);*r1p=r1;*r0p=r0;}
+static void f4017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-4096);*r1p=r1;*r0p=r0;}
+static void f4018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,4095);*r1p=r1;*r0p=r0;}
+static void f4019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-4097);*r1p=r1;*r0p=r0;}
+static void f4020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,8192);*r1p=r1;*r0p=r0;}
+static void f4021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-8192);*r1p=r1;*r0p=r0;}
+static void f4022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,8191);*r1p=r1;*r0p=r0;}
+static void f4023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-8193);*r1p=r1;*r0p=r0;}
+static void f4024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,16384);*r1p=r1;*r0p=r0;}
+static void f4025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-16384);*r1p=r1;*r0p=r0;}
+static void f4026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,16383);*r1p=r1;*r0p=r0;}
+static void f4027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-16385);*r1p=r1;*r0p=r0;}
+static void f4028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,32768);*r1p=r1;*r0p=r0;}
+static void f4029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-32768);*r1p=r1;*r0p=r0;}
+static void f4030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,32767);*r1p=r1;*r0p=r0;}
+static void f4031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,32767,0,-32769);*r1p=r1;*r0p=r0;}
+static void f4032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,1);*r1p=r1;*r0p=r0;}
+static void f4033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-1);*r1p=r1;*r0p=r0;}
+static void f4034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,0);*r1p=r1;*r0p=r0;}
+static void f4035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-2);*r1p=r1;*r0p=r0;}
+static void f4036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,2);*r1p=r1;*r0p=r0;}
+static void f4037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-2);*r1p=r1;*r0p=r0;}
+static void f4038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,1);*r1p=r1;*r0p=r0;}
+static void f4039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-3);*r1p=r1;*r0p=r0;}
+static void f4040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,4);*r1p=r1;*r0p=r0;}
+static void f4041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-4);*r1p=r1;*r0p=r0;}
+static void f4042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,3);*r1p=r1;*r0p=r0;}
+static void f4043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-5);*r1p=r1;*r0p=r0;}
+static void f4044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,8);*r1p=r1;*r0p=r0;}
+static void f4045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-8);*r1p=r1;*r0p=r0;}
+static void f4046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,7);*r1p=r1;*r0p=r0;}
+static void f4047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-9);*r1p=r1;*r0p=r0;}
+static void f4048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,16);*r1p=r1;*r0p=r0;}
+static void f4049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-16);*r1p=r1;*r0p=r0;}
+static void f4050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,15);*r1p=r1;*r0p=r0;}
+static void f4051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-17);*r1p=r1;*r0p=r0;}
+static void f4052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,32);*r1p=r1;*r0p=r0;}
+static void f4053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-32);*r1p=r1;*r0p=r0;}
+static void f4054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,31);*r1p=r1;*r0p=r0;}
+static void f4055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-33);*r1p=r1;*r0p=r0;}
+static void f4056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,64);*r1p=r1;*r0p=r0;}
+static void f4057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-64);*r1p=r1;*r0p=r0;}
+static void f4058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,63);*r1p=r1;*r0p=r0;}
+static void f4059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-65);*r1p=r1;*r0p=r0;}
+static void f4060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,128);*r1p=r1;*r0p=r0;}
+static void f4061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-128);*r1p=r1;*r0p=r0;}
+static void f4062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,127);*r1p=r1;*r0p=r0;}
+static void f4063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-129);*r1p=r1;*r0p=r0;}
+static void f4064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,256);*r1p=r1;*r0p=r0;}
+static void f4065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-256);*r1p=r1;*r0p=r0;}
+static void f4066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,255);*r1p=r1;*r0p=r0;}
+static void f4067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-257);*r1p=r1;*r0p=r0;}
+static void f4068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,512);*r1p=r1;*r0p=r0;}
+static void f4069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-512);*r1p=r1;*r0p=r0;}
+static void f4070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,511);*r1p=r1;*r0p=r0;}
+static void f4071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-513);*r1p=r1;*r0p=r0;}
+static void f4072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,1024);*r1p=r1;*r0p=r0;}
+static void f4073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-1024);*r1p=r1;*r0p=r0;}
+static void f4074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,1023);*r1p=r1;*r0p=r0;}
+static void f4075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-1025);*r1p=r1;*r0p=r0;}
+static void f4076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,2048);*r1p=r1;*r0p=r0;}
+static void f4077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-2048);*r1p=r1;*r0p=r0;}
+static void f4078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,2047);*r1p=r1;*r0p=r0;}
+static void f4079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-2049);*r1p=r1;*r0p=r0;}
+static void f4080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,4096);*r1p=r1;*r0p=r0;}
+static void f4081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-4096);*r1p=r1;*r0p=r0;}
+static void f4082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,4095);*r1p=r1;*r0p=r0;}
+static void f4083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-4097);*r1p=r1;*r0p=r0;}
+static void f4084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,8192);*r1p=r1;*r0p=r0;}
+static void f4085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-8192);*r1p=r1;*r0p=r0;}
+static void f4086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,8191);*r1p=r1;*r0p=r0;}
+static void f4087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-8193);*r1p=r1;*r0p=r0;}
+static void f4088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,16384);*r1p=r1;*r0p=r0;}
+static void f4089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-16384);*r1p=r1;*r0p=r0;}
+static void f4090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,16383);*r1p=r1;*r0p=r0;}
+static void f4091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-16385);*r1p=r1;*r0p=r0;}
+static void f4092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,32768);*r1p=r1;*r0p=r0;}
+static void f4093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-32768);*r1p=r1;*r0p=r0;}
+static void f4094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,32767);*r1p=r1;*r0p=r0;}
+static void f4095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;add_ssaaaa(r1,r0,0,-32769,0,-32769);*r1p=r1;*r0p=r0;}
+typedef void (*func_t) (mp_limb_t*, mp_limb_t*);
+static const func_t funcs[4096] = {
+f0,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,
+f16,f17,f18,f19,f20,f21,f22,f23,f24,f25,f26,f27,f28,f29,f30,f31,
+f32,f33,f34,f35,f36,f37,f38,f39,f40,f41,f42,f43,f44,f45,f46,f47,
+f48,f49,f50,f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,
+f64,f65,f66,f67,f68,f69,f70,f71,f72,f73,f74,f75,f76,f77,f78,f79,
+f80,f81,f82,f83,f84,f85,f86,f87,f88,f89,f90,f91,f92,f93,f94,f95,
+f96,f97,f98,f99,f100,f101,f102,f103,f104,f105,f106,f107,f108,f109,f110,f111,
+f112,f113,f114,f115,f116,f117,f118,f119,f120,f121,f122,f123,f124,f125,f126,f127,
+f128,f129,f130,f131,f132,f133,f134,f135,f136,f137,f138,f139,f140,f141,f142,f143,
+f144,f145,f146,f147,f148,f149,f150,f151,f152,f153,f154,f155,f156,f157,f158,f159,
+f160,f161,f162,f163,f164,f165,f166,f167,f168,f169,f170,f171,f172,f173,f174,f175,
+f176,f177,f178,f179,f180,f181,f182,f183,f184,f185,f186,f187,f188,f189,f190,f191,
+f192,f193,f194,f195,f196,f197,f198,f199,f200,f201,f202,f203,f204,f205,f206,f207,
+f208,f209,f210,f211,f212,f213,f214,f215,f216,f217,f218,f219,f220,f221,f222,f223,
+f224,f225,f226,f227,f228,f229,f230,f231,f232,f233,f234,f235,f236,f237,f238,f239,
+f240,f241,f242,f243,f244,f245,f246,f247,f248,f249,f250,f251,f252,f253,f254,f255,
+f256,f257,f258,f259,f260,f261,f262,f263,f264,f265,f266,f267,f268,f269,f270,f271,
+f272,f273,f274,f275,f276,f277,f278,f279,f280,f281,f282,f283,f284,f285,f286,f287,
+f288,f289,f290,f291,f292,f293,f294,f295,f296,f297,f298,f299,f300,f301,f302,f303,
+f304,f305,f306,f307,f308,f309,f310,f311,f312,f313,f314,f315,f316,f317,f318,f319,
+f320,f321,f322,f323,f324,f325,f326,f327,f328,f329,f330,f331,f332,f333,f334,f335,
+f336,f337,f338,f339,f340,f341,f342,f343,f344,f345,f346,f347,f348,f349,f350,f351,
+f352,f353,f354,f355,f356,f357,f358,f359,f360,f361,f362,f363,f364,f365,f366,f367,
+f368,f369,f370,f371,f372,f373,f374,f375,f376,f377,f378,f379,f380,f381,f382,f383,
+f384,f385,f386,f387,f388,f389,f390,f391,f392,f393,f394,f395,f396,f397,f398,f399,
+f400,f401,f402,f403,f404,f405,f406,f407,f408,f409,f410,f411,f412,f413,f414,f415,
+f416,f417,f418,f419,f420,f421,f422,f423,f424,f425,f426,f427,f428,f429,f430,f431,
+f432,f433,f434,f435,f436,f437,f438,f439,f440,f441,f442,f443,f444,f445,f446,f447,
+f448,f449,f450,f451,f452,f453,f454,f455,f456,f457,f458,f459,f460,f461,f462,f463,
+f464,f465,f466,f467,f468,f469,f470,f471,f472,f473,f474,f475,f476,f477,f478,f479,
+f480,f481,f482,f483,f484,f485,f486,f487,f488,f489,f490,f491,f492,f493,f494,f495,
+f496,f497,f498,f499,f500,f501,f502,f503,f504,f505,f506,f507,f508,f509,f510,f511,
+f512,f513,f514,f515,f516,f517,f518,f519,f520,f521,f522,f523,f524,f525,f526,f527,
+f528,f529,f530,f531,f532,f533,f534,f535,f536,f537,f538,f539,f540,f541,f542,f543,
+f544,f545,f546,f547,f548,f549,f550,f551,f552,f553,f554,f555,f556,f557,f558,f559,
+f560,f561,f562,f563,f564,f565,f566,f567,f568,f569,f570,f571,f572,f573,f574,f575,
+f576,f577,f578,f579,f580,f581,f582,f583,f584,f585,f586,f587,f588,f589,f590,f591,
+f592,f593,f594,f595,f596,f597,f598,f599,f600,f601,f602,f603,f604,f605,f606,f607,
+f608,f609,f610,f611,f612,f613,f614,f615,f616,f617,f618,f619,f620,f621,f622,f623,
+f624,f625,f626,f627,f628,f629,f630,f631,f632,f633,f634,f635,f636,f637,f638,f639,
+f640,f641,f642,f643,f644,f645,f646,f647,f648,f649,f650,f651,f652,f653,f654,f655,
+f656,f657,f658,f659,f660,f661,f662,f663,f664,f665,f666,f667,f668,f669,f670,f671,
+f672,f673,f674,f675,f676,f677,f678,f679,f680,f681,f682,f683,f684,f685,f686,f687,
+f688,f689,f690,f691,f692,f693,f694,f695,f696,f697,f698,f699,f700,f701,f702,f703,
+f704,f705,f706,f707,f708,f709,f710,f711,f712,f713,f714,f715,f716,f717,f718,f719,
+f720,f721,f722,f723,f724,f725,f726,f727,f728,f729,f730,f731,f732,f733,f734,f735,
+f736,f737,f738,f739,f740,f741,f742,f743,f744,f745,f746,f747,f748,f749,f750,f751,
+f752,f753,f754,f755,f756,f757,f758,f759,f760,f761,f762,f763,f764,f765,f766,f767,
+f768,f769,f770,f771,f772,f773,f774,f775,f776,f777,f778,f779,f780,f781,f782,f783,
+f784,f785,f786,f787,f788,f789,f790,f791,f792,f793,f794,f795,f796,f797,f798,f799,
+f800,f801,f802,f803,f804,f805,f806,f807,f808,f809,f810,f811,f812,f813,f814,f815,
+f816,f817,f818,f819,f820,f821,f822,f823,f824,f825,f826,f827,f828,f829,f830,f831,
+f832,f833,f834,f835,f836,f837,f838,f839,f840,f841,f842,f843,f844,f845,f846,f847,
+f848,f849,f850,f851,f852,f853,f854,f855,f856,f857,f858,f859,f860,f861,f862,f863,
+f864,f865,f866,f867,f868,f869,f870,f871,f872,f873,f874,f875,f876,f877,f878,f879,
+f880,f881,f882,f883,f884,f885,f886,f887,f888,f889,f890,f891,f892,f893,f894,f895,
+f896,f897,f898,f899,f900,f901,f902,f903,f904,f905,f906,f907,f908,f909,f910,f911,
+f912,f913,f914,f915,f916,f917,f918,f919,f920,f921,f922,f923,f924,f925,f926,f927,
+f928,f929,f930,f931,f932,f933,f934,f935,f936,f937,f938,f939,f940,f941,f942,f943,
+f944,f945,f946,f947,f948,f949,f950,f951,f952,f953,f954,f955,f956,f957,f958,f959,
+f960,f961,f962,f963,f964,f965,f966,f967,f968,f969,f970,f971,f972,f973,f974,f975,
+f976,f977,f978,f979,f980,f981,f982,f983,f984,f985,f986,f987,f988,f989,f990,f991,
+f992,f993,f994,f995,f996,f997,f998,f999,f1000,f1001,f1002,f1003,f1004,f1005,f1006,f1007,
+f1008,f1009,f1010,f1011,f1012,f1013,f1014,f1015,f1016,f1017,f1018,f1019,f1020,f1021,f1022,f1023,
+f1024,f1025,f1026,f1027,f1028,f1029,f1030,f1031,f1032,f1033,f1034,f1035,f1036,f1037,f1038,f1039,
+f1040,f1041,f1042,f1043,f1044,f1045,f1046,f1047,f1048,f1049,f1050,f1051,f1052,f1053,f1054,f1055,
+f1056,f1057,f1058,f1059,f1060,f1061,f1062,f1063,f1064,f1065,f1066,f1067,f1068,f1069,f1070,f1071,
+f1072,f1073,f1074,f1075,f1076,f1077,f1078,f1079,f1080,f1081,f1082,f1083,f1084,f1085,f1086,f1087,
+f1088,f1089,f1090,f1091,f1092,f1093,f1094,f1095,f1096,f1097,f1098,f1099,f1100,f1101,f1102,f1103,
+f1104,f1105,f1106,f1107,f1108,f1109,f1110,f1111,f1112,f1113,f1114,f1115,f1116,f1117,f1118,f1119,
+f1120,f1121,f1122,f1123,f1124,f1125,f1126,f1127,f1128,f1129,f1130,f1131,f1132,f1133,f1134,f1135,
+f1136,f1137,f1138,f1139,f1140,f1141,f1142,f1143,f1144,f1145,f1146,f1147,f1148,f1149,f1150,f1151,
+f1152,f1153,f1154,f1155,f1156,f1157,f1158,f1159,f1160,f1161,f1162,f1163,f1164,f1165,f1166,f1167,
+f1168,f1169,f1170,f1171,f1172,f1173,f1174,f1175,f1176,f1177,f1178,f1179,f1180,f1181,f1182,f1183,
+f1184,f1185,f1186,f1187,f1188,f1189,f1190,f1191,f1192,f1193,f1194,f1195,f1196,f1197,f1198,f1199,
+f1200,f1201,f1202,f1203,f1204,f1205,f1206,f1207,f1208,f1209,f1210,f1211,f1212,f1213,f1214,f1215,
+f1216,f1217,f1218,f1219,f1220,f1221,f1222,f1223,f1224,f1225,f1226,f1227,f1228,f1229,f1230,f1231,
+f1232,f1233,f1234,f1235,f1236,f1237,f1238,f1239,f1240,f1241,f1242,f1243,f1244,f1245,f1246,f1247,
+f1248,f1249,f1250,f1251,f1252,f1253,f1254,f1255,f1256,f1257,f1258,f1259,f1260,f1261,f1262,f1263,
+f1264,f1265,f1266,f1267,f1268,f1269,f1270,f1271,f1272,f1273,f1274,f1275,f1276,f1277,f1278,f1279,
+f1280,f1281,f1282,f1283,f1284,f1285,f1286,f1287,f1288,f1289,f1290,f1291,f1292,f1293,f1294,f1295,
+f1296,f1297,f1298,f1299,f1300,f1301,f1302,f1303,f1304,f1305,f1306,f1307,f1308,f1309,f1310,f1311,
+f1312,f1313,f1314,f1315,f1316,f1317,f1318,f1319,f1320,f1321,f1322,f1323,f1324,f1325,f1326,f1327,
+f1328,f1329,f1330,f1331,f1332,f1333,f1334,f1335,f1336,f1337,f1338,f1339,f1340,f1341,f1342,f1343,
+f1344,f1345,f1346,f1347,f1348,f1349,f1350,f1351,f1352,f1353,f1354,f1355,f1356,f1357,f1358,f1359,
+f1360,f1361,f1362,f1363,f1364,f1365,f1366,f1367,f1368,f1369,f1370,f1371,f1372,f1373,f1374,f1375,
+f1376,f1377,f1378,f1379,f1380,f1381,f1382,f1383,f1384,f1385,f1386,f1387,f1388,f1389,f1390,f1391,
+f1392,f1393,f1394,f1395,f1396,f1397,f1398,f1399,f1400,f1401,f1402,f1403,f1404,f1405,f1406,f1407,
+f1408,f1409,f1410,f1411,f1412,f1413,f1414,f1415,f1416,f1417,f1418,f1419,f1420,f1421,f1422,f1423,
+f1424,f1425,f1426,f1427,f1428,f1429,f1430,f1431,f1432,f1433,f1434,f1435,f1436,f1437,f1438,f1439,
+f1440,f1441,f1442,f1443,f1444,f1445,f1446,f1447,f1448,f1449,f1450,f1451,f1452,f1453,f1454,f1455,
+f1456,f1457,f1458,f1459,f1460,f1461,f1462,f1463,f1464,f1465,f1466,f1467,f1468,f1469,f1470,f1471,
+f1472,f1473,f1474,f1475,f1476,f1477,f1478,f1479,f1480,f1481,f1482,f1483,f1484,f1485,f1486,f1487,
+f1488,f1489,f1490,f1491,f1492,f1493,f1494,f1495,f1496,f1497,f1498,f1499,f1500,f1501,f1502,f1503,
+f1504,f1505,f1506,f1507,f1508,f1509,f1510,f1511,f1512,f1513,f1514,f1515,f1516,f1517,f1518,f1519,
+f1520,f1521,f1522,f1523,f1524,f1525,f1526,f1527,f1528,f1529,f1530,f1531,f1532,f1533,f1534,f1535,
+f1536,f1537,f1538,f1539,f1540,f1541,f1542,f1543,f1544,f1545,f1546,f1547,f1548,f1549,f1550,f1551,
+f1552,f1553,f1554,f1555,f1556,f1557,f1558,f1559,f1560,f1561,f1562,f1563,f1564,f1565,f1566,f1567,
+f1568,f1569,f1570,f1571,f1572,f1573,f1574,f1575,f1576,f1577,f1578,f1579,f1580,f1581,f1582,f1583,
+f1584,f1585,f1586,f1587,f1588,f1589,f1590,f1591,f1592,f1593,f1594,f1595,f1596,f1597,f1598,f1599,
+f1600,f1601,f1602,f1603,f1604,f1605,f1606,f1607,f1608,f1609,f1610,f1611,f1612,f1613,f1614,f1615,
+f1616,f1617,f1618,f1619,f1620,f1621,f1622,f1623,f1624,f1625,f1626,f1627,f1628,f1629,f1630,f1631,
+f1632,f1633,f1634,f1635,f1636,f1637,f1638,f1639,f1640,f1641,f1642,f1643,f1644,f1645,f1646,f1647,
+f1648,f1649,f1650,f1651,f1652,f1653,f1654,f1655,f1656,f1657,f1658,f1659,f1660,f1661,f1662,f1663,
+f1664,f1665,f1666,f1667,f1668,f1669,f1670,f1671,f1672,f1673,f1674,f1675,f1676,f1677,f1678,f1679,
+f1680,f1681,f1682,f1683,f1684,f1685,f1686,f1687,f1688,f1689,f1690,f1691,f1692,f1693,f1694,f1695,
+f1696,f1697,f1698,f1699,f1700,f1701,f1702,f1703,f1704,f1705,f1706,f1707,f1708,f1709,f1710,f1711,
+f1712,f1713,f1714,f1715,f1716,f1717,f1718,f1719,f1720,f1721,f1722,f1723,f1724,f1725,f1726,f1727,
+f1728,f1729,f1730,f1731,f1732,f1733,f1734,f1735,f1736,f1737,f1738,f1739,f1740,f1741,f1742,f1743,
+f1744,f1745,f1746,f1747,f1748,f1749,f1750,f1751,f1752,f1753,f1754,f1755,f1756,f1757,f1758,f1759,
+f1760,f1761,f1762,f1763,f1764,f1765,f1766,f1767,f1768,f1769,f1770,f1771,f1772,f1773,f1774,f1775,
+f1776,f1777,f1778,f1779,f1780,f1781,f1782,f1783,f1784,f1785,f1786,f1787,f1788,f1789,f1790,f1791,
+f1792,f1793,f1794,f1795,f1796,f1797,f1798,f1799,f1800,f1801,f1802,f1803,f1804,f1805,f1806,f1807,
+f1808,f1809,f1810,f1811,f1812,f1813,f1814,f1815,f1816,f1817,f1818,f1819,f1820,f1821,f1822,f1823,
+f1824,f1825,f1826,f1827,f1828,f1829,f1830,f1831,f1832,f1833,f1834,f1835,f1836,f1837,f1838,f1839,
+f1840,f1841,f1842,f1843,f1844,f1845,f1846,f1847,f1848,f1849,f1850,f1851,f1852,f1853,f1854,f1855,
+f1856,f1857,f1858,f1859,f1860,f1861,f1862,f1863,f1864,f1865,f1866,f1867,f1868,f1869,f1870,f1871,
+f1872,f1873,f1874,f1875,f1876,f1877,f1878,f1879,f1880,f1881,f1882,f1883,f1884,f1885,f1886,f1887,
+f1888,f1889,f1890,f1891,f1892,f1893,f1894,f1895,f1896,f1897,f1898,f1899,f1900,f1901,f1902,f1903,
+f1904,f1905,f1906,f1907,f1908,f1909,f1910,f1911,f1912,f1913,f1914,f1915,f1916,f1917,f1918,f1919,
+f1920,f1921,f1922,f1923,f1924,f1925,f1926,f1927,f1928,f1929,f1930,f1931,f1932,f1933,f1934,f1935,
+f1936,f1937,f1938,f1939,f1940,f1941,f1942,f1943,f1944,f1945,f1946,f1947,f1948,f1949,f1950,f1951,
+f1952,f1953,f1954,f1955,f1956,f1957,f1958,f1959,f1960,f1961,f1962,f1963,f1964,f1965,f1966,f1967,
+f1968,f1969,f1970,f1971,f1972,f1973,f1974,f1975,f1976,f1977,f1978,f1979,f1980,f1981,f1982,f1983,
+f1984,f1985,f1986,f1987,f1988,f1989,f1990,f1991,f1992,f1993,f1994,f1995,f1996,f1997,f1998,f1999,
+f2000,f2001,f2002,f2003,f2004,f2005,f2006,f2007,f2008,f2009,f2010,f2011,f2012,f2013,f2014,f2015,
+f2016,f2017,f2018,f2019,f2020,f2021,f2022,f2023,f2024,f2025,f2026,f2027,f2028,f2029,f2030,f2031,
+f2032,f2033,f2034,f2035,f2036,f2037,f2038,f2039,f2040,f2041,f2042,f2043,f2044,f2045,f2046,f2047,
+f2048,f2049,f2050,f2051,f2052,f2053,f2054,f2055,f2056,f2057,f2058,f2059,f2060,f2061,f2062,f2063,
+f2064,f2065,f2066,f2067,f2068,f2069,f2070,f2071,f2072,f2073,f2074,f2075,f2076,f2077,f2078,f2079,
+f2080,f2081,f2082,f2083,f2084,f2085,f2086,f2087,f2088,f2089,f2090,f2091,f2092,f2093,f2094,f2095,
+f2096,f2097,f2098,f2099,f2100,f2101,f2102,f2103,f2104,f2105,f2106,f2107,f2108,f2109,f2110,f2111,
+f2112,f2113,f2114,f2115,f2116,f2117,f2118,f2119,f2120,f2121,f2122,f2123,f2124,f2125,f2126,f2127,
+f2128,f2129,f2130,f2131,f2132,f2133,f2134,f2135,f2136,f2137,f2138,f2139,f2140,f2141,f2142,f2143,
+f2144,f2145,f2146,f2147,f2148,f2149,f2150,f2151,f2152,f2153,f2154,f2155,f2156,f2157,f2158,f2159,
+f2160,f2161,f2162,f2163,f2164,f2165,f2166,f2167,f2168,f2169,f2170,f2171,f2172,f2173,f2174,f2175,
+f2176,f2177,f2178,f2179,f2180,f2181,f2182,f2183,f2184,f2185,f2186,f2187,f2188,f2189,f2190,f2191,
+f2192,f2193,f2194,f2195,f2196,f2197,f2198,f2199,f2200,f2201,f2202,f2203,f2204,f2205,f2206,f2207,
+f2208,f2209,f2210,f2211,f2212,f2213,f2214,f2215,f2216,f2217,f2218,f2219,f2220,f2221,f2222,f2223,
+f2224,f2225,f2226,f2227,f2228,f2229,f2230,f2231,f2232,f2233,f2234,f2235,f2236,f2237,f2238,f2239,
+f2240,f2241,f2242,f2243,f2244,f2245,f2246,f2247,f2248,f2249,f2250,f2251,f2252,f2253,f2254,f2255,
+f2256,f2257,f2258,f2259,f2260,f2261,f2262,f2263,f2264,f2265,f2266,f2267,f2268,f2269,f2270,f2271,
+f2272,f2273,f2274,f2275,f2276,f2277,f2278,f2279,f2280,f2281,f2282,f2283,f2284,f2285,f2286,f2287,
+f2288,f2289,f2290,f2291,f2292,f2293,f2294,f2295,f2296,f2297,f2298,f2299,f2300,f2301,f2302,f2303,
+f2304,f2305,f2306,f2307,f2308,f2309,f2310,f2311,f2312,f2313,f2314,f2315,f2316,f2317,f2318,f2319,
+f2320,f2321,f2322,f2323,f2324,f2325,f2326,f2327,f2328,f2329,f2330,f2331,f2332,f2333,f2334,f2335,
+f2336,f2337,f2338,f2339,f2340,f2341,f2342,f2343,f2344,f2345,f2346,f2347,f2348,f2349,f2350,f2351,
+f2352,f2353,f2354,f2355,f2356,f2357,f2358,f2359,f2360,f2361,f2362,f2363,f2364,f2365,f2366,f2367,
+f2368,f2369,f2370,f2371,f2372,f2373,f2374,f2375,f2376,f2377,f2378,f2379,f2380,f2381,f2382,f2383,
+f2384,f2385,f2386,f2387,f2388,f2389,f2390,f2391,f2392,f2393,f2394,f2395,f2396,f2397,f2398,f2399,
+f2400,f2401,f2402,f2403,f2404,f2405,f2406,f2407,f2408,f2409,f2410,f2411,f2412,f2413,f2414,f2415,
+f2416,f2417,f2418,f2419,f2420,f2421,f2422,f2423,f2424,f2425,f2426,f2427,f2428,f2429,f2430,f2431,
+f2432,f2433,f2434,f2435,f2436,f2437,f2438,f2439,f2440,f2441,f2442,f2443,f2444,f2445,f2446,f2447,
+f2448,f2449,f2450,f2451,f2452,f2453,f2454,f2455,f2456,f2457,f2458,f2459,f2460,f2461,f2462,f2463,
+f2464,f2465,f2466,f2467,f2468,f2469,f2470,f2471,f2472,f2473,f2474,f2475,f2476,f2477,f2478,f2479,
+f2480,f2481,f2482,f2483,f2484,f2485,f2486,f2487,f2488,f2489,f2490,f2491,f2492,f2493,f2494,f2495,
+f2496,f2497,f2498,f2499,f2500,f2501,f2502,f2503,f2504,f2505,f2506,f2507,f2508,f2509,f2510,f2511,
+f2512,f2513,f2514,f2515,f2516,f2517,f2518,f2519,f2520,f2521,f2522,f2523,f2524,f2525,f2526,f2527,
+f2528,f2529,f2530,f2531,f2532,f2533,f2534,f2535,f2536,f2537,f2538,f2539,f2540,f2541,f2542,f2543,
+f2544,f2545,f2546,f2547,f2548,f2549,f2550,f2551,f2552,f2553,f2554,f2555,f2556,f2557,f2558,f2559,
+f2560,f2561,f2562,f2563,f2564,f2565,f2566,f2567,f2568,f2569,f2570,f2571,f2572,f2573,f2574,f2575,
+f2576,f2577,f2578,f2579,f2580,f2581,f2582,f2583,f2584,f2585,f2586,f2587,f2588,f2589,f2590,f2591,
+f2592,f2593,f2594,f2595,f2596,f2597,f2598,f2599,f2600,f2601,f2602,f2603,f2604,f2605,f2606,f2607,
+f2608,f2609,f2610,f2611,f2612,f2613,f2614,f2615,f2616,f2617,f2618,f2619,f2620,f2621,f2622,f2623,
+f2624,f2625,f2626,f2627,f2628,f2629,f2630,f2631,f2632,f2633,f2634,f2635,f2636,f2637,f2638,f2639,
+f2640,f2641,f2642,f2643,f2644,f2645,f2646,f2647,f2648,f2649,f2650,f2651,f2652,f2653,f2654,f2655,
+f2656,f2657,f2658,f2659,f2660,f2661,f2662,f2663,f2664,f2665,f2666,f2667,f2668,f2669,f2670,f2671,
+f2672,f2673,f2674,f2675,f2676,f2677,f2678,f2679,f2680,f2681,f2682,f2683,f2684,f2685,f2686,f2687,
+f2688,f2689,f2690,f2691,f2692,f2693,f2694,f2695,f2696,f2697,f2698,f2699,f2700,f2701,f2702,f2703,
+f2704,f2705,f2706,f2707,f2708,f2709,f2710,f2711,f2712,f2713,f2714,f2715,f2716,f2717,f2718,f2719,
+f2720,f2721,f2722,f2723,f2724,f2725,f2726,f2727,f2728,f2729,f2730,f2731,f2732,f2733,f2734,f2735,
+f2736,f2737,f2738,f2739,f2740,f2741,f2742,f2743,f2744,f2745,f2746,f2747,f2748,f2749,f2750,f2751,
+f2752,f2753,f2754,f2755,f2756,f2757,f2758,f2759,f2760,f2761,f2762,f2763,f2764,f2765,f2766,f2767,
+f2768,f2769,f2770,f2771,f2772,f2773,f2774,f2775,f2776,f2777,f2778,f2779,f2780,f2781,f2782,f2783,
+f2784,f2785,f2786,f2787,f2788,f2789,f2790,f2791,f2792,f2793,f2794,f2795,f2796,f2797,f2798,f2799,
+f2800,f2801,f2802,f2803,f2804,f2805,f2806,f2807,f2808,f2809,f2810,f2811,f2812,f2813,f2814,f2815,
+f2816,f2817,f2818,f2819,f2820,f2821,f2822,f2823,f2824,f2825,f2826,f2827,f2828,f2829,f2830,f2831,
+f2832,f2833,f2834,f2835,f2836,f2837,f2838,f2839,f2840,f2841,f2842,f2843,f2844,f2845,f2846,f2847,
+f2848,f2849,f2850,f2851,f2852,f2853,f2854,f2855,f2856,f2857,f2858,f2859,f2860,f2861,f2862,f2863,
+f2864,f2865,f2866,f2867,f2868,f2869,f2870,f2871,f2872,f2873,f2874,f2875,f2876,f2877,f2878,f2879,
+f2880,f2881,f2882,f2883,f2884,f2885,f2886,f2887,f2888,f2889,f2890,f2891,f2892,f2893,f2894,f2895,
+f2896,f2897,f2898,f2899,f2900,f2901,f2902,f2903,f2904,f2905,f2906,f2907,f2908,f2909,f2910,f2911,
+f2912,f2913,f2914,f2915,f2916,f2917,f2918,f2919,f2920,f2921,f2922,f2923,f2924,f2925,f2926,f2927,
+f2928,f2929,f2930,f2931,f2932,f2933,f2934,f2935,f2936,f2937,f2938,f2939,f2940,f2941,f2942,f2943,
+f2944,f2945,f2946,f2947,f2948,f2949,f2950,f2951,f2952,f2953,f2954,f2955,f2956,f2957,f2958,f2959,
+f2960,f2961,f2962,f2963,f2964,f2965,f2966,f2967,f2968,f2969,f2970,f2971,f2972,f2973,f2974,f2975,
+f2976,f2977,f2978,f2979,f2980,f2981,f2982,f2983,f2984,f2985,f2986,f2987,f2988,f2989,f2990,f2991,
+f2992,f2993,f2994,f2995,f2996,f2997,f2998,f2999,f3000,f3001,f3002,f3003,f3004,f3005,f3006,f3007,
+f3008,f3009,f3010,f3011,f3012,f3013,f3014,f3015,f3016,f3017,f3018,f3019,f3020,f3021,f3022,f3023,
+f3024,f3025,f3026,f3027,f3028,f3029,f3030,f3031,f3032,f3033,f3034,f3035,f3036,f3037,f3038,f3039,
+f3040,f3041,f3042,f3043,f3044,f3045,f3046,f3047,f3048,f3049,f3050,f3051,f3052,f3053,f3054,f3055,
+f3056,f3057,f3058,f3059,f3060,f3061,f3062,f3063,f3064,f3065,f3066,f3067,f3068,f3069,f3070,f3071,
+f3072,f3073,f3074,f3075,f3076,f3077,f3078,f3079,f3080,f3081,f3082,f3083,f3084,f3085,f3086,f3087,
+f3088,f3089,f3090,f3091,f3092,f3093,f3094,f3095,f3096,f3097,f3098,f3099,f3100,f3101,f3102,f3103,
+f3104,f3105,f3106,f3107,f3108,f3109,f3110,f3111,f3112,f3113,f3114,f3115,f3116,f3117,f3118,f3119,
+f3120,f3121,f3122,f3123,f3124,f3125,f3126,f3127,f3128,f3129,f3130,f3131,f3132,f3133,f3134,f3135,
+f3136,f3137,f3138,f3139,f3140,f3141,f3142,f3143,f3144,f3145,f3146,f3147,f3148,f3149,f3150,f3151,
+f3152,f3153,f3154,f3155,f3156,f3157,f3158,f3159,f3160,f3161,f3162,f3163,f3164,f3165,f3166,f3167,
+f3168,f3169,f3170,f3171,f3172,f3173,f3174,f3175,f3176,f3177,f3178,f3179,f3180,f3181,f3182,f3183,
+f3184,f3185,f3186,f3187,f3188,f3189,f3190,f3191,f3192,f3193,f3194,f3195,f3196,f3197,f3198,f3199,
+f3200,f3201,f3202,f3203,f3204,f3205,f3206,f3207,f3208,f3209,f3210,f3211,f3212,f3213,f3214,f3215,
+f3216,f3217,f3218,f3219,f3220,f3221,f3222,f3223,f3224,f3225,f3226,f3227,f3228,f3229,f3230,f3231,
+f3232,f3233,f3234,f3235,f3236,f3237,f3238,f3239,f3240,f3241,f3242,f3243,f3244,f3245,f3246,f3247,
+f3248,f3249,f3250,f3251,f3252,f3253,f3254,f3255,f3256,f3257,f3258,f3259,f3260,f3261,f3262,f3263,
+f3264,f3265,f3266,f3267,f3268,f3269,f3270,f3271,f3272,f3273,f3274,f3275,f3276,f3277,f3278,f3279,
+f3280,f3281,f3282,f3283,f3284,f3285,f3286,f3287,f3288,f3289,f3290,f3291,f3292,f3293,f3294,f3295,
+f3296,f3297,f3298,f3299,f3300,f3301,f3302,f3303,f3304,f3305,f3306,f3307,f3308,f3309,f3310,f3311,
+f3312,f3313,f3314,f3315,f3316,f3317,f3318,f3319,f3320,f3321,f3322,f3323,f3324,f3325,f3326,f3327,
+f3328,f3329,f3330,f3331,f3332,f3333,f3334,f3335,f3336,f3337,f3338,f3339,f3340,f3341,f3342,f3343,
+f3344,f3345,f3346,f3347,f3348,f3349,f3350,f3351,f3352,f3353,f3354,f3355,f3356,f3357,f3358,f3359,
+f3360,f3361,f3362,f3363,f3364,f3365,f3366,f3367,f3368,f3369,f3370,f3371,f3372,f3373,f3374,f3375,
+f3376,f3377,f3378,f3379,f3380,f3381,f3382,f3383,f3384,f3385,f3386,f3387,f3388,f3389,f3390,f3391,
+f3392,f3393,f3394,f3395,f3396,f3397,f3398,f3399,f3400,f3401,f3402,f3403,f3404,f3405,f3406,f3407,
+f3408,f3409,f3410,f3411,f3412,f3413,f3414,f3415,f3416,f3417,f3418,f3419,f3420,f3421,f3422,f3423,
+f3424,f3425,f3426,f3427,f3428,f3429,f3430,f3431,f3432,f3433,f3434,f3435,f3436,f3437,f3438,f3439,
+f3440,f3441,f3442,f3443,f3444,f3445,f3446,f3447,f3448,f3449,f3450,f3451,f3452,f3453,f3454,f3455,
+f3456,f3457,f3458,f3459,f3460,f3461,f3462,f3463,f3464,f3465,f3466,f3467,f3468,f3469,f3470,f3471,
+f3472,f3473,f3474,f3475,f3476,f3477,f3478,f3479,f3480,f3481,f3482,f3483,f3484,f3485,f3486,f3487,
+f3488,f3489,f3490,f3491,f3492,f3493,f3494,f3495,f3496,f3497,f3498,f3499,f3500,f3501,f3502,f3503,
+f3504,f3505,f3506,f3507,f3508,f3509,f3510,f3511,f3512,f3513,f3514,f3515,f3516,f3517,f3518,f3519,
+f3520,f3521,f3522,f3523,f3524,f3525,f3526,f3527,f3528,f3529,f3530,f3531,f3532,f3533,f3534,f3535,
+f3536,f3537,f3538,f3539,f3540,f3541,f3542,f3543,f3544,f3545,f3546,f3547,f3548,f3549,f3550,f3551,
+f3552,f3553,f3554,f3555,f3556,f3557,f3558,f3559,f3560,f3561,f3562,f3563,f3564,f3565,f3566,f3567,
+f3568,f3569,f3570,f3571,f3572,f3573,f3574,f3575,f3576,f3577,f3578,f3579,f3580,f3581,f3582,f3583,
+f3584,f3585,f3586,f3587,f3588,f3589,f3590,f3591,f3592,f3593,f3594,f3595,f3596,f3597,f3598,f3599,
+f3600,f3601,f3602,f3603,f3604,f3605,f3606,f3607,f3608,f3609,f3610,f3611,f3612,f3613,f3614,f3615,
+f3616,f3617,f3618,f3619,f3620,f3621,f3622,f3623,f3624,f3625,f3626,f3627,f3628,f3629,f3630,f3631,
+f3632,f3633,f3634,f3635,f3636,f3637,f3638,f3639,f3640,f3641,f3642,f3643,f3644,f3645,f3646,f3647,
+f3648,f3649,f3650,f3651,f3652,f3653,f3654,f3655,f3656,f3657,f3658,f3659,f3660,f3661,f3662,f3663,
+f3664,f3665,f3666,f3667,f3668,f3669,f3670,f3671,f3672,f3673,f3674,f3675,f3676,f3677,f3678,f3679,
+f3680,f3681,f3682,f3683,f3684,f3685,f3686,f3687,f3688,f3689,f3690,f3691,f3692,f3693,f3694,f3695,
+f3696,f3697,f3698,f3699,f3700,f3701,f3702,f3703,f3704,f3705,f3706,f3707,f3708,f3709,f3710,f3711,
+f3712,f3713,f3714,f3715,f3716,f3717,f3718,f3719,f3720,f3721,f3722,f3723,f3724,f3725,f3726,f3727,
+f3728,f3729,f3730,f3731,f3732,f3733,f3734,f3735,f3736,f3737,f3738,f3739,f3740,f3741,f3742,f3743,
+f3744,f3745,f3746,f3747,f3748,f3749,f3750,f3751,f3752,f3753,f3754,f3755,f3756,f3757,f3758,f3759,
+f3760,f3761,f3762,f3763,f3764,f3765,f3766,f3767,f3768,f3769,f3770,f3771,f3772,f3773,f3774,f3775,
+f3776,f3777,f3778,f3779,f3780,f3781,f3782,f3783,f3784,f3785,f3786,f3787,f3788,f3789,f3790,f3791,
+f3792,f3793,f3794,f3795,f3796,f3797,f3798,f3799,f3800,f3801,f3802,f3803,f3804,f3805,f3806,f3807,
+f3808,f3809,f3810,f3811,f3812,f3813,f3814,f3815,f3816,f3817,f3818,f3819,f3820,f3821,f3822,f3823,
+f3824,f3825,f3826,f3827,f3828,f3829,f3830,f3831,f3832,f3833,f3834,f3835,f3836,f3837,f3838,f3839,
+f3840,f3841,f3842,f3843,f3844,f3845,f3846,f3847,f3848,f3849,f3850,f3851,f3852,f3853,f3854,f3855,
+f3856,f3857,f3858,f3859,f3860,f3861,f3862,f3863,f3864,f3865,f3866,f3867,f3868,f3869,f3870,f3871,
+f3872,f3873,f3874,f3875,f3876,f3877,f3878,f3879,f3880,f3881,f3882,f3883,f3884,f3885,f3886,f3887,
+f3888,f3889,f3890,f3891,f3892,f3893,f3894,f3895,f3896,f3897,f3898,f3899,f3900,f3901,f3902,f3903,
+f3904,f3905,f3906,f3907,f3908,f3909,f3910,f3911,f3912,f3913,f3914,f3915,f3916,f3917,f3918,f3919,
+f3920,f3921,f3922,f3923,f3924,f3925,f3926,f3927,f3928,f3929,f3930,f3931,f3932,f3933,f3934,f3935,
+f3936,f3937,f3938,f3939,f3940,f3941,f3942,f3943,f3944,f3945,f3946,f3947,f3948,f3949,f3950,f3951,
+f3952,f3953,f3954,f3955,f3956,f3957,f3958,f3959,f3960,f3961,f3962,f3963,f3964,f3965,f3966,f3967,
+f3968,f3969,f3970,f3971,f3972,f3973,f3974,f3975,f3976,f3977,f3978,f3979,f3980,f3981,f3982,f3983,
+f3984,f3985,f3986,f3987,f3988,f3989,f3990,f3991,f3992,f3993,f3994,f3995,f3996,f3997,f3998,f3999,
+f4000,f4001,f4002,f4003,f4004,f4005,f4006,f4007,f4008,f4009,f4010,f4011,f4012,f4013,f4014,f4015,
+f4016,f4017,f4018,f4019,f4020,f4021,f4022,f4023,f4024,f4025,f4026,f4027,f4028,f4029,f4030,f4031,
+f4032,f4033,f4034,f4035,f4036,f4037,f4038,f4039,f4040,f4041,f4042,f4043,f4044,f4045,f4046,f4047,
+f4048,f4049,f4050,f4051,f4052,f4053,f4054,f4055,f4056,f4057,f4058,f4059,f4060,f4061,f4062,f4063,
+f4064,f4065,f4066,f4067,f4068,f4069,f4070,f4071,f4072,f4073,f4074,f4075,f4076,f4077,f4078,f4079,
+f4080,f4081,f4082,f4083,f4084,f4085,f4086,f4087,f4088,f4089,f4090,f4091,f4092,f4093,f4094,f4095,
+};
+static const int ref[4096][2] = {
+{     2, 0},
+{     0, 1},{     1, 0},{    -1, 0},{     3, 0},{    -1, 0},{     2, 0},{    -2, 0},{     5, 0},
+{    -3, 0},{     4, 0},{    -4, 0},{     9, 0},{    -7, 0},{     8, 0},{    -8, 0},{    17, 0},
+{   -15, 0},{    16, 0},{   -16, 0},{    33, 0},{   -31, 0},{    32, 0},{   -32, 0},{    65, 0},
+{   -63, 0},{    64, 0},{   -64, 0},{   129, 0},{  -127, 0},{   128, 0},{  -128, 0},{   257, 0},
+{  -255, 0},{   256, 0},{  -256, 0},{   513, 0},{  -511, 0},{   512, 0},{  -512, 0},{  1025, 0},
+{ -1023, 0},{  1024, 0},{ -1024, 0},{  2049, 0},{ -2047, 0},{  2048, 0},{ -2048, 0},{  4097, 0},
+{ -4095, 0},{  4096, 0},{ -4096, 0},{  8193, 0},{ -8191, 0},{  8192, 0},{ -8192, 0},{ 16385, 0},
+{-16383, 0},{ 16384, 0},{-16384, 0},{ 32769, 0},{-32767, 0},{ 32768, 0},{-32768, 0},{     0, 1},
+{    -2, 1},{    -1, 0},{    -3, 1},{     1, 1},{    -3, 1},{     0, 1},{    -4, 1},{     3, 1},
+{    -5, 1},{     2, 1},{    -6, 1},{     7, 1},{    -9, 1},{     6, 1},{   -10, 1},{    15, 1},
+{   -17, 1},{    14, 1},{   -18, 1},{    31, 1},{   -33, 1},{    30, 1},{   -34, 1},{    63, 1},
+{   -65, 1},{    62, 1},{   -66, 1},{   127, 1},{  -129, 1},{   126, 1},{  -130, 1},{   255, 1},
+{  -257, 1},{   254, 1},{  -258, 1},{   511, 1},{  -513, 1},{   510, 1},{  -514, 1},{  1023, 1},
+{ -1025, 1},{  1022, 1},{ -1026, 1},{  2047, 1},{ -2049, 1},{  2046, 1},{ -2050, 1},{  4095, 1},
+{ -4097, 1},{  4094, 1},{ -4098, 1},{  8191, 1},{ -8193, 1},{  8190, 1},{ -8194, 1},{ 16383, 1},
+{-16385, 1},{ 16382, 1},{-16386, 1},{ 32767, 1},{-32769, 1},{ 32766, 1},{-32770, 1},{     1, 0},
+{    -1, 0},{     0, 0},{    -2, 0},{     2, 0},{    -2, 0},{     1, 0},{    -3, 0},{     4, 0},
+{    -4, 0},{     3, 0},{    -5, 0},{     8, 0},{    -8, 0},{     7, 0},{    -9, 0},{    16, 0},
+{   -16, 0},{    15, 0},{   -17, 0},{    32, 0},{   -32, 0},{    31, 0},{   -33, 0},{    64, 0},
+{   -64, 0},{    63, 0},{   -65, 0},{   128, 0},{  -128, 0},{   127, 0},{  -129, 0},{   256, 0},
+{  -256, 0},{   255, 0},{  -257, 0},{   512, 0},{  -512, 0},{   511, 0},{  -513, 0},{  1024, 0},
+{ -1024, 0},{  1023, 0},{ -1025, 0},{  2048, 0},{ -2048, 0},{  2047, 0},{ -2049, 0},{  4096, 0},
+{ -4096, 0},{  4095, 0},{ -4097, 0},{  8192, 0},{ -8192, 0},{  8191, 0},{ -8193, 0},{ 16384, 0},
+{-16384, 0},{ 16383, 0},{-16385, 0},{ 32768, 0},{-32768, 0},{ 32767, 0},{-32769, 0},{    -1, 0},
+{    -3, 1},{    -2, 0},{    -4, 1},{     0, 1},{    -4, 1},{    -1, 0},{    -5, 1},{     2, 1},
+{    -6, 1},{     1, 1},{    -7, 1},{     6, 1},{   -10, 1},{     5, 1},{   -11, 1},{    14, 1},
+{   -18, 1},{    13, 1},{   -19, 1},{    30, 1},{   -34, 1},{    29, 1},{   -35, 1},{    62, 1},
+{   -66, 1},{    61, 1},{   -67, 1},{   126, 1},{  -130, 1},{   125, 1},{  -131, 1},{   254, 1},
+{  -258, 1},{   253, 1},{  -259, 1},{   510, 1},{  -514, 1},{   509, 1},{  -515, 1},{  1022, 1},
+{ -1026, 1},{  1021, 1},{ -1027, 1},{  2046, 1},{ -2050, 1},{  2045, 1},{ -2051, 1},{  4094, 1},
+{ -4098, 1},{  4093, 1},{ -4099, 1},{  8190, 1},{ -8194, 1},{  8189, 1},{ -8195, 1},{ 16382, 1},
+{-16386, 1},{ 16381, 1},{-16387, 1},{ 32766, 1},{-32770, 1},{ 32765, 1},{-32771, 1},{     3, 0},
+{     1, 1},{     2, 0},{     0, 1},{     4, 0},{     0, 1},{     3, 0},{    -1, 0},{     6, 0},
+{    -2, 0},{     5, 0},{    -3, 0},{    10, 0},{    -6, 0},{     9, 0},{    -7, 0},{    18, 0},
+{   -14, 0},{    17, 0},{   -15, 0},{    34, 0},{   -30, 0},{    33, 0},{   -31, 0},{    66, 0},
+{   -62, 0},{    65, 0},{   -63, 0},{   130, 0},{  -126, 0},{   129, 0},{  -127, 0},{   258, 0},
+{  -254, 0},{   257, 0},{  -255, 0},{   514, 0},{  -510, 0},{   513, 0},{  -511, 0},{  1026, 0},
+{ -1022, 0},{  1025, 0},{ -1023, 0},{  2050, 0},{ -2046, 0},{  2049, 0},{ -2047, 0},{  4098, 0},
+{ -4094, 0},{  4097, 0},{ -4095, 0},{  8194, 0},{ -8190, 0},{  8193, 0},{ -8191, 0},{ 16386, 0},
+{-16382, 0},{ 16385, 0},{-16383, 0},{ 32770, 0},{-32766, 0},{ 32769, 0},{-32767, 0},{    -1, 0},
+{    -3, 1},{    -2, 0},{    -4, 1},{     0, 1},{    -4, 1},{    -1, 0},{    -5, 1},{     2, 1},
+{    -6, 1},{     1, 1},{    -7, 1},{     6, 1},{   -10, 1},{     5, 1},{   -11, 1},{    14, 1},
+{   -18, 1},{    13, 1},{   -19, 1},{    30, 1},{   -34, 1},{    29, 1},{   -35, 1},{    62, 1},
+{   -66, 1},{    61, 1},{   -67, 1},{   126, 1},{  -130, 1},{   125, 1},{  -131, 1},{   254, 1},
+{  -258, 1},{   253, 1},{  -259, 1},{   510, 1},{  -514, 1},{   509, 1},{  -515, 1},{  1022, 1},
+{ -1026, 1},{  1021, 1},{ -1027, 1},{  2046, 1},{ -2050, 1},{  2045, 1},{ -2051, 1},{  4094, 1},
+{ -4098, 1},{  4093, 1},{ -4099, 1},{  8190, 1},{ -8194, 1},{  8189, 1},{ -8195, 1},{ 16382, 1},
+{-16386, 1},{ 16381, 1},{-16387, 1},{ 32766, 1},{-32770, 1},{ 32765, 1},{-32771, 1},{     2, 0},
+{     0, 1},{     1, 0},{    -1, 0},{     3, 0},{    -1, 0},{     2, 0},{    -2, 0},{     5, 0},
+{    -3, 0},{     4, 0},{    -4, 0},{     9, 0},{    -7, 0},{     8, 0},{    -8, 0},{    17, 0},
+{   -15, 0},{    16, 0},{   -16, 0},{    33, 0},{   -31, 0},{    32, 0},{   -32, 0},{    65, 0},
+{   -63, 0},{    64, 0},{   -64, 0},{   129, 0},{  -127, 0},{   128, 0},{  -128, 0},{   257, 0},
+{  -255, 0},{   256, 0},{  -256, 0},{   513, 0},{  -511, 0},{   512, 0},{  -512, 0},{  1025, 0},
+{ -1023, 0},{  1024, 0},{ -1024, 0},{  2049, 0},{ -2047, 0},{  2048, 0},{ -2048, 0},{  4097, 0},
+{ -4095, 0},{  4096, 0},{ -4096, 0},{  8193, 0},{ -8191, 0},{  8192, 0},{ -8192, 0},{ 16385, 0},
+{-16383, 0},{ 16384, 0},{-16384, 0},{ 32769, 0},{-32767, 0},{ 32768, 0},{-32768, 0},{    -2, 0},
+{    -4, 1},{    -3, 0},{    -5, 1},{    -1, 0},{    -5, 1},{    -2, 0},{    -6, 1},{     1, 1},
+{    -7, 1},{     0, 1},{    -8, 1},{     5, 1},{   -11, 1},{     4, 1},{   -12, 1},{    13, 1},
+{   -19, 1},{    12, 1},{   -20, 1},{    29, 1},{   -35, 1},{    28, 1},{   -36, 1},{    61, 1},
+{   -67, 1},{    60, 1},{   -68, 1},{   125, 1},{  -131, 1},{   124, 1},{  -132, 1},{   253, 1},
+{  -259, 1},{   252, 1},{  -260, 1},{   509, 1},{  -515, 1},{   508, 1},{  -516, 1},{  1021, 1},
+{ -1027, 1},{  1020, 1},{ -1028, 1},{  2045, 1},{ -2051, 1},{  2044, 1},{ -2052, 1},{  4093, 1},
+{ -4099, 1},{  4092, 1},{ -4100, 1},{  8189, 1},{ -8195, 1},{  8188, 1},{ -8196, 1},{ 16381, 1},
+{-16387, 1},{ 16380, 1},{-16388, 1},{ 32765, 1},{-32771, 1},{ 32764, 1},{-32772, 1},{     5, 0},
+{     3, 1},{     4, 0},{     2, 1},{     6, 0},{     2, 1},{     5, 0},{     1, 1},{     8, 0},
+{     0, 1},{     7, 0},{    -1, 0},{    12, 0},{    -4, 0},{    11, 0},{    -5, 0},{    20, 0},
+{   -12, 0},{    19, 0},{   -13, 0},{    36, 0},{   -28, 0},{    35, 0},{   -29, 0},{    68, 0},
+{   -60, 0},{    67, 0},{   -61, 0},{   132, 0},{  -124, 0},{   131, 0},{  -125, 0},{   260, 0},
+{  -252, 0},{   259, 0},{  -253, 0},{   516, 0},{  -508, 0},{   515, 0},{  -509, 0},{  1028, 0},
+{ -1020, 0},{  1027, 0},{ -1021, 0},{  2052, 0},{ -2044, 0},{  2051, 0},{ -2045, 0},{  4100, 0},
+{ -4092, 0},{  4099, 0},{ -4093, 0},{  8196, 0},{ -8188, 0},{  8195, 0},{ -8189, 0},{ 16388, 0},
+{-16380, 0},{ 16387, 0},{-16381, 0},{ 32772, 0},{-32764, 0},{ 32771, 0},{-32765, 0},{    -3, 0},
+{    -5, 1},{    -4, 0},{    -6, 1},{    -2, 0},{    -6, 1},{    -3, 0},{    -7, 1},{     0, 1},
+{    -8, 1},{    -1, 0},{    -9, 1},{     4, 1},{   -12, 1},{     3, 1},{   -13, 1},{    12, 1},
+{   -20, 1},{    11, 1},{   -21, 1},{    28, 1},{   -36, 1},{    27, 1},{   -37, 1},{    60, 1},
+{   -68, 1},{    59, 1},{   -69, 1},{   124, 1},{  -132, 1},{   123, 1},{  -133, 1},{   252, 1},
+{  -260, 1},{   251, 1},{  -261, 1},{   508, 1},{  -516, 1},{   507, 1},{  -517, 1},{  1020, 1},
+{ -1028, 1},{  1019, 1},{ -1029, 1},{  2044, 1},{ -2052, 1},{  2043, 1},{ -2053, 1},{  4092, 1},
+{ -4100, 1},{  4091, 1},{ -4101, 1},{  8188, 1},{ -8196, 1},{  8187, 1},{ -8197, 1},{ 16380, 1},
+{-16388, 1},{ 16379, 1},{-16389, 1},{ 32764, 1},{-32772, 1},{ 32763, 1},{-32773, 1},{     4, 0},
+{     2, 1},{     3, 0},{     1, 1},{     5, 0},{     1, 1},{     4, 0},{     0, 1},{     7, 0},
+{    -1, 0},{     6, 0},{    -2, 0},{    11, 0},{    -5, 0},{    10, 0},{    -6, 0},{    19, 0},
+{   -13, 0},{    18, 0},{   -14, 0},{    35, 0},{   -29, 0},{    34, 0},{   -30, 0},{    67, 0},
+{   -61, 0},{    66, 0},{   -62, 0},{   131, 0},{  -125, 0},{   130, 0},{  -126, 0},{   259, 0},
+{  -253, 0},{   258, 0},{  -254, 0},{   515, 0},{  -509, 0},{   514, 0},{  -510, 0},{  1027, 0},
+{ -1021, 0},{  1026, 0},{ -1022, 0},{  2051, 0},{ -2045, 0},{  2050, 0},{ -2046, 0},{  4099, 0},
+{ -4093, 0},{  4098, 0},{ -4094, 0},{  8195, 0},{ -8189, 0},{  8194, 0},{ -8190, 0},{ 16387, 0},
+{-16381, 0},{ 16386, 0},{-16382, 0},{ 32771, 0},{-32765, 0},{ 32770, 0},{-32766, 0},{    -4, 0},
+{    -6, 1},{    -5, 0},{    -7, 1},{    -3, 0},{    -7, 1},{    -4, 0},{    -8, 1},{    -1, 0},
+{    -9, 1},{    -2, 0},{   -10, 1},{     3, 1},{   -13, 1},{     2, 1},{   -14, 1},{    11, 1},
+{   -21, 1},{    10, 1},{   -22, 1},{    27, 1},{   -37, 1},{    26, 1},{   -38, 1},{    59, 1},
+{   -69, 1},{    58, 1},{   -70, 1},{   123, 1},{  -133, 1},{   122, 1},{  -134, 1},{   251, 1},
+{  -261, 1},{   250, 1},{  -262, 1},{   507, 1},{  -517, 1},{   506, 1},{  -518, 1},{  1019, 1},
+{ -1029, 1},{  1018, 1},{ -1030, 1},{  2043, 1},{ -2053, 1},{  2042, 1},{ -2054, 1},{  4091, 1},
+{ -4101, 1},{  4090, 1},{ -4102, 1},{  8187, 1},{ -8197, 1},{  8186, 1},{ -8198, 1},{ 16379, 1},
+{-16389, 1},{ 16378, 1},{-16390, 1},{ 32763, 1},{-32773, 1},{ 32762, 1},{-32774, 1},{     9, 0},
+{     7, 1},{     8, 0},{     6, 1},{    10, 0},{     6, 1},{     9, 0},{     5, 1},{    12, 0},
+{     4, 1},{    11, 0},{     3, 1},{    16, 0},{     0, 1},{    15, 0},{    -1, 0},{    24, 0},
+{    -8, 0},{    23, 0},{    -9, 0},{    40, 0},{   -24, 0},{    39, 0},{   -25, 0},{    72, 0},
+{   -56, 0},{    71, 0},{   -57, 0},{   136, 0},{  -120, 0},{   135, 0},{  -121, 0},{   264, 0},
+{  -248, 0},{   263, 0},{  -249, 0},{   520, 0},{  -504, 0},{   519, 0},{  -505, 0},{  1032, 0},
+{ -1016, 0},{  1031, 0},{ -1017, 0},{  2056, 0},{ -2040, 0},{  2055, 0},{ -2041, 0},{  4104, 0},
+{ -4088, 0},{  4103, 0},{ -4089, 0},{  8200, 0},{ -8184, 0},{  8199, 0},{ -8185, 0},{ 16392, 0},
+{-16376, 0},{ 16391, 0},{-16377, 0},{ 32776, 0},{-32760, 0},{ 32775, 0},{-32761, 0},{    -7, 0},
+{    -9, 1},{    -8, 0},{   -10, 1},{    -6, 0},{   -10, 1},{    -7, 0},{   -11, 1},{    -4, 0},
+{   -12, 1},{    -5, 0},{   -13, 1},{     0, 1},{   -16, 1},{    -1, 0},{   -17, 1},{     8, 1},
+{   -24, 1},{     7, 1},{   -25, 1},{    24, 1},{   -40, 1},{    23, 1},{   -41, 1},{    56, 1},
+{   -72, 1},{    55, 1},{   -73, 1},{   120, 1},{  -136, 1},{   119, 1},{  -137, 1},{   248, 1},
+{  -264, 1},{   247, 1},{  -265, 1},{   504, 1},{  -520, 1},{   503, 1},{  -521, 1},{  1016, 1},
+{ -1032, 1},{  1015, 1},{ -1033, 1},{  2040, 1},{ -2056, 1},{  2039, 1},{ -2057, 1},{  4088, 1},
+{ -4104, 1},{  4087, 1},{ -4105, 1},{  8184, 1},{ -8200, 1},{  8183, 1},{ -8201, 1},{ 16376, 1},
+{-16392, 1},{ 16375, 1},{-16393, 1},{ 32760, 1},{-32776, 1},{ 32759, 1},{-32777, 1},{     8, 0},
+{     6, 1},{     7, 0},{     5, 1},{     9, 0},{     5, 1},{     8, 0},{     4, 1},{    11, 0},
+{     3, 1},{    10, 0},{     2, 1},{    15, 0},{    -1, 0},{    14, 0},{    -2, 0},{    23, 0},
+{    -9, 0},{    22, 0},{   -10, 0},{    39, 0},{   -25, 0},{    38, 0},{   -26, 0},{    71, 0},
+{   -57, 0},{    70, 0},{   -58, 0},{   135, 0},{  -121, 0},{   134, 0},{  -122, 0},{   263, 0},
+{  -249, 0},{   262, 0},{  -250, 0},{   519, 0},{  -505, 0},{   518, 0},{  -506, 0},{  1031, 0},
+{ -1017, 0},{  1030, 0},{ -1018, 0},{  2055, 0},{ -2041, 0},{  2054, 0},{ -2042, 0},{  4103, 0},
+{ -4089, 0},{  4102, 0},{ -4090, 0},{  8199, 0},{ -8185, 0},{  8198, 0},{ -8186, 0},{ 16391, 0},
+{-16377, 0},{ 16390, 0},{-16378, 0},{ 32775, 0},{-32761, 0},{ 32774, 0},{-32762, 0},{    -8, 0},
+{   -10, 1},{    -9, 0},{   -11, 1},{    -7, 0},{   -11, 1},{    -8, 0},{   -12, 1},{    -5, 0},
+{   -13, 1},{    -6, 0},{   -14, 1},{    -1, 0},{   -17, 1},{    -2, 0},{   -18, 1},{     7, 1},
+{   -25, 1},{     6, 1},{   -26, 1},{    23, 1},{   -41, 1},{    22, 1},{   -42, 1},{    55, 1},
+{   -73, 1},{    54, 1},{   -74, 1},{   119, 1},{  -137, 1},{   118, 1},{  -138, 1},{   247, 1},
+{  -265, 1},{   246, 1},{  -266, 1},{   503, 1},{  -521, 1},{   502, 1},{  -522, 1},{  1015, 1},
+{ -1033, 1},{  1014, 1},{ -1034, 1},{  2039, 1},{ -2057, 1},{  2038, 1},{ -2058, 1},{  4087, 1},
+{ -4105, 1},{  4086, 1},{ -4106, 1},{  8183, 1},{ -8201, 1},{  8182, 1},{ -8202, 1},{ 16375, 1},
+{-16393, 1},{ 16374, 1},{-16394, 1},{ 32759, 1},{-32777, 1},{ 32758, 1},{-32778, 1},{    17, 0},
+{    15, 1},{    16, 0},{    14, 1},{    18, 0},{    14, 1},{    17, 0},{    13, 1},{    20, 0},
+{    12, 1},{    19, 0},{    11, 1},{    24, 0},{     8, 1},{    23, 0},{     7, 1},{    32, 0},
+{     0, 1},{    31, 0},{    -1, 0},{    48, 0},{   -16, 0},{    47, 0},{   -17, 0},{    80, 0},
+{   -48, 0},{    79, 0},{   -49, 0},{   144, 0},{  -112, 0},{   143, 0},{  -113, 0},{   272, 0},
+{  -240, 0},{   271, 0},{  -241, 0},{   528, 0},{  -496, 0},{   527, 0},{  -497, 0},{  1040, 0},
+{ -1008, 0},{  1039, 0},{ -1009, 0},{  2064, 0},{ -2032, 0},{  2063, 0},{ -2033, 0},{  4112, 0},
+{ -4080, 0},{  4111, 0},{ -4081, 0},{  8208, 0},{ -8176, 0},{  8207, 0},{ -8177, 0},{ 16400, 0},
+{-16368, 0},{ 16399, 0},{-16369, 0},{ 32784, 0},{-32752, 0},{ 32783, 0},{-32753, 0},{   -15, 0},
+{   -17, 1},{   -16, 0},{   -18, 1},{   -14, 0},{   -18, 1},{   -15, 0},{   -19, 1},{   -12, 0},
+{   -20, 1},{   -13, 0},{   -21, 1},{    -8, 0},{   -24, 1},{    -9, 0},{   -25, 1},{     0, 1},
+{   -32, 1},{    -1, 0},{   -33, 1},{    16, 1},{   -48, 1},{    15, 1},{   -49, 1},{    48, 1},
+{   -80, 1},{    47, 1},{   -81, 1},{   112, 1},{  -144, 1},{   111, 1},{  -145, 1},{   240, 1},
+{  -272, 1},{   239, 1},{  -273, 1},{   496, 1},{  -528, 1},{   495, 1},{  -529, 1},{  1008, 1},
+{ -1040, 1},{  1007, 1},{ -1041, 1},{  2032, 1},{ -2064, 1},{  2031, 1},{ -2065, 1},{  4080, 1},
+{ -4112, 1},{  4079, 1},{ -4113, 1},{  8176, 1},{ -8208, 1},{  8175, 1},{ -8209, 1},{ 16368, 1},
+{-16400, 1},{ 16367, 1},{-16401, 1},{ 32752, 1},{-32784, 1},{ 32751, 1},{-32785, 1},{    16, 0},
+{    14, 1},{    15, 0},{    13, 1},{    17, 0},{    13, 1},{    16, 0},{    12, 1},{    19, 0},
+{    11, 1},{    18, 0},{    10, 1},{    23, 0},{     7, 1},{    22, 0},{     6, 1},{    31, 0},
+{    -1, 0},{    30, 0},{    -2, 0},{    47, 0},{   -17, 0},{    46, 0},{   -18, 0},{    79, 0},
+{   -49, 0},{    78, 0},{   -50, 0},{   143, 0},{  -113, 0},{   142, 0},{  -114, 0},{   271, 0},
+{  -241, 0},{   270, 0},{  -242, 0},{   527, 0},{  -497, 0},{   526, 0},{  -498, 0},{  1039, 0},
+{ -1009, 0},{  1038, 0},{ -1010, 0},{  2063, 0},{ -2033, 0},{  2062, 0},{ -2034, 0},{  4111, 0},
+{ -4081, 0},{  4110, 0},{ -4082, 0},{  8207, 0},{ -8177, 0},{  8206, 0},{ -8178, 0},{ 16399, 0},
+{-16369, 0},{ 16398, 0},{-16370, 0},{ 32783, 0},{-32753, 0},{ 32782, 0},{-32754, 0},{   -16, 0},
+{   -18, 1},{   -17, 0},{   -19, 1},{   -15, 0},{   -19, 1},{   -16, 0},{   -20, 1},{   -13, 0},
+{   -21, 1},{   -14, 0},{   -22, 1},{    -9, 0},{   -25, 1},{   -10, 0},{   -26, 1},{    -1, 0},
+{   -33, 1},{    -2, 0},{   -34, 1},{    15, 1},{   -49, 1},{    14, 1},{   -50, 1},{    47, 1},
+{   -81, 1},{    46, 1},{   -82, 1},{   111, 1},{  -145, 1},{   110, 1},{  -146, 1},{   239, 1},
+{  -273, 1},{   238, 1},{  -274, 1},{   495, 1},{  -529, 1},{   494, 1},{  -530, 1},{  1007, 1},
+{ -1041, 1},{  1006, 1},{ -1042, 1},{  2031, 1},{ -2065, 1},{  2030, 1},{ -2066, 1},{  4079, 1},
+{ -4113, 1},{  4078, 1},{ -4114, 1},{  8175, 1},{ -8209, 1},{  8174, 1},{ -8210, 1},{ 16367, 1},
+{-16401, 1},{ 16366, 1},{-16402, 1},{ 32751, 1},{-32785, 1},{ 32750, 1},{-32786, 1},{    33, 0},
+{    31, 1},{    32, 0},{    30, 1},{    34, 0},{    30, 1},{    33, 0},{    29, 1},{    36, 0},
+{    28, 1},{    35, 0},{    27, 1},{    40, 0},{    24, 1},{    39, 0},{    23, 1},{    48, 0},
+{    16, 1},{    47, 0},{    15, 1},{    64, 0},{     0, 1},{    63, 0},{    -1, 0},{    96, 0},
+{   -32, 0},{    95, 0},{   -33, 0},{   160, 0},{   -96, 0},{   159, 0},{   -97, 0},{   288, 0},
+{  -224, 0},{   287, 0},{  -225, 0},{   544, 0},{  -480, 0},{   543, 0},{  -481, 0},{  1056, 0},
+{  -992, 0},{  1055, 0},{  -993, 0},{  2080, 0},{ -2016, 0},{  2079, 0},{ -2017, 0},{  4128, 0},
+{ -4064, 0},{  4127, 0},{ -4065, 0},{  8224, 0},{ -8160, 0},{  8223, 0},{ -8161, 0},{ 16416, 0},
+{-16352, 0},{ 16415, 0},{-16353, 0},{ 32800, 0},{-32736, 0},{ 32799, 0},{-32737, 0},{   -31, 0},
+{   -33, 1},{   -32, 0},{   -34, 1},{   -30, 0},{   -34, 1},{   -31, 0},{   -35, 1},{   -28, 0},
+{   -36, 1},{   -29, 0},{   -37, 1},{   -24, 0},{   -40, 1},{   -25, 0},{   -41, 1},{   -16, 0},
+{   -48, 1},{   -17, 0},{   -49, 1},{     0, 1},{   -64, 1},{    -1, 0},{   -65, 1},{    32, 1},
+{   -96, 1},{    31, 1},{   -97, 1},{    96, 1},{  -160, 1},{    95, 1},{  -161, 1},{   224, 1},
+{  -288, 1},{   223, 1},{  -289, 1},{   480, 1},{  -544, 1},{   479, 1},{  -545, 1},{   992, 1},
+{ -1056, 1},{   991, 1},{ -1057, 1},{  2016, 1},{ -2080, 1},{  2015, 1},{ -2081, 1},{  4064, 1},
+{ -4128, 1},{  4063, 1},{ -4129, 1},{  8160, 1},{ -8224, 1},{  8159, 1},{ -8225, 1},{ 16352, 1},
+{-16416, 1},{ 16351, 1},{-16417, 1},{ 32736, 1},{-32800, 1},{ 32735, 1},{-32801, 1},{    32, 0},
+{    30, 1},{    31, 0},{    29, 1},{    33, 0},{    29, 1},{    32, 0},{    28, 1},{    35, 0},
+{    27, 1},{    34, 0},{    26, 1},{    39, 0},{    23, 1},{    38, 0},{    22, 1},{    47, 0},
+{    15, 1},{    46, 0},{    14, 1},{    63, 0},{    -1, 0},{    62, 0},{    -2, 0},{    95, 0},
+{   -33, 0},{    94, 0},{   -34, 0},{   159, 0},{   -97, 0},{   158, 0},{   -98, 0},{   287, 0},
+{  -225, 0},{   286, 0},{  -226, 0},{   543, 0},{  -481, 0},{   542, 0},{  -482, 0},{  1055, 0},
+{  -993, 0},{  1054, 0},{  -994, 0},{  2079, 0},{ -2017, 0},{  2078, 0},{ -2018, 0},{  4127, 0},
+{ -4065, 0},{  4126, 0},{ -4066, 0},{  8223, 0},{ -8161, 0},{  8222, 0},{ -8162, 0},{ 16415, 0},
+{-16353, 0},{ 16414, 0},{-16354, 0},{ 32799, 0},{-32737, 0},{ 32798, 0},{-32738, 0},{   -32, 0},
+{   -34, 1},{   -33, 0},{   -35, 1},{   -31, 0},{   -35, 1},{   -32, 0},{   -36, 1},{   -29, 0},
+{   -37, 1},{   -30, 0},{   -38, 1},{   -25, 0},{   -41, 1},{   -26, 0},{   -42, 1},{   -17, 0},
+{   -49, 1},{   -18, 0},{   -50, 1},{    -1, 0},{   -65, 1},{    -2, 0},{   -66, 1},{    31, 1},
+{   -97, 1},{    30, 1},{   -98, 1},{    95, 1},{  -161, 1},{    94, 1},{  -162, 1},{   223, 1},
+{  -289, 1},{   222, 1},{  -290, 1},{   479, 1},{  -545, 1},{   478, 1},{  -546, 1},{   991, 1},
+{ -1057, 1},{   990, 1},{ -1058, 1},{  2015, 1},{ -2081, 1},{  2014, 1},{ -2082, 1},{  4063, 1},
+{ -4129, 1},{  4062, 1},{ -4130, 1},{  8159, 1},{ -8225, 1},{  8158, 1},{ -8226, 1},{ 16351, 1},
+{-16417, 1},{ 16350, 1},{-16418, 1},{ 32735, 1},{-32801, 1},{ 32734, 1},{-32802, 1},{    65, 0},
+{    63, 1},{    64, 0},{    62, 1},{    66, 0},{    62, 1},{    65, 0},{    61, 1},{    68, 0},
+{    60, 1},{    67, 0},{    59, 1},{    72, 0},{    56, 1},{    71, 0},{    55, 1},{    80, 0},
+{    48, 1},{    79, 0},{    47, 1},{    96, 0},{    32, 1},{    95, 0},{    31, 1},{   128, 0},
+{     0, 1},{   127, 0},{    -1, 0},{   192, 0},{   -64, 0},{   191, 0},{   -65, 0},{   320, 0},
+{  -192, 0},{   319, 0},{  -193, 0},{   576, 0},{  -448, 0},{   575, 0},{  -449, 0},{  1088, 0},
+{  -960, 0},{  1087, 0},{  -961, 0},{  2112, 0},{ -1984, 0},{  2111, 0},{ -1985, 0},{  4160, 0},
+{ -4032, 0},{  4159, 0},{ -4033, 0},{  8256, 0},{ -8128, 0},{  8255, 0},{ -8129, 0},{ 16448, 0},
+{-16320, 0},{ 16447, 0},{-16321, 0},{ 32832, 0},{-32704, 0},{ 32831, 0},{-32705, 0},{   -63, 0},
+{   -65, 1},{   -64, 0},{   -66, 1},{   -62, 0},{   -66, 1},{   -63, 0},{   -67, 1},{   -60, 0},
+{   -68, 1},{   -61, 0},{   -69, 1},{   -56, 0},{   -72, 1},{   -57, 0},{   -73, 1},{   -48, 0},
+{   -80, 1},{   -49, 0},{   -81, 1},{   -32, 0},{   -96, 1},{   -33, 0},{   -97, 1},{     0, 1},
+{  -128, 1},{    -1, 0},{  -129, 1},{    64, 1},{  -192, 1},{    63, 1},{  -193, 1},{   192, 1},
+{  -320, 1},{   191, 1},{  -321, 1},{   448, 1},{  -576, 1},{   447, 1},{  -577, 1},{   960, 1},
+{ -1088, 1},{   959, 1},{ -1089, 1},{  1984, 1},{ -2112, 1},{  1983, 1},{ -2113, 1},{  4032, 1},
+{ -4160, 1},{  4031, 1},{ -4161, 1},{  8128, 1},{ -8256, 1},{  8127, 1},{ -8257, 1},{ 16320, 1},
+{-16448, 1},{ 16319, 1},{-16449, 1},{ 32704, 1},{-32832, 1},{ 32703, 1},{-32833, 1},{    64, 0},
+{    62, 1},{    63, 0},{    61, 1},{    65, 0},{    61, 1},{    64, 0},{    60, 1},{    67, 0},
+{    59, 1},{    66, 0},{    58, 1},{    71, 0},{    55, 1},{    70, 0},{    54, 1},{    79, 0},
+{    47, 1},{    78, 0},{    46, 1},{    95, 0},{    31, 1},{    94, 0},{    30, 1},{   127, 0},
+{    -1, 0},{   126, 0},{    -2, 0},{   191, 0},{   -65, 0},{   190, 0},{   -66, 0},{   319, 0},
+{  -193, 0},{   318, 0},{  -194, 0},{   575, 0},{  -449, 0},{   574, 0},{  -450, 0},{  1087, 0},
+{  -961, 0},{  1086, 0},{  -962, 0},{  2111, 0},{ -1985, 0},{  2110, 0},{ -1986, 0},{  4159, 0},
+{ -4033, 0},{  4158, 0},{ -4034, 0},{  8255, 0},{ -8129, 0},{  8254, 0},{ -8130, 0},{ 16447, 0},
+{-16321, 0},{ 16446, 0},{-16322, 0},{ 32831, 0},{-32705, 0},{ 32830, 0},{-32706, 0},{   -64, 0},
+{   -66, 1},{   -65, 0},{   -67, 1},{   -63, 0},{   -67, 1},{   -64, 0},{   -68, 1},{   -61, 0},
+{   -69, 1},{   -62, 0},{   -70, 1},{   -57, 0},{   -73, 1},{   -58, 0},{   -74, 1},{   -49, 0},
+{   -81, 1},{   -50, 0},{   -82, 1},{   -33, 0},{   -97, 1},{   -34, 0},{   -98, 1},{    -1, 0},
+{  -129, 1},{    -2, 0},{  -130, 1},{    63, 1},{  -193, 1},{    62, 1},{  -194, 1},{   191, 1},
+{  -321, 1},{   190, 1},{  -322, 1},{   447, 1},{  -577, 1},{   446, 1},{  -578, 1},{   959, 1},
+{ -1089, 1},{   958, 1},{ -1090, 1},{  1983, 1},{ -2113, 1},{  1982, 1},{ -2114, 1},{  4031, 1},
+{ -4161, 1},{  4030, 1},{ -4162, 1},{  8127, 1},{ -8257, 1},{  8126, 1},{ -8258, 1},{ 16319, 1},
+{-16449, 1},{ 16318, 1},{-16450, 1},{ 32703, 1},{-32833, 1},{ 32702, 1},{-32834, 1},{   129, 0},
+{   127, 1},{   128, 0},{   126, 1},{   130, 0},{   126, 1},{   129, 0},{   125, 1},{   132, 0},
+{   124, 1},{   131, 0},{   123, 1},{   136, 0},{   120, 1},{   135, 0},{   119, 1},{   144, 0},
+{   112, 1},{   143, 0},{   111, 1},{   160, 0},{    96, 1},{   159, 0},{    95, 1},{   192, 0},
+{    64, 1},{   191, 0},{    63, 1},{   256, 0},{     0, 1},{   255, 0},{    -1, 0},{   384, 0},
+{  -128, 0},{   383, 0},{  -129, 0},{   640, 0},{  -384, 0},{   639, 0},{  -385, 0},{  1152, 0},
+{  -896, 0},{  1151, 0},{  -897, 0},{  2176, 0},{ -1920, 0},{  2175, 0},{ -1921, 0},{  4224, 0},
+{ -3968, 0},{  4223, 0},{ -3969, 0},{  8320, 0},{ -8064, 0},{  8319, 0},{ -8065, 0},{ 16512, 0},
+{-16256, 0},{ 16511, 0},{-16257, 0},{ 32896, 0},{-32640, 0},{ 32895, 0},{-32641, 0},{  -127, 0},
+{  -129, 1},{  -128, 0},{  -130, 1},{  -126, 0},{  -130, 1},{  -127, 0},{  -131, 1},{  -124, 0},
+{  -132, 1},{  -125, 0},{  -133, 1},{  -120, 0},{  -136, 1},{  -121, 0},{  -137, 1},{  -112, 0},
+{  -144, 1},{  -113, 0},{  -145, 1},{   -96, 0},{  -160, 1},{   -97, 0},{  -161, 1},{   -64, 0},
+{  -192, 1},{   -65, 0},{  -193, 1},{     0, 1},{  -256, 1},{    -1, 0},{  -257, 1},{   128, 1},
+{  -384, 1},{   127, 1},{  -385, 1},{   384, 1},{  -640, 1},{   383, 1},{  -641, 1},{   896, 1},
+{ -1152, 1},{   895, 1},{ -1153, 1},{  1920, 1},{ -2176, 1},{  1919, 1},{ -2177, 1},{  3968, 1},
+{ -4224, 1},{  3967, 1},{ -4225, 1},{  8064, 1},{ -8320, 1},{  8063, 1},{ -8321, 1},{ 16256, 1},
+{-16512, 1},{ 16255, 1},{-16513, 1},{ 32640, 1},{-32896, 1},{ 32639, 1},{-32897, 1},{   128, 0},
+{   126, 1},{   127, 0},{   125, 1},{   129, 0},{   125, 1},{   128, 0},{   124, 1},{   131, 0},
+{   123, 1},{   130, 0},{   122, 1},{   135, 0},{   119, 1},{   134, 0},{   118, 1},{   143, 0},
+{   111, 1},{   142, 0},{   110, 1},{   159, 0},{    95, 1},{   158, 0},{    94, 1},{   191, 0},
+{    63, 1},{   190, 0},{    62, 1},{   255, 0},{    -1, 0},{   254, 0},{    -2, 0},{   383, 0},
+{  -129, 0},{   382, 0},{  -130, 0},{   639, 0},{  -385, 0},{   638, 0},{  -386, 0},{  1151, 0},
+{  -897, 0},{  1150, 0},{  -898, 0},{  2175, 0},{ -1921, 0},{  2174, 0},{ -1922, 0},{  4223, 0},
+{ -3969, 0},{  4222, 0},{ -3970, 0},{  8319, 0},{ -8065, 0},{  8318, 0},{ -8066, 0},{ 16511, 0},
+{-16257, 0},{ 16510, 0},{-16258, 0},{ 32895, 0},{-32641, 0},{ 32894, 0},{-32642, 0},{  -128, 0},
+{  -130, 1},{  -129, 0},{  -131, 1},{  -127, 0},{  -131, 1},{  -128, 0},{  -132, 1},{  -125, 0},
+{  -133, 1},{  -126, 0},{  -134, 1},{  -121, 0},{  -137, 1},{  -122, 0},{  -138, 1},{  -113, 0},
+{  -145, 1},{  -114, 0},{  -146, 1},{   -97, 0},{  -161, 1},{   -98, 0},{  -162, 1},{   -65, 0},
+{  -193, 1},{   -66, 0},{  -194, 1},{    -1, 0},{  -257, 1},{    -2, 0},{  -258, 1},{   127, 1},
+{  -385, 1},{   126, 1},{  -386, 1},{   383, 1},{  -641, 1},{   382, 1},{  -642, 1},{   895, 1},
+{ -1153, 1},{   894, 1},{ -1154, 1},{  1919, 1},{ -2177, 1},{  1918, 1},{ -2178, 1},{  3967, 1},
+{ -4225, 1},{  3966, 1},{ -4226, 1},{  8063, 1},{ -8321, 1},{  8062, 1},{ -8322, 1},{ 16255, 1},
+{-16513, 1},{ 16254, 1},{-16514, 1},{ 32639, 1},{-32897, 1},{ 32638, 1},{-32898, 1},{   257, 0},
+{   255, 1},{   256, 0},{   254, 1},{   258, 0},{   254, 1},{   257, 0},{   253, 1},{   260, 0},
+{   252, 1},{   259, 0},{   251, 1},{   264, 0},{   248, 1},{   263, 0},{   247, 1},{   272, 0},
+{   240, 1},{   271, 0},{   239, 1},{   288, 0},{   224, 1},{   287, 0},{   223, 1},{   320, 0},
+{   192, 1},{   319, 0},{   191, 1},{   384, 0},{   128, 1},{   383, 0},{   127, 1},{   512, 0},
+{     0, 1},{   511, 0},{    -1, 0},{   768, 0},{  -256, 0},{   767, 0},{  -257, 0},{  1280, 0},
+{  -768, 0},{  1279, 0},{  -769, 0},{  2304, 0},{ -1792, 0},{  2303, 0},{ -1793, 0},{  4352, 0},
+{ -3840, 0},{  4351, 0},{ -3841, 0},{  8448, 0},{ -7936, 0},{  8447, 0},{ -7937, 0},{ 16640, 0},
+{-16128, 0},{ 16639, 0},{-16129, 0},{ 33024, 0},{-32512, 0},{ 33023, 0},{-32513, 0},{  -255, 0},
+{  -257, 1},{  -256, 0},{  -258, 1},{  -254, 0},{  -258, 1},{  -255, 0},{  -259, 1},{  -252, 0},
+{  -260, 1},{  -253, 0},{  -261, 1},{  -248, 0},{  -264, 1},{  -249, 0},{  -265, 1},{  -240, 0},
+{  -272, 1},{  -241, 0},{  -273, 1},{  -224, 0},{  -288, 1},{  -225, 0},{  -289, 1},{  -192, 0},
+{  -320, 1},{  -193, 0},{  -321, 1},{  -128, 0},{  -384, 1},{  -129, 0},{  -385, 1},{     0, 1},
+{  -512, 1},{    -1, 0},{  -513, 1},{   256, 1},{  -768, 1},{   255, 1},{  -769, 1},{   768, 1},
+{ -1280, 1},{   767, 1},{ -1281, 1},{  1792, 1},{ -2304, 1},{  1791, 1},{ -2305, 1},{  3840, 1},
+{ -4352, 1},{  3839, 1},{ -4353, 1},{  7936, 1},{ -8448, 1},{  7935, 1},{ -8449, 1},{ 16128, 1},
+{-16640, 1},{ 16127, 1},{-16641, 1},{ 32512, 1},{-33024, 1},{ 32511, 1},{-33025, 1},{   256, 0},
+{   254, 1},{   255, 0},{   253, 1},{   257, 0},{   253, 1},{   256, 0},{   252, 1},{   259, 0},
+{   251, 1},{   258, 0},{   250, 1},{   263, 0},{   247, 1},{   262, 0},{   246, 1},{   271, 0},
+{   239, 1},{   270, 0},{   238, 1},{   287, 0},{   223, 1},{   286, 0},{   222, 1},{   319, 0},
+{   191, 1},{   318, 0},{   190, 1},{   383, 0},{   127, 1},{   382, 0},{   126, 1},{   511, 0},
+{    -1, 0},{   510, 0},{    -2, 0},{   767, 0},{  -257, 0},{   766, 0},{  -258, 0},{  1279, 0},
+{  -769, 0},{  1278, 0},{  -770, 0},{  2303, 0},{ -1793, 0},{  2302, 0},{ -1794, 0},{  4351, 0},
+{ -3841, 0},{  4350, 0},{ -3842, 0},{  8447, 0},{ -7937, 0},{  8446, 0},{ -7938, 0},{ 16639, 0},
+{-16129, 0},{ 16638, 0},{-16130, 0},{ 33023, 0},{-32513, 0},{ 33022, 0},{-32514, 0},{  -256, 0},
+{  -258, 1},{  -257, 0},{  -259, 1},{  -255, 0},{  -259, 1},{  -256, 0},{  -260, 1},{  -253, 0},
+{  -261, 1},{  -254, 0},{  -262, 1},{  -249, 0},{  -265, 1},{  -250, 0},{  -266, 1},{  -241, 0},
+{  -273, 1},{  -242, 0},{  -274, 1},{  -225, 0},{  -289, 1},{  -226, 0},{  -290, 1},{  -193, 0},
+{  -321, 1},{  -194, 0},{  -322, 1},{  -129, 0},{  -385, 1},{  -130, 0},{  -386, 1},{    -1, 0},
+{  -513, 1},{    -2, 0},{  -514, 1},{   255, 1},{  -769, 1},{   254, 1},{  -770, 1},{   767, 1},
+{ -1281, 1},{   766, 1},{ -1282, 1},{  1791, 1},{ -2305, 1},{  1790, 1},{ -2306, 1},{  3839, 1},
+{ -4353, 1},{  3838, 1},{ -4354, 1},{  7935, 1},{ -8449, 1},{  7934, 1},{ -8450, 1},{ 16127, 1},
+{-16641, 1},{ 16126, 1},{-16642, 1},{ 32511, 1},{-33025, 1},{ 32510, 1},{-33026, 1},{   513, 0},
+{   511, 1},{   512, 0},{   510, 1},{   514, 0},{   510, 1},{   513, 0},{   509, 1},{   516, 0},
+{   508, 1},{   515, 0},{   507, 1},{   520, 0},{   504, 1},{   519, 0},{   503, 1},{   528, 0},
+{   496, 1},{   527, 0},{   495, 1},{   544, 0},{   480, 1},{   543, 0},{   479, 1},{   576, 0},
+{   448, 1},{   575, 0},{   447, 1},{   640, 0},{   384, 1},{   639, 0},{   383, 1},{   768, 0},
+{   256, 1},{   767, 0},{   255, 1},{  1024, 0},{     0, 1},{  1023, 0},{    -1, 0},{  1536, 0},
+{  -512, 0},{  1535, 0},{  -513, 0},{  2560, 0},{ -1536, 0},{  2559, 0},{ -1537, 0},{  4608, 0},
+{ -3584, 0},{  4607, 0},{ -3585, 0},{  8704, 0},{ -7680, 0},{  8703, 0},{ -7681, 0},{ 16896, 0},
+{-15872, 0},{ 16895, 0},{-15873, 0},{ 33280, 0},{-32256, 0},{ 33279, 0},{-32257, 0},{  -511, 0},
+{  -513, 1},{  -512, 0},{  -514, 1},{  -510, 0},{  -514, 1},{  -511, 0},{  -515, 1},{  -508, 0},
+{  -516, 1},{  -509, 0},{  -517, 1},{  -504, 0},{  -520, 1},{  -505, 0},{  -521, 1},{  -496, 0},
+{  -528, 1},{  -497, 0},{  -529, 1},{  -480, 0},{  -544, 1},{  -481, 0},{  -545, 1},{  -448, 0},
+{  -576, 1},{  -449, 0},{  -577, 1},{  -384, 0},{  -640, 1},{  -385, 0},{  -641, 1},{  -256, 0},
+{  -768, 1},{  -257, 0},{  -769, 1},{     0, 1},{ -1024, 1},{    -1, 0},{ -1025, 1},{   512, 1},
+{ -1536, 1},{   511, 1},{ -1537, 1},{  1536, 1},{ -2560, 1},{  1535, 1},{ -2561, 1},{  3584, 1},
+{ -4608, 1},{  3583, 1},{ -4609, 1},{  7680, 1},{ -8704, 1},{  7679, 1},{ -8705, 1},{ 15872, 1},
+{-16896, 1},{ 15871, 1},{-16897, 1},{ 32256, 1},{-33280, 1},{ 32255, 1},{-33281, 1},{   512, 0},
+{   510, 1},{   511, 0},{   509, 1},{   513, 0},{   509, 1},{   512, 0},{   508, 1},{   515, 0},
+{   507, 1},{   514, 0},{   506, 1},{   519, 0},{   503, 1},{   518, 0},{   502, 1},{   527, 0},
+{   495, 1},{   526, 0},{   494, 1},{   543, 0},{   479, 1},{   542, 0},{   478, 1},{   575, 0},
+{   447, 1},{   574, 0},{   446, 1},{   639, 0},{   383, 1},{   638, 0},{   382, 1},{   767, 0},
+{   255, 1},{   766, 0},{   254, 1},{  1023, 0},{    -1, 0},{  1022, 0},{    -2, 0},{  1535, 0},
+{  -513, 0},{  1534, 0},{  -514, 0},{  2559, 0},{ -1537, 0},{  2558, 0},{ -1538, 0},{  4607, 0},
+{ -3585, 0},{  4606, 0},{ -3586, 0},{  8703, 0},{ -7681, 0},{  8702, 0},{ -7682, 0},{ 16895, 0},
+{-15873, 0},{ 16894, 0},{-15874, 0},{ 33279, 0},{-32257, 0},{ 33278, 0},{-32258, 0},{  -512, 0},
+{  -514, 1},{  -513, 0},{  -515, 1},{  -511, 0},{  -515, 1},{  -512, 0},{  -516, 1},{  -509, 0},
+{  -517, 1},{  -510, 0},{  -518, 1},{  -505, 0},{  -521, 1},{  -506, 0},{  -522, 1},{  -497, 0},
+{  -529, 1},{  -498, 0},{  -530, 1},{  -481, 0},{  -545, 1},{  -482, 0},{  -546, 1},{  -449, 0},
+{  -577, 1},{  -450, 0},{  -578, 1},{  -385, 0},{  -641, 1},{  -386, 0},{  -642, 1},{  -257, 0},
+{  -769, 1},{  -258, 0},{  -770, 1},{    -1, 0},{ -1025, 1},{    -2, 0},{ -1026, 1},{   511, 1},
+{ -1537, 1},{   510, 1},{ -1538, 1},{  1535, 1},{ -2561, 1},{  1534, 1},{ -2562, 1},{  3583, 1},
+{ -4609, 1},{  3582, 1},{ -4610, 1},{  7679, 1},{ -8705, 1},{  7678, 1},{ -8706, 1},{ 15871, 1},
+{-16897, 1},{ 15870, 1},{-16898, 1},{ 32255, 1},{-33281, 1},{ 32254, 1},{-33282, 1},{  1025, 0},
+{  1023, 1},{  1024, 0},{  1022, 1},{  1026, 0},{  1022, 1},{  1025, 0},{  1021, 1},{  1028, 0},
+{  1020, 1},{  1027, 0},{  1019, 1},{  1032, 0},{  1016, 1},{  1031, 0},{  1015, 1},{  1040, 0},
+{  1008, 1},{  1039, 0},{  1007, 1},{  1056, 0},{   992, 1},{  1055, 0},{   991, 1},{  1088, 0},
+{   960, 1},{  1087, 0},{   959, 1},{  1152, 0},{   896, 1},{  1151, 0},{   895, 1},{  1280, 0},
+{   768, 1},{  1279, 0},{   767, 1},{  1536, 0},{   512, 1},{  1535, 0},{   511, 1},{  2048, 0},
+{     0, 1},{  2047, 0},{    -1, 0},{  3072, 0},{ -1024, 0},{  3071, 0},{ -1025, 0},{  5120, 0},
+{ -3072, 0},{  5119, 0},{ -3073, 0},{  9216, 0},{ -7168, 0},{  9215, 0},{ -7169, 0},{ 17408, 0},
+{-15360, 0},{ 17407, 0},{-15361, 0},{ 33792, 0},{-31744, 0},{ 33791, 0},{-31745, 0},{ -1023, 0},
+{ -1025, 1},{ -1024, 0},{ -1026, 1},{ -1022, 0},{ -1026, 1},{ -1023, 0},{ -1027, 1},{ -1020, 0},
+{ -1028, 1},{ -1021, 0},{ -1029, 1},{ -1016, 0},{ -1032, 1},{ -1017, 0},{ -1033, 1},{ -1008, 0},
+{ -1040, 1},{ -1009, 0},{ -1041, 1},{  -992, 0},{ -1056, 1},{  -993, 0},{ -1057, 1},{  -960, 0},
+{ -1088, 1},{  -961, 0},{ -1089, 1},{  -896, 0},{ -1152, 1},{  -897, 0},{ -1153, 1},{  -768, 0},
+{ -1280, 1},{  -769, 0},{ -1281, 1},{  -512, 0},{ -1536, 1},{  -513, 0},{ -1537, 1},{     0, 1},
+{ -2048, 1},{    -1, 0},{ -2049, 1},{  1024, 1},{ -3072, 1},{  1023, 1},{ -3073, 1},{  3072, 1},
+{ -5120, 1},{  3071, 1},{ -5121, 1},{  7168, 1},{ -9216, 1},{  7167, 1},{ -9217, 1},{ 15360, 1},
+{-17408, 1},{ 15359, 1},{-17409, 1},{ 31744, 1},{-33792, 1},{ 31743, 1},{-33793, 1},{  1024, 0},
+{  1022, 1},{  1023, 0},{  1021, 1},{  1025, 0},{  1021, 1},{  1024, 0},{  1020, 1},{  1027, 0},
+{  1019, 1},{  1026, 0},{  1018, 1},{  1031, 0},{  1015, 1},{  1030, 0},{  1014, 1},{  1039, 0},
+{  1007, 1},{  1038, 0},{  1006, 1},{  1055, 0},{   991, 1},{  1054, 0},{   990, 1},{  1087, 0},
+{   959, 1},{  1086, 0},{   958, 1},{  1151, 0},{   895, 1},{  1150, 0},{   894, 1},{  1279, 0},
+{   767, 1},{  1278, 0},{   766, 1},{  1535, 0},{   511, 1},{  1534, 0},{   510, 1},{  2047, 0},
+{    -1, 0},{  2046, 0},{    -2, 0},{  3071, 0},{ -1025, 0},{  3070, 0},{ -1026, 0},{  5119, 0},
+{ -3073, 0},{  5118, 0},{ -3074, 0},{  9215, 0},{ -7169, 0},{  9214, 0},{ -7170, 0},{ 17407, 0},
+{-15361, 0},{ 17406, 0},{-15362, 0},{ 33791, 0},{-31745, 0},{ 33790, 0},{-31746, 0},{ -1024, 0},
+{ -1026, 1},{ -1025, 0},{ -1027, 1},{ -1023, 0},{ -1027, 1},{ -1024, 0},{ -1028, 1},{ -1021, 0},
+{ -1029, 1},{ -1022, 0},{ -1030, 1},{ -1017, 0},{ -1033, 1},{ -1018, 0},{ -1034, 1},{ -1009, 0},
+{ -1041, 1},{ -1010, 0},{ -1042, 1},{  -993, 0},{ -1057, 1},{  -994, 0},{ -1058, 1},{  -961, 0},
+{ -1089, 1},{  -962, 0},{ -1090, 1},{  -897, 0},{ -1153, 1},{  -898, 0},{ -1154, 1},{  -769, 0},
+{ -1281, 1},{  -770, 0},{ -1282, 1},{  -513, 0},{ -1537, 1},{  -514, 0},{ -1538, 1},{    -1, 0},
+{ -2049, 1},{    -2, 0},{ -2050, 1},{  1023, 1},{ -3073, 1},{  1022, 1},{ -3074, 1},{  3071, 1},
+{ -5121, 1},{  3070, 1},{ -5122, 1},{  7167, 1},{ -9217, 1},{  7166, 1},{ -9218, 1},{ 15359, 1},
+{-17409, 1},{ 15358, 1},{-17410, 1},{ 31743, 1},{-33793, 1},{ 31742, 1},{-33794, 1},{  2049, 0},
+{  2047, 1},{  2048, 0},{  2046, 1},{  2050, 0},{  2046, 1},{  2049, 0},{  2045, 1},{  2052, 0},
+{  2044, 1},{  2051, 0},{  2043, 1},{  2056, 0},{  2040, 1},{  2055, 0},{  2039, 1},{  2064, 0},
+{  2032, 1},{  2063, 0},{  2031, 1},{  2080, 0},{  2016, 1},{  2079, 0},{  2015, 1},{  2112, 0},
+{  1984, 1},{  2111, 0},{  1983, 1},{  2176, 0},{  1920, 1},{  2175, 0},{  1919, 1},{  2304, 0},
+{  1792, 1},{  2303, 0},{  1791, 1},{  2560, 0},{  1536, 1},{  2559, 0},{  1535, 1},{  3072, 0},
+{  1024, 1},{  3071, 0},{  1023, 1},{  4096, 0},{     0, 1},{  4095, 0},{    -1, 0},{  6144, 0},
+{ -2048, 0},{  6143, 0},{ -2049, 0},{ 10240, 0},{ -6144, 0},{ 10239, 0},{ -6145, 0},{ 18432, 0},
+{-14336, 0},{ 18431, 0},{-14337, 0},{ 34816, 0},{-30720, 0},{ 34815, 0},{-30721, 0},{ -2047, 0},
+{ -2049, 1},{ -2048, 0},{ -2050, 1},{ -2046, 0},{ -2050, 1},{ -2047, 0},{ -2051, 1},{ -2044, 0},
+{ -2052, 1},{ -2045, 0},{ -2053, 1},{ -2040, 0},{ -2056, 1},{ -2041, 0},{ -2057, 1},{ -2032, 0},
+{ -2064, 1},{ -2033, 0},{ -2065, 1},{ -2016, 0},{ -2080, 1},{ -2017, 0},{ -2081, 1},{ -1984, 0},
+{ -2112, 1},{ -1985, 0},{ -2113, 1},{ -1920, 0},{ -2176, 1},{ -1921, 0},{ -2177, 1},{ -1792, 0},
+{ -2304, 1},{ -1793, 0},{ -2305, 1},{ -1536, 0},{ -2560, 1},{ -1537, 0},{ -2561, 1},{ -1024, 0},
+{ -3072, 1},{ -1025, 0},{ -3073, 1},{     0, 1},{ -4096, 1},{    -1, 0},{ -4097, 1},{  2048, 1},
+{ -6144, 1},{  2047, 1},{ -6145, 1},{  6144, 1},{-10240, 1},{  6143, 1},{-10241, 1},{ 14336, 1},
+{-18432, 1},{ 14335, 1},{-18433, 1},{ 30720, 1},{-34816, 1},{ 30719, 1},{-34817, 1},{  2048, 0},
+{  2046, 1},{  2047, 0},{  2045, 1},{  2049, 0},{  2045, 1},{  2048, 0},{  2044, 1},{  2051, 0},
+{  2043, 1},{  2050, 0},{  2042, 1},{  2055, 0},{  2039, 1},{  2054, 0},{  2038, 1},{  2063, 0},
+{  2031, 1},{  2062, 0},{  2030, 1},{  2079, 0},{  2015, 1},{  2078, 0},{  2014, 1},{  2111, 0},
+{  1983, 1},{  2110, 0},{  1982, 1},{  2175, 0},{  1919, 1},{  2174, 0},{  1918, 1},{  2303, 0},
+{  1791, 1},{  2302, 0},{  1790, 1},{  2559, 0},{  1535, 1},{  2558, 0},{  1534, 1},{  3071, 0},
+{  1023, 1},{  3070, 0},{  1022, 1},{  4095, 0},{    -1, 0},{  4094, 0},{    -2, 0},{  6143, 0},
+{ -2049, 0},{  6142, 0},{ -2050, 0},{ 10239, 0},{ -6145, 0},{ 10238, 0},{ -6146, 0},{ 18431, 0},
+{-14337, 0},{ 18430, 0},{-14338, 0},{ 34815, 0},{-30721, 0},{ 34814, 0},{-30722, 0},{ -2048, 0},
+{ -2050, 1},{ -2049, 0},{ -2051, 1},{ -2047, 0},{ -2051, 1},{ -2048, 0},{ -2052, 1},{ -2045, 0},
+{ -2053, 1},{ -2046, 0},{ -2054, 1},{ -2041, 0},{ -2057, 1},{ -2042, 0},{ -2058, 1},{ -2033, 0},
+{ -2065, 1},{ -2034, 0},{ -2066, 1},{ -2017, 0},{ -2081, 1},{ -2018, 0},{ -2082, 1},{ -1985, 0},
+{ -2113, 1},{ -1986, 0},{ -2114, 1},{ -1921, 0},{ -2177, 1},{ -1922, 0},{ -2178, 1},{ -1793, 0},
+{ -2305, 1},{ -1794, 0},{ -2306, 1},{ -1537, 0},{ -2561, 1},{ -1538, 0},{ -2562, 1},{ -1025, 0},
+{ -3073, 1},{ -1026, 0},{ -3074, 1},{    -1, 0},{ -4097, 1},{    -2, 0},{ -4098, 1},{  2047, 1},
+{ -6145, 1},{  2046, 1},{ -6146, 1},{  6143, 1},{-10241, 1},{  6142, 1},{-10242, 1},{ 14335, 1},
+{-18433, 1},{ 14334, 1},{-18434, 1},{ 30719, 1},{-34817, 1},{ 30718, 1},{-34818, 1},{  4097, 0},
+{  4095, 1},{  4096, 0},{  4094, 1},{  4098, 0},{  4094, 1},{  4097, 0},{  4093, 1},{  4100, 0},
+{  4092, 1},{  4099, 0},{  4091, 1},{  4104, 0},{  4088, 1},{  4103, 0},{  4087, 1},{  4112, 0},
+{  4080, 1},{  4111, 0},{  4079, 1},{  4128, 0},{  4064, 1},{  4127, 0},{  4063, 1},{  4160, 0},
+{  4032, 1},{  4159, 0},{  4031, 1},{  4224, 0},{  3968, 1},{  4223, 0},{  3967, 1},{  4352, 0},
+{  3840, 1},{  4351, 0},{  3839, 1},{  4608, 0},{  3584, 1},{  4607, 0},{  3583, 1},{  5120, 0},
+{  3072, 1},{  5119, 0},{  3071, 1},{  6144, 0},{  2048, 1},{  6143, 0},{  2047, 1},{  8192, 0},
+{     0, 1},{  8191, 0},{    -1, 0},{ 12288, 0},{ -4096, 0},{ 12287, 0},{ -4097, 0},{ 20480, 0},
+{-12288, 0},{ 20479, 0},{-12289, 0},{ 36864, 0},{-28672, 0},{ 36863, 0},{-28673, 0},{ -4095, 0},
+{ -4097, 1},{ -4096, 0},{ -4098, 1},{ -4094, 0},{ -4098, 1},{ -4095, 0},{ -4099, 1},{ -4092, 0},
+{ -4100, 1},{ -4093, 0},{ -4101, 1},{ -4088, 0},{ -4104, 1},{ -4089, 0},{ -4105, 1},{ -4080, 0},
+{ -4112, 1},{ -4081, 0},{ -4113, 1},{ -4064, 0},{ -4128, 1},{ -4065, 0},{ -4129, 1},{ -4032, 0},
+{ -4160, 1},{ -4033, 0},{ -4161, 1},{ -3968, 0},{ -4224, 1},{ -3969, 0},{ -4225, 1},{ -3840, 0},
+{ -4352, 1},{ -3841, 0},{ -4353, 1},{ -3584, 0},{ -4608, 1},{ -3585, 0},{ -4609, 1},{ -3072, 0},
+{ -5120, 1},{ -3073, 0},{ -5121, 1},{ -2048, 0},{ -6144, 1},{ -2049, 0},{ -6145, 1},{     0, 1},
+{ -8192, 1},{    -1, 0},{ -8193, 1},{  4096, 1},{-12288, 1},{  4095, 1},{-12289, 1},{ 12288, 1},
+{-20480, 1},{ 12287, 1},{-20481, 1},{ 28672, 1},{-36864, 1},{ 28671, 1},{-36865, 1},{  4096, 0},
+{  4094, 1},{  4095, 0},{  4093, 1},{  4097, 0},{  4093, 1},{  4096, 0},{  4092, 1},{  4099, 0},
+{  4091, 1},{  4098, 0},{  4090, 1},{  4103, 0},{  4087, 1},{  4102, 0},{  4086, 1},{  4111, 0},
+{  4079, 1},{  4110, 0},{  4078, 1},{  4127, 0},{  4063, 1},{  4126, 0},{  4062, 1},{  4159, 0},
+{  4031, 1},{  4158, 0},{  4030, 1},{  4223, 0},{  3967, 1},{  4222, 0},{  3966, 1},{  4351, 0},
+{  3839, 1},{  4350, 0},{  3838, 1},{  4607, 0},{  3583, 1},{  4606, 0},{  3582, 1},{  5119, 0},
+{  3071, 1},{  5118, 0},{  3070, 1},{  6143, 0},{  2047, 1},{  6142, 0},{  2046, 1},{  8191, 0},
+{    -1, 0},{  8190, 0},{    -2, 0},{ 12287, 0},{ -4097, 0},{ 12286, 0},{ -4098, 0},{ 20479, 0},
+{-12289, 0},{ 20478, 0},{-12290, 0},{ 36863, 0},{-28673, 0},{ 36862, 0},{-28674, 0},{ -4096, 0},
+{ -4098, 1},{ -4097, 0},{ -4099, 1},{ -4095, 0},{ -4099, 1},{ -4096, 0},{ -4100, 1},{ -4093, 0},
+{ -4101, 1},{ -4094, 0},{ -4102, 1},{ -4089, 0},{ -4105, 1},{ -4090, 0},{ -4106, 1},{ -4081, 0},
+{ -4113, 1},{ -4082, 0},{ -4114, 1},{ -4065, 0},{ -4129, 1},{ -4066, 0},{ -4130, 1},{ -4033, 0},
+{ -4161, 1},{ -4034, 0},{ -4162, 1},{ -3969, 0},{ -4225, 1},{ -3970, 0},{ -4226, 1},{ -3841, 0},
+{ -4353, 1},{ -3842, 0},{ -4354, 1},{ -3585, 0},{ -4609, 1},{ -3586, 0},{ -4610, 1},{ -3073, 0},
+{ -5121, 1},{ -3074, 0},{ -5122, 1},{ -2049, 0},{ -6145, 1},{ -2050, 0},{ -6146, 1},{    -1, 0},
+{ -8193, 1},{    -2, 0},{ -8194, 1},{  4095, 1},{-12289, 1},{  4094, 1},{-12290, 1},{ 12287, 1},
+{-20481, 1},{ 12286, 1},{-20482, 1},{ 28671, 1},{-36865, 1},{ 28670, 1},{-36866, 1},{  8193, 0},
+{  8191, 1},{  8192, 0},{  8190, 1},{  8194, 0},{  8190, 1},{  8193, 0},{  8189, 1},{  8196, 0},
+{  8188, 1},{  8195, 0},{  8187, 1},{  8200, 0},{  8184, 1},{  8199, 0},{  8183, 1},{  8208, 0},
+{  8176, 1},{  8207, 0},{  8175, 1},{  8224, 0},{  8160, 1},{  8223, 0},{  8159, 1},{  8256, 0},
+{  8128, 1},{  8255, 0},{  8127, 1},{  8320, 0},{  8064, 1},{  8319, 0},{  8063, 1},{  8448, 0},
+{  7936, 1},{  8447, 0},{  7935, 1},{  8704, 0},{  7680, 1},{  8703, 0},{  7679, 1},{  9216, 0},
+{  7168, 1},{  9215, 0},{  7167, 1},{ 10240, 0},{  6144, 1},{ 10239, 0},{  6143, 1},{ 12288, 0},
+{  4096, 1},{ 12287, 0},{  4095, 1},{ 16384, 0},{     0, 1},{ 16383, 0},{    -1, 0},{ 24576, 0},
+{ -8192, 0},{ 24575, 0},{ -8193, 0},{ 40960, 0},{-24576, 0},{ 40959, 0},{-24577, 0},{ -8191, 0},
+{ -8193, 1},{ -8192, 0},{ -8194, 1},{ -8190, 0},{ -8194, 1},{ -8191, 0},{ -8195, 1},{ -8188, 0},
+{ -8196, 1},{ -8189, 0},{ -8197, 1},{ -8184, 0},{ -8200, 1},{ -8185, 0},{ -8201, 1},{ -8176, 0},
+{ -8208, 1},{ -8177, 0},{ -8209, 1},{ -8160, 0},{ -8224, 1},{ -8161, 0},{ -8225, 1},{ -8128, 0},
+{ -8256, 1},{ -8129, 0},{ -8257, 1},{ -8064, 0},{ -8320, 1},{ -8065, 0},{ -8321, 1},{ -7936, 0},
+{ -8448, 1},{ -7937, 0},{ -8449, 1},{ -7680, 0},{ -8704, 1},{ -7681, 0},{ -8705, 1},{ -7168, 0},
+{ -9216, 1},{ -7169, 0},{ -9217, 1},{ -6144, 0},{-10240, 1},{ -6145, 0},{-10241, 1},{ -4096, 0},
+{-12288, 1},{ -4097, 0},{-12289, 1},{     0, 1},{-16384, 1},{    -1, 0},{-16385, 1},{  8192, 1},
+{-24576, 1},{  8191, 1},{-24577, 1},{ 24576, 1},{-40960, 1},{ 24575, 1},{-40961, 1},{  8192, 0},
+{  8190, 1},{  8191, 0},{  8189, 1},{  8193, 0},{  8189, 1},{  8192, 0},{  8188, 1},{  8195, 0},
+{  8187, 1},{  8194, 0},{  8186, 1},{  8199, 0},{  8183, 1},{  8198, 0},{  8182, 1},{  8207, 0},
+{  8175, 1},{  8206, 0},{  8174, 1},{  8223, 0},{  8159, 1},{  8222, 0},{  8158, 1},{  8255, 0},
+{  8127, 1},{  8254, 0},{  8126, 1},{  8319, 0},{  8063, 1},{  8318, 0},{  8062, 1},{  8447, 0},
+{  7935, 1},{  8446, 0},{  7934, 1},{  8703, 0},{  7679, 1},{  8702, 0},{  7678, 1},{  9215, 0},
+{  7167, 1},{  9214, 0},{  7166, 1},{ 10239, 0},{  6143, 1},{ 10238, 0},{  6142, 1},{ 12287, 0},
+{  4095, 1},{ 12286, 0},{  4094, 1},{ 16383, 0},{    -1, 0},{ 16382, 0},{    -2, 0},{ 24575, 0},
+{ -8193, 0},{ 24574, 0},{ -8194, 0},{ 40959, 0},{-24577, 0},{ 40958, 0},{-24578, 0},{ -8192, 0},
+{ -8194, 1},{ -8193, 0},{ -8195, 1},{ -8191, 0},{ -8195, 1},{ -8192, 0},{ -8196, 1},{ -8189, 0},
+{ -8197, 1},{ -8190, 0},{ -8198, 1},{ -8185, 0},{ -8201, 1},{ -8186, 0},{ -8202, 1},{ -8177, 0},
+{ -8209, 1},{ -8178, 0},{ -8210, 1},{ -8161, 0},{ -8225, 1},{ -8162, 0},{ -8226, 1},{ -8129, 0},
+{ -8257, 1},{ -8130, 0},{ -8258, 1},{ -8065, 0},{ -8321, 1},{ -8066, 0},{ -8322, 1},{ -7937, 0},
+{ -8449, 1},{ -7938, 0},{ -8450, 1},{ -7681, 0},{ -8705, 1},{ -7682, 0},{ -8706, 1},{ -7169, 0},
+{ -9217, 1},{ -7170, 0},{ -9218, 1},{ -6145, 0},{-10241, 1},{ -6146, 0},{-10242, 1},{ -4097, 0},
+{-12289, 1},{ -4098, 0},{-12290, 1},{    -1, 0},{-16385, 1},{    -2, 0},{-16386, 1},{  8191, 1},
+{-24577, 1},{  8190, 1},{-24578, 1},{ 24575, 1},{-40961, 1},{ 24574, 1},{-40962, 1},{ 16385, 0},
+{ 16383, 1},{ 16384, 0},{ 16382, 1},{ 16386, 0},{ 16382, 1},{ 16385, 0},{ 16381, 1},{ 16388, 0},
+{ 16380, 1},{ 16387, 0},{ 16379, 1},{ 16392, 0},{ 16376, 1},{ 16391, 0},{ 16375, 1},{ 16400, 0},
+{ 16368, 1},{ 16399, 0},{ 16367, 1},{ 16416, 0},{ 16352, 1},{ 16415, 0},{ 16351, 1},{ 16448, 0},
+{ 16320, 1},{ 16447, 0},{ 16319, 1},{ 16512, 0},{ 16256, 1},{ 16511, 0},{ 16255, 1},{ 16640, 0},
+{ 16128, 1},{ 16639, 0},{ 16127, 1},{ 16896, 0},{ 15872, 1},{ 16895, 0},{ 15871, 1},{ 17408, 0},
+{ 15360, 1},{ 17407, 0},{ 15359, 1},{ 18432, 0},{ 14336, 1},{ 18431, 0},{ 14335, 1},{ 20480, 0},
+{ 12288, 1},{ 20479, 0},{ 12287, 1},{ 24576, 0},{  8192, 1},{ 24575, 0},{  8191, 1},{ 32768, 0},
+{     0, 1},{ 32767, 0},{    -1, 0},{ 49152, 0},{-16384, 0},{ 49151, 0},{-16385, 0},{-16383, 0},
+{-16385, 1},{-16384, 0},{-16386, 1},{-16382, 0},{-16386, 1},{-16383, 0},{-16387, 1},{-16380, 0},
+{-16388, 1},{-16381, 0},{-16389, 1},{-16376, 0},{-16392, 1},{-16377, 0},{-16393, 1},{-16368, 0},
+{-16400, 1},{-16369, 0},{-16401, 1},{-16352, 0},{-16416, 1},{-16353, 0},{-16417, 1},{-16320, 0},
+{-16448, 1},{-16321, 0},{-16449, 1},{-16256, 0},{-16512, 1},{-16257, 0},{-16513, 1},{-16128, 0},
+{-16640, 1},{-16129, 0},{-16641, 1},{-15872, 0},{-16896, 1},{-15873, 0},{-16897, 1},{-15360, 0},
+{-17408, 1},{-15361, 0},{-17409, 1},{-14336, 0},{-18432, 1},{-14337, 0},{-18433, 1},{-12288, 0},
+{-20480, 1},{-12289, 0},{-20481, 1},{ -8192, 0},{-24576, 1},{ -8193, 0},{-24577, 1},{     0, 1},
+{-32768, 1},{    -1, 0},{-32769, 1},{ 16384, 1},{-49152, 1},{ 16383, 1},{-49153, 1},{ 16384, 0},
+{ 16382, 1},{ 16383, 0},{ 16381, 1},{ 16385, 0},{ 16381, 1},{ 16384, 0},{ 16380, 1},{ 16387, 0},
+{ 16379, 1},{ 16386, 0},{ 16378, 1},{ 16391, 0},{ 16375, 1},{ 16390, 0},{ 16374, 1},{ 16399, 0},
+{ 16367, 1},{ 16398, 0},{ 16366, 1},{ 16415, 0},{ 16351, 1},{ 16414, 0},{ 16350, 1},{ 16447, 0},
+{ 16319, 1},{ 16446, 0},{ 16318, 1},{ 16511, 0},{ 16255, 1},{ 16510, 0},{ 16254, 1},{ 16639, 0},
+{ 16127, 1},{ 16638, 0},{ 16126, 1},{ 16895, 0},{ 15871, 1},{ 16894, 0},{ 15870, 1},{ 17407, 0},
+{ 15359, 1},{ 17406, 0},{ 15358, 1},{ 18431, 0},{ 14335, 1},{ 18430, 0},{ 14334, 1},{ 20479, 0},
+{ 12287, 1},{ 20478, 0},{ 12286, 1},{ 24575, 0},{  8191, 1},{ 24574, 0},{  8190, 1},{ 32767, 0},
+{    -1, 0},{ 32766, 0},{    -2, 0},{ 49151, 0},{-16385, 0},{ 49150, 0},{-16386, 0},{-16384, 0},
+{-16386, 1},{-16385, 0},{-16387, 1},{-16383, 0},{-16387, 1},{-16384, 0},{-16388, 1},{-16381, 0},
+{-16389, 1},{-16382, 0},{-16390, 1},{-16377, 0},{-16393, 1},{-16378, 0},{-16394, 1},{-16369, 0},
+{-16401, 1},{-16370, 0},{-16402, 1},{-16353, 0},{-16417, 1},{-16354, 0},{-16418, 1},{-16321, 0},
+{-16449, 1},{-16322, 0},{-16450, 1},{-16257, 0},{-16513, 1},{-16258, 0},{-16514, 1},{-16129, 0},
+{-16641, 1},{-16130, 0},{-16642, 1},{-15873, 0},{-16897, 1},{-15874, 0},{-16898, 1},{-15361, 0},
+{-17409, 1},{-15362, 0},{-17410, 1},{-14337, 0},{-18433, 1},{-14338, 0},{-18434, 1},{-12289, 0},
+{-20481, 1},{-12290, 0},{-20482, 1},{ -8193, 0},{-24577, 1},{ -8194, 0},{-24578, 1},{    -1, 0},
+{-32769, 1},{    -2, 0},{-32770, 1},{ 16383, 1},{-49153, 1},{ 16382, 1},{-49154, 1},{ 32769, 0},
+{ 32767, 1},{ 32768, 0},{ 32766, 1},{ 32770, 0},{ 32766, 1},{ 32769, 0},{ 32765, 1},{ 32772, 0},
+{ 32764, 1},{ 32771, 0},{ 32763, 1},{ 32776, 0},{ 32760, 1},{ 32775, 0},{ 32759, 1},{ 32784, 0},
+{ 32752, 1},{ 32783, 0},{ 32751, 1},{ 32800, 0},{ 32736, 1},{ 32799, 0},{ 32735, 1},{ 32832, 0},
+{ 32704, 1},{ 32831, 0},{ 32703, 1},{ 32896, 0},{ 32640, 1},{ 32895, 0},{ 32639, 1},{ 33024, 0},
+{ 32512, 1},{ 33023, 0},{ 32511, 1},{ 33280, 0},{ 32256, 1},{ 33279, 0},{ 32255, 1},{ 33792, 0},
+{ 31744, 1},{ 33791, 0},{ 31743, 1},{ 34816, 0},{ 30720, 1},{ 34815, 0},{ 30719, 1},{ 36864, 0},
+{ 28672, 1},{ 36863, 0},{ 28671, 1},{ 40960, 0},{ 24576, 1},{ 40959, 0},{ 24575, 1},{ 49152, 0},
+{ 16384, 1},{ 49151, 0},{ 16383, 1},{ 65536, 0},{     0, 1},{ 65535, 0},{    -1, 0},{-32767, 0},
+{-32769, 1},{-32768, 0},{-32770, 1},{-32766, 0},{-32770, 1},{-32767, 0},{-32771, 1},{-32764, 0},
+{-32772, 1},{-32765, 0},{-32773, 1},{-32760, 0},{-32776, 1},{-32761, 0},{-32777, 1},{-32752, 0},
+{-32784, 1},{-32753, 0},{-32785, 1},{-32736, 0},{-32800, 1},{-32737, 0},{-32801, 1},{-32704, 0},
+{-32832, 1},{-32705, 0},{-32833, 1},{-32640, 0},{-32896, 1},{-32641, 0},{-32897, 1},{-32512, 0},
+{-33024, 1},{-32513, 0},{-33025, 1},{-32256, 0},{-33280, 1},{-32257, 0},{-33281, 1},{-31744, 0},
+{-33792, 1},{-31745, 0},{-33793, 1},{-30720, 0},{-34816, 1},{-30721, 0},{-34817, 1},{-28672, 0},
+{-36864, 1},{-28673, 0},{-36865, 1},{-24576, 0},{-40960, 1},{-24577, 0},{-40961, 1},{-16384, 0},
+{-49152, 1},{-16385, 0},{-49153, 1},{     0, 1},{-65536, 1},{    -1, 0},{-65537, 1},{ 32768, 0},
+{ 32766, 1},{ 32767, 0},{ 32765, 1},{ 32769, 0},{ 32765, 1},{ 32768, 0},{ 32764, 1},{ 32771, 0},
+{ 32763, 1},{ 32770, 0},{ 32762, 1},{ 32775, 0},{ 32759, 1},{ 32774, 0},{ 32758, 1},{ 32783, 0},
+{ 32751, 1},{ 32782, 0},{ 32750, 1},{ 32799, 0},{ 32735, 1},{ 32798, 0},{ 32734, 1},{ 32831, 0},
+{ 32703, 1},{ 32830, 0},{ 32702, 1},{ 32895, 0},{ 32639, 1},{ 32894, 0},{ 32638, 1},{ 33023, 0},
+{ 32511, 1},{ 33022, 0},{ 32510, 1},{ 33279, 0},{ 32255, 1},{ 33278, 0},{ 32254, 1},{ 33791, 0},
+{ 31743, 1},{ 33790, 0},{ 31742, 1},{ 34815, 0},{ 30719, 1},{ 34814, 0},{ 30718, 1},{ 36863, 0},
+{ 28671, 1},{ 36862, 0},{ 28670, 1},{ 40959, 0},{ 24575, 1},{ 40958, 0},{ 24574, 1},{ 49151, 0},
+{ 16383, 1},{ 49150, 0},{ 16382, 1},{ 65535, 0},{    -1, 0},{ 65534, 0},{    -2, 0},{-32768, 0},
+{-32770, 1},{-32769, 0},{-32771, 1},{-32767, 0},{-32771, 1},{-32768, 0},{-32772, 1},{-32765, 0},
+{-32773, 1},{-32766, 0},{-32774, 1},{-32761, 0},{-32777, 1},{-32762, 0},{-32778, 1},{-32753, 0},
+{-32785, 1},{-32754, 0},{-32786, 1},{-32737, 0},{-32801, 1},{-32738, 0},{-32802, 1},{-32705, 0},
+{-32833, 1},{-32706, 0},{-32834, 1},{-32641, 0},{-32897, 1},{-32642, 0},{-32898, 1},{-32513, 0},
+{-33025, 1},{-32514, 0},{-33026, 1},{-32257, 0},{-33281, 1},{-32258, 0},{-33282, 1},{-31745, 0},
+{-33793, 1},{-31746, 0},{-33794, 1},{-30721, 0},{-34817, 1},{-30722, 0},{-34818, 1},{-28673, 0},
+{-36865, 1},{-28674, 0},{-36866, 1},{-24577, 0},{-40961, 1},{-24578, 0},{-40962, 1},{-16385, 0},
+{-49153, 1},{-16386, 0},{-49154, 1},{    -1, 0},{-65537, 1},{    -2, 0},{-65538, 1},};
+int main ()
+{
+  mp_limb_t r1, r0;
+  int err = 0;
+  size_t ind = 0;
+  for (size_t i = 0; i < 4096; i++)
+    {
+      int ii = i / 64, jj = i % 64;
+      funcs[i](&r1, &r0);
+      if (r0 != (mp_limb_signed_t) ref[ind][0] || r1 != (mp_limb_signed_t) ref[ind][1]) {
+         printf ("error for f%zu(%d,%d): want (%d,%d) got (%d,%d)\n", i, (int) ops[ii], (int) ops[jj], ref[ind][1], ref[ind][0], (int) r1, (int) r0);
+         err++;
+       }
+      ind++;
+    }
+  return err != 0;
+}
diff --git a/tests/devel/test-sub_ddmmss.c b/tests/devel/test-sub_ddmmss.c
new file mode 100644
index 0000000..87eecc6
--- /dev/null
+++ b/tests/devel/test-sub_ddmmss.c
@@ -0,0 +1,4908 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+static const int ops[64] = {
+1,-1,0,-2,
+2,-2,1,-3,
+4,-4,3,-5,
+8,-8,7,-9,
+16,-16,15,-17,
+32,-32,31,-33,
+64,-64,63,-65,
+128,-128,127,-129,
+256,-256,255,-257,
+512,-512,511,-513,
+1024,-1024,1023,-1025,
+2048,-2048,2047,-2049,
+4096,-4096,4095,-4097,
+8192,-8192,8191,-8193,
+16384,-16384,16383,-16385,
+32768,-32768,32767,-32769,
+};
+static void f0(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f1(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-1);*r1p=r1;*r0p=r0;}
+static void f2(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,0);*r1p=r1;*r0p=r0;}
+static void f3(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f4(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,2);*r1p=r1;*r0p=r0;}
+static void f5(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f6(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f7(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-3);*r1p=r1;*r0p=r0;}
+static void f8(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,4);*r1p=r1;*r0p=r0;}
+static void f9(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-4);*r1p=r1;*r0p=r0;}
+static void f10(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,3);*r1p=r1;*r0p=r0;}
+static void f11(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-5);*r1p=r1;*r0p=r0;}
+static void f12(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,8);*r1p=r1;*r0p=r0;}
+static void f13(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-8);*r1p=r1;*r0p=r0;}
+static void f14(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,7);*r1p=r1;*r0p=r0;}
+static void f15(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-9);*r1p=r1;*r0p=r0;}
+static void f16(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,16);*r1p=r1;*r0p=r0;}
+static void f17(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-16);*r1p=r1;*r0p=r0;}
+static void f18(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,15);*r1p=r1;*r0p=r0;}
+static void f19(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-17);*r1p=r1;*r0p=r0;}
+static void f20(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,32);*r1p=r1;*r0p=r0;}
+static void f21(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-32);*r1p=r1;*r0p=r0;}
+static void f22(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,31);*r1p=r1;*r0p=r0;}
+static void f23(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-33);*r1p=r1;*r0p=r0;}
+static void f24(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,64);*r1p=r1;*r0p=r0;}
+static void f25(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-64);*r1p=r1;*r0p=r0;}
+static void f26(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,63);*r1p=r1;*r0p=r0;}
+static void f27(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-65);*r1p=r1;*r0p=r0;}
+static void f28(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,128);*r1p=r1;*r0p=r0;}
+static void f29(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-128);*r1p=r1;*r0p=r0;}
+static void f30(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,127);*r1p=r1;*r0p=r0;}
+static void f31(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-129);*r1p=r1;*r0p=r0;}
+static void f32(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,256);*r1p=r1;*r0p=r0;}
+static void f33(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-256);*r1p=r1;*r0p=r0;}
+static void f34(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,255);*r1p=r1;*r0p=r0;}
+static void f35(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-257);*r1p=r1;*r0p=r0;}
+static void f36(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,512);*r1p=r1;*r0p=r0;}
+static void f37(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-512);*r1p=r1;*r0p=r0;}
+static void f38(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,511);*r1p=r1;*r0p=r0;}
+static void f39(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-513);*r1p=r1;*r0p=r0;}
+static void f40(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1024);*r1p=r1;*r0p=r0;}
+static void f41(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-1024);*r1p=r1;*r0p=r0;}
+static void f42(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1023);*r1p=r1;*r0p=r0;}
+static void f43(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-1025);*r1p=r1;*r0p=r0;}
+static void f44(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,2048);*r1p=r1;*r0p=r0;}
+static void f45(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2048);*r1p=r1;*r0p=r0;}
+static void f46(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,2047);*r1p=r1;*r0p=r0;}
+static void f47(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2049);*r1p=r1;*r0p=r0;}
+static void f48(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,4096);*r1p=r1;*r0p=r0;}
+static void f49(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-4096);*r1p=r1;*r0p=r0;}
+static void f50(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,4095);*r1p=r1;*r0p=r0;}
+static void f51(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-4097);*r1p=r1;*r0p=r0;}
+static void f52(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,8192);*r1p=r1;*r0p=r0;}
+static void f53(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-8192);*r1p=r1;*r0p=r0;}
+static void f54(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,8191);*r1p=r1;*r0p=r0;}
+static void f55(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-8193);*r1p=r1;*r0p=r0;}
+static void f56(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,16384);*r1p=r1;*r0p=r0;}
+static void f57(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-16384);*r1p=r1;*r0p=r0;}
+static void f58(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,16383);*r1p=r1;*r0p=r0;}
+static void f59(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-16385);*r1p=r1;*r0p=r0;}
+static void f60(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,32768);*r1p=r1;*r0p=r0;}
+static void f61(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-32768);*r1p=r1;*r0p=r0;}
+static void f62(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,32767);*r1p=r1;*r0p=r0;}
+static void f63(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-32769);*r1p=r1;*r0p=r0;}
+static void f64(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,1);*r1p=r1;*r0p=r0;}
+static void f65(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-1);*r1p=r1;*r0p=r0;}
+static void f66(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,0);*r1p=r1;*r0p=r0;}
+static void f67(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-2);*r1p=r1;*r0p=r0;}
+static void f68(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,2);*r1p=r1;*r0p=r0;}
+static void f69(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-2);*r1p=r1;*r0p=r0;}
+static void f70(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,1);*r1p=r1;*r0p=r0;}
+static void f71(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-3);*r1p=r1;*r0p=r0;}
+static void f72(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,4);*r1p=r1;*r0p=r0;}
+static void f73(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-4);*r1p=r1;*r0p=r0;}
+static void f74(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,3);*r1p=r1;*r0p=r0;}
+static void f75(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-5);*r1p=r1;*r0p=r0;}
+static void f76(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,8);*r1p=r1;*r0p=r0;}
+static void f77(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-8);*r1p=r1;*r0p=r0;}
+static void f78(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,7);*r1p=r1;*r0p=r0;}
+static void f79(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-9);*r1p=r1;*r0p=r0;}
+static void f80(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,16);*r1p=r1;*r0p=r0;}
+static void f81(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-16);*r1p=r1;*r0p=r0;}
+static void f82(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,15);*r1p=r1;*r0p=r0;}
+static void f83(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-17);*r1p=r1;*r0p=r0;}
+static void f84(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,32);*r1p=r1;*r0p=r0;}
+static void f85(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-32);*r1p=r1;*r0p=r0;}
+static void f86(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,31);*r1p=r1;*r0p=r0;}
+static void f87(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-33);*r1p=r1;*r0p=r0;}
+static void f88(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,64);*r1p=r1;*r0p=r0;}
+static void f89(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-64);*r1p=r1;*r0p=r0;}
+static void f90(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,63);*r1p=r1;*r0p=r0;}
+static void f91(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-65);*r1p=r1;*r0p=r0;}
+static void f92(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,128);*r1p=r1;*r0p=r0;}
+static void f93(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-128);*r1p=r1;*r0p=r0;}
+static void f94(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,127);*r1p=r1;*r0p=r0;}
+static void f95(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-129);*r1p=r1;*r0p=r0;}
+static void f96(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,256);*r1p=r1;*r0p=r0;}
+static void f97(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-256);*r1p=r1;*r0p=r0;}
+static void f98(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,255);*r1p=r1;*r0p=r0;}
+static void f99(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-257);*r1p=r1;*r0p=r0;}
+static void f100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,512);*r1p=r1;*r0p=r0;}
+static void f101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-512);*r1p=r1;*r0p=r0;}
+static void f102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,511);*r1p=r1;*r0p=r0;}
+static void f103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-513);*r1p=r1;*r0p=r0;}
+static void f104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,1024);*r1p=r1;*r0p=r0;}
+static void f105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-1024);*r1p=r1;*r0p=r0;}
+static void f106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,1023);*r1p=r1;*r0p=r0;}
+static void f107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-1025);*r1p=r1;*r0p=r0;}
+static void f108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,2048);*r1p=r1;*r0p=r0;}
+static void f109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-2048);*r1p=r1;*r0p=r0;}
+static void f110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,2047);*r1p=r1;*r0p=r0;}
+static void f111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-2049);*r1p=r1;*r0p=r0;}
+static void f112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,4096);*r1p=r1;*r0p=r0;}
+static void f113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-4096);*r1p=r1;*r0p=r0;}
+static void f114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,4095);*r1p=r1;*r0p=r0;}
+static void f115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-4097);*r1p=r1;*r0p=r0;}
+static void f116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,8192);*r1p=r1;*r0p=r0;}
+static void f117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-8192);*r1p=r1;*r0p=r0;}
+static void f118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,8191);*r1p=r1;*r0p=r0;}
+static void f119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-8193);*r1p=r1;*r0p=r0;}
+static void f120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,16384);*r1p=r1;*r0p=r0;}
+static void f121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-16384);*r1p=r1;*r0p=r0;}
+static void f122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,16383);*r1p=r1;*r0p=r0;}
+static void f123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-16385);*r1p=r1;*r0p=r0;}
+static void f124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,32768);*r1p=r1;*r0p=r0;}
+static void f125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-32768);*r1p=r1;*r0p=r0;}
+static void f126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,32767);*r1p=r1;*r0p=r0;}
+static void f127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1,0,-32769);*r1p=r1;*r0p=r0;}
+static void f128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,1);*r1p=r1;*r0p=r0;}
+static void f129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-1);*r1p=r1;*r0p=r0;}
+static void f130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,0);*r1p=r1;*r0p=r0;}
+static void f131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-2);*r1p=r1;*r0p=r0;}
+static void f132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,2);*r1p=r1;*r0p=r0;}
+static void f133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-2);*r1p=r1;*r0p=r0;}
+static void f134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,1);*r1p=r1;*r0p=r0;}
+static void f135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-3);*r1p=r1;*r0p=r0;}
+static void f136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,4);*r1p=r1;*r0p=r0;}
+static void f137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-4);*r1p=r1;*r0p=r0;}
+static void f138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,3);*r1p=r1;*r0p=r0;}
+static void f139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-5);*r1p=r1;*r0p=r0;}
+static void f140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,8);*r1p=r1;*r0p=r0;}
+static void f141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-8);*r1p=r1;*r0p=r0;}
+static void f142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,7);*r1p=r1;*r0p=r0;}
+static void f143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-9);*r1p=r1;*r0p=r0;}
+static void f144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,16);*r1p=r1;*r0p=r0;}
+static void f145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-16);*r1p=r1;*r0p=r0;}
+static void f146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,15);*r1p=r1;*r0p=r0;}
+static void f147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-17);*r1p=r1;*r0p=r0;}
+static void f148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,32);*r1p=r1;*r0p=r0;}
+static void f149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-32);*r1p=r1;*r0p=r0;}
+static void f150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,31);*r1p=r1;*r0p=r0;}
+static void f151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-33);*r1p=r1;*r0p=r0;}
+static void f152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,64);*r1p=r1;*r0p=r0;}
+static void f153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-64);*r1p=r1;*r0p=r0;}
+static void f154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,63);*r1p=r1;*r0p=r0;}
+static void f155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-65);*r1p=r1;*r0p=r0;}
+static void f156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,128);*r1p=r1;*r0p=r0;}
+static void f157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-128);*r1p=r1;*r0p=r0;}
+static void f158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,127);*r1p=r1;*r0p=r0;}
+static void f159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-129);*r1p=r1;*r0p=r0;}
+static void f160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,256);*r1p=r1;*r0p=r0;}
+static void f161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-256);*r1p=r1;*r0p=r0;}
+static void f162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,255);*r1p=r1;*r0p=r0;}
+static void f163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-257);*r1p=r1;*r0p=r0;}
+static void f164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,512);*r1p=r1;*r0p=r0;}
+static void f165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-512);*r1p=r1;*r0p=r0;}
+static void f166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,511);*r1p=r1;*r0p=r0;}
+static void f167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-513);*r1p=r1;*r0p=r0;}
+static void f168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,1024);*r1p=r1;*r0p=r0;}
+static void f169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-1024);*r1p=r1;*r0p=r0;}
+static void f170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,1023);*r1p=r1;*r0p=r0;}
+static void f171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-1025);*r1p=r1;*r0p=r0;}
+static void f172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,2048);*r1p=r1;*r0p=r0;}
+static void f173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-2048);*r1p=r1;*r0p=r0;}
+static void f174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,2047);*r1p=r1;*r0p=r0;}
+static void f175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-2049);*r1p=r1;*r0p=r0;}
+static void f176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,4096);*r1p=r1;*r0p=r0;}
+static void f177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-4096);*r1p=r1;*r0p=r0;}
+static void f178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,4095);*r1p=r1;*r0p=r0;}
+static void f179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-4097);*r1p=r1;*r0p=r0;}
+static void f180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,8192);*r1p=r1;*r0p=r0;}
+static void f181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-8192);*r1p=r1;*r0p=r0;}
+static void f182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,8191);*r1p=r1;*r0p=r0;}
+static void f183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-8193);*r1p=r1;*r0p=r0;}
+static void f184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,16384);*r1p=r1;*r0p=r0;}
+static void f185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-16384);*r1p=r1;*r0p=r0;}
+static void f186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,16383);*r1p=r1;*r0p=r0;}
+static void f187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-16385);*r1p=r1;*r0p=r0;}
+static void f188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,32768);*r1p=r1;*r0p=r0;}
+static void f189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-32768);*r1p=r1;*r0p=r0;}
+static void f190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,32767);*r1p=r1;*r0p=r0;}
+static void f191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,0,0,-32769);*r1p=r1;*r0p=r0;}
+static void f192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-1);*r1p=r1;*r0p=r0;}
+static void f194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,0);*r1p=r1;*r0p=r0;}
+static void f195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,2);*r1p=r1;*r0p=r0;}
+static void f197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-3);*r1p=r1;*r0p=r0;}
+static void f200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,4);*r1p=r1;*r0p=r0;}
+static void f201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-4);*r1p=r1;*r0p=r0;}
+static void f202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,3);*r1p=r1;*r0p=r0;}
+static void f203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-5);*r1p=r1;*r0p=r0;}
+static void f204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,8);*r1p=r1;*r0p=r0;}
+static void f205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-8);*r1p=r1;*r0p=r0;}
+static void f206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,7);*r1p=r1;*r0p=r0;}
+static void f207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-9);*r1p=r1;*r0p=r0;}
+static void f208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,16);*r1p=r1;*r0p=r0;}
+static void f209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-16);*r1p=r1;*r0p=r0;}
+static void f210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,15);*r1p=r1;*r0p=r0;}
+static void f211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-17);*r1p=r1;*r0p=r0;}
+static void f212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,32);*r1p=r1;*r0p=r0;}
+static void f213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-32);*r1p=r1;*r0p=r0;}
+static void f214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,31);*r1p=r1;*r0p=r0;}
+static void f215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-33);*r1p=r1;*r0p=r0;}
+static void f216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,64);*r1p=r1;*r0p=r0;}
+static void f217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-64);*r1p=r1;*r0p=r0;}
+static void f218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,63);*r1p=r1;*r0p=r0;}
+static void f219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-65);*r1p=r1;*r0p=r0;}
+static void f220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,128);*r1p=r1;*r0p=r0;}
+static void f221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-128);*r1p=r1;*r0p=r0;}
+static void f222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,127);*r1p=r1;*r0p=r0;}
+static void f223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-129);*r1p=r1;*r0p=r0;}
+static void f224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,256);*r1p=r1;*r0p=r0;}
+static void f225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-256);*r1p=r1;*r0p=r0;}
+static void f226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,255);*r1p=r1;*r0p=r0;}
+static void f227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-257);*r1p=r1;*r0p=r0;}
+static void f228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,512);*r1p=r1;*r0p=r0;}
+static void f229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-512);*r1p=r1;*r0p=r0;}
+static void f230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,511);*r1p=r1;*r0p=r0;}
+static void f231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-513);*r1p=r1;*r0p=r0;}
+static void f232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1024);*r1p=r1;*r0p=r0;}
+static void f233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-1024);*r1p=r1;*r0p=r0;}
+static void f234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1023);*r1p=r1;*r0p=r0;}
+static void f235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-1025);*r1p=r1;*r0p=r0;}
+static void f236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,2048);*r1p=r1;*r0p=r0;}
+static void f237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2048);*r1p=r1;*r0p=r0;}
+static void f238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,2047);*r1p=r1;*r0p=r0;}
+static void f239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2049);*r1p=r1;*r0p=r0;}
+static void f240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,4096);*r1p=r1;*r0p=r0;}
+static void f241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-4096);*r1p=r1;*r0p=r0;}
+static void f242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,4095);*r1p=r1;*r0p=r0;}
+static void f243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-4097);*r1p=r1;*r0p=r0;}
+static void f244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,8192);*r1p=r1;*r0p=r0;}
+static void f245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-8192);*r1p=r1;*r0p=r0;}
+static void f246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,8191);*r1p=r1;*r0p=r0;}
+static void f247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-8193);*r1p=r1;*r0p=r0;}
+static void f248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,16384);*r1p=r1;*r0p=r0;}
+static void f249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-16384);*r1p=r1;*r0p=r0;}
+static void f250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,16383);*r1p=r1;*r0p=r0;}
+static void f251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-16385);*r1p=r1;*r0p=r0;}
+static void f252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,32768);*r1p=r1;*r0p=r0;}
+static void f253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-32768);*r1p=r1;*r0p=r0;}
+static void f254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,32767);*r1p=r1;*r0p=r0;}
+static void f255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-32769);*r1p=r1;*r0p=r0;}
+static void f256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,1);*r1p=r1;*r0p=r0;}
+static void f257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-1);*r1p=r1;*r0p=r0;}
+static void f258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,0);*r1p=r1;*r0p=r0;}
+static void f259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-2);*r1p=r1;*r0p=r0;}
+static void f260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,2);*r1p=r1;*r0p=r0;}
+static void f261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-2);*r1p=r1;*r0p=r0;}
+static void f262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,1);*r1p=r1;*r0p=r0;}
+static void f263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-3);*r1p=r1;*r0p=r0;}
+static void f264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,4);*r1p=r1;*r0p=r0;}
+static void f265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-4);*r1p=r1;*r0p=r0;}
+static void f266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,3);*r1p=r1;*r0p=r0;}
+static void f267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-5);*r1p=r1;*r0p=r0;}
+static void f268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,8);*r1p=r1;*r0p=r0;}
+static void f269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-8);*r1p=r1;*r0p=r0;}
+static void f270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,7);*r1p=r1;*r0p=r0;}
+static void f271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-9);*r1p=r1;*r0p=r0;}
+static void f272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,16);*r1p=r1;*r0p=r0;}
+static void f273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-16);*r1p=r1;*r0p=r0;}
+static void f274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,15);*r1p=r1;*r0p=r0;}
+static void f275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-17);*r1p=r1;*r0p=r0;}
+static void f276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,32);*r1p=r1;*r0p=r0;}
+static void f277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-32);*r1p=r1;*r0p=r0;}
+static void f278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,31);*r1p=r1;*r0p=r0;}
+static void f279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-33);*r1p=r1;*r0p=r0;}
+static void f280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,64);*r1p=r1;*r0p=r0;}
+static void f281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-64);*r1p=r1;*r0p=r0;}
+static void f282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,63);*r1p=r1;*r0p=r0;}
+static void f283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-65);*r1p=r1;*r0p=r0;}
+static void f284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,128);*r1p=r1;*r0p=r0;}
+static void f285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-128);*r1p=r1;*r0p=r0;}
+static void f286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,127);*r1p=r1;*r0p=r0;}
+static void f287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-129);*r1p=r1;*r0p=r0;}
+static void f288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,256);*r1p=r1;*r0p=r0;}
+static void f289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-256);*r1p=r1;*r0p=r0;}
+static void f290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,255);*r1p=r1;*r0p=r0;}
+static void f291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-257);*r1p=r1;*r0p=r0;}
+static void f292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,512);*r1p=r1;*r0p=r0;}
+static void f293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-512);*r1p=r1;*r0p=r0;}
+static void f294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,511);*r1p=r1;*r0p=r0;}
+static void f295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-513);*r1p=r1;*r0p=r0;}
+static void f296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,1024);*r1p=r1;*r0p=r0;}
+static void f297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-1024);*r1p=r1;*r0p=r0;}
+static void f298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,1023);*r1p=r1;*r0p=r0;}
+static void f299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-1025);*r1p=r1;*r0p=r0;}
+static void f300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,2048);*r1p=r1;*r0p=r0;}
+static void f301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-2048);*r1p=r1;*r0p=r0;}
+static void f302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,2047);*r1p=r1;*r0p=r0;}
+static void f303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-2049);*r1p=r1;*r0p=r0;}
+static void f304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,4096);*r1p=r1;*r0p=r0;}
+static void f305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-4096);*r1p=r1;*r0p=r0;}
+static void f306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,4095);*r1p=r1;*r0p=r0;}
+static void f307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-4097);*r1p=r1;*r0p=r0;}
+static void f308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,8192);*r1p=r1;*r0p=r0;}
+static void f309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-8192);*r1p=r1;*r0p=r0;}
+static void f310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,8191);*r1p=r1;*r0p=r0;}
+static void f311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-8193);*r1p=r1;*r0p=r0;}
+static void f312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,16384);*r1p=r1;*r0p=r0;}
+static void f313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-16384);*r1p=r1;*r0p=r0;}
+static void f314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,16383);*r1p=r1;*r0p=r0;}
+static void f315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-16385);*r1p=r1;*r0p=r0;}
+static void f316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,32768);*r1p=r1;*r0p=r0;}
+static void f317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-32768);*r1p=r1;*r0p=r0;}
+static void f318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,32767);*r1p=r1;*r0p=r0;}
+static void f319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2,0,-32769);*r1p=r1;*r0p=r0;}
+static void f320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-1);*r1p=r1;*r0p=r0;}
+static void f322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,0);*r1p=r1;*r0p=r0;}
+static void f323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,2);*r1p=r1;*r0p=r0;}
+static void f325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2);*r1p=r1;*r0p=r0;}
+static void f326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1);*r1p=r1;*r0p=r0;}
+static void f327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-3);*r1p=r1;*r0p=r0;}
+static void f328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,4);*r1p=r1;*r0p=r0;}
+static void f329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-4);*r1p=r1;*r0p=r0;}
+static void f330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,3);*r1p=r1;*r0p=r0;}
+static void f331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-5);*r1p=r1;*r0p=r0;}
+static void f332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,8);*r1p=r1;*r0p=r0;}
+static void f333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-8);*r1p=r1;*r0p=r0;}
+static void f334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,7);*r1p=r1;*r0p=r0;}
+static void f335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-9);*r1p=r1;*r0p=r0;}
+static void f336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,16);*r1p=r1;*r0p=r0;}
+static void f337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-16);*r1p=r1;*r0p=r0;}
+static void f338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,15);*r1p=r1;*r0p=r0;}
+static void f339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-17);*r1p=r1;*r0p=r0;}
+static void f340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,32);*r1p=r1;*r0p=r0;}
+static void f341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-32);*r1p=r1;*r0p=r0;}
+static void f342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,31);*r1p=r1;*r0p=r0;}
+static void f343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-33);*r1p=r1;*r0p=r0;}
+static void f344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,64);*r1p=r1;*r0p=r0;}
+static void f345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-64);*r1p=r1;*r0p=r0;}
+static void f346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,63);*r1p=r1;*r0p=r0;}
+static void f347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-65);*r1p=r1;*r0p=r0;}
+static void f348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,128);*r1p=r1;*r0p=r0;}
+static void f349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-128);*r1p=r1;*r0p=r0;}
+static void f350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,127);*r1p=r1;*r0p=r0;}
+static void f351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-129);*r1p=r1;*r0p=r0;}
+static void f352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,256);*r1p=r1;*r0p=r0;}
+static void f353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-256);*r1p=r1;*r0p=r0;}
+static void f354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,255);*r1p=r1;*r0p=r0;}
+static void f355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-257);*r1p=r1;*r0p=r0;}
+static void f356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,512);*r1p=r1;*r0p=r0;}
+static void f357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-512);*r1p=r1;*r0p=r0;}
+static void f358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,511);*r1p=r1;*r0p=r0;}
+static void f359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-513);*r1p=r1;*r0p=r0;}
+static void f360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1024);*r1p=r1;*r0p=r0;}
+static void f361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-1024);*r1p=r1;*r0p=r0;}
+static void f362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,1023);*r1p=r1;*r0p=r0;}
+static void f363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-1025);*r1p=r1;*r0p=r0;}
+static void f364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,2048);*r1p=r1;*r0p=r0;}
+static void f365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2048);*r1p=r1;*r0p=r0;}
+static void f366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,2047);*r1p=r1;*r0p=r0;}
+static void f367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-2049);*r1p=r1;*r0p=r0;}
+static void f368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,4096);*r1p=r1;*r0p=r0;}
+static void f369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-4096);*r1p=r1;*r0p=r0;}
+static void f370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,4095);*r1p=r1;*r0p=r0;}
+static void f371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-4097);*r1p=r1;*r0p=r0;}
+static void f372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,8192);*r1p=r1;*r0p=r0;}
+static void f373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-8192);*r1p=r1;*r0p=r0;}
+static void f374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,8191);*r1p=r1;*r0p=r0;}
+static void f375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-8193);*r1p=r1;*r0p=r0;}
+static void f376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,16384);*r1p=r1;*r0p=r0;}
+static void f377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-16384);*r1p=r1;*r0p=r0;}
+static void f378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,16383);*r1p=r1;*r0p=r0;}
+static void f379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-16385);*r1p=r1;*r0p=r0;}
+static void f380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,32768);*r1p=r1;*r0p=r0;}
+static void f381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-32768);*r1p=r1;*r0p=r0;}
+static void f382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,32767);*r1p=r1;*r0p=r0;}
+static void f383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2,0,-32769);*r1p=r1;*r0p=r0;}
+static void f384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-1);*r1p=r1;*r0p=r0;}
+static void f386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,0);*r1p=r1;*r0p=r0;}
+static void f387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,2);*r1p=r1;*r0p=r0;}
+static void f389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2);*r1p=r1;*r0p=r0;}
+static void f390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1);*r1p=r1;*r0p=r0;}
+static void f391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-3);*r1p=r1;*r0p=r0;}
+static void f392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,4);*r1p=r1;*r0p=r0;}
+static void f393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-4);*r1p=r1;*r0p=r0;}
+static void f394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,3);*r1p=r1;*r0p=r0;}
+static void f395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-5);*r1p=r1;*r0p=r0;}
+static void f396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,8);*r1p=r1;*r0p=r0;}
+static void f397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-8);*r1p=r1;*r0p=r0;}
+static void f398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,7);*r1p=r1;*r0p=r0;}
+static void f399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-9);*r1p=r1;*r0p=r0;}
+static void f400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,16);*r1p=r1;*r0p=r0;}
+static void f401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-16);*r1p=r1;*r0p=r0;}
+static void f402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,15);*r1p=r1;*r0p=r0;}
+static void f403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-17);*r1p=r1;*r0p=r0;}
+static void f404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,32);*r1p=r1;*r0p=r0;}
+static void f405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-32);*r1p=r1;*r0p=r0;}
+static void f406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,31);*r1p=r1;*r0p=r0;}
+static void f407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-33);*r1p=r1;*r0p=r0;}
+static void f408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,64);*r1p=r1;*r0p=r0;}
+static void f409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-64);*r1p=r1;*r0p=r0;}
+static void f410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,63);*r1p=r1;*r0p=r0;}
+static void f411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-65);*r1p=r1;*r0p=r0;}
+static void f412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,128);*r1p=r1;*r0p=r0;}
+static void f413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-128);*r1p=r1;*r0p=r0;}
+static void f414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,127);*r1p=r1;*r0p=r0;}
+static void f415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-129);*r1p=r1;*r0p=r0;}
+static void f416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,256);*r1p=r1;*r0p=r0;}
+static void f417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-256);*r1p=r1;*r0p=r0;}
+static void f418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,255);*r1p=r1;*r0p=r0;}
+static void f419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-257);*r1p=r1;*r0p=r0;}
+static void f420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,512);*r1p=r1;*r0p=r0;}
+static void f421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-512);*r1p=r1;*r0p=r0;}
+static void f422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,511);*r1p=r1;*r0p=r0;}
+static void f423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-513);*r1p=r1;*r0p=r0;}
+static void f424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1024);*r1p=r1;*r0p=r0;}
+static void f425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-1024);*r1p=r1;*r0p=r0;}
+static void f426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,1023);*r1p=r1;*r0p=r0;}
+static void f427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-1025);*r1p=r1;*r0p=r0;}
+static void f428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,2048);*r1p=r1;*r0p=r0;}
+static void f429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2048);*r1p=r1;*r0p=r0;}
+static void f430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,2047);*r1p=r1;*r0p=r0;}
+static void f431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-2049);*r1p=r1;*r0p=r0;}
+static void f432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,4096);*r1p=r1;*r0p=r0;}
+static void f433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-4096);*r1p=r1;*r0p=r0;}
+static void f434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,4095);*r1p=r1;*r0p=r0;}
+static void f435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-4097);*r1p=r1;*r0p=r0;}
+static void f436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,8192);*r1p=r1;*r0p=r0;}
+static void f437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-8192);*r1p=r1;*r0p=r0;}
+static void f438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,8191);*r1p=r1;*r0p=r0;}
+static void f439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-8193);*r1p=r1;*r0p=r0;}
+static void f440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,16384);*r1p=r1;*r0p=r0;}
+static void f441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-16384);*r1p=r1;*r0p=r0;}
+static void f442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,16383);*r1p=r1;*r0p=r0;}
+static void f443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-16385);*r1p=r1;*r0p=r0;}
+static void f444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,32768);*r1p=r1;*r0p=r0;}
+static void f445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-32768);*r1p=r1;*r0p=r0;}
+static void f446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,32767);*r1p=r1;*r0p=r0;}
+static void f447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1,0,-32769);*r1p=r1;*r0p=r0;}
+static void f448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,1);*r1p=r1;*r0p=r0;}
+static void f449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-1);*r1p=r1;*r0p=r0;}
+static void f450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,0);*r1p=r1;*r0p=r0;}
+static void f451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-2);*r1p=r1;*r0p=r0;}
+static void f452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,2);*r1p=r1;*r0p=r0;}
+static void f453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-2);*r1p=r1;*r0p=r0;}
+static void f454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,1);*r1p=r1;*r0p=r0;}
+static void f455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-3);*r1p=r1;*r0p=r0;}
+static void f456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,4);*r1p=r1;*r0p=r0;}
+static void f457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-4);*r1p=r1;*r0p=r0;}
+static void f458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,3);*r1p=r1;*r0p=r0;}
+static void f459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-5);*r1p=r1;*r0p=r0;}
+static void f460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,8);*r1p=r1;*r0p=r0;}
+static void f461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-8);*r1p=r1;*r0p=r0;}
+static void f462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,7);*r1p=r1;*r0p=r0;}
+static void f463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-9);*r1p=r1;*r0p=r0;}
+static void f464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,16);*r1p=r1;*r0p=r0;}
+static void f465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-16);*r1p=r1;*r0p=r0;}
+static void f466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,15);*r1p=r1;*r0p=r0;}
+static void f467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-17);*r1p=r1;*r0p=r0;}
+static void f468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,32);*r1p=r1;*r0p=r0;}
+static void f469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-32);*r1p=r1;*r0p=r0;}
+static void f470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,31);*r1p=r1;*r0p=r0;}
+static void f471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-33);*r1p=r1;*r0p=r0;}
+static void f472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,64);*r1p=r1;*r0p=r0;}
+static void f473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-64);*r1p=r1;*r0p=r0;}
+static void f474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,63);*r1p=r1;*r0p=r0;}
+static void f475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-65);*r1p=r1;*r0p=r0;}
+static void f476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,128);*r1p=r1;*r0p=r0;}
+static void f477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-128);*r1p=r1;*r0p=r0;}
+static void f478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,127);*r1p=r1;*r0p=r0;}
+static void f479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-129);*r1p=r1;*r0p=r0;}
+static void f480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,256);*r1p=r1;*r0p=r0;}
+static void f481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-256);*r1p=r1;*r0p=r0;}
+static void f482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,255);*r1p=r1;*r0p=r0;}
+static void f483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-257);*r1p=r1;*r0p=r0;}
+static void f484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,512);*r1p=r1;*r0p=r0;}
+static void f485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-512);*r1p=r1;*r0p=r0;}
+static void f486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,511);*r1p=r1;*r0p=r0;}
+static void f487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-513);*r1p=r1;*r0p=r0;}
+static void f488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,1024);*r1p=r1;*r0p=r0;}
+static void f489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-1024);*r1p=r1;*r0p=r0;}
+static void f490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,1023);*r1p=r1;*r0p=r0;}
+static void f491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-1025);*r1p=r1;*r0p=r0;}
+static void f492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,2048);*r1p=r1;*r0p=r0;}
+static void f493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-2048);*r1p=r1;*r0p=r0;}
+static void f494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,2047);*r1p=r1;*r0p=r0;}
+static void f495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-2049);*r1p=r1;*r0p=r0;}
+static void f496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,4096);*r1p=r1;*r0p=r0;}
+static void f497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-4096);*r1p=r1;*r0p=r0;}
+static void f498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,4095);*r1p=r1;*r0p=r0;}
+static void f499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-4097);*r1p=r1;*r0p=r0;}
+static void f500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,8192);*r1p=r1;*r0p=r0;}
+static void f501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-8192);*r1p=r1;*r0p=r0;}
+static void f502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,8191);*r1p=r1;*r0p=r0;}
+static void f503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-8193);*r1p=r1;*r0p=r0;}
+static void f504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,16384);*r1p=r1;*r0p=r0;}
+static void f505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-16384);*r1p=r1;*r0p=r0;}
+static void f506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,16383);*r1p=r1;*r0p=r0;}
+static void f507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-16385);*r1p=r1;*r0p=r0;}
+static void f508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,32768);*r1p=r1;*r0p=r0;}
+static void f509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-32768);*r1p=r1;*r0p=r0;}
+static void f510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,32767);*r1p=r1;*r0p=r0;}
+static void f511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-3,0,-32769);*r1p=r1;*r0p=r0;}
+static void f512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,1);*r1p=r1;*r0p=r0;}
+static void f513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-1);*r1p=r1;*r0p=r0;}
+static void f514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,0);*r1p=r1;*r0p=r0;}
+static void f515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-2);*r1p=r1;*r0p=r0;}
+static void f516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,2);*r1p=r1;*r0p=r0;}
+static void f517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-2);*r1p=r1;*r0p=r0;}
+static void f518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,1);*r1p=r1;*r0p=r0;}
+static void f519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-3);*r1p=r1;*r0p=r0;}
+static void f520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,4);*r1p=r1;*r0p=r0;}
+static void f521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-4);*r1p=r1;*r0p=r0;}
+static void f522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,3);*r1p=r1;*r0p=r0;}
+static void f523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-5);*r1p=r1;*r0p=r0;}
+static void f524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,8);*r1p=r1;*r0p=r0;}
+static void f525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-8);*r1p=r1;*r0p=r0;}
+static void f526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,7);*r1p=r1;*r0p=r0;}
+static void f527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-9);*r1p=r1;*r0p=r0;}
+static void f528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,16);*r1p=r1;*r0p=r0;}
+static void f529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-16);*r1p=r1;*r0p=r0;}
+static void f530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,15);*r1p=r1;*r0p=r0;}
+static void f531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-17);*r1p=r1;*r0p=r0;}
+static void f532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,32);*r1p=r1;*r0p=r0;}
+static void f533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-32);*r1p=r1;*r0p=r0;}
+static void f534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,31);*r1p=r1;*r0p=r0;}
+static void f535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-33);*r1p=r1;*r0p=r0;}
+static void f536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,64);*r1p=r1;*r0p=r0;}
+static void f537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-64);*r1p=r1;*r0p=r0;}
+static void f538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,63);*r1p=r1;*r0p=r0;}
+static void f539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-65);*r1p=r1;*r0p=r0;}
+static void f540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,128);*r1p=r1;*r0p=r0;}
+static void f541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-128);*r1p=r1;*r0p=r0;}
+static void f542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,127);*r1p=r1;*r0p=r0;}
+static void f543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-129);*r1p=r1;*r0p=r0;}
+static void f544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,256);*r1p=r1;*r0p=r0;}
+static void f545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-256);*r1p=r1;*r0p=r0;}
+static void f546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,255);*r1p=r1;*r0p=r0;}
+static void f547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-257);*r1p=r1;*r0p=r0;}
+static void f548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,512);*r1p=r1;*r0p=r0;}
+static void f549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-512);*r1p=r1;*r0p=r0;}
+static void f550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,511);*r1p=r1;*r0p=r0;}
+static void f551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-513);*r1p=r1;*r0p=r0;}
+static void f552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,1024);*r1p=r1;*r0p=r0;}
+static void f553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-1024);*r1p=r1;*r0p=r0;}
+static void f554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,1023);*r1p=r1;*r0p=r0;}
+static void f555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-1025);*r1p=r1;*r0p=r0;}
+static void f556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,2048);*r1p=r1;*r0p=r0;}
+static void f557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-2048);*r1p=r1;*r0p=r0;}
+static void f558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,2047);*r1p=r1;*r0p=r0;}
+static void f559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-2049);*r1p=r1;*r0p=r0;}
+static void f560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,4096);*r1p=r1;*r0p=r0;}
+static void f561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-4096);*r1p=r1;*r0p=r0;}
+static void f562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,4095);*r1p=r1;*r0p=r0;}
+static void f563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-4097);*r1p=r1;*r0p=r0;}
+static void f564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,8192);*r1p=r1;*r0p=r0;}
+static void f565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-8192);*r1p=r1;*r0p=r0;}
+static void f566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,8191);*r1p=r1;*r0p=r0;}
+static void f567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-8193);*r1p=r1;*r0p=r0;}
+static void f568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,16384);*r1p=r1;*r0p=r0;}
+static void f569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-16384);*r1p=r1;*r0p=r0;}
+static void f570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,16383);*r1p=r1;*r0p=r0;}
+static void f571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-16385);*r1p=r1;*r0p=r0;}
+static void f572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,32768);*r1p=r1;*r0p=r0;}
+static void f573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-32768);*r1p=r1;*r0p=r0;}
+static void f574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,32767);*r1p=r1;*r0p=r0;}
+static void f575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4,0,-32769);*r1p=r1;*r0p=r0;}
+static void f576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,1);*r1p=r1;*r0p=r0;}
+static void f577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-1);*r1p=r1;*r0p=r0;}
+static void f578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,0);*r1p=r1;*r0p=r0;}
+static void f579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-2);*r1p=r1;*r0p=r0;}
+static void f580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,2);*r1p=r1;*r0p=r0;}
+static void f581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-2);*r1p=r1;*r0p=r0;}
+static void f582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,1);*r1p=r1;*r0p=r0;}
+static void f583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-3);*r1p=r1;*r0p=r0;}
+static void f584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,4);*r1p=r1;*r0p=r0;}
+static void f585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-4);*r1p=r1;*r0p=r0;}
+static void f586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,3);*r1p=r1;*r0p=r0;}
+static void f587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-5);*r1p=r1;*r0p=r0;}
+static void f588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,8);*r1p=r1;*r0p=r0;}
+static void f589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-8);*r1p=r1;*r0p=r0;}
+static void f590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,7);*r1p=r1;*r0p=r0;}
+static void f591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-9);*r1p=r1;*r0p=r0;}
+static void f592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,16);*r1p=r1;*r0p=r0;}
+static void f593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-16);*r1p=r1;*r0p=r0;}
+static void f594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,15);*r1p=r1;*r0p=r0;}
+static void f595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-17);*r1p=r1;*r0p=r0;}
+static void f596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,32);*r1p=r1;*r0p=r0;}
+static void f597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-32);*r1p=r1;*r0p=r0;}
+static void f598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,31);*r1p=r1;*r0p=r0;}
+static void f599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-33);*r1p=r1;*r0p=r0;}
+static void f600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,64);*r1p=r1;*r0p=r0;}
+static void f601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-64);*r1p=r1;*r0p=r0;}
+static void f602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,63);*r1p=r1;*r0p=r0;}
+static void f603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-65);*r1p=r1;*r0p=r0;}
+static void f604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,128);*r1p=r1;*r0p=r0;}
+static void f605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-128);*r1p=r1;*r0p=r0;}
+static void f606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,127);*r1p=r1;*r0p=r0;}
+static void f607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-129);*r1p=r1;*r0p=r0;}
+static void f608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,256);*r1p=r1;*r0p=r0;}
+static void f609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-256);*r1p=r1;*r0p=r0;}
+static void f610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,255);*r1p=r1;*r0p=r0;}
+static void f611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-257);*r1p=r1;*r0p=r0;}
+static void f612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,512);*r1p=r1;*r0p=r0;}
+static void f613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-512);*r1p=r1;*r0p=r0;}
+static void f614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,511);*r1p=r1;*r0p=r0;}
+static void f615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-513);*r1p=r1;*r0p=r0;}
+static void f616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,1024);*r1p=r1;*r0p=r0;}
+static void f617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-1024);*r1p=r1;*r0p=r0;}
+static void f618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,1023);*r1p=r1;*r0p=r0;}
+static void f619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-1025);*r1p=r1;*r0p=r0;}
+static void f620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,2048);*r1p=r1;*r0p=r0;}
+static void f621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-2048);*r1p=r1;*r0p=r0;}
+static void f622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,2047);*r1p=r1;*r0p=r0;}
+static void f623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-2049);*r1p=r1;*r0p=r0;}
+static void f624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,4096);*r1p=r1;*r0p=r0;}
+static void f625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-4096);*r1p=r1;*r0p=r0;}
+static void f626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,4095);*r1p=r1;*r0p=r0;}
+static void f627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-4097);*r1p=r1;*r0p=r0;}
+static void f628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,8192);*r1p=r1;*r0p=r0;}
+static void f629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-8192);*r1p=r1;*r0p=r0;}
+static void f630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,8191);*r1p=r1;*r0p=r0;}
+static void f631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-8193);*r1p=r1;*r0p=r0;}
+static void f632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,16384);*r1p=r1;*r0p=r0;}
+static void f633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-16384);*r1p=r1;*r0p=r0;}
+static void f634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,16383);*r1p=r1;*r0p=r0;}
+static void f635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-16385);*r1p=r1;*r0p=r0;}
+static void f636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,32768);*r1p=r1;*r0p=r0;}
+static void f637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-32768);*r1p=r1;*r0p=r0;}
+static void f638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,32767);*r1p=r1;*r0p=r0;}
+static void f639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4,0,-32769);*r1p=r1;*r0p=r0;}
+static void f640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,1);*r1p=r1;*r0p=r0;}
+static void f641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-1);*r1p=r1;*r0p=r0;}
+static void f642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,0);*r1p=r1;*r0p=r0;}
+static void f643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-2);*r1p=r1;*r0p=r0;}
+static void f644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,2);*r1p=r1;*r0p=r0;}
+static void f645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-2);*r1p=r1;*r0p=r0;}
+static void f646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,1);*r1p=r1;*r0p=r0;}
+static void f647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-3);*r1p=r1;*r0p=r0;}
+static void f648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,4);*r1p=r1;*r0p=r0;}
+static void f649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-4);*r1p=r1;*r0p=r0;}
+static void f650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,3);*r1p=r1;*r0p=r0;}
+static void f651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-5);*r1p=r1;*r0p=r0;}
+static void f652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,8);*r1p=r1;*r0p=r0;}
+static void f653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-8);*r1p=r1;*r0p=r0;}
+static void f654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,7);*r1p=r1;*r0p=r0;}
+static void f655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-9);*r1p=r1;*r0p=r0;}
+static void f656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,16);*r1p=r1;*r0p=r0;}
+static void f657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-16);*r1p=r1;*r0p=r0;}
+static void f658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,15);*r1p=r1;*r0p=r0;}
+static void f659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-17);*r1p=r1;*r0p=r0;}
+static void f660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,32);*r1p=r1;*r0p=r0;}
+static void f661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-32);*r1p=r1;*r0p=r0;}
+static void f662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,31);*r1p=r1;*r0p=r0;}
+static void f663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-33);*r1p=r1;*r0p=r0;}
+static void f664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,64);*r1p=r1;*r0p=r0;}
+static void f665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-64);*r1p=r1;*r0p=r0;}
+static void f666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,63);*r1p=r1;*r0p=r0;}
+static void f667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-65);*r1p=r1;*r0p=r0;}
+static void f668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,128);*r1p=r1;*r0p=r0;}
+static void f669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-128);*r1p=r1;*r0p=r0;}
+static void f670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,127);*r1p=r1;*r0p=r0;}
+static void f671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-129);*r1p=r1;*r0p=r0;}
+static void f672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,256);*r1p=r1;*r0p=r0;}
+static void f673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-256);*r1p=r1;*r0p=r0;}
+static void f674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,255);*r1p=r1;*r0p=r0;}
+static void f675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-257);*r1p=r1;*r0p=r0;}
+static void f676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,512);*r1p=r1;*r0p=r0;}
+static void f677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-512);*r1p=r1;*r0p=r0;}
+static void f678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,511);*r1p=r1;*r0p=r0;}
+static void f679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-513);*r1p=r1;*r0p=r0;}
+static void f680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,1024);*r1p=r1;*r0p=r0;}
+static void f681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-1024);*r1p=r1;*r0p=r0;}
+static void f682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,1023);*r1p=r1;*r0p=r0;}
+static void f683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-1025);*r1p=r1;*r0p=r0;}
+static void f684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,2048);*r1p=r1;*r0p=r0;}
+static void f685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-2048);*r1p=r1;*r0p=r0;}
+static void f686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,2047);*r1p=r1;*r0p=r0;}
+static void f687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-2049);*r1p=r1;*r0p=r0;}
+static void f688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,4096);*r1p=r1;*r0p=r0;}
+static void f689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-4096);*r1p=r1;*r0p=r0;}
+static void f690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,4095);*r1p=r1;*r0p=r0;}
+static void f691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-4097);*r1p=r1;*r0p=r0;}
+static void f692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,8192);*r1p=r1;*r0p=r0;}
+static void f693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-8192);*r1p=r1;*r0p=r0;}
+static void f694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,8191);*r1p=r1;*r0p=r0;}
+static void f695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-8193);*r1p=r1;*r0p=r0;}
+static void f696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,16384);*r1p=r1;*r0p=r0;}
+static void f697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-16384);*r1p=r1;*r0p=r0;}
+static void f698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,16383);*r1p=r1;*r0p=r0;}
+static void f699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-16385);*r1p=r1;*r0p=r0;}
+static void f700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,32768);*r1p=r1;*r0p=r0;}
+static void f701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-32768);*r1p=r1;*r0p=r0;}
+static void f702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,32767);*r1p=r1;*r0p=r0;}
+static void f703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,3,0,-32769);*r1p=r1;*r0p=r0;}
+static void f704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,1);*r1p=r1;*r0p=r0;}
+static void f705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-1);*r1p=r1;*r0p=r0;}
+static void f706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,0);*r1p=r1;*r0p=r0;}
+static void f707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-2);*r1p=r1;*r0p=r0;}
+static void f708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,2);*r1p=r1;*r0p=r0;}
+static void f709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-2);*r1p=r1;*r0p=r0;}
+static void f710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,1);*r1p=r1;*r0p=r0;}
+static void f711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-3);*r1p=r1;*r0p=r0;}
+static void f712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,4);*r1p=r1;*r0p=r0;}
+static void f713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-4);*r1p=r1;*r0p=r0;}
+static void f714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,3);*r1p=r1;*r0p=r0;}
+static void f715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-5);*r1p=r1;*r0p=r0;}
+static void f716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,8);*r1p=r1;*r0p=r0;}
+static void f717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-8);*r1p=r1;*r0p=r0;}
+static void f718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,7);*r1p=r1;*r0p=r0;}
+static void f719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-9);*r1p=r1;*r0p=r0;}
+static void f720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,16);*r1p=r1;*r0p=r0;}
+static void f721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-16);*r1p=r1;*r0p=r0;}
+static void f722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,15);*r1p=r1;*r0p=r0;}
+static void f723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-17);*r1p=r1;*r0p=r0;}
+static void f724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,32);*r1p=r1;*r0p=r0;}
+static void f725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-32);*r1p=r1;*r0p=r0;}
+static void f726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,31);*r1p=r1;*r0p=r0;}
+static void f727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-33);*r1p=r1;*r0p=r0;}
+static void f728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,64);*r1p=r1;*r0p=r0;}
+static void f729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-64);*r1p=r1;*r0p=r0;}
+static void f730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,63);*r1p=r1;*r0p=r0;}
+static void f731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-65);*r1p=r1;*r0p=r0;}
+static void f732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,128);*r1p=r1;*r0p=r0;}
+static void f733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-128);*r1p=r1;*r0p=r0;}
+static void f734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,127);*r1p=r1;*r0p=r0;}
+static void f735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-129);*r1p=r1;*r0p=r0;}
+static void f736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,256);*r1p=r1;*r0p=r0;}
+static void f737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-256);*r1p=r1;*r0p=r0;}
+static void f738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,255);*r1p=r1;*r0p=r0;}
+static void f739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-257);*r1p=r1;*r0p=r0;}
+static void f740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,512);*r1p=r1;*r0p=r0;}
+static void f741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-512);*r1p=r1;*r0p=r0;}
+static void f742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,511);*r1p=r1;*r0p=r0;}
+static void f743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-513);*r1p=r1;*r0p=r0;}
+static void f744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,1024);*r1p=r1;*r0p=r0;}
+static void f745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-1024);*r1p=r1;*r0p=r0;}
+static void f746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,1023);*r1p=r1;*r0p=r0;}
+static void f747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-1025);*r1p=r1;*r0p=r0;}
+static void f748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,2048);*r1p=r1;*r0p=r0;}
+static void f749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-2048);*r1p=r1;*r0p=r0;}
+static void f750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,2047);*r1p=r1;*r0p=r0;}
+static void f751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-2049);*r1p=r1;*r0p=r0;}
+static void f752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,4096);*r1p=r1;*r0p=r0;}
+static void f753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-4096);*r1p=r1;*r0p=r0;}
+static void f754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,4095);*r1p=r1;*r0p=r0;}
+static void f755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-4097);*r1p=r1;*r0p=r0;}
+static void f756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,8192);*r1p=r1;*r0p=r0;}
+static void f757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-8192);*r1p=r1;*r0p=r0;}
+static void f758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,8191);*r1p=r1;*r0p=r0;}
+static void f759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-8193);*r1p=r1;*r0p=r0;}
+static void f760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,16384);*r1p=r1;*r0p=r0;}
+static void f761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-16384);*r1p=r1;*r0p=r0;}
+static void f762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,16383);*r1p=r1;*r0p=r0;}
+static void f763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-16385);*r1p=r1;*r0p=r0;}
+static void f764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,32768);*r1p=r1;*r0p=r0;}
+static void f765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-32768);*r1p=r1;*r0p=r0;}
+static void f766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,32767);*r1p=r1;*r0p=r0;}
+static void f767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-5,0,-32769);*r1p=r1;*r0p=r0;}
+static void f768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,1);*r1p=r1;*r0p=r0;}
+static void f769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-1);*r1p=r1;*r0p=r0;}
+static void f770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,0);*r1p=r1;*r0p=r0;}
+static void f771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-2);*r1p=r1;*r0p=r0;}
+static void f772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,2);*r1p=r1;*r0p=r0;}
+static void f773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-2);*r1p=r1;*r0p=r0;}
+static void f774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,1);*r1p=r1;*r0p=r0;}
+static void f775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-3);*r1p=r1;*r0p=r0;}
+static void f776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,4);*r1p=r1;*r0p=r0;}
+static void f777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-4);*r1p=r1;*r0p=r0;}
+static void f778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,3);*r1p=r1;*r0p=r0;}
+static void f779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-5);*r1p=r1;*r0p=r0;}
+static void f780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,8);*r1p=r1;*r0p=r0;}
+static void f781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-8);*r1p=r1;*r0p=r0;}
+static void f782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,7);*r1p=r1;*r0p=r0;}
+static void f783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-9);*r1p=r1;*r0p=r0;}
+static void f784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,16);*r1p=r1;*r0p=r0;}
+static void f785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-16);*r1p=r1;*r0p=r0;}
+static void f786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,15);*r1p=r1;*r0p=r0;}
+static void f787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-17);*r1p=r1;*r0p=r0;}
+static void f788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,32);*r1p=r1;*r0p=r0;}
+static void f789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-32);*r1p=r1;*r0p=r0;}
+static void f790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,31);*r1p=r1;*r0p=r0;}
+static void f791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-33);*r1p=r1;*r0p=r0;}
+static void f792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,64);*r1p=r1;*r0p=r0;}
+static void f793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-64);*r1p=r1;*r0p=r0;}
+static void f794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,63);*r1p=r1;*r0p=r0;}
+static void f795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-65);*r1p=r1;*r0p=r0;}
+static void f796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,128);*r1p=r1;*r0p=r0;}
+static void f797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-128);*r1p=r1;*r0p=r0;}
+static void f798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,127);*r1p=r1;*r0p=r0;}
+static void f799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-129);*r1p=r1;*r0p=r0;}
+static void f800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,256);*r1p=r1;*r0p=r0;}
+static void f801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-256);*r1p=r1;*r0p=r0;}
+static void f802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,255);*r1p=r1;*r0p=r0;}
+static void f803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-257);*r1p=r1;*r0p=r0;}
+static void f804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,512);*r1p=r1;*r0p=r0;}
+static void f805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-512);*r1p=r1;*r0p=r0;}
+static void f806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,511);*r1p=r1;*r0p=r0;}
+static void f807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-513);*r1p=r1;*r0p=r0;}
+static void f808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,1024);*r1p=r1;*r0p=r0;}
+static void f809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-1024);*r1p=r1;*r0p=r0;}
+static void f810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,1023);*r1p=r1;*r0p=r0;}
+static void f811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-1025);*r1p=r1;*r0p=r0;}
+static void f812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,2048);*r1p=r1;*r0p=r0;}
+static void f813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-2048);*r1p=r1;*r0p=r0;}
+static void f814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,2047);*r1p=r1;*r0p=r0;}
+static void f815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-2049);*r1p=r1;*r0p=r0;}
+static void f816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,4096);*r1p=r1;*r0p=r0;}
+static void f817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-4096);*r1p=r1;*r0p=r0;}
+static void f818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,4095);*r1p=r1;*r0p=r0;}
+static void f819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-4097);*r1p=r1;*r0p=r0;}
+static void f820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,8192);*r1p=r1;*r0p=r0;}
+static void f821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-8192);*r1p=r1;*r0p=r0;}
+static void f822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,8191);*r1p=r1;*r0p=r0;}
+static void f823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-8193);*r1p=r1;*r0p=r0;}
+static void f824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,16384);*r1p=r1;*r0p=r0;}
+static void f825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-16384);*r1p=r1;*r0p=r0;}
+static void f826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,16383);*r1p=r1;*r0p=r0;}
+static void f827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-16385);*r1p=r1;*r0p=r0;}
+static void f828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,32768);*r1p=r1;*r0p=r0;}
+static void f829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-32768);*r1p=r1;*r0p=r0;}
+static void f830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,32767);*r1p=r1;*r0p=r0;}
+static void f831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8,0,-32769);*r1p=r1;*r0p=r0;}
+static void f832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,1);*r1p=r1;*r0p=r0;}
+static void f833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-1);*r1p=r1;*r0p=r0;}
+static void f834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,0);*r1p=r1;*r0p=r0;}
+static void f835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-2);*r1p=r1;*r0p=r0;}
+static void f836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,2);*r1p=r1;*r0p=r0;}
+static void f837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-2);*r1p=r1;*r0p=r0;}
+static void f838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,1);*r1p=r1;*r0p=r0;}
+static void f839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-3);*r1p=r1;*r0p=r0;}
+static void f840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,4);*r1p=r1;*r0p=r0;}
+static void f841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-4);*r1p=r1;*r0p=r0;}
+static void f842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,3);*r1p=r1;*r0p=r0;}
+static void f843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-5);*r1p=r1;*r0p=r0;}
+static void f844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,8);*r1p=r1;*r0p=r0;}
+static void f845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-8);*r1p=r1;*r0p=r0;}
+static void f846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,7);*r1p=r1;*r0p=r0;}
+static void f847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-9);*r1p=r1;*r0p=r0;}
+static void f848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,16);*r1p=r1;*r0p=r0;}
+static void f849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-16);*r1p=r1;*r0p=r0;}
+static void f850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,15);*r1p=r1;*r0p=r0;}
+static void f851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-17);*r1p=r1;*r0p=r0;}
+static void f852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,32);*r1p=r1;*r0p=r0;}
+static void f853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-32);*r1p=r1;*r0p=r0;}
+static void f854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,31);*r1p=r1;*r0p=r0;}
+static void f855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-33);*r1p=r1;*r0p=r0;}
+static void f856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,64);*r1p=r1;*r0p=r0;}
+static void f857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-64);*r1p=r1;*r0p=r0;}
+static void f858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,63);*r1p=r1;*r0p=r0;}
+static void f859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-65);*r1p=r1;*r0p=r0;}
+static void f860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,128);*r1p=r1;*r0p=r0;}
+static void f861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-128);*r1p=r1;*r0p=r0;}
+static void f862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,127);*r1p=r1;*r0p=r0;}
+static void f863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-129);*r1p=r1;*r0p=r0;}
+static void f864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,256);*r1p=r1;*r0p=r0;}
+static void f865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-256);*r1p=r1;*r0p=r0;}
+static void f866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,255);*r1p=r1;*r0p=r0;}
+static void f867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-257);*r1p=r1;*r0p=r0;}
+static void f868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,512);*r1p=r1;*r0p=r0;}
+static void f869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-512);*r1p=r1;*r0p=r0;}
+static void f870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,511);*r1p=r1;*r0p=r0;}
+static void f871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-513);*r1p=r1;*r0p=r0;}
+static void f872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,1024);*r1p=r1;*r0p=r0;}
+static void f873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-1024);*r1p=r1;*r0p=r0;}
+static void f874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,1023);*r1p=r1;*r0p=r0;}
+static void f875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-1025);*r1p=r1;*r0p=r0;}
+static void f876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,2048);*r1p=r1;*r0p=r0;}
+static void f877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-2048);*r1p=r1;*r0p=r0;}
+static void f878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,2047);*r1p=r1;*r0p=r0;}
+static void f879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-2049);*r1p=r1;*r0p=r0;}
+static void f880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,4096);*r1p=r1;*r0p=r0;}
+static void f881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-4096);*r1p=r1;*r0p=r0;}
+static void f882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,4095);*r1p=r1;*r0p=r0;}
+static void f883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-4097);*r1p=r1;*r0p=r0;}
+static void f884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,8192);*r1p=r1;*r0p=r0;}
+static void f885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-8192);*r1p=r1;*r0p=r0;}
+static void f886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,8191);*r1p=r1;*r0p=r0;}
+static void f887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-8193);*r1p=r1;*r0p=r0;}
+static void f888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,16384);*r1p=r1;*r0p=r0;}
+static void f889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-16384);*r1p=r1;*r0p=r0;}
+static void f890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,16383);*r1p=r1;*r0p=r0;}
+static void f891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-16385);*r1p=r1;*r0p=r0;}
+static void f892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,32768);*r1p=r1;*r0p=r0;}
+static void f893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-32768);*r1p=r1;*r0p=r0;}
+static void f894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,32767);*r1p=r1;*r0p=r0;}
+static void f895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8,0,-32769);*r1p=r1;*r0p=r0;}
+static void f896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,1);*r1p=r1;*r0p=r0;}
+static void f897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-1);*r1p=r1;*r0p=r0;}
+static void f898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,0);*r1p=r1;*r0p=r0;}
+static void f899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-2);*r1p=r1;*r0p=r0;}
+static void f900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,2);*r1p=r1;*r0p=r0;}
+static void f901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-2);*r1p=r1;*r0p=r0;}
+static void f902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,1);*r1p=r1;*r0p=r0;}
+static void f903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-3);*r1p=r1;*r0p=r0;}
+static void f904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,4);*r1p=r1;*r0p=r0;}
+static void f905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-4);*r1p=r1;*r0p=r0;}
+static void f906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,3);*r1p=r1;*r0p=r0;}
+static void f907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-5);*r1p=r1;*r0p=r0;}
+static void f908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,8);*r1p=r1;*r0p=r0;}
+static void f909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-8);*r1p=r1;*r0p=r0;}
+static void f910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,7);*r1p=r1;*r0p=r0;}
+static void f911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-9);*r1p=r1;*r0p=r0;}
+static void f912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,16);*r1p=r1;*r0p=r0;}
+static void f913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-16);*r1p=r1;*r0p=r0;}
+static void f914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,15);*r1p=r1;*r0p=r0;}
+static void f915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-17);*r1p=r1;*r0p=r0;}
+static void f916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,32);*r1p=r1;*r0p=r0;}
+static void f917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-32);*r1p=r1;*r0p=r0;}
+static void f918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,31);*r1p=r1;*r0p=r0;}
+static void f919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-33);*r1p=r1;*r0p=r0;}
+static void f920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,64);*r1p=r1;*r0p=r0;}
+static void f921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-64);*r1p=r1;*r0p=r0;}
+static void f922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,63);*r1p=r1;*r0p=r0;}
+static void f923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-65);*r1p=r1;*r0p=r0;}
+static void f924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,128);*r1p=r1;*r0p=r0;}
+static void f925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-128);*r1p=r1;*r0p=r0;}
+static void f926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,127);*r1p=r1;*r0p=r0;}
+static void f927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-129);*r1p=r1;*r0p=r0;}
+static void f928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,256);*r1p=r1;*r0p=r0;}
+static void f929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-256);*r1p=r1;*r0p=r0;}
+static void f930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,255);*r1p=r1;*r0p=r0;}
+static void f931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-257);*r1p=r1;*r0p=r0;}
+static void f932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,512);*r1p=r1;*r0p=r0;}
+static void f933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-512);*r1p=r1;*r0p=r0;}
+static void f934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,511);*r1p=r1;*r0p=r0;}
+static void f935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-513);*r1p=r1;*r0p=r0;}
+static void f936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,1024);*r1p=r1;*r0p=r0;}
+static void f937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-1024);*r1p=r1;*r0p=r0;}
+static void f938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,1023);*r1p=r1;*r0p=r0;}
+static void f939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-1025);*r1p=r1;*r0p=r0;}
+static void f940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,2048);*r1p=r1;*r0p=r0;}
+static void f941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-2048);*r1p=r1;*r0p=r0;}
+static void f942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,2047);*r1p=r1;*r0p=r0;}
+static void f943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-2049);*r1p=r1;*r0p=r0;}
+static void f944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,4096);*r1p=r1;*r0p=r0;}
+static void f945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-4096);*r1p=r1;*r0p=r0;}
+static void f946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,4095);*r1p=r1;*r0p=r0;}
+static void f947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-4097);*r1p=r1;*r0p=r0;}
+static void f948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,8192);*r1p=r1;*r0p=r0;}
+static void f949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-8192);*r1p=r1;*r0p=r0;}
+static void f950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,8191);*r1p=r1;*r0p=r0;}
+static void f951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-8193);*r1p=r1;*r0p=r0;}
+static void f952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,16384);*r1p=r1;*r0p=r0;}
+static void f953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-16384);*r1p=r1;*r0p=r0;}
+static void f954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,16383);*r1p=r1;*r0p=r0;}
+static void f955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-16385);*r1p=r1;*r0p=r0;}
+static void f956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,32768);*r1p=r1;*r0p=r0;}
+static void f957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-32768);*r1p=r1;*r0p=r0;}
+static void f958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,32767);*r1p=r1;*r0p=r0;}
+static void f959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,7,0,-32769);*r1p=r1;*r0p=r0;}
+static void f960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,1);*r1p=r1;*r0p=r0;}
+static void f961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-1);*r1p=r1;*r0p=r0;}
+static void f962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,0);*r1p=r1;*r0p=r0;}
+static void f963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-2);*r1p=r1;*r0p=r0;}
+static void f964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,2);*r1p=r1;*r0p=r0;}
+static void f965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-2);*r1p=r1;*r0p=r0;}
+static void f966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,1);*r1p=r1;*r0p=r0;}
+static void f967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-3);*r1p=r1;*r0p=r0;}
+static void f968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,4);*r1p=r1;*r0p=r0;}
+static void f969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-4);*r1p=r1;*r0p=r0;}
+static void f970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,3);*r1p=r1;*r0p=r0;}
+static void f971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-5);*r1p=r1;*r0p=r0;}
+static void f972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,8);*r1p=r1;*r0p=r0;}
+static void f973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-8);*r1p=r1;*r0p=r0;}
+static void f974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,7);*r1p=r1;*r0p=r0;}
+static void f975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-9);*r1p=r1;*r0p=r0;}
+static void f976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,16);*r1p=r1;*r0p=r0;}
+static void f977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-16);*r1p=r1;*r0p=r0;}
+static void f978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,15);*r1p=r1;*r0p=r0;}
+static void f979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-17);*r1p=r1;*r0p=r0;}
+static void f980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,32);*r1p=r1;*r0p=r0;}
+static void f981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-32);*r1p=r1;*r0p=r0;}
+static void f982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,31);*r1p=r1;*r0p=r0;}
+static void f983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-33);*r1p=r1;*r0p=r0;}
+static void f984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,64);*r1p=r1;*r0p=r0;}
+static void f985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-64);*r1p=r1;*r0p=r0;}
+static void f986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,63);*r1p=r1;*r0p=r0;}
+static void f987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-65);*r1p=r1;*r0p=r0;}
+static void f988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,128);*r1p=r1;*r0p=r0;}
+static void f989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-128);*r1p=r1;*r0p=r0;}
+static void f990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,127);*r1p=r1;*r0p=r0;}
+static void f991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-129);*r1p=r1;*r0p=r0;}
+static void f992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,256);*r1p=r1;*r0p=r0;}
+static void f993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-256);*r1p=r1;*r0p=r0;}
+static void f994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,255);*r1p=r1;*r0p=r0;}
+static void f995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-257);*r1p=r1;*r0p=r0;}
+static void f996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,512);*r1p=r1;*r0p=r0;}
+static void f997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-512);*r1p=r1;*r0p=r0;}
+static void f998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,511);*r1p=r1;*r0p=r0;}
+static void f999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-513);*r1p=r1;*r0p=r0;}
+static void f1000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,1024);*r1p=r1;*r0p=r0;}
+static void f1001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,1023);*r1p=r1;*r0p=r0;}
+static void f1003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,2048);*r1p=r1;*r0p=r0;}
+static void f1005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,2047);*r1p=r1;*r0p=r0;}
+static void f1007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,4096);*r1p=r1;*r0p=r0;}
+static void f1009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,4095);*r1p=r1;*r0p=r0;}
+static void f1011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,8192);*r1p=r1;*r0p=r0;}
+static void f1013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,8191);*r1p=r1;*r0p=r0;}
+static void f1015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,16384);*r1p=r1;*r0p=r0;}
+static void f1017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,16383);*r1p=r1;*r0p=r0;}
+static void f1019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,32768);*r1p=r1;*r0p=r0;}
+static void f1021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,32767);*r1p=r1;*r0p=r0;}
+static void f1023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-9,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,1);*r1p=r1;*r0p=r0;}
+static void f1025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-1);*r1p=r1;*r0p=r0;}
+static void f1026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,0);*r1p=r1;*r0p=r0;}
+static void f1027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,2);*r1p=r1;*r0p=r0;}
+static void f1029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,1);*r1p=r1;*r0p=r0;}
+static void f1031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-3);*r1p=r1;*r0p=r0;}
+static void f1032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,4);*r1p=r1;*r0p=r0;}
+static void f1033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-4);*r1p=r1;*r0p=r0;}
+static void f1034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,3);*r1p=r1;*r0p=r0;}
+static void f1035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-5);*r1p=r1;*r0p=r0;}
+static void f1036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,8);*r1p=r1;*r0p=r0;}
+static void f1037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-8);*r1p=r1;*r0p=r0;}
+static void f1038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,7);*r1p=r1;*r0p=r0;}
+static void f1039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-9);*r1p=r1;*r0p=r0;}
+static void f1040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,16);*r1p=r1;*r0p=r0;}
+static void f1041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-16);*r1p=r1;*r0p=r0;}
+static void f1042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,15);*r1p=r1;*r0p=r0;}
+static void f1043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-17);*r1p=r1;*r0p=r0;}
+static void f1044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,32);*r1p=r1;*r0p=r0;}
+static void f1045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-32);*r1p=r1;*r0p=r0;}
+static void f1046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,31);*r1p=r1;*r0p=r0;}
+static void f1047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-33);*r1p=r1;*r0p=r0;}
+static void f1048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,64);*r1p=r1;*r0p=r0;}
+static void f1049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-64);*r1p=r1;*r0p=r0;}
+static void f1050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,63);*r1p=r1;*r0p=r0;}
+static void f1051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-65);*r1p=r1;*r0p=r0;}
+static void f1052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,128);*r1p=r1;*r0p=r0;}
+static void f1053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-128);*r1p=r1;*r0p=r0;}
+static void f1054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,127);*r1p=r1;*r0p=r0;}
+static void f1055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-129);*r1p=r1;*r0p=r0;}
+static void f1056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,256);*r1p=r1;*r0p=r0;}
+static void f1057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-256);*r1p=r1;*r0p=r0;}
+static void f1058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,255);*r1p=r1;*r0p=r0;}
+static void f1059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-257);*r1p=r1;*r0p=r0;}
+static void f1060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,512);*r1p=r1;*r0p=r0;}
+static void f1061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-512);*r1p=r1;*r0p=r0;}
+static void f1062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,511);*r1p=r1;*r0p=r0;}
+static void f1063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-513);*r1p=r1;*r0p=r0;}
+static void f1064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,1024);*r1p=r1;*r0p=r0;}
+static void f1065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,1023);*r1p=r1;*r0p=r0;}
+static void f1067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,2048);*r1p=r1;*r0p=r0;}
+static void f1069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,2047);*r1p=r1;*r0p=r0;}
+static void f1071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,4096);*r1p=r1;*r0p=r0;}
+static void f1073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,4095);*r1p=r1;*r0p=r0;}
+static void f1075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,8192);*r1p=r1;*r0p=r0;}
+static void f1077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,8191);*r1p=r1;*r0p=r0;}
+static void f1079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,16384);*r1p=r1;*r0p=r0;}
+static void f1081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,16383);*r1p=r1;*r0p=r0;}
+static void f1083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,32768);*r1p=r1;*r0p=r0;}
+static void f1085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,32767);*r1p=r1;*r0p=r0;}
+static void f1087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,1);*r1p=r1;*r0p=r0;}
+static void f1089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-1);*r1p=r1;*r0p=r0;}
+static void f1090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,0);*r1p=r1;*r0p=r0;}
+static void f1091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,2);*r1p=r1;*r0p=r0;}
+static void f1093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-2);*r1p=r1;*r0p=r0;}
+static void f1094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,1);*r1p=r1;*r0p=r0;}
+static void f1095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-3);*r1p=r1;*r0p=r0;}
+static void f1096(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,4);*r1p=r1;*r0p=r0;}
+static void f1097(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-4);*r1p=r1;*r0p=r0;}
+static void f1098(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,3);*r1p=r1;*r0p=r0;}
+static void f1099(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-5);*r1p=r1;*r0p=r0;}
+static void f1100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,8);*r1p=r1;*r0p=r0;}
+static void f1101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-8);*r1p=r1;*r0p=r0;}
+static void f1102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,7);*r1p=r1;*r0p=r0;}
+static void f1103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-9);*r1p=r1;*r0p=r0;}
+static void f1104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,16);*r1p=r1;*r0p=r0;}
+static void f1105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-16);*r1p=r1;*r0p=r0;}
+static void f1106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,15);*r1p=r1;*r0p=r0;}
+static void f1107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-17);*r1p=r1;*r0p=r0;}
+static void f1108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,32);*r1p=r1;*r0p=r0;}
+static void f1109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-32);*r1p=r1;*r0p=r0;}
+static void f1110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,31);*r1p=r1;*r0p=r0;}
+static void f1111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-33);*r1p=r1;*r0p=r0;}
+static void f1112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,64);*r1p=r1;*r0p=r0;}
+static void f1113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-64);*r1p=r1;*r0p=r0;}
+static void f1114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,63);*r1p=r1;*r0p=r0;}
+static void f1115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-65);*r1p=r1;*r0p=r0;}
+static void f1116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,128);*r1p=r1;*r0p=r0;}
+static void f1117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-128);*r1p=r1;*r0p=r0;}
+static void f1118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,127);*r1p=r1;*r0p=r0;}
+static void f1119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-129);*r1p=r1;*r0p=r0;}
+static void f1120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,256);*r1p=r1;*r0p=r0;}
+static void f1121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-256);*r1p=r1;*r0p=r0;}
+static void f1122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,255);*r1p=r1;*r0p=r0;}
+static void f1123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-257);*r1p=r1;*r0p=r0;}
+static void f1124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,512);*r1p=r1;*r0p=r0;}
+static void f1125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-512);*r1p=r1;*r0p=r0;}
+static void f1126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,511);*r1p=r1;*r0p=r0;}
+static void f1127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-513);*r1p=r1;*r0p=r0;}
+static void f1128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,1024);*r1p=r1;*r0p=r0;}
+static void f1129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,1023);*r1p=r1;*r0p=r0;}
+static void f1131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,2048);*r1p=r1;*r0p=r0;}
+static void f1133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,2047);*r1p=r1;*r0p=r0;}
+static void f1135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,4096);*r1p=r1;*r0p=r0;}
+static void f1137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,4095);*r1p=r1;*r0p=r0;}
+static void f1139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,8192);*r1p=r1;*r0p=r0;}
+static void f1141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,8191);*r1p=r1;*r0p=r0;}
+static void f1143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,16384);*r1p=r1;*r0p=r0;}
+static void f1145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,16383);*r1p=r1;*r0p=r0;}
+static void f1147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,32768);*r1p=r1;*r0p=r0;}
+static void f1149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,32767);*r1p=r1;*r0p=r0;}
+static void f1151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,1);*r1p=r1;*r0p=r0;}
+static void f1153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-1);*r1p=r1;*r0p=r0;}
+static void f1154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,0);*r1p=r1;*r0p=r0;}
+static void f1155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-2);*r1p=r1;*r0p=r0;}
+static void f1156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,2);*r1p=r1;*r0p=r0;}
+static void f1157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-2);*r1p=r1;*r0p=r0;}
+static void f1158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,1);*r1p=r1;*r0p=r0;}
+static void f1159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-3);*r1p=r1;*r0p=r0;}
+static void f1160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,4);*r1p=r1;*r0p=r0;}
+static void f1161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-4);*r1p=r1;*r0p=r0;}
+static void f1162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,3);*r1p=r1;*r0p=r0;}
+static void f1163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-5);*r1p=r1;*r0p=r0;}
+static void f1164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,8);*r1p=r1;*r0p=r0;}
+static void f1165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-8);*r1p=r1;*r0p=r0;}
+static void f1166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,7);*r1p=r1;*r0p=r0;}
+static void f1167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-9);*r1p=r1;*r0p=r0;}
+static void f1168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,16);*r1p=r1;*r0p=r0;}
+static void f1169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-16);*r1p=r1;*r0p=r0;}
+static void f1170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,15);*r1p=r1;*r0p=r0;}
+static void f1171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-17);*r1p=r1;*r0p=r0;}
+static void f1172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,32);*r1p=r1;*r0p=r0;}
+static void f1173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-32);*r1p=r1;*r0p=r0;}
+static void f1174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,31);*r1p=r1;*r0p=r0;}
+static void f1175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-33);*r1p=r1;*r0p=r0;}
+static void f1176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,64);*r1p=r1;*r0p=r0;}
+static void f1177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-64);*r1p=r1;*r0p=r0;}
+static void f1178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,63);*r1p=r1;*r0p=r0;}
+static void f1179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-65);*r1p=r1;*r0p=r0;}
+static void f1180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,128);*r1p=r1;*r0p=r0;}
+static void f1181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-128);*r1p=r1;*r0p=r0;}
+static void f1182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,127);*r1p=r1;*r0p=r0;}
+static void f1183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-129);*r1p=r1;*r0p=r0;}
+static void f1184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,256);*r1p=r1;*r0p=r0;}
+static void f1185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-256);*r1p=r1;*r0p=r0;}
+static void f1186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,255);*r1p=r1;*r0p=r0;}
+static void f1187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-257);*r1p=r1;*r0p=r0;}
+static void f1188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,512);*r1p=r1;*r0p=r0;}
+static void f1189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-512);*r1p=r1;*r0p=r0;}
+static void f1190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,511);*r1p=r1;*r0p=r0;}
+static void f1191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-513);*r1p=r1;*r0p=r0;}
+static void f1192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,1024);*r1p=r1;*r0p=r0;}
+static void f1193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,1023);*r1p=r1;*r0p=r0;}
+static void f1195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,2048);*r1p=r1;*r0p=r0;}
+static void f1197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,2047);*r1p=r1;*r0p=r0;}
+static void f1199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,4096);*r1p=r1;*r0p=r0;}
+static void f1201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,4095);*r1p=r1;*r0p=r0;}
+static void f1203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,8192);*r1p=r1;*r0p=r0;}
+static void f1205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,8191);*r1p=r1;*r0p=r0;}
+static void f1207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,16384);*r1p=r1;*r0p=r0;}
+static void f1209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,16383);*r1p=r1;*r0p=r0;}
+static void f1211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,32768);*r1p=r1;*r0p=r0;}
+static void f1213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,32767);*r1p=r1;*r0p=r0;}
+static void f1215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,15,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,1);*r1p=r1;*r0p=r0;}
+static void f1217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-1);*r1p=r1;*r0p=r0;}
+static void f1218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,0);*r1p=r1;*r0p=r0;}
+static void f1219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-2);*r1p=r1;*r0p=r0;}
+static void f1220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,2);*r1p=r1;*r0p=r0;}
+static void f1221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-2);*r1p=r1;*r0p=r0;}
+static void f1222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,1);*r1p=r1;*r0p=r0;}
+static void f1223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-3);*r1p=r1;*r0p=r0;}
+static void f1224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,4);*r1p=r1;*r0p=r0;}
+static void f1225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-4);*r1p=r1;*r0p=r0;}
+static void f1226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,3);*r1p=r1;*r0p=r0;}
+static void f1227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-5);*r1p=r1;*r0p=r0;}
+static void f1228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,8);*r1p=r1;*r0p=r0;}
+static void f1229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-8);*r1p=r1;*r0p=r0;}
+static void f1230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,7);*r1p=r1;*r0p=r0;}
+static void f1231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-9);*r1p=r1;*r0p=r0;}
+static void f1232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,16);*r1p=r1;*r0p=r0;}
+static void f1233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-16);*r1p=r1;*r0p=r0;}
+static void f1234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,15);*r1p=r1;*r0p=r0;}
+static void f1235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-17);*r1p=r1;*r0p=r0;}
+static void f1236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,32);*r1p=r1;*r0p=r0;}
+static void f1237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-32);*r1p=r1;*r0p=r0;}
+static void f1238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,31);*r1p=r1;*r0p=r0;}
+static void f1239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-33);*r1p=r1;*r0p=r0;}
+static void f1240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,64);*r1p=r1;*r0p=r0;}
+static void f1241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-64);*r1p=r1;*r0p=r0;}
+static void f1242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,63);*r1p=r1;*r0p=r0;}
+static void f1243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-65);*r1p=r1;*r0p=r0;}
+static void f1244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,128);*r1p=r1;*r0p=r0;}
+static void f1245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-128);*r1p=r1;*r0p=r0;}
+static void f1246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,127);*r1p=r1;*r0p=r0;}
+static void f1247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-129);*r1p=r1;*r0p=r0;}
+static void f1248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,256);*r1p=r1;*r0p=r0;}
+static void f1249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-256);*r1p=r1;*r0p=r0;}
+static void f1250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,255);*r1p=r1;*r0p=r0;}
+static void f1251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-257);*r1p=r1;*r0p=r0;}
+static void f1252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,512);*r1p=r1;*r0p=r0;}
+static void f1253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-512);*r1p=r1;*r0p=r0;}
+static void f1254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,511);*r1p=r1;*r0p=r0;}
+static void f1255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-513);*r1p=r1;*r0p=r0;}
+static void f1256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,1024);*r1p=r1;*r0p=r0;}
+static void f1257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,1023);*r1p=r1;*r0p=r0;}
+static void f1259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,2048);*r1p=r1;*r0p=r0;}
+static void f1261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,2047);*r1p=r1;*r0p=r0;}
+static void f1263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,4096);*r1p=r1;*r0p=r0;}
+static void f1265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,4095);*r1p=r1;*r0p=r0;}
+static void f1267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,8192);*r1p=r1;*r0p=r0;}
+static void f1269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,8191);*r1p=r1;*r0p=r0;}
+static void f1271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,16384);*r1p=r1;*r0p=r0;}
+static void f1273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,16383);*r1p=r1;*r0p=r0;}
+static void f1275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,32768);*r1p=r1;*r0p=r0;}
+static void f1277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,32767);*r1p=r1;*r0p=r0;}
+static void f1279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-17,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,1);*r1p=r1;*r0p=r0;}
+static void f1281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-1);*r1p=r1;*r0p=r0;}
+static void f1282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,0);*r1p=r1;*r0p=r0;}
+static void f1283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,2);*r1p=r1;*r0p=r0;}
+static void f1285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,1);*r1p=r1;*r0p=r0;}
+static void f1287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-3);*r1p=r1;*r0p=r0;}
+static void f1288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,4);*r1p=r1;*r0p=r0;}
+static void f1289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-4);*r1p=r1;*r0p=r0;}
+static void f1290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,3);*r1p=r1;*r0p=r0;}
+static void f1291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-5);*r1p=r1;*r0p=r0;}
+static void f1292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,8);*r1p=r1;*r0p=r0;}
+static void f1293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-8);*r1p=r1;*r0p=r0;}
+static void f1294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,7);*r1p=r1;*r0p=r0;}
+static void f1295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-9);*r1p=r1;*r0p=r0;}
+static void f1296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,16);*r1p=r1;*r0p=r0;}
+static void f1297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-16);*r1p=r1;*r0p=r0;}
+static void f1298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,15);*r1p=r1;*r0p=r0;}
+static void f1299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-17);*r1p=r1;*r0p=r0;}
+static void f1300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,32);*r1p=r1;*r0p=r0;}
+static void f1301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-32);*r1p=r1;*r0p=r0;}
+static void f1302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,31);*r1p=r1;*r0p=r0;}
+static void f1303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-33);*r1p=r1;*r0p=r0;}
+static void f1304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,64);*r1p=r1;*r0p=r0;}
+static void f1305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-64);*r1p=r1;*r0p=r0;}
+static void f1306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,63);*r1p=r1;*r0p=r0;}
+static void f1307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-65);*r1p=r1;*r0p=r0;}
+static void f1308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,128);*r1p=r1;*r0p=r0;}
+static void f1309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-128);*r1p=r1;*r0p=r0;}
+static void f1310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,127);*r1p=r1;*r0p=r0;}
+static void f1311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-129);*r1p=r1;*r0p=r0;}
+static void f1312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,256);*r1p=r1;*r0p=r0;}
+static void f1313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-256);*r1p=r1;*r0p=r0;}
+static void f1314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,255);*r1p=r1;*r0p=r0;}
+static void f1315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-257);*r1p=r1;*r0p=r0;}
+static void f1316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,512);*r1p=r1;*r0p=r0;}
+static void f1317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-512);*r1p=r1;*r0p=r0;}
+static void f1318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,511);*r1p=r1;*r0p=r0;}
+static void f1319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-513);*r1p=r1;*r0p=r0;}
+static void f1320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,1024);*r1p=r1;*r0p=r0;}
+static void f1321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,1023);*r1p=r1;*r0p=r0;}
+static void f1323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,2048);*r1p=r1;*r0p=r0;}
+static void f1325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,2047);*r1p=r1;*r0p=r0;}
+static void f1327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,4096);*r1p=r1;*r0p=r0;}
+static void f1329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,4095);*r1p=r1;*r0p=r0;}
+static void f1331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,8192);*r1p=r1;*r0p=r0;}
+static void f1333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,8191);*r1p=r1;*r0p=r0;}
+static void f1335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,16384);*r1p=r1;*r0p=r0;}
+static void f1337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,16383);*r1p=r1;*r0p=r0;}
+static void f1339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,32768);*r1p=r1;*r0p=r0;}
+static void f1341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,32767);*r1p=r1;*r0p=r0;}
+static void f1343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,1);*r1p=r1;*r0p=r0;}
+static void f1345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-1);*r1p=r1;*r0p=r0;}
+static void f1346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,0);*r1p=r1;*r0p=r0;}
+static void f1347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,2);*r1p=r1;*r0p=r0;}
+static void f1349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-2);*r1p=r1;*r0p=r0;}
+static void f1350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,1);*r1p=r1;*r0p=r0;}
+static void f1351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-3);*r1p=r1;*r0p=r0;}
+static void f1352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,4);*r1p=r1;*r0p=r0;}
+static void f1353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-4);*r1p=r1;*r0p=r0;}
+static void f1354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,3);*r1p=r1;*r0p=r0;}
+static void f1355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-5);*r1p=r1;*r0p=r0;}
+static void f1356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,8);*r1p=r1;*r0p=r0;}
+static void f1357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-8);*r1p=r1;*r0p=r0;}
+static void f1358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,7);*r1p=r1;*r0p=r0;}
+static void f1359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-9);*r1p=r1;*r0p=r0;}
+static void f1360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,16);*r1p=r1;*r0p=r0;}
+static void f1361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-16);*r1p=r1;*r0p=r0;}
+static void f1362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,15);*r1p=r1;*r0p=r0;}
+static void f1363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-17);*r1p=r1;*r0p=r0;}
+static void f1364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,32);*r1p=r1;*r0p=r0;}
+static void f1365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-32);*r1p=r1;*r0p=r0;}
+static void f1366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,31);*r1p=r1;*r0p=r0;}
+static void f1367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-33);*r1p=r1;*r0p=r0;}
+static void f1368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,64);*r1p=r1;*r0p=r0;}
+static void f1369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-64);*r1p=r1;*r0p=r0;}
+static void f1370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,63);*r1p=r1;*r0p=r0;}
+static void f1371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-65);*r1p=r1;*r0p=r0;}
+static void f1372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,128);*r1p=r1;*r0p=r0;}
+static void f1373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-128);*r1p=r1;*r0p=r0;}
+static void f1374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,127);*r1p=r1;*r0p=r0;}
+static void f1375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-129);*r1p=r1;*r0p=r0;}
+static void f1376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,256);*r1p=r1;*r0p=r0;}
+static void f1377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-256);*r1p=r1;*r0p=r0;}
+static void f1378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,255);*r1p=r1;*r0p=r0;}
+static void f1379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-257);*r1p=r1;*r0p=r0;}
+static void f1380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,512);*r1p=r1;*r0p=r0;}
+static void f1381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-512);*r1p=r1;*r0p=r0;}
+static void f1382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,511);*r1p=r1;*r0p=r0;}
+static void f1383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-513);*r1p=r1;*r0p=r0;}
+static void f1384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,1024);*r1p=r1;*r0p=r0;}
+static void f1385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,1023);*r1p=r1;*r0p=r0;}
+static void f1387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,2048);*r1p=r1;*r0p=r0;}
+static void f1389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,2047);*r1p=r1;*r0p=r0;}
+static void f1391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,4096);*r1p=r1;*r0p=r0;}
+static void f1393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,4095);*r1p=r1;*r0p=r0;}
+static void f1395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,8192);*r1p=r1;*r0p=r0;}
+static void f1397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,8191);*r1p=r1;*r0p=r0;}
+static void f1399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,16384);*r1p=r1;*r0p=r0;}
+static void f1401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,16383);*r1p=r1;*r0p=r0;}
+static void f1403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,32768);*r1p=r1;*r0p=r0;}
+static void f1405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,32767);*r1p=r1;*r0p=r0;}
+static void f1407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,1);*r1p=r1;*r0p=r0;}
+static void f1409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-1);*r1p=r1;*r0p=r0;}
+static void f1410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,0);*r1p=r1;*r0p=r0;}
+static void f1411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-2);*r1p=r1;*r0p=r0;}
+static void f1412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,2);*r1p=r1;*r0p=r0;}
+static void f1413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-2);*r1p=r1;*r0p=r0;}
+static void f1414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,1);*r1p=r1;*r0p=r0;}
+static void f1415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-3);*r1p=r1;*r0p=r0;}
+static void f1416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,4);*r1p=r1;*r0p=r0;}
+static void f1417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-4);*r1p=r1;*r0p=r0;}
+static void f1418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,3);*r1p=r1;*r0p=r0;}
+static void f1419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-5);*r1p=r1;*r0p=r0;}
+static void f1420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,8);*r1p=r1;*r0p=r0;}
+static void f1421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-8);*r1p=r1;*r0p=r0;}
+static void f1422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,7);*r1p=r1;*r0p=r0;}
+static void f1423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-9);*r1p=r1;*r0p=r0;}
+static void f1424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,16);*r1p=r1;*r0p=r0;}
+static void f1425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-16);*r1p=r1;*r0p=r0;}
+static void f1426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,15);*r1p=r1;*r0p=r0;}
+static void f1427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-17);*r1p=r1;*r0p=r0;}
+static void f1428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,32);*r1p=r1;*r0p=r0;}
+static void f1429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-32);*r1p=r1;*r0p=r0;}
+static void f1430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,31);*r1p=r1;*r0p=r0;}
+static void f1431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-33);*r1p=r1;*r0p=r0;}
+static void f1432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,64);*r1p=r1;*r0p=r0;}
+static void f1433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-64);*r1p=r1;*r0p=r0;}
+static void f1434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,63);*r1p=r1;*r0p=r0;}
+static void f1435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-65);*r1p=r1;*r0p=r0;}
+static void f1436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,128);*r1p=r1;*r0p=r0;}
+static void f1437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-128);*r1p=r1;*r0p=r0;}
+static void f1438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,127);*r1p=r1;*r0p=r0;}
+static void f1439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-129);*r1p=r1;*r0p=r0;}
+static void f1440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,256);*r1p=r1;*r0p=r0;}
+static void f1441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-256);*r1p=r1;*r0p=r0;}
+static void f1442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,255);*r1p=r1;*r0p=r0;}
+static void f1443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-257);*r1p=r1;*r0p=r0;}
+static void f1444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,512);*r1p=r1;*r0p=r0;}
+static void f1445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-512);*r1p=r1;*r0p=r0;}
+static void f1446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,511);*r1p=r1;*r0p=r0;}
+static void f1447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-513);*r1p=r1;*r0p=r0;}
+static void f1448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,1024);*r1p=r1;*r0p=r0;}
+static void f1449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,1023);*r1p=r1;*r0p=r0;}
+static void f1451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,2048);*r1p=r1;*r0p=r0;}
+static void f1453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,2047);*r1p=r1;*r0p=r0;}
+static void f1455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,4096);*r1p=r1;*r0p=r0;}
+static void f1457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,4095);*r1p=r1;*r0p=r0;}
+static void f1459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,8192);*r1p=r1;*r0p=r0;}
+static void f1461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,8191);*r1p=r1;*r0p=r0;}
+static void f1463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,16384);*r1p=r1;*r0p=r0;}
+static void f1465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,16383);*r1p=r1;*r0p=r0;}
+static void f1467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,32768);*r1p=r1;*r0p=r0;}
+static void f1469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,32767);*r1p=r1;*r0p=r0;}
+static void f1471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,31,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,1);*r1p=r1;*r0p=r0;}
+static void f1473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-1);*r1p=r1;*r0p=r0;}
+static void f1474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,0);*r1p=r1;*r0p=r0;}
+static void f1475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-2);*r1p=r1;*r0p=r0;}
+static void f1476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,2);*r1p=r1;*r0p=r0;}
+static void f1477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-2);*r1p=r1;*r0p=r0;}
+static void f1478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,1);*r1p=r1;*r0p=r0;}
+static void f1479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-3);*r1p=r1;*r0p=r0;}
+static void f1480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,4);*r1p=r1;*r0p=r0;}
+static void f1481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-4);*r1p=r1;*r0p=r0;}
+static void f1482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,3);*r1p=r1;*r0p=r0;}
+static void f1483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-5);*r1p=r1;*r0p=r0;}
+static void f1484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,8);*r1p=r1;*r0p=r0;}
+static void f1485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-8);*r1p=r1;*r0p=r0;}
+static void f1486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,7);*r1p=r1;*r0p=r0;}
+static void f1487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-9);*r1p=r1;*r0p=r0;}
+static void f1488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,16);*r1p=r1;*r0p=r0;}
+static void f1489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-16);*r1p=r1;*r0p=r0;}
+static void f1490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,15);*r1p=r1;*r0p=r0;}
+static void f1491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-17);*r1p=r1;*r0p=r0;}
+static void f1492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,32);*r1p=r1;*r0p=r0;}
+static void f1493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-32);*r1p=r1;*r0p=r0;}
+static void f1494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,31);*r1p=r1;*r0p=r0;}
+static void f1495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-33);*r1p=r1;*r0p=r0;}
+static void f1496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,64);*r1p=r1;*r0p=r0;}
+static void f1497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-64);*r1p=r1;*r0p=r0;}
+static void f1498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,63);*r1p=r1;*r0p=r0;}
+static void f1499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-65);*r1p=r1;*r0p=r0;}
+static void f1500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,128);*r1p=r1;*r0p=r0;}
+static void f1501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-128);*r1p=r1;*r0p=r0;}
+static void f1502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,127);*r1p=r1;*r0p=r0;}
+static void f1503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-129);*r1p=r1;*r0p=r0;}
+static void f1504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,256);*r1p=r1;*r0p=r0;}
+static void f1505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-256);*r1p=r1;*r0p=r0;}
+static void f1506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,255);*r1p=r1;*r0p=r0;}
+static void f1507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-257);*r1p=r1;*r0p=r0;}
+static void f1508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,512);*r1p=r1;*r0p=r0;}
+static void f1509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-512);*r1p=r1;*r0p=r0;}
+static void f1510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,511);*r1p=r1;*r0p=r0;}
+static void f1511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-513);*r1p=r1;*r0p=r0;}
+static void f1512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,1024);*r1p=r1;*r0p=r0;}
+static void f1513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,1023);*r1p=r1;*r0p=r0;}
+static void f1515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,2048);*r1p=r1;*r0p=r0;}
+static void f1517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,2047);*r1p=r1;*r0p=r0;}
+static void f1519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,4096);*r1p=r1;*r0p=r0;}
+static void f1521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,4095);*r1p=r1;*r0p=r0;}
+static void f1523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,8192);*r1p=r1;*r0p=r0;}
+static void f1525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,8191);*r1p=r1;*r0p=r0;}
+static void f1527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,16384);*r1p=r1;*r0p=r0;}
+static void f1529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,16383);*r1p=r1;*r0p=r0;}
+static void f1531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,32768);*r1p=r1;*r0p=r0;}
+static void f1533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,32767);*r1p=r1;*r0p=r0;}
+static void f1535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-33,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,1);*r1p=r1;*r0p=r0;}
+static void f1537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-1);*r1p=r1;*r0p=r0;}
+static void f1538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,0);*r1p=r1;*r0p=r0;}
+static void f1539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,2);*r1p=r1;*r0p=r0;}
+static void f1541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,1);*r1p=r1;*r0p=r0;}
+static void f1543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-3);*r1p=r1;*r0p=r0;}
+static void f1544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,4);*r1p=r1;*r0p=r0;}
+static void f1545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-4);*r1p=r1;*r0p=r0;}
+static void f1546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,3);*r1p=r1;*r0p=r0;}
+static void f1547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-5);*r1p=r1;*r0p=r0;}
+static void f1548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,8);*r1p=r1;*r0p=r0;}
+static void f1549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-8);*r1p=r1;*r0p=r0;}
+static void f1550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,7);*r1p=r1;*r0p=r0;}
+static void f1551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-9);*r1p=r1;*r0p=r0;}
+static void f1552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,16);*r1p=r1;*r0p=r0;}
+static void f1553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-16);*r1p=r1;*r0p=r0;}
+static void f1554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,15);*r1p=r1;*r0p=r0;}
+static void f1555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-17);*r1p=r1;*r0p=r0;}
+static void f1556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,32);*r1p=r1;*r0p=r0;}
+static void f1557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-32);*r1p=r1;*r0p=r0;}
+static void f1558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,31);*r1p=r1;*r0p=r0;}
+static void f1559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-33);*r1p=r1;*r0p=r0;}
+static void f1560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,64);*r1p=r1;*r0p=r0;}
+static void f1561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-64);*r1p=r1;*r0p=r0;}
+static void f1562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,63);*r1p=r1;*r0p=r0;}
+static void f1563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-65);*r1p=r1;*r0p=r0;}
+static void f1564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,128);*r1p=r1;*r0p=r0;}
+static void f1565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-128);*r1p=r1;*r0p=r0;}
+static void f1566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,127);*r1p=r1;*r0p=r0;}
+static void f1567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-129);*r1p=r1;*r0p=r0;}
+static void f1568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,256);*r1p=r1;*r0p=r0;}
+static void f1569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-256);*r1p=r1;*r0p=r0;}
+static void f1570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,255);*r1p=r1;*r0p=r0;}
+static void f1571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-257);*r1p=r1;*r0p=r0;}
+static void f1572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,512);*r1p=r1;*r0p=r0;}
+static void f1573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-512);*r1p=r1;*r0p=r0;}
+static void f1574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,511);*r1p=r1;*r0p=r0;}
+static void f1575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-513);*r1p=r1;*r0p=r0;}
+static void f1576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,1024);*r1p=r1;*r0p=r0;}
+static void f1577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,1023);*r1p=r1;*r0p=r0;}
+static void f1579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,2048);*r1p=r1;*r0p=r0;}
+static void f1581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,2047);*r1p=r1;*r0p=r0;}
+static void f1583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,4096);*r1p=r1;*r0p=r0;}
+static void f1585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,4095);*r1p=r1;*r0p=r0;}
+static void f1587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,8192);*r1p=r1;*r0p=r0;}
+static void f1589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,8191);*r1p=r1;*r0p=r0;}
+static void f1591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,16384);*r1p=r1;*r0p=r0;}
+static void f1593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,16383);*r1p=r1;*r0p=r0;}
+static void f1595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,32768);*r1p=r1;*r0p=r0;}
+static void f1597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,32767);*r1p=r1;*r0p=r0;}
+static void f1599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,64,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,1);*r1p=r1;*r0p=r0;}
+static void f1601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-1);*r1p=r1;*r0p=r0;}
+static void f1602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,0);*r1p=r1;*r0p=r0;}
+static void f1603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,2);*r1p=r1;*r0p=r0;}
+static void f1605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-2);*r1p=r1;*r0p=r0;}
+static void f1606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,1);*r1p=r1;*r0p=r0;}
+static void f1607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-3);*r1p=r1;*r0p=r0;}
+static void f1608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,4);*r1p=r1;*r0p=r0;}
+static void f1609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-4);*r1p=r1;*r0p=r0;}
+static void f1610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,3);*r1p=r1;*r0p=r0;}
+static void f1611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-5);*r1p=r1;*r0p=r0;}
+static void f1612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,8);*r1p=r1;*r0p=r0;}
+static void f1613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-8);*r1p=r1;*r0p=r0;}
+static void f1614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,7);*r1p=r1;*r0p=r0;}
+static void f1615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-9);*r1p=r1;*r0p=r0;}
+static void f1616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,16);*r1p=r1;*r0p=r0;}
+static void f1617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-16);*r1p=r1;*r0p=r0;}
+static void f1618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,15);*r1p=r1;*r0p=r0;}
+static void f1619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-17);*r1p=r1;*r0p=r0;}
+static void f1620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,32);*r1p=r1;*r0p=r0;}
+static void f1621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-32);*r1p=r1;*r0p=r0;}
+static void f1622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,31);*r1p=r1;*r0p=r0;}
+static void f1623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-33);*r1p=r1;*r0p=r0;}
+static void f1624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,64);*r1p=r1;*r0p=r0;}
+static void f1625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-64);*r1p=r1;*r0p=r0;}
+static void f1626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,63);*r1p=r1;*r0p=r0;}
+static void f1627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-65);*r1p=r1;*r0p=r0;}
+static void f1628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,128);*r1p=r1;*r0p=r0;}
+static void f1629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-128);*r1p=r1;*r0p=r0;}
+static void f1630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,127);*r1p=r1;*r0p=r0;}
+static void f1631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-129);*r1p=r1;*r0p=r0;}
+static void f1632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,256);*r1p=r1;*r0p=r0;}
+static void f1633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-256);*r1p=r1;*r0p=r0;}
+static void f1634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,255);*r1p=r1;*r0p=r0;}
+static void f1635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-257);*r1p=r1;*r0p=r0;}
+static void f1636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,512);*r1p=r1;*r0p=r0;}
+static void f1637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-512);*r1p=r1;*r0p=r0;}
+static void f1638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,511);*r1p=r1;*r0p=r0;}
+static void f1639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-513);*r1p=r1;*r0p=r0;}
+static void f1640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,1024);*r1p=r1;*r0p=r0;}
+static void f1641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,1023);*r1p=r1;*r0p=r0;}
+static void f1643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,2048);*r1p=r1;*r0p=r0;}
+static void f1645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,2047);*r1p=r1;*r0p=r0;}
+static void f1647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,4096);*r1p=r1;*r0p=r0;}
+static void f1649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,4095);*r1p=r1;*r0p=r0;}
+static void f1651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,8192);*r1p=r1;*r0p=r0;}
+static void f1653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,8191);*r1p=r1;*r0p=r0;}
+static void f1655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,16384);*r1p=r1;*r0p=r0;}
+static void f1657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,16383);*r1p=r1;*r0p=r0;}
+static void f1659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,32768);*r1p=r1;*r0p=r0;}
+static void f1661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,32767);*r1p=r1;*r0p=r0;}
+static void f1663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-64,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,1);*r1p=r1;*r0p=r0;}
+static void f1665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-1);*r1p=r1;*r0p=r0;}
+static void f1666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,0);*r1p=r1;*r0p=r0;}
+static void f1667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-2);*r1p=r1;*r0p=r0;}
+static void f1668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,2);*r1p=r1;*r0p=r0;}
+static void f1669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-2);*r1p=r1;*r0p=r0;}
+static void f1670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,1);*r1p=r1;*r0p=r0;}
+static void f1671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-3);*r1p=r1;*r0p=r0;}
+static void f1672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,4);*r1p=r1;*r0p=r0;}
+static void f1673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-4);*r1p=r1;*r0p=r0;}
+static void f1674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,3);*r1p=r1;*r0p=r0;}
+static void f1675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-5);*r1p=r1;*r0p=r0;}
+static void f1676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,8);*r1p=r1;*r0p=r0;}
+static void f1677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-8);*r1p=r1;*r0p=r0;}
+static void f1678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,7);*r1p=r1;*r0p=r0;}
+static void f1679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-9);*r1p=r1;*r0p=r0;}
+static void f1680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,16);*r1p=r1;*r0p=r0;}
+static void f1681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-16);*r1p=r1;*r0p=r0;}
+static void f1682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,15);*r1p=r1;*r0p=r0;}
+static void f1683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-17);*r1p=r1;*r0p=r0;}
+static void f1684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,32);*r1p=r1;*r0p=r0;}
+static void f1685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-32);*r1p=r1;*r0p=r0;}
+static void f1686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,31);*r1p=r1;*r0p=r0;}
+static void f1687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-33);*r1p=r1;*r0p=r0;}
+static void f1688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,64);*r1p=r1;*r0p=r0;}
+static void f1689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-64);*r1p=r1;*r0p=r0;}
+static void f1690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,63);*r1p=r1;*r0p=r0;}
+static void f1691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-65);*r1p=r1;*r0p=r0;}
+static void f1692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,128);*r1p=r1;*r0p=r0;}
+static void f1693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-128);*r1p=r1;*r0p=r0;}
+static void f1694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,127);*r1p=r1;*r0p=r0;}
+static void f1695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-129);*r1p=r1;*r0p=r0;}
+static void f1696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,256);*r1p=r1;*r0p=r0;}
+static void f1697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-256);*r1p=r1;*r0p=r0;}
+static void f1698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,255);*r1p=r1;*r0p=r0;}
+static void f1699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-257);*r1p=r1;*r0p=r0;}
+static void f1700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,512);*r1p=r1;*r0p=r0;}
+static void f1701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-512);*r1p=r1;*r0p=r0;}
+static void f1702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,511);*r1p=r1;*r0p=r0;}
+static void f1703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-513);*r1p=r1;*r0p=r0;}
+static void f1704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,1024);*r1p=r1;*r0p=r0;}
+static void f1705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,1023);*r1p=r1;*r0p=r0;}
+static void f1707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,2048);*r1p=r1;*r0p=r0;}
+static void f1709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,2047);*r1p=r1;*r0p=r0;}
+static void f1711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,4096);*r1p=r1;*r0p=r0;}
+static void f1713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,4095);*r1p=r1;*r0p=r0;}
+static void f1715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,8192);*r1p=r1;*r0p=r0;}
+static void f1717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,8191);*r1p=r1;*r0p=r0;}
+static void f1719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,16384);*r1p=r1;*r0p=r0;}
+static void f1721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,16383);*r1p=r1;*r0p=r0;}
+static void f1723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,32768);*r1p=r1;*r0p=r0;}
+static void f1725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,32767);*r1p=r1;*r0p=r0;}
+static void f1727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,63,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,1);*r1p=r1;*r0p=r0;}
+static void f1729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-1);*r1p=r1;*r0p=r0;}
+static void f1730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,0);*r1p=r1;*r0p=r0;}
+static void f1731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-2);*r1p=r1;*r0p=r0;}
+static void f1732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,2);*r1p=r1;*r0p=r0;}
+static void f1733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-2);*r1p=r1;*r0p=r0;}
+static void f1734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,1);*r1p=r1;*r0p=r0;}
+static void f1735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-3);*r1p=r1;*r0p=r0;}
+static void f1736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,4);*r1p=r1;*r0p=r0;}
+static void f1737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-4);*r1p=r1;*r0p=r0;}
+static void f1738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,3);*r1p=r1;*r0p=r0;}
+static void f1739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-5);*r1p=r1;*r0p=r0;}
+static void f1740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,8);*r1p=r1;*r0p=r0;}
+static void f1741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-8);*r1p=r1;*r0p=r0;}
+static void f1742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,7);*r1p=r1;*r0p=r0;}
+static void f1743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-9);*r1p=r1;*r0p=r0;}
+static void f1744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,16);*r1p=r1;*r0p=r0;}
+static void f1745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-16);*r1p=r1;*r0p=r0;}
+static void f1746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,15);*r1p=r1;*r0p=r0;}
+static void f1747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-17);*r1p=r1;*r0p=r0;}
+static void f1748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,32);*r1p=r1;*r0p=r0;}
+static void f1749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-32);*r1p=r1;*r0p=r0;}
+static void f1750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,31);*r1p=r1;*r0p=r0;}
+static void f1751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-33);*r1p=r1;*r0p=r0;}
+static void f1752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,64);*r1p=r1;*r0p=r0;}
+static void f1753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-64);*r1p=r1;*r0p=r0;}
+static void f1754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,63);*r1p=r1;*r0p=r0;}
+static void f1755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-65);*r1p=r1;*r0p=r0;}
+static void f1756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,128);*r1p=r1;*r0p=r0;}
+static void f1757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-128);*r1p=r1;*r0p=r0;}
+static void f1758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,127);*r1p=r1;*r0p=r0;}
+static void f1759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-129);*r1p=r1;*r0p=r0;}
+static void f1760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,256);*r1p=r1;*r0p=r0;}
+static void f1761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-256);*r1p=r1;*r0p=r0;}
+static void f1762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,255);*r1p=r1;*r0p=r0;}
+static void f1763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-257);*r1p=r1;*r0p=r0;}
+static void f1764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,512);*r1p=r1;*r0p=r0;}
+static void f1765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-512);*r1p=r1;*r0p=r0;}
+static void f1766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,511);*r1p=r1;*r0p=r0;}
+static void f1767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-513);*r1p=r1;*r0p=r0;}
+static void f1768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,1024);*r1p=r1;*r0p=r0;}
+static void f1769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,1023);*r1p=r1;*r0p=r0;}
+static void f1771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,2048);*r1p=r1;*r0p=r0;}
+static void f1773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,2047);*r1p=r1;*r0p=r0;}
+static void f1775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,4096);*r1p=r1;*r0p=r0;}
+static void f1777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,4095);*r1p=r1;*r0p=r0;}
+static void f1779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,8192);*r1p=r1;*r0p=r0;}
+static void f1781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,8191);*r1p=r1;*r0p=r0;}
+static void f1783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,16384);*r1p=r1;*r0p=r0;}
+static void f1785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,16383);*r1p=r1;*r0p=r0;}
+static void f1787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,32768);*r1p=r1;*r0p=r0;}
+static void f1789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,32767);*r1p=r1;*r0p=r0;}
+static void f1791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-65,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,1);*r1p=r1;*r0p=r0;}
+static void f1793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-1);*r1p=r1;*r0p=r0;}
+static void f1794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,0);*r1p=r1;*r0p=r0;}
+static void f1795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,2);*r1p=r1;*r0p=r0;}
+static void f1797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,1);*r1p=r1;*r0p=r0;}
+static void f1799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-3);*r1p=r1;*r0p=r0;}
+static void f1800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,4);*r1p=r1;*r0p=r0;}
+static void f1801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-4);*r1p=r1;*r0p=r0;}
+static void f1802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,3);*r1p=r1;*r0p=r0;}
+static void f1803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-5);*r1p=r1;*r0p=r0;}
+static void f1804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,8);*r1p=r1;*r0p=r0;}
+static void f1805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-8);*r1p=r1;*r0p=r0;}
+static void f1806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,7);*r1p=r1;*r0p=r0;}
+static void f1807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-9);*r1p=r1;*r0p=r0;}
+static void f1808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,16);*r1p=r1;*r0p=r0;}
+static void f1809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-16);*r1p=r1;*r0p=r0;}
+static void f1810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,15);*r1p=r1;*r0p=r0;}
+static void f1811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-17);*r1p=r1;*r0p=r0;}
+static void f1812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,32);*r1p=r1;*r0p=r0;}
+static void f1813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-32);*r1p=r1;*r0p=r0;}
+static void f1814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,31);*r1p=r1;*r0p=r0;}
+static void f1815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-33);*r1p=r1;*r0p=r0;}
+static void f1816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,64);*r1p=r1;*r0p=r0;}
+static void f1817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-64);*r1p=r1;*r0p=r0;}
+static void f1818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,63);*r1p=r1;*r0p=r0;}
+static void f1819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-65);*r1p=r1;*r0p=r0;}
+static void f1820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,128);*r1p=r1;*r0p=r0;}
+static void f1821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-128);*r1p=r1;*r0p=r0;}
+static void f1822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,127);*r1p=r1;*r0p=r0;}
+static void f1823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-129);*r1p=r1;*r0p=r0;}
+static void f1824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,256);*r1p=r1;*r0p=r0;}
+static void f1825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-256);*r1p=r1;*r0p=r0;}
+static void f1826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,255);*r1p=r1;*r0p=r0;}
+static void f1827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-257);*r1p=r1;*r0p=r0;}
+static void f1828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,512);*r1p=r1;*r0p=r0;}
+static void f1829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-512);*r1p=r1;*r0p=r0;}
+static void f1830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,511);*r1p=r1;*r0p=r0;}
+static void f1831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-513);*r1p=r1;*r0p=r0;}
+static void f1832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,1024);*r1p=r1;*r0p=r0;}
+static void f1833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,1023);*r1p=r1;*r0p=r0;}
+static void f1835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,2048);*r1p=r1;*r0p=r0;}
+static void f1837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,2047);*r1p=r1;*r0p=r0;}
+static void f1839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,4096);*r1p=r1;*r0p=r0;}
+static void f1841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,4095);*r1p=r1;*r0p=r0;}
+static void f1843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,8192);*r1p=r1;*r0p=r0;}
+static void f1845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,8191);*r1p=r1;*r0p=r0;}
+static void f1847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,16384);*r1p=r1;*r0p=r0;}
+static void f1849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,16383);*r1p=r1;*r0p=r0;}
+static void f1851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,32768);*r1p=r1;*r0p=r0;}
+static void f1853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,32767);*r1p=r1;*r0p=r0;}
+static void f1855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,128,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,1);*r1p=r1;*r0p=r0;}
+static void f1857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-1);*r1p=r1;*r0p=r0;}
+static void f1858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,0);*r1p=r1;*r0p=r0;}
+static void f1859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,2);*r1p=r1;*r0p=r0;}
+static void f1861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-2);*r1p=r1;*r0p=r0;}
+static void f1862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,1);*r1p=r1;*r0p=r0;}
+static void f1863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-3);*r1p=r1;*r0p=r0;}
+static void f1864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,4);*r1p=r1;*r0p=r0;}
+static void f1865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-4);*r1p=r1;*r0p=r0;}
+static void f1866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,3);*r1p=r1;*r0p=r0;}
+static void f1867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-5);*r1p=r1;*r0p=r0;}
+static void f1868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,8);*r1p=r1;*r0p=r0;}
+static void f1869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-8);*r1p=r1;*r0p=r0;}
+static void f1870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,7);*r1p=r1;*r0p=r0;}
+static void f1871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-9);*r1p=r1;*r0p=r0;}
+static void f1872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,16);*r1p=r1;*r0p=r0;}
+static void f1873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-16);*r1p=r1;*r0p=r0;}
+static void f1874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,15);*r1p=r1;*r0p=r0;}
+static void f1875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-17);*r1p=r1;*r0p=r0;}
+static void f1876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,32);*r1p=r1;*r0p=r0;}
+static void f1877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-32);*r1p=r1;*r0p=r0;}
+static void f1878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,31);*r1p=r1;*r0p=r0;}
+static void f1879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-33);*r1p=r1;*r0p=r0;}
+static void f1880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,64);*r1p=r1;*r0p=r0;}
+static void f1881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-64);*r1p=r1;*r0p=r0;}
+static void f1882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,63);*r1p=r1;*r0p=r0;}
+static void f1883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-65);*r1p=r1;*r0p=r0;}
+static void f1884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,128);*r1p=r1;*r0p=r0;}
+static void f1885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-128);*r1p=r1;*r0p=r0;}
+static void f1886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,127);*r1p=r1;*r0p=r0;}
+static void f1887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-129);*r1p=r1;*r0p=r0;}
+static void f1888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,256);*r1p=r1;*r0p=r0;}
+static void f1889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-256);*r1p=r1;*r0p=r0;}
+static void f1890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,255);*r1p=r1;*r0p=r0;}
+static void f1891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-257);*r1p=r1;*r0p=r0;}
+static void f1892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,512);*r1p=r1;*r0p=r0;}
+static void f1893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-512);*r1p=r1;*r0p=r0;}
+static void f1894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,511);*r1p=r1;*r0p=r0;}
+static void f1895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-513);*r1p=r1;*r0p=r0;}
+static void f1896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,1024);*r1p=r1;*r0p=r0;}
+static void f1897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,1023);*r1p=r1;*r0p=r0;}
+static void f1899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,2048);*r1p=r1;*r0p=r0;}
+static void f1901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,2047);*r1p=r1;*r0p=r0;}
+static void f1903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,4096);*r1p=r1;*r0p=r0;}
+static void f1905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,4095);*r1p=r1;*r0p=r0;}
+static void f1907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,8192);*r1p=r1;*r0p=r0;}
+static void f1909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,8191);*r1p=r1;*r0p=r0;}
+static void f1911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,16384);*r1p=r1;*r0p=r0;}
+static void f1913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,16383);*r1p=r1;*r0p=r0;}
+static void f1915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,32768);*r1p=r1;*r0p=r0;}
+static void f1917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,32767);*r1p=r1;*r0p=r0;}
+static void f1919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-128,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,1);*r1p=r1;*r0p=r0;}
+static void f1921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-1);*r1p=r1;*r0p=r0;}
+static void f1922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,0);*r1p=r1;*r0p=r0;}
+static void f1923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-2);*r1p=r1;*r0p=r0;}
+static void f1924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,2);*r1p=r1;*r0p=r0;}
+static void f1925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-2);*r1p=r1;*r0p=r0;}
+static void f1926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,1);*r1p=r1;*r0p=r0;}
+static void f1927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-3);*r1p=r1;*r0p=r0;}
+static void f1928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,4);*r1p=r1;*r0p=r0;}
+static void f1929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-4);*r1p=r1;*r0p=r0;}
+static void f1930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,3);*r1p=r1;*r0p=r0;}
+static void f1931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-5);*r1p=r1;*r0p=r0;}
+static void f1932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,8);*r1p=r1;*r0p=r0;}
+static void f1933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-8);*r1p=r1;*r0p=r0;}
+static void f1934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,7);*r1p=r1;*r0p=r0;}
+static void f1935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-9);*r1p=r1;*r0p=r0;}
+static void f1936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,16);*r1p=r1;*r0p=r0;}
+static void f1937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-16);*r1p=r1;*r0p=r0;}
+static void f1938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,15);*r1p=r1;*r0p=r0;}
+static void f1939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-17);*r1p=r1;*r0p=r0;}
+static void f1940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,32);*r1p=r1;*r0p=r0;}
+static void f1941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-32);*r1p=r1;*r0p=r0;}
+static void f1942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,31);*r1p=r1;*r0p=r0;}
+static void f1943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-33);*r1p=r1;*r0p=r0;}
+static void f1944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,64);*r1p=r1;*r0p=r0;}
+static void f1945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-64);*r1p=r1;*r0p=r0;}
+static void f1946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,63);*r1p=r1;*r0p=r0;}
+static void f1947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-65);*r1p=r1;*r0p=r0;}
+static void f1948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,128);*r1p=r1;*r0p=r0;}
+static void f1949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-128);*r1p=r1;*r0p=r0;}
+static void f1950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,127);*r1p=r1;*r0p=r0;}
+static void f1951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-129);*r1p=r1;*r0p=r0;}
+static void f1952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,256);*r1p=r1;*r0p=r0;}
+static void f1953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-256);*r1p=r1;*r0p=r0;}
+static void f1954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,255);*r1p=r1;*r0p=r0;}
+static void f1955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-257);*r1p=r1;*r0p=r0;}
+static void f1956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,512);*r1p=r1;*r0p=r0;}
+static void f1957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-512);*r1p=r1;*r0p=r0;}
+static void f1958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,511);*r1p=r1;*r0p=r0;}
+static void f1959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-513);*r1p=r1;*r0p=r0;}
+static void f1960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,1024);*r1p=r1;*r0p=r0;}
+static void f1961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-1024);*r1p=r1;*r0p=r0;}
+static void f1962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,1023);*r1p=r1;*r0p=r0;}
+static void f1963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-1025);*r1p=r1;*r0p=r0;}
+static void f1964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,2048);*r1p=r1;*r0p=r0;}
+static void f1965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-2048);*r1p=r1;*r0p=r0;}
+static void f1966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,2047);*r1p=r1;*r0p=r0;}
+static void f1967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-2049);*r1p=r1;*r0p=r0;}
+static void f1968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,4096);*r1p=r1;*r0p=r0;}
+static void f1969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-4096);*r1p=r1;*r0p=r0;}
+static void f1970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,4095);*r1p=r1;*r0p=r0;}
+static void f1971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-4097);*r1p=r1;*r0p=r0;}
+static void f1972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,8192);*r1p=r1;*r0p=r0;}
+static void f1973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-8192);*r1p=r1;*r0p=r0;}
+static void f1974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,8191);*r1p=r1;*r0p=r0;}
+static void f1975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-8193);*r1p=r1;*r0p=r0;}
+static void f1976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,16384);*r1p=r1;*r0p=r0;}
+static void f1977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-16384);*r1p=r1;*r0p=r0;}
+static void f1978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,16383);*r1p=r1;*r0p=r0;}
+static void f1979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-16385);*r1p=r1;*r0p=r0;}
+static void f1980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,32768);*r1p=r1;*r0p=r0;}
+static void f1981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-32768);*r1p=r1;*r0p=r0;}
+static void f1982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,32767);*r1p=r1;*r0p=r0;}
+static void f1983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,127,0,-32769);*r1p=r1;*r0p=r0;}
+static void f1984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,1);*r1p=r1;*r0p=r0;}
+static void f1985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-1);*r1p=r1;*r0p=r0;}
+static void f1986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,0);*r1p=r1;*r0p=r0;}
+static void f1987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-2);*r1p=r1;*r0p=r0;}
+static void f1988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,2);*r1p=r1;*r0p=r0;}
+static void f1989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-2);*r1p=r1;*r0p=r0;}
+static void f1990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,1);*r1p=r1;*r0p=r0;}
+static void f1991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-3);*r1p=r1;*r0p=r0;}
+static void f1992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,4);*r1p=r1;*r0p=r0;}
+static void f1993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-4);*r1p=r1;*r0p=r0;}
+static void f1994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,3);*r1p=r1;*r0p=r0;}
+static void f1995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-5);*r1p=r1;*r0p=r0;}
+static void f1996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,8);*r1p=r1;*r0p=r0;}
+static void f1997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-8);*r1p=r1;*r0p=r0;}
+static void f1998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,7);*r1p=r1;*r0p=r0;}
+static void f1999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-9);*r1p=r1;*r0p=r0;}
+static void f2000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,16);*r1p=r1;*r0p=r0;}
+static void f2001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-16);*r1p=r1;*r0p=r0;}
+static void f2002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,15);*r1p=r1;*r0p=r0;}
+static void f2003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-17);*r1p=r1;*r0p=r0;}
+static void f2004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,32);*r1p=r1;*r0p=r0;}
+static void f2005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-32);*r1p=r1;*r0p=r0;}
+static void f2006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,31);*r1p=r1;*r0p=r0;}
+static void f2007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-33);*r1p=r1;*r0p=r0;}
+static void f2008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,64);*r1p=r1;*r0p=r0;}
+static void f2009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-64);*r1p=r1;*r0p=r0;}
+static void f2010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,63);*r1p=r1;*r0p=r0;}
+static void f2011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-65);*r1p=r1;*r0p=r0;}
+static void f2012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,128);*r1p=r1;*r0p=r0;}
+static void f2013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-128);*r1p=r1;*r0p=r0;}
+static void f2014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,127);*r1p=r1;*r0p=r0;}
+static void f2015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-129);*r1p=r1;*r0p=r0;}
+static void f2016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,256);*r1p=r1;*r0p=r0;}
+static void f2017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-256);*r1p=r1;*r0p=r0;}
+static void f2018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,255);*r1p=r1;*r0p=r0;}
+static void f2019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-257);*r1p=r1;*r0p=r0;}
+static void f2020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,512);*r1p=r1;*r0p=r0;}
+static void f2021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-512);*r1p=r1;*r0p=r0;}
+static void f2022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,511);*r1p=r1;*r0p=r0;}
+static void f2023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-513);*r1p=r1;*r0p=r0;}
+static void f2024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,1024);*r1p=r1;*r0p=r0;}
+static void f2025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,1023);*r1p=r1;*r0p=r0;}
+static void f2027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,2048);*r1p=r1;*r0p=r0;}
+static void f2029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,2047);*r1p=r1;*r0p=r0;}
+static void f2031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,4096);*r1p=r1;*r0p=r0;}
+static void f2033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,4095);*r1p=r1;*r0p=r0;}
+static void f2035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,8192);*r1p=r1;*r0p=r0;}
+static void f2037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,8191);*r1p=r1;*r0p=r0;}
+static void f2039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,16384);*r1p=r1;*r0p=r0;}
+static void f2041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,16383);*r1p=r1;*r0p=r0;}
+static void f2043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,32768);*r1p=r1;*r0p=r0;}
+static void f2045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,32767);*r1p=r1;*r0p=r0;}
+static void f2047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-129,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,1);*r1p=r1;*r0p=r0;}
+static void f2049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-1);*r1p=r1;*r0p=r0;}
+static void f2050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,0);*r1p=r1;*r0p=r0;}
+static void f2051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,2);*r1p=r1;*r0p=r0;}
+static void f2053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,1);*r1p=r1;*r0p=r0;}
+static void f2055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-3);*r1p=r1;*r0p=r0;}
+static void f2056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,4);*r1p=r1;*r0p=r0;}
+static void f2057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-4);*r1p=r1;*r0p=r0;}
+static void f2058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,3);*r1p=r1;*r0p=r0;}
+static void f2059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-5);*r1p=r1;*r0p=r0;}
+static void f2060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,8);*r1p=r1;*r0p=r0;}
+static void f2061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-8);*r1p=r1;*r0p=r0;}
+static void f2062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,7);*r1p=r1;*r0p=r0;}
+static void f2063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-9);*r1p=r1;*r0p=r0;}
+static void f2064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,16);*r1p=r1;*r0p=r0;}
+static void f2065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-16);*r1p=r1;*r0p=r0;}
+static void f2066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,15);*r1p=r1;*r0p=r0;}
+static void f2067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-17);*r1p=r1;*r0p=r0;}
+static void f2068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,32);*r1p=r1;*r0p=r0;}
+static void f2069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-32);*r1p=r1;*r0p=r0;}
+static void f2070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,31);*r1p=r1;*r0p=r0;}
+static void f2071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-33);*r1p=r1;*r0p=r0;}
+static void f2072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,64);*r1p=r1;*r0p=r0;}
+static void f2073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-64);*r1p=r1;*r0p=r0;}
+static void f2074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,63);*r1p=r1;*r0p=r0;}
+static void f2075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-65);*r1p=r1;*r0p=r0;}
+static void f2076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,128);*r1p=r1;*r0p=r0;}
+static void f2077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-128);*r1p=r1;*r0p=r0;}
+static void f2078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,127);*r1p=r1;*r0p=r0;}
+static void f2079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-129);*r1p=r1;*r0p=r0;}
+static void f2080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,256);*r1p=r1;*r0p=r0;}
+static void f2081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-256);*r1p=r1;*r0p=r0;}
+static void f2082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,255);*r1p=r1;*r0p=r0;}
+static void f2083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-257);*r1p=r1;*r0p=r0;}
+static void f2084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,512);*r1p=r1;*r0p=r0;}
+static void f2085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-512);*r1p=r1;*r0p=r0;}
+static void f2086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,511);*r1p=r1;*r0p=r0;}
+static void f2087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-513);*r1p=r1;*r0p=r0;}
+static void f2088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,1024);*r1p=r1;*r0p=r0;}
+static void f2089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,1023);*r1p=r1;*r0p=r0;}
+static void f2091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,2048);*r1p=r1;*r0p=r0;}
+static void f2093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,2047);*r1p=r1;*r0p=r0;}
+static void f2095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2096(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,4096);*r1p=r1;*r0p=r0;}
+static void f2097(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2098(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,4095);*r1p=r1;*r0p=r0;}
+static void f2099(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,8192);*r1p=r1;*r0p=r0;}
+static void f2101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,8191);*r1p=r1;*r0p=r0;}
+static void f2103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,16384);*r1p=r1;*r0p=r0;}
+static void f2105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,16383);*r1p=r1;*r0p=r0;}
+static void f2107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,32768);*r1p=r1;*r0p=r0;}
+static void f2109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,32767);*r1p=r1;*r0p=r0;}
+static void f2111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,256,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,1);*r1p=r1;*r0p=r0;}
+static void f2113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-1);*r1p=r1;*r0p=r0;}
+static void f2114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,0);*r1p=r1;*r0p=r0;}
+static void f2115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,2);*r1p=r1;*r0p=r0;}
+static void f2117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-2);*r1p=r1;*r0p=r0;}
+static void f2118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,1);*r1p=r1;*r0p=r0;}
+static void f2119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-3);*r1p=r1;*r0p=r0;}
+static void f2120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,4);*r1p=r1;*r0p=r0;}
+static void f2121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-4);*r1p=r1;*r0p=r0;}
+static void f2122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,3);*r1p=r1;*r0p=r0;}
+static void f2123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-5);*r1p=r1;*r0p=r0;}
+static void f2124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,8);*r1p=r1;*r0p=r0;}
+static void f2125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-8);*r1p=r1;*r0p=r0;}
+static void f2126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,7);*r1p=r1;*r0p=r0;}
+static void f2127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-9);*r1p=r1;*r0p=r0;}
+static void f2128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,16);*r1p=r1;*r0p=r0;}
+static void f2129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-16);*r1p=r1;*r0p=r0;}
+static void f2130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,15);*r1p=r1;*r0p=r0;}
+static void f2131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-17);*r1p=r1;*r0p=r0;}
+static void f2132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,32);*r1p=r1;*r0p=r0;}
+static void f2133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-32);*r1p=r1;*r0p=r0;}
+static void f2134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,31);*r1p=r1;*r0p=r0;}
+static void f2135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-33);*r1p=r1;*r0p=r0;}
+static void f2136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,64);*r1p=r1;*r0p=r0;}
+static void f2137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-64);*r1p=r1;*r0p=r0;}
+static void f2138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,63);*r1p=r1;*r0p=r0;}
+static void f2139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-65);*r1p=r1;*r0p=r0;}
+static void f2140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,128);*r1p=r1;*r0p=r0;}
+static void f2141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-128);*r1p=r1;*r0p=r0;}
+static void f2142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,127);*r1p=r1;*r0p=r0;}
+static void f2143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-129);*r1p=r1;*r0p=r0;}
+static void f2144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,256);*r1p=r1;*r0p=r0;}
+static void f2145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-256);*r1p=r1;*r0p=r0;}
+static void f2146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,255);*r1p=r1;*r0p=r0;}
+static void f2147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-257);*r1p=r1;*r0p=r0;}
+static void f2148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,512);*r1p=r1;*r0p=r0;}
+static void f2149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-512);*r1p=r1;*r0p=r0;}
+static void f2150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,511);*r1p=r1;*r0p=r0;}
+static void f2151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-513);*r1p=r1;*r0p=r0;}
+static void f2152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,1024);*r1p=r1;*r0p=r0;}
+static void f2153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,1023);*r1p=r1;*r0p=r0;}
+static void f2155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,2048);*r1p=r1;*r0p=r0;}
+static void f2157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,2047);*r1p=r1;*r0p=r0;}
+static void f2159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,4096);*r1p=r1;*r0p=r0;}
+static void f2161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,4095);*r1p=r1;*r0p=r0;}
+static void f2163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,8192);*r1p=r1;*r0p=r0;}
+static void f2165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,8191);*r1p=r1;*r0p=r0;}
+static void f2167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,16384);*r1p=r1;*r0p=r0;}
+static void f2169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,16383);*r1p=r1;*r0p=r0;}
+static void f2171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,32768);*r1p=r1;*r0p=r0;}
+static void f2173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,32767);*r1p=r1;*r0p=r0;}
+static void f2175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-256,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,1);*r1p=r1;*r0p=r0;}
+static void f2177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-1);*r1p=r1;*r0p=r0;}
+static void f2178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,0);*r1p=r1;*r0p=r0;}
+static void f2179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-2);*r1p=r1;*r0p=r0;}
+static void f2180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,2);*r1p=r1;*r0p=r0;}
+static void f2181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-2);*r1p=r1;*r0p=r0;}
+static void f2182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,1);*r1p=r1;*r0p=r0;}
+static void f2183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-3);*r1p=r1;*r0p=r0;}
+static void f2184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,4);*r1p=r1;*r0p=r0;}
+static void f2185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-4);*r1p=r1;*r0p=r0;}
+static void f2186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,3);*r1p=r1;*r0p=r0;}
+static void f2187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-5);*r1p=r1;*r0p=r0;}
+static void f2188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,8);*r1p=r1;*r0p=r0;}
+static void f2189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-8);*r1p=r1;*r0p=r0;}
+static void f2190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,7);*r1p=r1;*r0p=r0;}
+static void f2191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-9);*r1p=r1;*r0p=r0;}
+static void f2192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,16);*r1p=r1;*r0p=r0;}
+static void f2193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-16);*r1p=r1;*r0p=r0;}
+static void f2194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,15);*r1p=r1;*r0p=r0;}
+static void f2195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-17);*r1p=r1;*r0p=r0;}
+static void f2196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,32);*r1p=r1;*r0p=r0;}
+static void f2197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-32);*r1p=r1;*r0p=r0;}
+static void f2198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,31);*r1p=r1;*r0p=r0;}
+static void f2199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-33);*r1p=r1;*r0p=r0;}
+static void f2200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,64);*r1p=r1;*r0p=r0;}
+static void f2201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-64);*r1p=r1;*r0p=r0;}
+static void f2202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,63);*r1p=r1;*r0p=r0;}
+static void f2203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-65);*r1p=r1;*r0p=r0;}
+static void f2204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,128);*r1p=r1;*r0p=r0;}
+static void f2205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-128);*r1p=r1;*r0p=r0;}
+static void f2206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,127);*r1p=r1;*r0p=r0;}
+static void f2207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-129);*r1p=r1;*r0p=r0;}
+static void f2208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,256);*r1p=r1;*r0p=r0;}
+static void f2209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-256);*r1p=r1;*r0p=r0;}
+static void f2210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,255);*r1p=r1;*r0p=r0;}
+static void f2211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-257);*r1p=r1;*r0p=r0;}
+static void f2212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,512);*r1p=r1;*r0p=r0;}
+static void f2213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-512);*r1p=r1;*r0p=r0;}
+static void f2214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,511);*r1p=r1;*r0p=r0;}
+static void f2215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-513);*r1p=r1;*r0p=r0;}
+static void f2216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,1024);*r1p=r1;*r0p=r0;}
+static void f2217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,1023);*r1p=r1;*r0p=r0;}
+static void f2219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,2048);*r1p=r1;*r0p=r0;}
+static void f2221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,2047);*r1p=r1;*r0p=r0;}
+static void f2223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,4096);*r1p=r1;*r0p=r0;}
+static void f2225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,4095);*r1p=r1;*r0p=r0;}
+static void f2227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,8192);*r1p=r1;*r0p=r0;}
+static void f2229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,8191);*r1p=r1;*r0p=r0;}
+static void f2231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,16384);*r1p=r1;*r0p=r0;}
+static void f2233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,16383);*r1p=r1;*r0p=r0;}
+static void f2235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,32768);*r1p=r1;*r0p=r0;}
+static void f2237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,32767);*r1p=r1;*r0p=r0;}
+static void f2239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,255,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,1);*r1p=r1;*r0p=r0;}
+static void f2241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-1);*r1p=r1;*r0p=r0;}
+static void f2242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,0);*r1p=r1;*r0p=r0;}
+static void f2243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-2);*r1p=r1;*r0p=r0;}
+static void f2244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,2);*r1p=r1;*r0p=r0;}
+static void f2245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-2);*r1p=r1;*r0p=r0;}
+static void f2246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,1);*r1p=r1;*r0p=r0;}
+static void f2247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-3);*r1p=r1;*r0p=r0;}
+static void f2248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,4);*r1p=r1;*r0p=r0;}
+static void f2249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-4);*r1p=r1;*r0p=r0;}
+static void f2250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,3);*r1p=r1;*r0p=r0;}
+static void f2251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-5);*r1p=r1;*r0p=r0;}
+static void f2252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,8);*r1p=r1;*r0p=r0;}
+static void f2253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-8);*r1p=r1;*r0p=r0;}
+static void f2254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,7);*r1p=r1;*r0p=r0;}
+static void f2255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-9);*r1p=r1;*r0p=r0;}
+static void f2256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,16);*r1p=r1;*r0p=r0;}
+static void f2257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-16);*r1p=r1;*r0p=r0;}
+static void f2258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,15);*r1p=r1;*r0p=r0;}
+static void f2259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-17);*r1p=r1;*r0p=r0;}
+static void f2260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,32);*r1p=r1;*r0p=r0;}
+static void f2261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-32);*r1p=r1;*r0p=r0;}
+static void f2262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,31);*r1p=r1;*r0p=r0;}
+static void f2263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-33);*r1p=r1;*r0p=r0;}
+static void f2264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,64);*r1p=r1;*r0p=r0;}
+static void f2265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-64);*r1p=r1;*r0p=r0;}
+static void f2266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,63);*r1p=r1;*r0p=r0;}
+static void f2267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-65);*r1p=r1;*r0p=r0;}
+static void f2268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,128);*r1p=r1;*r0p=r0;}
+static void f2269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-128);*r1p=r1;*r0p=r0;}
+static void f2270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,127);*r1p=r1;*r0p=r0;}
+static void f2271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-129);*r1p=r1;*r0p=r0;}
+static void f2272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,256);*r1p=r1;*r0p=r0;}
+static void f2273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-256);*r1p=r1;*r0p=r0;}
+static void f2274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,255);*r1p=r1;*r0p=r0;}
+static void f2275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-257);*r1p=r1;*r0p=r0;}
+static void f2276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,512);*r1p=r1;*r0p=r0;}
+static void f2277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-512);*r1p=r1;*r0p=r0;}
+static void f2278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,511);*r1p=r1;*r0p=r0;}
+static void f2279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-513);*r1p=r1;*r0p=r0;}
+static void f2280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,1024);*r1p=r1;*r0p=r0;}
+static void f2281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,1023);*r1p=r1;*r0p=r0;}
+static void f2283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,2048);*r1p=r1;*r0p=r0;}
+static void f2285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,2047);*r1p=r1;*r0p=r0;}
+static void f2287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,4096);*r1p=r1;*r0p=r0;}
+static void f2289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,4095);*r1p=r1;*r0p=r0;}
+static void f2291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,8192);*r1p=r1;*r0p=r0;}
+static void f2293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,8191);*r1p=r1;*r0p=r0;}
+static void f2295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,16384);*r1p=r1;*r0p=r0;}
+static void f2297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,16383);*r1p=r1;*r0p=r0;}
+static void f2299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,32768);*r1p=r1;*r0p=r0;}
+static void f2301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,32767);*r1p=r1;*r0p=r0;}
+static void f2303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-257,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,1);*r1p=r1;*r0p=r0;}
+static void f2305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-1);*r1p=r1;*r0p=r0;}
+static void f2306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,0);*r1p=r1;*r0p=r0;}
+static void f2307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,2);*r1p=r1;*r0p=r0;}
+static void f2309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,1);*r1p=r1;*r0p=r0;}
+static void f2311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-3);*r1p=r1;*r0p=r0;}
+static void f2312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,4);*r1p=r1;*r0p=r0;}
+static void f2313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-4);*r1p=r1;*r0p=r0;}
+static void f2314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,3);*r1p=r1;*r0p=r0;}
+static void f2315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-5);*r1p=r1;*r0p=r0;}
+static void f2316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,8);*r1p=r1;*r0p=r0;}
+static void f2317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-8);*r1p=r1;*r0p=r0;}
+static void f2318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,7);*r1p=r1;*r0p=r0;}
+static void f2319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-9);*r1p=r1;*r0p=r0;}
+static void f2320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,16);*r1p=r1;*r0p=r0;}
+static void f2321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-16);*r1p=r1;*r0p=r0;}
+static void f2322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,15);*r1p=r1;*r0p=r0;}
+static void f2323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-17);*r1p=r1;*r0p=r0;}
+static void f2324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,32);*r1p=r1;*r0p=r0;}
+static void f2325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-32);*r1p=r1;*r0p=r0;}
+static void f2326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,31);*r1p=r1;*r0p=r0;}
+static void f2327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-33);*r1p=r1;*r0p=r0;}
+static void f2328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,64);*r1p=r1;*r0p=r0;}
+static void f2329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-64);*r1p=r1;*r0p=r0;}
+static void f2330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,63);*r1p=r1;*r0p=r0;}
+static void f2331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-65);*r1p=r1;*r0p=r0;}
+static void f2332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,128);*r1p=r1;*r0p=r0;}
+static void f2333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-128);*r1p=r1;*r0p=r0;}
+static void f2334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,127);*r1p=r1;*r0p=r0;}
+static void f2335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-129);*r1p=r1;*r0p=r0;}
+static void f2336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,256);*r1p=r1;*r0p=r0;}
+static void f2337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-256);*r1p=r1;*r0p=r0;}
+static void f2338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,255);*r1p=r1;*r0p=r0;}
+static void f2339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-257);*r1p=r1;*r0p=r0;}
+static void f2340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,512);*r1p=r1;*r0p=r0;}
+static void f2341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-512);*r1p=r1;*r0p=r0;}
+static void f2342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,511);*r1p=r1;*r0p=r0;}
+static void f2343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-513);*r1p=r1;*r0p=r0;}
+static void f2344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,1024);*r1p=r1;*r0p=r0;}
+static void f2345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,1023);*r1p=r1;*r0p=r0;}
+static void f2347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,2048);*r1p=r1;*r0p=r0;}
+static void f2349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,2047);*r1p=r1;*r0p=r0;}
+static void f2351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,4096);*r1p=r1;*r0p=r0;}
+static void f2353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,4095);*r1p=r1;*r0p=r0;}
+static void f2355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,8192);*r1p=r1;*r0p=r0;}
+static void f2357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,8191);*r1p=r1;*r0p=r0;}
+static void f2359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,16384);*r1p=r1;*r0p=r0;}
+static void f2361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,16383);*r1p=r1;*r0p=r0;}
+static void f2363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,32768);*r1p=r1;*r0p=r0;}
+static void f2365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,32767);*r1p=r1;*r0p=r0;}
+static void f2367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,512,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,1);*r1p=r1;*r0p=r0;}
+static void f2369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-1);*r1p=r1;*r0p=r0;}
+static void f2370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,0);*r1p=r1;*r0p=r0;}
+static void f2371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,2);*r1p=r1;*r0p=r0;}
+static void f2373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-2);*r1p=r1;*r0p=r0;}
+static void f2374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,1);*r1p=r1;*r0p=r0;}
+static void f2375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-3);*r1p=r1;*r0p=r0;}
+static void f2376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,4);*r1p=r1;*r0p=r0;}
+static void f2377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-4);*r1p=r1;*r0p=r0;}
+static void f2378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,3);*r1p=r1;*r0p=r0;}
+static void f2379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-5);*r1p=r1;*r0p=r0;}
+static void f2380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,8);*r1p=r1;*r0p=r0;}
+static void f2381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-8);*r1p=r1;*r0p=r0;}
+static void f2382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,7);*r1p=r1;*r0p=r0;}
+static void f2383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-9);*r1p=r1;*r0p=r0;}
+static void f2384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,16);*r1p=r1;*r0p=r0;}
+static void f2385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-16);*r1p=r1;*r0p=r0;}
+static void f2386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,15);*r1p=r1;*r0p=r0;}
+static void f2387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-17);*r1p=r1;*r0p=r0;}
+static void f2388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,32);*r1p=r1;*r0p=r0;}
+static void f2389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-32);*r1p=r1;*r0p=r0;}
+static void f2390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,31);*r1p=r1;*r0p=r0;}
+static void f2391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-33);*r1p=r1;*r0p=r0;}
+static void f2392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,64);*r1p=r1;*r0p=r0;}
+static void f2393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-64);*r1p=r1;*r0p=r0;}
+static void f2394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,63);*r1p=r1;*r0p=r0;}
+static void f2395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-65);*r1p=r1;*r0p=r0;}
+static void f2396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,128);*r1p=r1;*r0p=r0;}
+static void f2397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-128);*r1p=r1;*r0p=r0;}
+static void f2398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,127);*r1p=r1;*r0p=r0;}
+static void f2399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-129);*r1p=r1;*r0p=r0;}
+static void f2400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,256);*r1p=r1;*r0p=r0;}
+static void f2401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-256);*r1p=r1;*r0p=r0;}
+static void f2402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,255);*r1p=r1;*r0p=r0;}
+static void f2403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-257);*r1p=r1;*r0p=r0;}
+static void f2404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,512);*r1p=r1;*r0p=r0;}
+static void f2405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-512);*r1p=r1;*r0p=r0;}
+static void f2406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,511);*r1p=r1;*r0p=r0;}
+static void f2407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-513);*r1p=r1;*r0p=r0;}
+static void f2408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,1024);*r1p=r1;*r0p=r0;}
+static void f2409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,1023);*r1p=r1;*r0p=r0;}
+static void f2411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,2048);*r1p=r1;*r0p=r0;}
+static void f2413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,2047);*r1p=r1;*r0p=r0;}
+static void f2415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,4096);*r1p=r1;*r0p=r0;}
+static void f2417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,4095);*r1p=r1;*r0p=r0;}
+static void f2419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,8192);*r1p=r1;*r0p=r0;}
+static void f2421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,8191);*r1p=r1;*r0p=r0;}
+static void f2423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,16384);*r1p=r1;*r0p=r0;}
+static void f2425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,16383);*r1p=r1;*r0p=r0;}
+static void f2427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,32768);*r1p=r1;*r0p=r0;}
+static void f2429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,32767);*r1p=r1;*r0p=r0;}
+static void f2431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-512,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,1);*r1p=r1;*r0p=r0;}
+static void f2433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-1);*r1p=r1;*r0p=r0;}
+static void f2434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,0);*r1p=r1;*r0p=r0;}
+static void f2435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-2);*r1p=r1;*r0p=r0;}
+static void f2436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,2);*r1p=r1;*r0p=r0;}
+static void f2437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-2);*r1p=r1;*r0p=r0;}
+static void f2438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,1);*r1p=r1;*r0p=r0;}
+static void f2439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-3);*r1p=r1;*r0p=r0;}
+static void f2440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,4);*r1p=r1;*r0p=r0;}
+static void f2441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-4);*r1p=r1;*r0p=r0;}
+static void f2442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,3);*r1p=r1;*r0p=r0;}
+static void f2443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-5);*r1p=r1;*r0p=r0;}
+static void f2444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,8);*r1p=r1;*r0p=r0;}
+static void f2445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-8);*r1p=r1;*r0p=r0;}
+static void f2446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,7);*r1p=r1;*r0p=r0;}
+static void f2447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-9);*r1p=r1;*r0p=r0;}
+static void f2448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,16);*r1p=r1;*r0p=r0;}
+static void f2449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-16);*r1p=r1;*r0p=r0;}
+static void f2450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,15);*r1p=r1;*r0p=r0;}
+static void f2451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-17);*r1p=r1;*r0p=r0;}
+static void f2452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,32);*r1p=r1;*r0p=r0;}
+static void f2453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-32);*r1p=r1;*r0p=r0;}
+static void f2454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,31);*r1p=r1;*r0p=r0;}
+static void f2455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-33);*r1p=r1;*r0p=r0;}
+static void f2456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,64);*r1p=r1;*r0p=r0;}
+static void f2457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-64);*r1p=r1;*r0p=r0;}
+static void f2458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,63);*r1p=r1;*r0p=r0;}
+static void f2459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-65);*r1p=r1;*r0p=r0;}
+static void f2460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,128);*r1p=r1;*r0p=r0;}
+static void f2461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-128);*r1p=r1;*r0p=r0;}
+static void f2462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,127);*r1p=r1;*r0p=r0;}
+static void f2463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-129);*r1p=r1;*r0p=r0;}
+static void f2464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,256);*r1p=r1;*r0p=r0;}
+static void f2465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-256);*r1p=r1;*r0p=r0;}
+static void f2466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,255);*r1p=r1;*r0p=r0;}
+static void f2467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-257);*r1p=r1;*r0p=r0;}
+static void f2468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,512);*r1p=r1;*r0p=r0;}
+static void f2469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-512);*r1p=r1;*r0p=r0;}
+static void f2470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,511);*r1p=r1;*r0p=r0;}
+static void f2471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-513);*r1p=r1;*r0p=r0;}
+static void f2472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,1024);*r1p=r1;*r0p=r0;}
+static void f2473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,1023);*r1p=r1;*r0p=r0;}
+static void f2475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,2048);*r1p=r1;*r0p=r0;}
+static void f2477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,2047);*r1p=r1;*r0p=r0;}
+static void f2479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,4096);*r1p=r1;*r0p=r0;}
+static void f2481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,4095);*r1p=r1;*r0p=r0;}
+static void f2483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,8192);*r1p=r1;*r0p=r0;}
+static void f2485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,8191);*r1p=r1;*r0p=r0;}
+static void f2487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,16384);*r1p=r1;*r0p=r0;}
+static void f2489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,16383);*r1p=r1;*r0p=r0;}
+static void f2491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,32768);*r1p=r1;*r0p=r0;}
+static void f2493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,32767);*r1p=r1;*r0p=r0;}
+static void f2495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,511,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,1);*r1p=r1;*r0p=r0;}
+static void f2497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-1);*r1p=r1;*r0p=r0;}
+static void f2498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,0);*r1p=r1;*r0p=r0;}
+static void f2499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-2);*r1p=r1;*r0p=r0;}
+static void f2500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,2);*r1p=r1;*r0p=r0;}
+static void f2501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-2);*r1p=r1;*r0p=r0;}
+static void f2502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,1);*r1p=r1;*r0p=r0;}
+static void f2503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-3);*r1p=r1;*r0p=r0;}
+static void f2504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,4);*r1p=r1;*r0p=r0;}
+static void f2505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-4);*r1p=r1;*r0p=r0;}
+static void f2506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,3);*r1p=r1;*r0p=r0;}
+static void f2507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-5);*r1p=r1;*r0p=r0;}
+static void f2508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,8);*r1p=r1;*r0p=r0;}
+static void f2509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-8);*r1p=r1;*r0p=r0;}
+static void f2510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,7);*r1p=r1;*r0p=r0;}
+static void f2511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-9);*r1p=r1;*r0p=r0;}
+static void f2512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,16);*r1p=r1;*r0p=r0;}
+static void f2513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-16);*r1p=r1;*r0p=r0;}
+static void f2514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,15);*r1p=r1;*r0p=r0;}
+static void f2515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-17);*r1p=r1;*r0p=r0;}
+static void f2516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,32);*r1p=r1;*r0p=r0;}
+static void f2517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-32);*r1p=r1;*r0p=r0;}
+static void f2518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,31);*r1p=r1;*r0p=r0;}
+static void f2519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-33);*r1p=r1;*r0p=r0;}
+static void f2520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,64);*r1p=r1;*r0p=r0;}
+static void f2521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-64);*r1p=r1;*r0p=r0;}
+static void f2522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,63);*r1p=r1;*r0p=r0;}
+static void f2523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-65);*r1p=r1;*r0p=r0;}
+static void f2524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,128);*r1p=r1;*r0p=r0;}
+static void f2525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-128);*r1p=r1;*r0p=r0;}
+static void f2526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,127);*r1p=r1;*r0p=r0;}
+static void f2527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-129);*r1p=r1;*r0p=r0;}
+static void f2528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,256);*r1p=r1;*r0p=r0;}
+static void f2529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-256);*r1p=r1;*r0p=r0;}
+static void f2530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,255);*r1p=r1;*r0p=r0;}
+static void f2531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-257);*r1p=r1;*r0p=r0;}
+static void f2532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,512);*r1p=r1;*r0p=r0;}
+static void f2533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-512);*r1p=r1;*r0p=r0;}
+static void f2534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,511);*r1p=r1;*r0p=r0;}
+static void f2535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-513);*r1p=r1;*r0p=r0;}
+static void f2536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,1024);*r1p=r1;*r0p=r0;}
+static void f2537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,1023);*r1p=r1;*r0p=r0;}
+static void f2539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,2048);*r1p=r1;*r0p=r0;}
+static void f2541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,2047);*r1p=r1;*r0p=r0;}
+static void f2543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,4096);*r1p=r1;*r0p=r0;}
+static void f2545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,4095);*r1p=r1;*r0p=r0;}
+static void f2547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,8192);*r1p=r1;*r0p=r0;}
+static void f2549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,8191);*r1p=r1;*r0p=r0;}
+static void f2551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,16384);*r1p=r1;*r0p=r0;}
+static void f2553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,16383);*r1p=r1;*r0p=r0;}
+static void f2555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,32768);*r1p=r1;*r0p=r0;}
+static void f2557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,32767);*r1p=r1;*r0p=r0;}
+static void f2559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-513,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-1);*r1p=r1;*r0p=r0;}
+static void f2562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,0);*r1p=r1;*r0p=r0;}
+static void f2563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,2);*r1p=r1;*r0p=r0;}
+static void f2565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-3);*r1p=r1;*r0p=r0;}
+static void f2568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,4);*r1p=r1;*r0p=r0;}
+static void f2569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-4);*r1p=r1;*r0p=r0;}
+static void f2570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,3);*r1p=r1;*r0p=r0;}
+static void f2571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-5);*r1p=r1;*r0p=r0;}
+static void f2572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,8);*r1p=r1;*r0p=r0;}
+static void f2573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-8);*r1p=r1;*r0p=r0;}
+static void f2574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,7);*r1p=r1;*r0p=r0;}
+static void f2575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-9);*r1p=r1;*r0p=r0;}
+static void f2576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,16);*r1p=r1;*r0p=r0;}
+static void f2577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-16);*r1p=r1;*r0p=r0;}
+static void f2578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,15);*r1p=r1;*r0p=r0;}
+static void f2579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-17);*r1p=r1;*r0p=r0;}
+static void f2580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,32);*r1p=r1;*r0p=r0;}
+static void f2581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-32);*r1p=r1;*r0p=r0;}
+static void f2582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,31);*r1p=r1;*r0p=r0;}
+static void f2583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-33);*r1p=r1;*r0p=r0;}
+static void f2584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,64);*r1p=r1;*r0p=r0;}
+static void f2585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-64);*r1p=r1;*r0p=r0;}
+static void f2586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,63);*r1p=r1;*r0p=r0;}
+static void f2587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-65);*r1p=r1;*r0p=r0;}
+static void f2588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,128);*r1p=r1;*r0p=r0;}
+static void f2589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-128);*r1p=r1;*r0p=r0;}
+static void f2590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,127);*r1p=r1;*r0p=r0;}
+static void f2591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-129);*r1p=r1;*r0p=r0;}
+static void f2592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,256);*r1p=r1;*r0p=r0;}
+static void f2593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-256);*r1p=r1;*r0p=r0;}
+static void f2594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,255);*r1p=r1;*r0p=r0;}
+static void f2595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-257);*r1p=r1;*r0p=r0;}
+static void f2596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,512);*r1p=r1;*r0p=r0;}
+static void f2597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-512);*r1p=r1;*r0p=r0;}
+static void f2598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,511);*r1p=r1;*r0p=r0;}
+static void f2599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-513);*r1p=r1;*r0p=r0;}
+static void f2600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,1024);*r1p=r1;*r0p=r0;}
+static void f2601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,1023);*r1p=r1;*r0p=r0;}
+static void f2603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,2048);*r1p=r1;*r0p=r0;}
+static void f2605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,2047);*r1p=r1;*r0p=r0;}
+static void f2607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,4096);*r1p=r1;*r0p=r0;}
+static void f2609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,4095);*r1p=r1;*r0p=r0;}
+static void f2611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,8192);*r1p=r1;*r0p=r0;}
+static void f2613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,8191);*r1p=r1;*r0p=r0;}
+static void f2615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,16384);*r1p=r1;*r0p=r0;}
+static void f2617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,16383);*r1p=r1;*r0p=r0;}
+static void f2619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,32768);*r1p=r1;*r0p=r0;}
+static void f2621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,32767);*r1p=r1;*r0p=r0;}
+static void f2623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1024,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-1);*r1p=r1;*r0p=r0;}
+static void f2626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,0);*r1p=r1;*r0p=r0;}
+static void f2627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,2);*r1p=r1;*r0p=r0;}
+static void f2629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-2);*r1p=r1;*r0p=r0;}
+static void f2630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,1);*r1p=r1;*r0p=r0;}
+static void f2631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-3);*r1p=r1;*r0p=r0;}
+static void f2632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,4);*r1p=r1;*r0p=r0;}
+static void f2633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-4);*r1p=r1;*r0p=r0;}
+static void f2634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,3);*r1p=r1;*r0p=r0;}
+static void f2635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-5);*r1p=r1;*r0p=r0;}
+static void f2636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,8);*r1p=r1;*r0p=r0;}
+static void f2637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-8);*r1p=r1;*r0p=r0;}
+static void f2638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,7);*r1p=r1;*r0p=r0;}
+static void f2639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-9);*r1p=r1;*r0p=r0;}
+static void f2640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,16);*r1p=r1;*r0p=r0;}
+static void f2641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-16);*r1p=r1;*r0p=r0;}
+static void f2642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,15);*r1p=r1;*r0p=r0;}
+static void f2643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-17);*r1p=r1;*r0p=r0;}
+static void f2644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,32);*r1p=r1;*r0p=r0;}
+static void f2645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-32);*r1p=r1;*r0p=r0;}
+static void f2646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,31);*r1p=r1;*r0p=r0;}
+static void f2647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-33);*r1p=r1;*r0p=r0;}
+static void f2648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,64);*r1p=r1;*r0p=r0;}
+static void f2649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-64);*r1p=r1;*r0p=r0;}
+static void f2650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,63);*r1p=r1;*r0p=r0;}
+static void f2651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-65);*r1p=r1;*r0p=r0;}
+static void f2652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,128);*r1p=r1;*r0p=r0;}
+static void f2653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-128);*r1p=r1;*r0p=r0;}
+static void f2654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,127);*r1p=r1;*r0p=r0;}
+static void f2655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-129);*r1p=r1;*r0p=r0;}
+static void f2656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,256);*r1p=r1;*r0p=r0;}
+static void f2657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-256);*r1p=r1;*r0p=r0;}
+static void f2658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,255);*r1p=r1;*r0p=r0;}
+static void f2659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-257);*r1p=r1;*r0p=r0;}
+static void f2660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,512);*r1p=r1;*r0p=r0;}
+static void f2661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-512);*r1p=r1;*r0p=r0;}
+static void f2662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,511);*r1p=r1;*r0p=r0;}
+static void f2663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-513);*r1p=r1;*r0p=r0;}
+static void f2664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,1024);*r1p=r1;*r0p=r0;}
+static void f2665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,1023);*r1p=r1;*r0p=r0;}
+static void f2667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,2048);*r1p=r1;*r0p=r0;}
+static void f2669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,2047);*r1p=r1;*r0p=r0;}
+static void f2671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,4096);*r1p=r1;*r0p=r0;}
+static void f2673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,4095);*r1p=r1;*r0p=r0;}
+static void f2675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,8192);*r1p=r1;*r0p=r0;}
+static void f2677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,8191);*r1p=r1;*r0p=r0;}
+static void f2679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,16384);*r1p=r1;*r0p=r0;}
+static void f2681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,16383);*r1p=r1;*r0p=r0;}
+static void f2683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,32768);*r1p=r1;*r0p=r0;}
+static void f2685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,32767);*r1p=r1;*r0p=r0;}
+static void f2687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1024,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,1);*r1p=r1;*r0p=r0;}
+static void f2689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-1);*r1p=r1;*r0p=r0;}
+static void f2690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,0);*r1p=r1;*r0p=r0;}
+static void f2691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-2);*r1p=r1;*r0p=r0;}
+static void f2692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,2);*r1p=r1;*r0p=r0;}
+static void f2693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-2);*r1p=r1;*r0p=r0;}
+static void f2694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,1);*r1p=r1;*r0p=r0;}
+static void f2695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-3);*r1p=r1;*r0p=r0;}
+static void f2696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,4);*r1p=r1;*r0p=r0;}
+static void f2697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-4);*r1p=r1;*r0p=r0;}
+static void f2698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,3);*r1p=r1;*r0p=r0;}
+static void f2699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-5);*r1p=r1;*r0p=r0;}
+static void f2700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,8);*r1p=r1;*r0p=r0;}
+static void f2701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-8);*r1p=r1;*r0p=r0;}
+static void f2702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,7);*r1p=r1;*r0p=r0;}
+static void f2703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-9);*r1p=r1;*r0p=r0;}
+static void f2704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,16);*r1p=r1;*r0p=r0;}
+static void f2705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-16);*r1p=r1;*r0p=r0;}
+static void f2706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,15);*r1p=r1;*r0p=r0;}
+static void f2707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-17);*r1p=r1;*r0p=r0;}
+static void f2708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,32);*r1p=r1;*r0p=r0;}
+static void f2709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-32);*r1p=r1;*r0p=r0;}
+static void f2710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,31);*r1p=r1;*r0p=r0;}
+static void f2711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-33);*r1p=r1;*r0p=r0;}
+static void f2712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,64);*r1p=r1;*r0p=r0;}
+static void f2713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-64);*r1p=r1;*r0p=r0;}
+static void f2714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,63);*r1p=r1;*r0p=r0;}
+static void f2715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-65);*r1p=r1;*r0p=r0;}
+static void f2716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,128);*r1p=r1;*r0p=r0;}
+static void f2717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-128);*r1p=r1;*r0p=r0;}
+static void f2718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,127);*r1p=r1;*r0p=r0;}
+static void f2719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-129);*r1p=r1;*r0p=r0;}
+static void f2720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,256);*r1p=r1;*r0p=r0;}
+static void f2721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-256);*r1p=r1;*r0p=r0;}
+static void f2722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,255);*r1p=r1;*r0p=r0;}
+static void f2723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-257);*r1p=r1;*r0p=r0;}
+static void f2724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,512);*r1p=r1;*r0p=r0;}
+static void f2725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-512);*r1p=r1;*r0p=r0;}
+static void f2726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,511);*r1p=r1;*r0p=r0;}
+static void f2727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-513);*r1p=r1;*r0p=r0;}
+static void f2728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,1024);*r1p=r1;*r0p=r0;}
+static void f2729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,1023);*r1p=r1;*r0p=r0;}
+static void f2731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,2048);*r1p=r1;*r0p=r0;}
+static void f2733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,2047);*r1p=r1;*r0p=r0;}
+static void f2735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,4096);*r1p=r1;*r0p=r0;}
+static void f2737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,4095);*r1p=r1;*r0p=r0;}
+static void f2739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,8192);*r1p=r1;*r0p=r0;}
+static void f2741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,8191);*r1p=r1;*r0p=r0;}
+static void f2743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,16384);*r1p=r1;*r0p=r0;}
+static void f2745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,16383);*r1p=r1;*r0p=r0;}
+static void f2747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,32768);*r1p=r1;*r0p=r0;}
+static void f2749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,32767);*r1p=r1;*r0p=r0;}
+static void f2751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,1023,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,1);*r1p=r1;*r0p=r0;}
+static void f2753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-1);*r1p=r1;*r0p=r0;}
+static void f2754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,0);*r1p=r1;*r0p=r0;}
+static void f2755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-2);*r1p=r1;*r0p=r0;}
+static void f2756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,2);*r1p=r1;*r0p=r0;}
+static void f2757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-2);*r1p=r1;*r0p=r0;}
+static void f2758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,1);*r1p=r1;*r0p=r0;}
+static void f2759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-3);*r1p=r1;*r0p=r0;}
+static void f2760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,4);*r1p=r1;*r0p=r0;}
+static void f2761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-4);*r1p=r1;*r0p=r0;}
+static void f2762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,3);*r1p=r1;*r0p=r0;}
+static void f2763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-5);*r1p=r1;*r0p=r0;}
+static void f2764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,8);*r1p=r1;*r0p=r0;}
+static void f2765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-8);*r1p=r1;*r0p=r0;}
+static void f2766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,7);*r1p=r1;*r0p=r0;}
+static void f2767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-9);*r1p=r1;*r0p=r0;}
+static void f2768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,16);*r1p=r1;*r0p=r0;}
+static void f2769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-16);*r1p=r1;*r0p=r0;}
+static void f2770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,15);*r1p=r1;*r0p=r0;}
+static void f2771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-17);*r1p=r1;*r0p=r0;}
+static void f2772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,32);*r1p=r1;*r0p=r0;}
+static void f2773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-32);*r1p=r1;*r0p=r0;}
+static void f2774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,31);*r1p=r1;*r0p=r0;}
+static void f2775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-33);*r1p=r1;*r0p=r0;}
+static void f2776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,64);*r1p=r1;*r0p=r0;}
+static void f2777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-64);*r1p=r1;*r0p=r0;}
+static void f2778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,63);*r1p=r1;*r0p=r0;}
+static void f2779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-65);*r1p=r1;*r0p=r0;}
+static void f2780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,128);*r1p=r1;*r0p=r0;}
+static void f2781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-128);*r1p=r1;*r0p=r0;}
+static void f2782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,127);*r1p=r1;*r0p=r0;}
+static void f2783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-129);*r1p=r1;*r0p=r0;}
+static void f2784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,256);*r1p=r1;*r0p=r0;}
+static void f2785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-256);*r1p=r1;*r0p=r0;}
+static void f2786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,255);*r1p=r1;*r0p=r0;}
+static void f2787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-257);*r1p=r1;*r0p=r0;}
+static void f2788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,512);*r1p=r1;*r0p=r0;}
+static void f2789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-512);*r1p=r1;*r0p=r0;}
+static void f2790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,511);*r1p=r1;*r0p=r0;}
+static void f2791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-513);*r1p=r1;*r0p=r0;}
+static void f2792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,1024);*r1p=r1;*r0p=r0;}
+static void f2793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,1023);*r1p=r1;*r0p=r0;}
+static void f2795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,2048);*r1p=r1;*r0p=r0;}
+static void f2797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,2047);*r1p=r1;*r0p=r0;}
+static void f2799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,4096);*r1p=r1;*r0p=r0;}
+static void f2801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,4095);*r1p=r1;*r0p=r0;}
+static void f2803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,8192);*r1p=r1;*r0p=r0;}
+static void f2805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,8191);*r1p=r1;*r0p=r0;}
+static void f2807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,16384);*r1p=r1;*r0p=r0;}
+static void f2809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,16383);*r1p=r1;*r0p=r0;}
+static void f2811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,32768);*r1p=r1;*r0p=r0;}
+static void f2813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,32767);*r1p=r1;*r0p=r0;}
+static void f2815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-1025,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-1);*r1p=r1;*r0p=r0;}
+static void f2818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,0);*r1p=r1;*r0p=r0;}
+static void f2819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,2);*r1p=r1;*r0p=r0;}
+static void f2821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-3);*r1p=r1;*r0p=r0;}
+static void f2824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,4);*r1p=r1;*r0p=r0;}
+static void f2825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-4);*r1p=r1;*r0p=r0;}
+static void f2826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,3);*r1p=r1;*r0p=r0;}
+static void f2827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-5);*r1p=r1;*r0p=r0;}
+static void f2828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,8);*r1p=r1;*r0p=r0;}
+static void f2829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-8);*r1p=r1;*r0p=r0;}
+static void f2830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,7);*r1p=r1;*r0p=r0;}
+static void f2831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-9);*r1p=r1;*r0p=r0;}
+static void f2832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,16);*r1p=r1;*r0p=r0;}
+static void f2833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-16);*r1p=r1;*r0p=r0;}
+static void f2834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,15);*r1p=r1;*r0p=r0;}
+static void f2835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-17);*r1p=r1;*r0p=r0;}
+static void f2836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,32);*r1p=r1;*r0p=r0;}
+static void f2837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-32);*r1p=r1;*r0p=r0;}
+static void f2838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,31);*r1p=r1;*r0p=r0;}
+static void f2839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-33);*r1p=r1;*r0p=r0;}
+static void f2840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,64);*r1p=r1;*r0p=r0;}
+static void f2841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-64);*r1p=r1;*r0p=r0;}
+static void f2842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,63);*r1p=r1;*r0p=r0;}
+static void f2843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-65);*r1p=r1;*r0p=r0;}
+static void f2844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,128);*r1p=r1;*r0p=r0;}
+static void f2845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-128);*r1p=r1;*r0p=r0;}
+static void f2846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,127);*r1p=r1;*r0p=r0;}
+static void f2847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-129);*r1p=r1;*r0p=r0;}
+static void f2848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,256);*r1p=r1;*r0p=r0;}
+static void f2849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-256);*r1p=r1;*r0p=r0;}
+static void f2850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,255);*r1p=r1;*r0p=r0;}
+static void f2851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-257);*r1p=r1;*r0p=r0;}
+static void f2852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,512);*r1p=r1;*r0p=r0;}
+static void f2853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-512);*r1p=r1;*r0p=r0;}
+static void f2854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,511);*r1p=r1;*r0p=r0;}
+static void f2855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-513);*r1p=r1;*r0p=r0;}
+static void f2856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,1024);*r1p=r1;*r0p=r0;}
+static void f2857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,1023);*r1p=r1;*r0p=r0;}
+static void f2859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,2048);*r1p=r1;*r0p=r0;}
+static void f2861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,2047);*r1p=r1;*r0p=r0;}
+static void f2863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,4096);*r1p=r1;*r0p=r0;}
+static void f2865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,4095);*r1p=r1;*r0p=r0;}
+static void f2867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,8192);*r1p=r1;*r0p=r0;}
+static void f2869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,8191);*r1p=r1;*r0p=r0;}
+static void f2871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,16384);*r1p=r1;*r0p=r0;}
+static void f2873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,16383);*r1p=r1;*r0p=r0;}
+static void f2875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,32768);*r1p=r1;*r0p=r0;}
+static void f2877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,32767);*r1p=r1;*r0p=r0;}
+static void f2879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2048,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-1);*r1p=r1;*r0p=r0;}
+static void f2882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,0);*r1p=r1;*r0p=r0;}
+static void f2883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,2);*r1p=r1;*r0p=r0;}
+static void f2885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-2);*r1p=r1;*r0p=r0;}
+static void f2886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,1);*r1p=r1;*r0p=r0;}
+static void f2887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-3);*r1p=r1;*r0p=r0;}
+static void f2888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,4);*r1p=r1;*r0p=r0;}
+static void f2889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-4);*r1p=r1;*r0p=r0;}
+static void f2890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,3);*r1p=r1;*r0p=r0;}
+static void f2891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-5);*r1p=r1;*r0p=r0;}
+static void f2892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,8);*r1p=r1;*r0p=r0;}
+static void f2893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-8);*r1p=r1;*r0p=r0;}
+static void f2894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,7);*r1p=r1;*r0p=r0;}
+static void f2895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-9);*r1p=r1;*r0p=r0;}
+static void f2896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,16);*r1p=r1;*r0p=r0;}
+static void f2897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-16);*r1p=r1;*r0p=r0;}
+static void f2898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,15);*r1p=r1;*r0p=r0;}
+static void f2899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-17);*r1p=r1;*r0p=r0;}
+static void f2900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,32);*r1p=r1;*r0p=r0;}
+static void f2901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-32);*r1p=r1;*r0p=r0;}
+static void f2902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,31);*r1p=r1;*r0p=r0;}
+static void f2903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-33);*r1p=r1;*r0p=r0;}
+static void f2904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,64);*r1p=r1;*r0p=r0;}
+static void f2905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-64);*r1p=r1;*r0p=r0;}
+static void f2906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,63);*r1p=r1;*r0p=r0;}
+static void f2907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-65);*r1p=r1;*r0p=r0;}
+static void f2908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,128);*r1p=r1;*r0p=r0;}
+static void f2909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-128);*r1p=r1;*r0p=r0;}
+static void f2910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,127);*r1p=r1;*r0p=r0;}
+static void f2911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-129);*r1p=r1;*r0p=r0;}
+static void f2912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,256);*r1p=r1;*r0p=r0;}
+static void f2913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-256);*r1p=r1;*r0p=r0;}
+static void f2914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,255);*r1p=r1;*r0p=r0;}
+static void f2915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-257);*r1p=r1;*r0p=r0;}
+static void f2916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,512);*r1p=r1;*r0p=r0;}
+static void f2917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-512);*r1p=r1;*r0p=r0;}
+static void f2918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,511);*r1p=r1;*r0p=r0;}
+static void f2919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-513);*r1p=r1;*r0p=r0;}
+static void f2920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,1024);*r1p=r1;*r0p=r0;}
+static void f2921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,1023);*r1p=r1;*r0p=r0;}
+static void f2923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,2048);*r1p=r1;*r0p=r0;}
+static void f2925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,2047);*r1p=r1;*r0p=r0;}
+static void f2927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,4096);*r1p=r1;*r0p=r0;}
+static void f2929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,4095);*r1p=r1;*r0p=r0;}
+static void f2931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,8192);*r1p=r1;*r0p=r0;}
+static void f2933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,8191);*r1p=r1;*r0p=r0;}
+static void f2935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-8193);*r1p=r1;*r0p=r0;}
+static void f2936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,16384);*r1p=r1;*r0p=r0;}
+static void f2937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-16384);*r1p=r1;*r0p=r0;}
+static void f2938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,16383);*r1p=r1;*r0p=r0;}
+static void f2939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-16385);*r1p=r1;*r0p=r0;}
+static void f2940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,32768);*r1p=r1;*r0p=r0;}
+static void f2941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-32768);*r1p=r1;*r0p=r0;}
+static void f2942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,32767);*r1p=r1;*r0p=r0;}
+static void f2943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2048,0,-32769);*r1p=r1;*r0p=r0;}
+static void f2944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,1);*r1p=r1;*r0p=r0;}
+static void f2945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-1);*r1p=r1;*r0p=r0;}
+static void f2946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,0);*r1p=r1;*r0p=r0;}
+static void f2947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-2);*r1p=r1;*r0p=r0;}
+static void f2948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,2);*r1p=r1;*r0p=r0;}
+static void f2949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-2);*r1p=r1;*r0p=r0;}
+static void f2950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,1);*r1p=r1;*r0p=r0;}
+static void f2951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-3);*r1p=r1;*r0p=r0;}
+static void f2952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,4);*r1p=r1;*r0p=r0;}
+static void f2953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-4);*r1p=r1;*r0p=r0;}
+static void f2954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,3);*r1p=r1;*r0p=r0;}
+static void f2955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-5);*r1p=r1;*r0p=r0;}
+static void f2956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,8);*r1p=r1;*r0p=r0;}
+static void f2957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-8);*r1p=r1;*r0p=r0;}
+static void f2958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,7);*r1p=r1;*r0p=r0;}
+static void f2959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-9);*r1p=r1;*r0p=r0;}
+static void f2960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,16);*r1p=r1;*r0p=r0;}
+static void f2961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-16);*r1p=r1;*r0p=r0;}
+static void f2962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,15);*r1p=r1;*r0p=r0;}
+static void f2963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-17);*r1p=r1;*r0p=r0;}
+static void f2964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,32);*r1p=r1;*r0p=r0;}
+static void f2965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-32);*r1p=r1;*r0p=r0;}
+static void f2966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,31);*r1p=r1;*r0p=r0;}
+static void f2967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-33);*r1p=r1;*r0p=r0;}
+static void f2968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,64);*r1p=r1;*r0p=r0;}
+static void f2969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-64);*r1p=r1;*r0p=r0;}
+static void f2970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,63);*r1p=r1;*r0p=r0;}
+static void f2971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-65);*r1p=r1;*r0p=r0;}
+static void f2972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,128);*r1p=r1;*r0p=r0;}
+static void f2973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-128);*r1p=r1;*r0p=r0;}
+static void f2974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,127);*r1p=r1;*r0p=r0;}
+static void f2975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-129);*r1p=r1;*r0p=r0;}
+static void f2976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,256);*r1p=r1;*r0p=r0;}
+static void f2977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-256);*r1p=r1;*r0p=r0;}
+static void f2978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,255);*r1p=r1;*r0p=r0;}
+static void f2979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-257);*r1p=r1;*r0p=r0;}
+static void f2980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,512);*r1p=r1;*r0p=r0;}
+static void f2981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-512);*r1p=r1;*r0p=r0;}
+static void f2982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,511);*r1p=r1;*r0p=r0;}
+static void f2983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-513);*r1p=r1;*r0p=r0;}
+static void f2984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,1024);*r1p=r1;*r0p=r0;}
+static void f2985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-1024);*r1p=r1;*r0p=r0;}
+static void f2986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,1023);*r1p=r1;*r0p=r0;}
+static void f2987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-1025);*r1p=r1;*r0p=r0;}
+static void f2988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,2048);*r1p=r1;*r0p=r0;}
+static void f2989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-2048);*r1p=r1;*r0p=r0;}
+static void f2990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,2047);*r1p=r1;*r0p=r0;}
+static void f2991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-2049);*r1p=r1;*r0p=r0;}
+static void f2992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,4096);*r1p=r1;*r0p=r0;}
+static void f2993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-4096);*r1p=r1;*r0p=r0;}
+static void f2994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,4095);*r1p=r1;*r0p=r0;}
+static void f2995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-4097);*r1p=r1;*r0p=r0;}
+static void f2996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,8192);*r1p=r1;*r0p=r0;}
+static void f2997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-8192);*r1p=r1;*r0p=r0;}
+static void f2998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,8191);*r1p=r1;*r0p=r0;}
+static void f2999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,16384);*r1p=r1;*r0p=r0;}
+static void f3001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,16383);*r1p=r1;*r0p=r0;}
+static void f3003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,32768);*r1p=r1;*r0p=r0;}
+static void f3005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,32767);*r1p=r1;*r0p=r0;}
+static void f3007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,2047,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,1);*r1p=r1;*r0p=r0;}
+static void f3009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-1);*r1p=r1;*r0p=r0;}
+static void f3010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,0);*r1p=r1;*r0p=r0;}
+static void f3011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-2);*r1p=r1;*r0p=r0;}
+static void f3012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,2);*r1p=r1;*r0p=r0;}
+static void f3013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-2);*r1p=r1;*r0p=r0;}
+static void f3014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,1);*r1p=r1;*r0p=r0;}
+static void f3015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-3);*r1p=r1;*r0p=r0;}
+static void f3016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,4);*r1p=r1;*r0p=r0;}
+static void f3017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-4);*r1p=r1;*r0p=r0;}
+static void f3018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,3);*r1p=r1;*r0p=r0;}
+static void f3019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-5);*r1p=r1;*r0p=r0;}
+static void f3020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,8);*r1p=r1;*r0p=r0;}
+static void f3021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-8);*r1p=r1;*r0p=r0;}
+static void f3022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,7);*r1p=r1;*r0p=r0;}
+static void f3023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-9);*r1p=r1;*r0p=r0;}
+static void f3024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,16);*r1p=r1;*r0p=r0;}
+static void f3025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-16);*r1p=r1;*r0p=r0;}
+static void f3026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,15);*r1p=r1;*r0p=r0;}
+static void f3027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-17);*r1p=r1;*r0p=r0;}
+static void f3028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,32);*r1p=r1;*r0p=r0;}
+static void f3029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-32);*r1p=r1;*r0p=r0;}
+static void f3030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,31);*r1p=r1;*r0p=r0;}
+static void f3031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-33);*r1p=r1;*r0p=r0;}
+static void f3032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,64);*r1p=r1;*r0p=r0;}
+static void f3033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-64);*r1p=r1;*r0p=r0;}
+static void f3034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,63);*r1p=r1;*r0p=r0;}
+static void f3035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-65);*r1p=r1;*r0p=r0;}
+static void f3036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,128);*r1p=r1;*r0p=r0;}
+static void f3037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-128);*r1p=r1;*r0p=r0;}
+static void f3038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,127);*r1p=r1;*r0p=r0;}
+static void f3039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-129);*r1p=r1;*r0p=r0;}
+static void f3040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,256);*r1p=r1;*r0p=r0;}
+static void f3041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-256);*r1p=r1;*r0p=r0;}
+static void f3042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,255);*r1p=r1;*r0p=r0;}
+static void f3043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-257);*r1p=r1;*r0p=r0;}
+static void f3044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,512);*r1p=r1;*r0p=r0;}
+static void f3045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-512);*r1p=r1;*r0p=r0;}
+static void f3046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,511);*r1p=r1;*r0p=r0;}
+static void f3047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-513);*r1p=r1;*r0p=r0;}
+static void f3048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,1024);*r1p=r1;*r0p=r0;}
+static void f3049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,1023);*r1p=r1;*r0p=r0;}
+static void f3051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,2048);*r1p=r1;*r0p=r0;}
+static void f3053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,2047);*r1p=r1;*r0p=r0;}
+static void f3055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,4096);*r1p=r1;*r0p=r0;}
+static void f3057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,4095);*r1p=r1;*r0p=r0;}
+static void f3059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,8192);*r1p=r1;*r0p=r0;}
+static void f3061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,8191);*r1p=r1;*r0p=r0;}
+static void f3063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,16384);*r1p=r1;*r0p=r0;}
+static void f3065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,16383);*r1p=r1;*r0p=r0;}
+static void f3067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,32768);*r1p=r1;*r0p=r0;}
+static void f3069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,32767);*r1p=r1;*r0p=r0;}
+static void f3071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-2049,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-1);*r1p=r1;*r0p=r0;}
+static void f3074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,0);*r1p=r1;*r0p=r0;}
+static void f3075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,2);*r1p=r1;*r0p=r0;}
+static void f3077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-3);*r1p=r1;*r0p=r0;}
+static void f3080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,4);*r1p=r1;*r0p=r0;}
+static void f3081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-4);*r1p=r1;*r0p=r0;}
+static void f3082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,3);*r1p=r1;*r0p=r0;}
+static void f3083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-5);*r1p=r1;*r0p=r0;}
+static void f3084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,8);*r1p=r1;*r0p=r0;}
+static void f3085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-8);*r1p=r1;*r0p=r0;}
+static void f3086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,7);*r1p=r1;*r0p=r0;}
+static void f3087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-9);*r1p=r1;*r0p=r0;}
+static void f3088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,16);*r1p=r1;*r0p=r0;}
+static void f3089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-16);*r1p=r1;*r0p=r0;}
+static void f3090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,15);*r1p=r1;*r0p=r0;}
+static void f3091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-17);*r1p=r1;*r0p=r0;}
+static void f3092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,32);*r1p=r1;*r0p=r0;}
+static void f3093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-32);*r1p=r1;*r0p=r0;}
+static void f3094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,31);*r1p=r1;*r0p=r0;}
+static void f3095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-33);*r1p=r1;*r0p=r0;}
+static void f3096(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,64);*r1p=r1;*r0p=r0;}
+static void f3097(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-64);*r1p=r1;*r0p=r0;}
+static void f3098(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,63);*r1p=r1;*r0p=r0;}
+static void f3099(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-65);*r1p=r1;*r0p=r0;}
+static void f3100(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,128);*r1p=r1;*r0p=r0;}
+static void f3101(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-128);*r1p=r1;*r0p=r0;}
+static void f3102(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,127);*r1p=r1;*r0p=r0;}
+static void f3103(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-129);*r1p=r1;*r0p=r0;}
+static void f3104(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,256);*r1p=r1;*r0p=r0;}
+static void f3105(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-256);*r1p=r1;*r0p=r0;}
+static void f3106(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,255);*r1p=r1;*r0p=r0;}
+static void f3107(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-257);*r1p=r1;*r0p=r0;}
+static void f3108(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,512);*r1p=r1;*r0p=r0;}
+static void f3109(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-512);*r1p=r1;*r0p=r0;}
+static void f3110(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,511);*r1p=r1;*r0p=r0;}
+static void f3111(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-513);*r1p=r1;*r0p=r0;}
+static void f3112(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,1024);*r1p=r1;*r0p=r0;}
+static void f3113(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3114(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,1023);*r1p=r1;*r0p=r0;}
+static void f3115(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3116(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,2048);*r1p=r1;*r0p=r0;}
+static void f3117(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3118(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,2047);*r1p=r1;*r0p=r0;}
+static void f3119(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3120(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,4096);*r1p=r1;*r0p=r0;}
+static void f3121(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3122(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,4095);*r1p=r1;*r0p=r0;}
+static void f3123(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3124(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,8192);*r1p=r1;*r0p=r0;}
+static void f3125(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3126(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,8191);*r1p=r1;*r0p=r0;}
+static void f3127(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3128(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,16384);*r1p=r1;*r0p=r0;}
+static void f3129(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3130(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,16383);*r1p=r1;*r0p=r0;}
+static void f3131(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3132(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,32768);*r1p=r1;*r0p=r0;}
+static void f3133(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3134(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,32767);*r1p=r1;*r0p=r0;}
+static void f3135(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4096,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3136(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3137(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-1);*r1p=r1;*r0p=r0;}
+static void f3138(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,0);*r1p=r1;*r0p=r0;}
+static void f3139(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3140(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,2);*r1p=r1;*r0p=r0;}
+static void f3141(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-2);*r1p=r1;*r0p=r0;}
+static void f3142(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,1);*r1p=r1;*r0p=r0;}
+static void f3143(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-3);*r1p=r1;*r0p=r0;}
+static void f3144(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,4);*r1p=r1;*r0p=r0;}
+static void f3145(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-4);*r1p=r1;*r0p=r0;}
+static void f3146(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,3);*r1p=r1;*r0p=r0;}
+static void f3147(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-5);*r1p=r1;*r0p=r0;}
+static void f3148(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,8);*r1p=r1;*r0p=r0;}
+static void f3149(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-8);*r1p=r1;*r0p=r0;}
+static void f3150(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,7);*r1p=r1;*r0p=r0;}
+static void f3151(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-9);*r1p=r1;*r0p=r0;}
+static void f3152(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,16);*r1p=r1;*r0p=r0;}
+static void f3153(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-16);*r1p=r1;*r0p=r0;}
+static void f3154(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,15);*r1p=r1;*r0p=r0;}
+static void f3155(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-17);*r1p=r1;*r0p=r0;}
+static void f3156(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,32);*r1p=r1;*r0p=r0;}
+static void f3157(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-32);*r1p=r1;*r0p=r0;}
+static void f3158(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,31);*r1p=r1;*r0p=r0;}
+static void f3159(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-33);*r1p=r1;*r0p=r0;}
+static void f3160(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,64);*r1p=r1;*r0p=r0;}
+static void f3161(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-64);*r1p=r1;*r0p=r0;}
+static void f3162(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,63);*r1p=r1;*r0p=r0;}
+static void f3163(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-65);*r1p=r1;*r0p=r0;}
+static void f3164(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,128);*r1p=r1;*r0p=r0;}
+static void f3165(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-128);*r1p=r1;*r0p=r0;}
+static void f3166(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,127);*r1p=r1;*r0p=r0;}
+static void f3167(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-129);*r1p=r1;*r0p=r0;}
+static void f3168(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,256);*r1p=r1;*r0p=r0;}
+static void f3169(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-256);*r1p=r1;*r0p=r0;}
+static void f3170(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,255);*r1p=r1;*r0p=r0;}
+static void f3171(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-257);*r1p=r1;*r0p=r0;}
+static void f3172(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,512);*r1p=r1;*r0p=r0;}
+static void f3173(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-512);*r1p=r1;*r0p=r0;}
+static void f3174(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,511);*r1p=r1;*r0p=r0;}
+static void f3175(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-513);*r1p=r1;*r0p=r0;}
+static void f3176(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,1024);*r1p=r1;*r0p=r0;}
+static void f3177(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3178(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,1023);*r1p=r1;*r0p=r0;}
+static void f3179(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3180(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,2048);*r1p=r1;*r0p=r0;}
+static void f3181(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3182(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,2047);*r1p=r1;*r0p=r0;}
+static void f3183(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3184(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,4096);*r1p=r1;*r0p=r0;}
+static void f3185(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3186(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,4095);*r1p=r1;*r0p=r0;}
+static void f3187(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3188(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,8192);*r1p=r1;*r0p=r0;}
+static void f3189(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3190(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,8191);*r1p=r1;*r0p=r0;}
+static void f3191(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3192(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,16384);*r1p=r1;*r0p=r0;}
+static void f3193(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3194(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,16383);*r1p=r1;*r0p=r0;}
+static void f3195(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3196(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,32768);*r1p=r1;*r0p=r0;}
+static void f3197(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3198(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,32767);*r1p=r1;*r0p=r0;}
+static void f3199(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4096,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3200(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,1);*r1p=r1;*r0p=r0;}
+static void f3201(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-1);*r1p=r1;*r0p=r0;}
+static void f3202(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,0);*r1p=r1;*r0p=r0;}
+static void f3203(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-2);*r1p=r1;*r0p=r0;}
+static void f3204(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,2);*r1p=r1;*r0p=r0;}
+static void f3205(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-2);*r1p=r1;*r0p=r0;}
+static void f3206(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,1);*r1p=r1;*r0p=r0;}
+static void f3207(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-3);*r1p=r1;*r0p=r0;}
+static void f3208(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,4);*r1p=r1;*r0p=r0;}
+static void f3209(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-4);*r1p=r1;*r0p=r0;}
+static void f3210(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,3);*r1p=r1;*r0p=r0;}
+static void f3211(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-5);*r1p=r1;*r0p=r0;}
+static void f3212(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,8);*r1p=r1;*r0p=r0;}
+static void f3213(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-8);*r1p=r1;*r0p=r0;}
+static void f3214(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,7);*r1p=r1;*r0p=r0;}
+static void f3215(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-9);*r1p=r1;*r0p=r0;}
+static void f3216(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,16);*r1p=r1;*r0p=r0;}
+static void f3217(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-16);*r1p=r1;*r0p=r0;}
+static void f3218(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,15);*r1p=r1;*r0p=r0;}
+static void f3219(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-17);*r1p=r1;*r0p=r0;}
+static void f3220(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,32);*r1p=r1;*r0p=r0;}
+static void f3221(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-32);*r1p=r1;*r0p=r0;}
+static void f3222(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,31);*r1p=r1;*r0p=r0;}
+static void f3223(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-33);*r1p=r1;*r0p=r0;}
+static void f3224(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,64);*r1p=r1;*r0p=r0;}
+static void f3225(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-64);*r1p=r1;*r0p=r0;}
+static void f3226(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,63);*r1p=r1;*r0p=r0;}
+static void f3227(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-65);*r1p=r1;*r0p=r0;}
+static void f3228(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,128);*r1p=r1;*r0p=r0;}
+static void f3229(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-128);*r1p=r1;*r0p=r0;}
+static void f3230(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,127);*r1p=r1;*r0p=r0;}
+static void f3231(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-129);*r1p=r1;*r0p=r0;}
+static void f3232(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,256);*r1p=r1;*r0p=r0;}
+static void f3233(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-256);*r1p=r1;*r0p=r0;}
+static void f3234(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,255);*r1p=r1;*r0p=r0;}
+static void f3235(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-257);*r1p=r1;*r0p=r0;}
+static void f3236(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,512);*r1p=r1;*r0p=r0;}
+static void f3237(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-512);*r1p=r1;*r0p=r0;}
+static void f3238(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,511);*r1p=r1;*r0p=r0;}
+static void f3239(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-513);*r1p=r1;*r0p=r0;}
+static void f3240(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,1024);*r1p=r1;*r0p=r0;}
+static void f3241(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3242(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,1023);*r1p=r1;*r0p=r0;}
+static void f3243(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3244(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,2048);*r1p=r1;*r0p=r0;}
+static void f3245(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3246(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,2047);*r1p=r1;*r0p=r0;}
+static void f3247(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3248(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,4096);*r1p=r1;*r0p=r0;}
+static void f3249(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3250(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,4095);*r1p=r1;*r0p=r0;}
+static void f3251(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3252(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,8192);*r1p=r1;*r0p=r0;}
+static void f3253(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3254(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,8191);*r1p=r1;*r0p=r0;}
+static void f3255(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3256(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,16384);*r1p=r1;*r0p=r0;}
+static void f3257(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3258(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,16383);*r1p=r1;*r0p=r0;}
+static void f3259(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3260(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,32768);*r1p=r1;*r0p=r0;}
+static void f3261(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3262(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,32767);*r1p=r1;*r0p=r0;}
+static void f3263(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,4095,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3264(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,1);*r1p=r1;*r0p=r0;}
+static void f3265(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-1);*r1p=r1;*r0p=r0;}
+static void f3266(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,0);*r1p=r1;*r0p=r0;}
+static void f3267(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-2);*r1p=r1;*r0p=r0;}
+static void f3268(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,2);*r1p=r1;*r0p=r0;}
+static void f3269(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-2);*r1p=r1;*r0p=r0;}
+static void f3270(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,1);*r1p=r1;*r0p=r0;}
+static void f3271(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-3);*r1p=r1;*r0p=r0;}
+static void f3272(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,4);*r1p=r1;*r0p=r0;}
+static void f3273(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-4);*r1p=r1;*r0p=r0;}
+static void f3274(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,3);*r1p=r1;*r0p=r0;}
+static void f3275(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-5);*r1p=r1;*r0p=r0;}
+static void f3276(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,8);*r1p=r1;*r0p=r0;}
+static void f3277(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-8);*r1p=r1;*r0p=r0;}
+static void f3278(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,7);*r1p=r1;*r0p=r0;}
+static void f3279(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-9);*r1p=r1;*r0p=r0;}
+static void f3280(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,16);*r1p=r1;*r0p=r0;}
+static void f3281(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-16);*r1p=r1;*r0p=r0;}
+static void f3282(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,15);*r1p=r1;*r0p=r0;}
+static void f3283(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-17);*r1p=r1;*r0p=r0;}
+static void f3284(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,32);*r1p=r1;*r0p=r0;}
+static void f3285(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-32);*r1p=r1;*r0p=r0;}
+static void f3286(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,31);*r1p=r1;*r0p=r0;}
+static void f3287(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-33);*r1p=r1;*r0p=r0;}
+static void f3288(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,64);*r1p=r1;*r0p=r0;}
+static void f3289(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-64);*r1p=r1;*r0p=r0;}
+static void f3290(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,63);*r1p=r1;*r0p=r0;}
+static void f3291(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-65);*r1p=r1;*r0p=r0;}
+static void f3292(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,128);*r1p=r1;*r0p=r0;}
+static void f3293(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-128);*r1p=r1;*r0p=r0;}
+static void f3294(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,127);*r1p=r1;*r0p=r0;}
+static void f3295(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-129);*r1p=r1;*r0p=r0;}
+static void f3296(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,256);*r1p=r1;*r0p=r0;}
+static void f3297(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-256);*r1p=r1;*r0p=r0;}
+static void f3298(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,255);*r1p=r1;*r0p=r0;}
+static void f3299(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-257);*r1p=r1;*r0p=r0;}
+static void f3300(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,512);*r1p=r1;*r0p=r0;}
+static void f3301(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-512);*r1p=r1;*r0p=r0;}
+static void f3302(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,511);*r1p=r1;*r0p=r0;}
+static void f3303(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-513);*r1p=r1;*r0p=r0;}
+static void f3304(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,1024);*r1p=r1;*r0p=r0;}
+static void f3305(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3306(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,1023);*r1p=r1;*r0p=r0;}
+static void f3307(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3308(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,2048);*r1p=r1;*r0p=r0;}
+static void f3309(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3310(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,2047);*r1p=r1;*r0p=r0;}
+static void f3311(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3312(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,4096);*r1p=r1;*r0p=r0;}
+static void f3313(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3314(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,4095);*r1p=r1;*r0p=r0;}
+static void f3315(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3316(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,8192);*r1p=r1;*r0p=r0;}
+static void f3317(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3318(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,8191);*r1p=r1;*r0p=r0;}
+static void f3319(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3320(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,16384);*r1p=r1;*r0p=r0;}
+static void f3321(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3322(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,16383);*r1p=r1;*r0p=r0;}
+static void f3323(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3324(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,32768);*r1p=r1;*r0p=r0;}
+static void f3325(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3326(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,32767);*r1p=r1;*r0p=r0;}
+static void f3327(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-4097,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3328(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3329(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-1);*r1p=r1;*r0p=r0;}
+static void f3330(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,0);*r1p=r1;*r0p=r0;}
+static void f3331(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3332(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,2);*r1p=r1;*r0p=r0;}
+static void f3333(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3334(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3335(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-3);*r1p=r1;*r0p=r0;}
+static void f3336(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,4);*r1p=r1;*r0p=r0;}
+static void f3337(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-4);*r1p=r1;*r0p=r0;}
+static void f3338(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,3);*r1p=r1;*r0p=r0;}
+static void f3339(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-5);*r1p=r1;*r0p=r0;}
+static void f3340(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,8);*r1p=r1;*r0p=r0;}
+static void f3341(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-8);*r1p=r1;*r0p=r0;}
+static void f3342(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,7);*r1p=r1;*r0p=r0;}
+static void f3343(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-9);*r1p=r1;*r0p=r0;}
+static void f3344(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,16);*r1p=r1;*r0p=r0;}
+static void f3345(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-16);*r1p=r1;*r0p=r0;}
+static void f3346(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,15);*r1p=r1;*r0p=r0;}
+static void f3347(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-17);*r1p=r1;*r0p=r0;}
+static void f3348(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,32);*r1p=r1;*r0p=r0;}
+static void f3349(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-32);*r1p=r1;*r0p=r0;}
+static void f3350(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,31);*r1p=r1;*r0p=r0;}
+static void f3351(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-33);*r1p=r1;*r0p=r0;}
+static void f3352(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,64);*r1p=r1;*r0p=r0;}
+static void f3353(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-64);*r1p=r1;*r0p=r0;}
+static void f3354(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,63);*r1p=r1;*r0p=r0;}
+static void f3355(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-65);*r1p=r1;*r0p=r0;}
+static void f3356(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,128);*r1p=r1;*r0p=r0;}
+static void f3357(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-128);*r1p=r1;*r0p=r0;}
+static void f3358(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,127);*r1p=r1;*r0p=r0;}
+static void f3359(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-129);*r1p=r1;*r0p=r0;}
+static void f3360(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,256);*r1p=r1;*r0p=r0;}
+static void f3361(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-256);*r1p=r1;*r0p=r0;}
+static void f3362(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,255);*r1p=r1;*r0p=r0;}
+static void f3363(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-257);*r1p=r1;*r0p=r0;}
+static void f3364(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,512);*r1p=r1;*r0p=r0;}
+static void f3365(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-512);*r1p=r1;*r0p=r0;}
+static void f3366(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,511);*r1p=r1;*r0p=r0;}
+static void f3367(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-513);*r1p=r1;*r0p=r0;}
+static void f3368(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,1024);*r1p=r1;*r0p=r0;}
+static void f3369(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3370(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,1023);*r1p=r1;*r0p=r0;}
+static void f3371(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3372(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,2048);*r1p=r1;*r0p=r0;}
+static void f3373(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3374(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,2047);*r1p=r1;*r0p=r0;}
+static void f3375(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3376(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,4096);*r1p=r1;*r0p=r0;}
+static void f3377(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3378(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,4095);*r1p=r1;*r0p=r0;}
+static void f3379(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3380(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,8192);*r1p=r1;*r0p=r0;}
+static void f3381(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3382(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,8191);*r1p=r1;*r0p=r0;}
+static void f3383(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3384(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,16384);*r1p=r1;*r0p=r0;}
+static void f3385(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3386(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,16383);*r1p=r1;*r0p=r0;}
+static void f3387(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3388(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,32768);*r1p=r1;*r0p=r0;}
+static void f3389(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3390(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,32767);*r1p=r1;*r0p=r0;}
+static void f3391(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8192,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3392(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3393(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-1);*r1p=r1;*r0p=r0;}
+static void f3394(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,0);*r1p=r1;*r0p=r0;}
+static void f3395(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3396(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,2);*r1p=r1;*r0p=r0;}
+static void f3397(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-2);*r1p=r1;*r0p=r0;}
+static void f3398(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,1);*r1p=r1;*r0p=r0;}
+static void f3399(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-3);*r1p=r1;*r0p=r0;}
+static void f3400(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,4);*r1p=r1;*r0p=r0;}
+static void f3401(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-4);*r1p=r1;*r0p=r0;}
+static void f3402(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,3);*r1p=r1;*r0p=r0;}
+static void f3403(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-5);*r1p=r1;*r0p=r0;}
+static void f3404(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,8);*r1p=r1;*r0p=r0;}
+static void f3405(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-8);*r1p=r1;*r0p=r0;}
+static void f3406(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,7);*r1p=r1;*r0p=r0;}
+static void f3407(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-9);*r1p=r1;*r0p=r0;}
+static void f3408(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,16);*r1p=r1;*r0p=r0;}
+static void f3409(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-16);*r1p=r1;*r0p=r0;}
+static void f3410(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,15);*r1p=r1;*r0p=r0;}
+static void f3411(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-17);*r1p=r1;*r0p=r0;}
+static void f3412(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,32);*r1p=r1;*r0p=r0;}
+static void f3413(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-32);*r1p=r1;*r0p=r0;}
+static void f3414(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,31);*r1p=r1;*r0p=r0;}
+static void f3415(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-33);*r1p=r1;*r0p=r0;}
+static void f3416(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,64);*r1p=r1;*r0p=r0;}
+static void f3417(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-64);*r1p=r1;*r0p=r0;}
+static void f3418(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,63);*r1p=r1;*r0p=r0;}
+static void f3419(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-65);*r1p=r1;*r0p=r0;}
+static void f3420(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,128);*r1p=r1;*r0p=r0;}
+static void f3421(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-128);*r1p=r1;*r0p=r0;}
+static void f3422(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,127);*r1p=r1;*r0p=r0;}
+static void f3423(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-129);*r1p=r1;*r0p=r0;}
+static void f3424(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,256);*r1p=r1;*r0p=r0;}
+static void f3425(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-256);*r1p=r1;*r0p=r0;}
+static void f3426(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,255);*r1p=r1;*r0p=r0;}
+static void f3427(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-257);*r1p=r1;*r0p=r0;}
+static void f3428(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,512);*r1p=r1;*r0p=r0;}
+static void f3429(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-512);*r1p=r1;*r0p=r0;}
+static void f3430(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,511);*r1p=r1;*r0p=r0;}
+static void f3431(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-513);*r1p=r1;*r0p=r0;}
+static void f3432(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,1024);*r1p=r1;*r0p=r0;}
+static void f3433(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3434(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,1023);*r1p=r1;*r0p=r0;}
+static void f3435(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3436(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,2048);*r1p=r1;*r0p=r0;}
+static void f3437(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3438(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,2047);*r1p=r1;*r0p=r0;}
+static void f3439(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3440(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,4096);*r1p=r1;*r0p=r0;}
+static void f3441(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3442(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,4095);*r1p=r1;*r0p=r0;}
+static void f3443(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3444(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,8192);*r1p=r1;*r0p=r0;}
+static void f3445(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3446(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,8191);*r1p=r1;*r0p=r0;}
+static void f3447(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3448(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,16384);*r1p=r1;*r0p=r0;}
+static void f3449(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3450(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,16383);*r1p=r1;*r0p=r0;}
+static void f3451(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3452(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,32768);*r1p=r1;*r0p=r0;}
+static void f3453(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3454(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,32767);*r1p=r1;*r0p=r0;}
+static void f3455(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8192,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3456(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,1);*r1p=r1;*r0p=r0;}
+static void f3457(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-1);*r1p=r1;*r0p=r0;}
+static void f3458(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,0);*r1p=r1;*r0p=r0;}
+static void f3459(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-2);*r1p=r1;*r0p=r0;}
+static void f3460(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,2);*r1p=r1;*r0p=r0;}
+static void f3461(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-2);*r1p=r1;*r0p=r0;}
+static void f3462(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,1);*r1p=r1;*r0p=r0;}
+static void f3463(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-3);*r1p=r1;*r0p=r0;}
+static void f3464(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,4);*r1p=r1;*r0p=r0;}
+static void f3465(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-4);*r1p=r1;*r0p=r0;}
+static void f3466(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,3);*r1p=r1;*r0p=r0;}
+static void f3467(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-5);*r1p=r1;*r0p=r0;}
+static void f3468(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,8);*r1p=r1;*r0p=r0;}
+static void f3469(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-8);*r1p=r1;*r0p=r0;}
+static void f3470(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,7);*r1p=r1;*r0p=r0;}
+static void f3471(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-9);*r1p=r1;*r0p=r0;}
+static void f3472(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,16);*r1p=r1;*r0p=r0;}
+static void f3473(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-16);*r1p=r1;*r0p=r0;}
+static void f3474(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,15);*r1p=r1;*r0p=r0;}
+static void f3475(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-17);*r1p=r1;*r0p=r0;}
+static void f3476(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,32);*r1p=r1;*r0p=r0;}
+static void f3477(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-32);*r1p=r1;*r0p=r0;}
+static void f3478(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,31);*r1p=r1;*r0p=r0;}
+static void f3479(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-33);*r1p=r1;*r0p=r0;}
+static void f3480(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,64);*r1p=r1;*r0p=r0;}
+static void f3481(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-64);*r1p=r1;*r0p=r0;}
+static void f3482(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,63);*r1p=r1;*r0p=r0;}
+static void f3483(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-65);*r1p=r1;*r0p=r0;}
+static void f3484(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,128);*r1p=r1;*r0p=r0;}
+static void f3485(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-128);*r1p=r1;*r0p=r0;}
+static void f3486(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,127);*r1p=r1;*r0p=r0;}
+static void f3487(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-129);*r1p=r1;*r0p=r0;}
+static void f3488(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,256);*r1p=r1;*r0p=r0;}
+static void f3489(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-256);*r1p=r1;*r0p=r0;}
+static void f3490(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,255);*r1p=r1;*r0p=r0;}
+static void f3491(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-257);*r1p=r1;*r0p=r0;}
+static void f3492(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,512);*r1p=r1;*r0p=r0;}
+static void f3493(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-512);*r1p=r1;*r0p=r0;}
+static void f3494(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,511);*r1p=r1;*r0p=r0;}
+static void f3495(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-513);*r1p=r1;*r0p=r0;}
+static void f3496(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,1024);*r1p=r1;*r0p=r0;}
+static void f3497(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3498(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,1023);*r1p=r1;*r0p=r0;}
+static void f3499(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3500(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,2048);*r1p=r1;*r0p=r0;}
+static void f3501(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3502(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,2047);*r1p=r1;*r0p=r0;}
+static void f3503(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3504(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,4096);*r1p=r1;*r0p=r0;}
+static void f3505(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3506(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,4095);*r1p=r1;*r0p=r0;}
+static void f3507(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3508(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,8192);*r1p=r1;*r0p=r0;}
+static void f3509(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3510(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,8191);*r1p=r1;*r0p=r0;}
+static void f3511(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3512(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,16384);*r1p=r1;*r0p=r0;}
+static void f3513(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3514(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,16383);*r1p=r1;*r0p=r0;}
+static void f3515(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3516(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,32768);*r1p=r1;*r0p=r0;}
+static void f3517(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3518(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,32767);*r1p=r1;*r0p=r0;}
+static void f3519(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,8191,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3520(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,1);*r1p=r1;*r0p=r0;}
+static void f3521(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-1);*r1p=r1;*r0p=r0;}
+static void f3522(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,0);*r1p=r1;*r0p=r0;}
+static void f3523(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-2);*r1p=r1;*r0p=r0;}
+static void f3524(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,2);*r1p=r1;*r0p=r0;}
+static void f3525(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-2);*r1p=r1;*r0p=r0;}
+static void f3526(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,1);*r1p=r1;*r0p=r0;}
+static void f3527(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-3);*r1p=r1;*r0p=r0;}
+static void f3528(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,4);*r1p=r1;*r0p=r0;}
+static void f3529(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-4);*r1p=r1;*r0p=r0;}
+static void f3530(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,3);*r1p=r1;*r0p=r0;}
+static void f3531(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-5);*r1p=r1;*r0p=r0;}
+static void f3532(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,8);*r1p=r1;*r0p=r0;}
+static void f3533(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-8);*r1p=r1;*r0p=r0;}
+static void f3534(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,7);*r1p=r1;*r0p=r0;}
+static void f3535(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-9);*r1p=r1;*r0p=r0;}
+static void f3536(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,16);*r1p=r1;*r0p=r0;}
+static void f3537(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-16);*r1p=r1;*r0p=r0;}
+static void f3538(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,15);*r1p=r1;*r0p=r0;}
+static void f3539(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-17);*r1p=r1;*r0p=r0;}
+static void f3540(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,32);*r1p=r1;*r0p=r0;}
+static void f3541(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-32);*r1p=r1;*r0p=r0;}
+static void f3542(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,31);*r1p=r1;*r0p=r0;}
+static void f3543(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-33);*r1p=r1;*r0p=r0;}
+static void f3544(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,64);*r1p=r1;*r0p=r0;}
+static void f3545(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-64);*r1p=r1;*r0p=r0;}
+static void f3546(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,63);*r1p=r1;*r0p=r0;}
+static void f3547(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-65);*r1p=r1;*r0p=r0;}
+static void f3548(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,128);*r1p=r1;*r0p=r0;}
+static void f3549(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-128);*r1p=r1;*r0p=r0;}
+static void f3550(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,127);*r1p=r1;*r0p=r0;}
+static void f3551(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-129);*r1p=r1;*r0p=r0;}
+static void f3552(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,256);*r1p=r1;*r0p=r0;}
+static void f3553(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-256);*r1p=r1;*r0p=r0;}
+static void f3554(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,255);*r1p=r1;*r0p=r0;}
+static void f3555(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-257);*r1p=r1;*r0p=r0;}
+static void f3556(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,512);*r1p=r1;*r0p=r0;}
+static void f3557(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-512);*r1p=r1;*r0p=r0;}
+static void f3558(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,511);*r1p=r1;*r0p=r0;}
+static void f3559(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-513);*r1p=r1;*r0p=r0;}
+static void f3560(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,1024);*r1p=r1;*r0p=r0;}
+static void f3561(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3562(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,1023);*r1p=r1;*r0p=r0;}
+static void f3563(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3564(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,2048);*r1p=r1;*r0p=r0;}
+static void f3565(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3566(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,2047);*r1p=r1;*r0p=r0;}
+static void f3567(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3568(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,4096);*r1p=r1;*r0p=r0;}
+static void f3569(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3570(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,4095);*r1p=r1;*r0p=r0;}
+static void f3571(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3572(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,8192);*r1p=r1;*r0p=r0;}
+static void f3573(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3574(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,8191);*r1p=r1;*r0p=r0;}
+static void f3575(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3576(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,16384);*r1p=r1;*r0p=r0;}
+static void f3577(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3578(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,16383);*r1p=r1;*r0p=r0;}
+static void f3579(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3580(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,32768);*r1p=r1;*r0p=r0;}
+static void f3581(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3582(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,32767);*r1p=r1;*r0p=r0;}
+static void f3583(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-8193,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3584(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3585(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-1);*r1p=r1;*r0p=r0;}
+static void f3586(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,0);*r1p=r1;*r0p=r0;}
+static void f3587(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3588(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,2);*r1p=r1;*r0p=r0;}
+static void f3589(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3590(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3591(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-3);*r1p=r1;*r0p=r0;}
+static void f3592(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,4);*r1p=r1;*r0p=r0;}
+static void f3593(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-4);*r1p=r1;*r0p=r0;}
+static void f3594(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,3);*r1p=r1;*r0p=r0;}
+static void f3595(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-5);*r1p=r1;*r0p=r0;}
+static void f3596(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,8);*r1p=r1;*r0p=r0;}
+static void f3597(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-8);*r1p=r1;*r0p=r0;}
+static void f3598(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,7);*r1p=r1;*r0p=r0;}
+static void f3599(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-9);*r1p=r1;*r0p=r0;}
+static void f3600(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,16);*r1p=r1;*r0p=r0;}
+static void f3601(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-16);*r1p=r1;*r0p=r0;}
+static void f3602(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,15);*r1p=r1;*r0p=r0;}
+static void f3603(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-17);*r1p=r1;*r0p=r0;}
+static void f3604(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,32);*r1p=r1;*r0p=r0;}
+static void f3605(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-32);*r1p=r1;*r0p=r0;}
+static void f3606(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,31);*r1p=r1;*r0p=r0;}
+static void f3607(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-33);*r1p=r1;*r0p=r0;}
+static void f3608(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,64);*r1p=r1;*r0p=r0;}
+static void f3609(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-64);*r1p=r1;*r0p=r0;}
+static void f3610(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,63);*r1p=r1;*r0p=r0;}
+static void f3611(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-65);*r1p=r1;*r0p=r0;}
+static void f3612(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,128);*r1p=r1;*r0p=r0;}
+static void f3613(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-128);*r1p=r1;*r0p=r0;}
+static void f3614(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,127);*r1p=r1;*r0p=r0;}
+static void f3615(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-129);*r1p=r1;*r0p=r0;}
+static void f3616(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,256);*r1p=r1;*r0p=r0;}
+static void f3617(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-256);*r1p=r1;*r0p=r0;}
+static void f3618(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,255);*r1p=r1;*r0p=r0;}
+static void f3619(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-257);*r1p=r1;*r0p=r0;}
+static void f3620(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,512);*r1p=r1;*r0p=r0;}
+static void f3621(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-512);*r1p=r1;*r0p=r0;}
+static void f3622(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,511);*r1p=r1;*r0p=r0;}
+static void f3623(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-513);*r1p=r1;*r0p=r0;}
+static void f3624(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,1024);*r1p=r1;*r0p=r0;}
+static void f3625(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3626(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,1023);*r1p=r1;*r0p=r0;}
+static void f3627(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3628(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,2048);*r1p=r1;*r0p=r0;}
+static void f3629(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3630(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,2047);*r1p=r1;*r0p=r0;}
+static void f3631(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3632(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,4096);*r1p=r1;*r0p=r0;}
+static void f3633(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3634(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,4095);*r1p=r1;*r0p=r0;}
+static void f3635(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3636(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,8192);*r1p=r1;*r0p=r0;}
+static void f3637(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3638(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,8191);*r1p=r1;*r0p=r0;}
+static void f3639(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3640(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,16384);*r1p=r1;*r0p=r0;}
+static void f3641(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3642(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,16383);*r1p=r1;*r0p=r0;}
+static void f3643(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3644(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,32768);*r1p=r1;*r0p=r0;}
+static void f3645(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3646(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,32767);*r1p=r1;*r0p=r0;}
+static void f3647(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16384,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3648(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3649(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-1);*r1p=r1;*r0p=r0;}
+static void f3650(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,0);*r1p=r1;*r0p=r0;}
+static void f3651(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3652(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,2);*r1p=r1;*r0p=r0;}
+static void f3653(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-2);*r1p=r1;*r0p=r0;}
+static void f3654(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,1);*r1p=r1;*r0p=r0;}
+static void f3655(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-3);*r1p=r1;*r0p=r0;}
+static void f3656(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,4);*r1p=r1;*r0p=r0;}
+static void f3657(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-4);*r1p=r1;*r0p=r0;}
+static void f3658(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,3);*r1p=r1;*r0p=r0;}
+static void f3659(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-5);*r1p=r1;*r0p=r0;}
+static void f3660(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,8);*r1p=r1;*r0p=r0;}
+static void f3661(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-8);*r1p=r1;*r0p=r0;}
+static void f3662(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,7);*r1p=r1;*r0p=r0;}
+static void f3663(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-9);*r1p=r1;*r0p=r0;}
+static void f3664(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,16);*r1p=r1;*r0p=r0;}
+static void f3665(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-16);*r1p=r1;*r0p=r0;}
+static void f3666(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,15);*r1p=r1;*r0p=r0;}
+static void f3667(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-17);*r1p=r1;*r0p=r0;}
+static void f3668(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,32);*r1p=r1;*r0p=r0;}
+static void f3669(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-32);*r1p=r1;*r0p=r0;}
+static void f3670(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,31);*r1p=r1;*r0p=r0;}
+static void f3671(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-33);*r1p=r1;*r0p=r0;}
+static void f3672(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,64);*r1p=r1;*r0p=r0;}
+static void f3673(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-64);*r1p=r1;*r0p=r0;}
+static void f3674(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,63);*r1p=r1;*r0p=r0;}
+static void f3675(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-65);*r1p=r1;*r0p=r0;}
+static void f3676(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,128);*r1p=r1;*r0p=r0;}
+static void f3677(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-128);*r1p=r1;*r0p=r0;}
+static void f3678(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,127);*r1p=r1;*r0p=r0;}
+static void f3679(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-129);*r1p=r1;*r0p=r0;}
+static void f3680(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,256);*r1p=r1;*r0p=r0;}
+static void f3681(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-256);*r1p=r1;*r0p=r0;}
+static void f3682(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,255);*r1p=r1;*r0p=r0;}
+static void f3683(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-257);*r1p=r1;*r0p=r0;}
+static void f3684(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,512);*r1p=r1;*r0p=r0;}
+static void f3685(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-512);*r1p=r1;*r0p=r0;}
+static void f3686(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,511);*r1p=r1;*r0p=r0;}
+static void f3687(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-513);*r1p=r1;*r0p=r0;}
+static void f3688(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,1024);*r1p=r1;*r0p=r0;}
+static void f3689(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3690(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,1023);*r1p=r1;*r0p=r0;}
+static void f3691(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3692(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,2048);*r1p=r1;*r0p=r0;}
+static void f3693(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3694(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,2047);*r1p=r1;*r0p=r0;}
+static void f3695(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3696(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,4096);*r1p=r1;*r0p=r0;}
+static void f3697(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3698(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,4095);*r1p=r1;*r0p=r0;}
+static void f3699(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3700(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,8192);*r1p=r1;*r0p=r0;}
+static void f3701(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3702(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,8191);*r1p=r1;*r0p=r0;}
+static void f3703(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3704(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,16384);*r1p=r1;*r0p=r0;}
+static void f3705(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3706(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,16383);*r1p=r1;*r0p=r0;}
+static void f3707(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3708(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,32768);*r1p=r1;*r0p=r0;}
+static void f3709(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3710(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,32767);*r1p=r1;*r0p=r0;}
+static void f3711(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16384,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3712(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,1);*r1p=r1;*r0p=r0;}
+static void f3713(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-1);*r1p=r1;*r0p=r0;}
+static void f3714(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,0);*r1p=r1;*r0p=r0;}
+static void f3715(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-2);*r1p=r1;*r0p=r0;}
+static void f3716(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,2);*r1p=r1;*r0p=r0;}
+static void f3717(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-2);*r1p=r1;*r0p=r0;}
+static void f3718(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,1);*r1p=r1;*r0p=r0;}
+static void f3719(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-3);*r1p=r1;*r0p=r0;}
+static void f3720(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,4);*r1p=r1;*r0p=r0;}
+static void f3721(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-4);*r1p=r1;*r0p=r0;}
+static void f3722(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,3);*r1p=r1;*r0p=r0;}
+static void f3723(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-5);*r1p=r1;*r0p=r0;}
+static void f3724(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,8);*r1p=r1;*r0p=r0;}
+static void f3725(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-8);*r1p=r1;*r0p=r0;}
+static void f3726(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,7);*r1p=r1;*r0p=r0;}
+static void f3727(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-9);*r1p=r1;*r0p=r0;}
+static void f3728(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,16);*r1p=r1;*r0p=r0;}
+static void f3729(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-16);*r1p=r1;*r0p=r0;}
+static void f3730(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,15);*r1p=r1;*r0p=r0;}
+static void f3731(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-17);*r1p=r1;*r0p=r0;}
+static void f3732(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,32);*r1p=r1;*r0p=r0;}
+static void f3733(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-32);*r1p=r1;*r0p=r0;}
+static void f3734(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,31);*r1p=r1;*r0p=r0;}
+static void f3735(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-33);*r1p=r1;*r0p=r0;}
+static void f3736(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,64);*r1p=r1;*r0p=r0;}
+static void f3737(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-64);*r1p=r1;*r0p=r0;}
+static void f3738(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,63);*r1p=r1;*r0p=r0;}
+static void f3739(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-65);*r1p=r1;*r0p=r0;}
+static void f3740(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,128);*r1p=r1;*r0p=r0;}
+static void f3741(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-128);*r1p=r1;*r0p=r0;}
+static void f3742(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,127);*r1p=r1;*r0p=r0;}
+static void f3743(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-129);*r1p=r1;*r0p=r0;}
+static void f3744(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,256);*r1p=r1;*r0p=r0;}
+static void f3745(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-256);*r1p=r1;*r0p=r0;}
+static void f3746(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,255);*r1p=r1;*r0p=r0;}
+static void f3747(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-257);*r1p=r1;*r0p=r0;}
+static void f3748(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,512);*r1p=r1;*r0p=r0;}
+static void f3749(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-512);*r1p=r1;*r0p=r0;}
+static void f3750(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,511);*r1p=r1;*r0p=r0;}
+static void f3751(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-513);*r1p=r1;*r0p=r0;}
+static void f3752(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,1024);*r1p=r1;*r0p=r0;}
+static void f3753(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3754(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,1023);*r1p=r1;*r0p=r0;}
+static void f3755(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3756(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,2048);*r1p=r1;*r0p=r0;}
+static void f3757(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3758(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,2047);*r1p=r1;*r0p=r0;}
+static void f3759(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3760(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,4096);*r1p=r1;*r0p=r0;}
+static void f3761(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3762(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,4095);*r1p=r1;*r0p=r0;}
+static void f3763(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3764(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,8192);*r1p=r1;*r0p=r0;}
+static void f3765(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3766(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,8191);*r1p=r1;*r0p=r0;}
+static void f3767(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3768(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,16384);*r1p=r1;*r0p=r0;}
+static void f3769(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3770(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,16383);*r1p=r1;*r0p=r0;}
+static void f3771(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3772(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,32768);*r1p=r1;*r0p=r0;}
+static void f3773(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3774(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,32767);*r1p=r1;*r0p=r0;}
+static void f3775(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,16383,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3776(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,1);*r1p=r1;*r0p=r0;}
+static void f3777(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-1);*r1p=r1;*r0p=r0;}
+static void f3778(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,0);*r1p=r1;*r0p=r0;}
+static void f3779(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-2);*r1p=r1;*r0p=r0;}
+static void f3780(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,2);*r1p=r1;*r0p=r0;}
+static void f3781(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-2);*r1p=r1;*r0p=r0;}
+static void f3782(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,1);*r1p=r1;*r0p=r0;}
+static void f3783(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-3);*r1p=r1;*r0p=r0;}
+static void f3784(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,4);*r1p=r1;*r0p=r0;}
+static void f3785(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-4);*r1p=r1;*r0p=r0;}
+static void f3786(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,3);*r1p=r1;*r0p=r0;}
+static void f3787(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-5);*r1p=r1;*r0p=r0;}
+static void f3788(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,8);*r1p=r1;*r0p=r0;}
+static void f3789(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-8);*r1p=r1;*r0p=r0;}
+static void f3790(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,7);*r1p=r1;*r0p=r0;}
+static void f3791(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-9);*r1p=r1;*r0p=r0;}
+static void f3792(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,16);*r1p=r1;*r0p=r0;}
+static void f3793(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-16);*r1p=r1;*r0p=r0;}
+static void f3794(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,15);*r1p=r1;*r0p=r0;}
+static void f3795(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-17);*r1p=r1;*r0p=r0;}
+static void f3796(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,32);*r1p=r1;*r0p=r0;}
+static void f3797(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-32);*r1p=r1;*r0p=r0;}
+static void f3798(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,31);*r1p=r1;*r0p=r0;}
+static void f3799(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-33);*r1p=r1;*r0p=r0;}
+static void f3800(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,64);*r1p=r1;*r0p=r0;}
+static void f3801(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-64);*r1p=r1;*r0p=r0;}
+static void f3802(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,63);*r1p=r1;*r0p=r0;}
+static void f3803(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-65);*r1p=r1;*r0p=r0;}
+static void f3804(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,128);*r1p=r1;*r0p=r0;}
+static void f3805(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-128);*r1p=r1;*r0p=r0;}
+static void f3806(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,127);*r1p=r1;*r0p=r0;}
+static void f3807(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-129);*r1p=r1;*r0p=r0;}
+static void f3808(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,256);*r1p=r1;*r0p=r0;}
+static void f3809(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-256);*r1p=r1;*r0p=r0;}
+static void f3810(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,255);*r1p=r1;*r0p=r0;}
+static void f3811(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-257);*r1p=r1;*r0p=r0;}
+static void f3812(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,512);*r1p=r1;*r0p=r0;}
+static void f3813(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-512);*r1p=r1;*r0p=r0;}
+static void f3814(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,511);*r1p=r1;*r0p=r0;}
+static void f3815(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-513);*r1p=r1;*r0p=r0;}
+static void f3816(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,1024);*r1p=r1;*r0p=r0;}
+static void f3817(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3818(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,1023);*r1p=r1;*r0p=r0;}
+static void f3819(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3820(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,2048);*r1p=r1;*r0p=r0;}
+static void f3821(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3822(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,2047);*r1p=r1;*r0p=r0;}
+static void f3823(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3824(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,4096);*r1p=r1;*r0p=r0;}
+static void f3825(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3826(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,4095);*r1p=r1;*r0p=r0;}
+static void f3827(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3828(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,8192);*r1p=r1;*r0p=r0;}
+static void f3829(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3830(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,8191);*r1p=r1;*r0p=r0;}
+static void f3831(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3832(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,16384);*r1p=r1;*r0p=r0;}
+static void f3833(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3834(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,16383);*r1p=r1;*r0p=r0;}
+static void f3835(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3836(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,32768);*r1p=r1;*r0p=r0;}
+static void f3837(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3838(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,32767);*r1p=r1;*r0p=r0;}
+static void f3839(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-16385,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3840(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3841(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-1);*r1p=r1;*r0p=r0;}
+static void f3842(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,0);*r1p=r1;*r0p=r0;}
+static void f3843(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3844(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,2);*r1p=r1;*r0p=r0;}
+static void f3845(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3846(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3847(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-3);*r1p=r1;*r0p=r0;}
+static void f3848(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,4);*r1p=r1;*r0p=r0;}
+static void f3849(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-4);*r1p=r1;*r0p=r0;}
+static void f3850(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,3);*r1p=r1;*r0p=r0;}
+static void f3851(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-5);*r1p=r1;*r0p=r0;}
+static void f3852(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,8);*r1p=r1;*r0p=r0;}
+static void f3853(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-8);*r1p=r1;*r0p=r0;}
+static void f3854(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,7);*r1p=r1;*r0p=r0;}
+static void f3855(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-9);*r1p=r1;*r0p=r0;}
+static void f3856(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,16);*r1p=r1;*r0p=r0;}
+static void f3857(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-16);*r1p=r1;*r0p=r0;}
+static void f3858(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,15);*r1p=r1;*r0p=r0;}
+static void f3859(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-17);*r1p=r1;*r0p=r0;}
+static void f3860(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,32);*r1p=r1;*r0p=r0;}
+static void f3861(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-32);*r1p=r1;*r0p=r0;}
+static void f3862(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,31);*r1p=r1;*r0p=r0;}
+static void f3863(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-33);*r1p=r1;*r0p=r0;}
+static void f3864(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,64);*r1p=r1;*r0p=r0;}
+static void f3865(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-64);*r1p=r1;*r0p=r0;}
+static void f3866(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,63);*r1p=r1;*r0p=r0;}
+static void f3867(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-65);*r1p=r1;*r0p=r0;}
+static void f3868(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,128);*r1p=r1;*r0p=r0;}
+static void f3869(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-128);*r1p=r1;*r0p=r0;}
+static void f3870(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,127);*r1p=r1;*r0p=r0;}
+static void f3871(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-129);*r1p=r1;*r0p=r0;}
+static void f3872(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,256);*r1p=r1;*r0p=r0;}
+static void f3873(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-256);*r1p=r1;*r0p=r0;}
+static void f3874(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,255);*r1p=r1;*r0p=r0;}
+static void f3875(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-257);*r1p=r1;*r0p=r0;}
+static void f3876(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,512);*r1p=r1;*r0p=r0;}
+static void f3877(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-512);*r1p=r1;*r0p=r0;}
+static void f3878(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,511);*r1p=r1;*r0p=r0;}
+static void f3879(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-513);*r1p=r1;*r0p=r0;}
+static void f3880(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,1024);*r1p=r1;*r0p=r0;}
+static void f3881(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3882(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,1023);*r1p=r1;*r0p=r0;}
+static void f3883(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3884(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,2048);*r1p=r1;*r0p=r0;}
+static void f3885(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3886(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,2047);*r1p=r1;*r0p=r0;}
+static void f3887(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3888(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,4096);*r1p=r1;*r0p=r0;}
+static void f3889(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3890(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,4095);*r1p=r1;*r0p=r0;}
+static void f3891(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3892(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,8192);*r1p=r1;*r0p=r0;}
+static void f3893(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3894(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,8191);*r1p=r1;*r0p=r0;}
+static void f3895(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3896(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,16384);*r1p=r1;*r0p=r0;}
+static void f3897(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3898(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,16383);*r1p=r1;*r0p=r0;}
+static void f3899(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3900(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,32768);*r1p=r1;*r0p=r0;}
+static void f3901(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3902(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,32767);*r1p=r1;*r0p=r0;}
+static void f3903(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32768,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3904(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3905(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-1);*r1p=r1;*r0p=r0;}
+static void f3906(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,0);*r1p=r1;*r0p=r0;}
+static void f3907(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3908(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,2);*r1p=r1;*r0p=r0;}
+static void f3909(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-2);*r1p=r1;*r0p=r0;}
+static void f3910(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,1);*r1p=r1;*r0p=r0;}
+static void f3911(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-3);*r1p=r1;*r0p=r0;}
+static void f3912(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,4);*r1p=r1;*r0p=r0;}
+static void f3913(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-4);*r1p=r1;*r0p=r0;}
+static void f3914(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,3);*r1p=r1;*r0p=r0;}
+static void f3915(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-5);*r1p=r1;*r0p=r0;}
+static void f3916(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,8);*r1p=r1;*r0p=r0;}
+static void f3917(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-8);*r1p=r1;*r0p=r0;}
+static void f3918(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,7);*r1p=r1;*r0p=r0;}
+static void f3919(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-9);*r1p=r1;*r0p=r0;}
+static void f3920(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,16);*r1p=r1;*r0p=r0;}
+static void f3921(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-16);*r1p=r1;*r0p=r0;}
+static void f3922(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,15);*r1p=r1;*r0p=r0;}
+static void f3923(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-17);*r1p=r1;*r0p=r0;}
+static void f3924(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,32);*r1p=r1;*r0p=r0;}
+static void f3925(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-32);*r1p=r1;*r0p=r0;}
+static void f3926(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,31);*r1p=r1;*r0p=r0;}
+static void f3927(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-33);*r1p=r1;*r0p=r0;}
+static void f3928(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,64);*r1p=r1;*r0p=r0;}
+static void f3929(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-64);*r1p=r1;*r0p=r0;}
+static void f3930(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,63);*r1p=r1;*r0p=r0;}
+static void f3931(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-65);*r1p=r1;*r0p=r0;}
+static void f3932(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,128);*r1p=r1;*r0p=r0;}
+static void f3933(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-128);*r1p=r1;*r0p=r0;}
+static void f3934(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,127);*r1p=r1;*r0p=r0;}
+static void f3935(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-129);*r1p=r1;*r0p=r0;}
+static void f3936(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,256);*r1p=r1;*r0p=r0;}
+static void f3937(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-256);*r1p=r1;*r0p=r0;}
+static void f3938(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,255);*r1p=r1;*r0p=r0;}
+static void f3939(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-257);*r1p=r1;*r0p=r0;}
+static void f3940(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,512);*r1p=r1;*r0p=r0;}
+static void f3941(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-512);*r1p=r1;*r0p=r0;}
+static void f3942(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,511);*r1p=r1;*r0p=r0;}
+static void f3943(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-513);*r1p=r1;*r0p=r0;}
+static void f3944(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,1024);*r1p=r1;*r0p=r0;}
+static void f3945(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-1024);*r1p=r1;*r0p=r0;}
+static void f3946(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,1023);*r1p=r1;*r0p=r0;}
+static void f3947(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-1025);*r1p=r1;*r0p=r0;}
+static void f3948(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,2048);*r1p=r1;*r0p=r0;}
+static void f3949(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-2048);*r1p=r1;*r0p=r0;}
+static void f3950(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,2047);*r1p=r1;*r0p=r0;}
+static void f3951(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-2049);*r1p=r1;*r0p=r0;}
+static void f3952(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,4096);*r1p=r1;*r0p=r0;}
+static void f3953(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-4096);*r1p=r1;*r0p=r0;}
+static void f3954(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,4095);*r1p=r1;*r0p=r0;}
+static void f3955(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-4097);*r1p=r1;*r0p=r0;}
+static void f3956(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,8192);*r1p=r1;*r0p=r0;}
+static void f3957(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-8192);*r1p=r1;*r0p=r0;}
+static void f3958(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,8191);*r1p=r1;*r0p=r0;}
+static void f3959(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-8193);*r1p=r1;*r0p=r0;}
+static void f3960(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,16384);*r1p=r1;*r0p=r0;}
+static void f3961(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-16384);*r1p=r1;*r0p=r0;}
+static void f3962(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,16383);*r1p=r1;*r0p=r0;}
+static void f3963(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-16385);*r1p=r1;*r0p=r0;}
+static void f3964(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,32768);*r1p=r1;*r0p=r0;}
+static void f3965(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-32768);*r1p=r1;*r0p=r0;}
+static void f3966(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,32767);*r1p=r1;*r0p=r0;}
+static void f3967(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32768,0,-32769);*r1p=r1;*r0p=r0;}
+static void f3968(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,1);*r1p=r1;*r0p=r0;}
+static void f3969(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-1);*r1p=r1;*r0p=r0;}
+static void f3970(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,0);*r1p=r1;*r0p=r0;}
+static void f3971(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-2);*r1p=r1;*r0p=r0;}
+static void f3972(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,2);*r1p=r1;*r0p=r0;}
+static void f3973(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-2);*r1p=r1;*r0p=r0;}
+static void f3974(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,1);*r1p=r1;*r0p=r0;}
+static void f3975(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-3);*r1p=r1;*r0p=r0;}
+static void f3976(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,4);*r1p=r1;*r0p=r0;}
+static void f3977(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-4);*r1p=r1;*r0p=r0;}
+static void f3978(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,3);*r1p=r1;*r0p=r0;}
+static void f3979(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-5);*r1p=r1;*r0p=r0;}
+static void f3980(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,8);*r1p=r1;*r0p=r0;}
+static void f3981(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-8);*r1p=r1;*r0p=r0;}
+static void f3982(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,7);*r1p=r1;*r0p=r0;}
+static void f3983(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-9);*r1p=r1;*r0p=r0;}
+static void f3984(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,16);*r1p=r1;*r0p=r0;}
+static void f3985(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-16);*r1p=r1;*r0p=r0;}
+static void f3986(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,15);*r1p=r1;*r0p=r0;}
+static void f3987(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-17);*r1p=r1;*r0p=r0;}
+static void f3988(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,32);*r1p=r1;*r0p=r0;}
+static void f3989(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-32);*r1p=r1;*r0p=r0;}
+static void f3990(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,31);*r1p=r1;*r0p=r0;}
+static void f3991(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-33);*r1p=r1;*r0p=r0;}
+static void f3992(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,64);*r1p=r1;*r0p=r0;}
+static void f3993(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-64);*r1p=r1;*r0p=r0;}
+static void f3994(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,63);*r1p=r1;*r0p=r0;}
+static void f3995(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-65);*r1p=r1;*r0p=r0;}
+static void f3996(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,128);*r1p=r1;*r0p=r0;}
+static void f3997(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-128);*r1p=r1;*r0p=r0;}
+static void f3998(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,127);*r1p=r1;*r0p=r0;}
+static void f3999(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-129);*r1p=r1;*r0p=r0;}
+static void f4000(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,256);*r1p=r1;*r0p=r0;}
+static void f4001(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-256);*r1p=r1;*r0p=r0;}
+static void f4002(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,255);*r1p=r1;*r0p=r0;}
+static void f4003(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-257);*r1p=r1;*r0p=r0;}
+static void f4004(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,512);*r1p=r1;*r0p=r0;}
+static void f4005(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-512);*r1p=r1;*r0p=r0;}
+static void f4006(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,511);*r1p=r1;*r0p=r0;}
+static void f4007(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-513);*r1p=r1;*r0p=r0;}
+static void f4008(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,1024);*r1p=r1;*r0p=r0;}
+static void f4009(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-1024);*r1p=r1;*r0p=r0;}
+static void f4010(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,1023);*r1p=r1;*r0p=r0;}
+static void f4011(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-1025);*r1p=r1;*r0p=r0;}
+static void f4012(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,2048);*r1p=r1;*r0p=r0;}
+static void f4013(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-2048);*r1p=r1;*r0p=r0;}
+static void f4014(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,2047);*r1p=r1;*r0p=r0;}
+static void f4015(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-2049);*r1p=r1;*r0p=r0;}
+static void f4016(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,4096);*r1p=r1;*r0p=r0;}
+static void f4017(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-4096);*r1p=r1;*r0p=r0;}
+static void f4018(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,4095);*r1p=r1;*r0p=r0;}
+static void f4019(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-4097);*r1p=r1;*r0p=r0;}
+static void f4020(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,8192);*r1p=r1;*r0p=r0;}
+static void f4021(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-8192);*r1p=r1;*r0p=r0;}
+static void f4022(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,8191);*r1p=r1;*r0p=r0;}
+static void f4023(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-8193);*r1p=r1;*r0p=r0;}
+static void f4024(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,16384);*r1p=r1;*r0p=r0;}
+static void f4025(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-16384);*r1p=r1;*r0p=r0;}
+static void f4026(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,16383);*r1p=r1;*r0p=r0;}
+static void f4027(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-16385);*r1p=r1;*r0p=r0;}
+static void f4028(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,32768);*r1p=r1;*r0p=r0;}
+static void f4029(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-32768);*r1p=r1;*r0p=r0;}
+static void f4030(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,32767);*r1p=r1;*r0p=r0;}
+static void f4031(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,32767,0,-32769);*r1p=r1;*r0p=r0;}
+static void f4032(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,1);*r1p=r1;*r0p=r0;}
+static void f4033(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-1);*r1p=r1;*r0p=r0;}
+static void f4034(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,0);*r1p=r1;*r0p=r0;}
+static void f4035(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-2);*r1p=r1;*r0p=r0;}
+static void f4036(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,2);*r1p=r1;*r0p=r0;}
+static void f4037(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-2);*r1p=r1;*r0p=r0;}
+static void f4038(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,1);*r1p=r1;*r0p=r0;}
+static void f4039(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-3);*r1p=r1;*r0p=r0;}
+static void f4040(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,4);*r1p=r1;*r0p=r0;}
+static void f4041(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-4);*r1p=r1;*r0p=r0;}
+static void f4042(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,3);*r1p=r1;*r0p=r0;}
+static void f4043(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-5);*r1p=r1;*r0p=r0;}
+static void f4044(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,8);*r1p=r1;*r0p=r0;}
+static void f4045(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-8);*r1p=r1;*r0p=r0;}
+static void f4046(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,7);*r1p=r1;*r0p=r0;}
+static void f4047(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-9);*r1p=r1;*r0p=r0;}
+static void f4048(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,16);*r1p=r1;*r0p=r0;}
+static void f4049(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-16);*r1p=r1;*r0p=r0;}
+static void f4050(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,15);*r1p=r1;*r0p=r0;}
+static void f4051(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-17);*r1p=r1;*r0p=r0;}
+static void f4052(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,32);*r1p=r1;*r0p=r0;}
+static void f4053(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-32);*r1p=r1;*r0p=r0;}
+static void f4054(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,31);*r1p=r1;*r0p=r0;}
+static void f4055(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-33);*r1p=r1;*r0p=r0;}
+static void f4056(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,64);*r1p=r1;*r0p=r0;}
+static void f4057(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-64);*r1p=r1;*r0p=r0;}
+static void f4058(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,63);*r1p=r1;*r0p=r0;}
+static void f4059(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-65);*r1p=r1;*r0p=r0;}
+static void f4060(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,128);*r1p=r1;*r0p=r0;}
+static void f4061(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-128);*r1p=r1;*r0p=r0;}
+static void f4062(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,127);*r1p=r1;*r0p=r0;}
+static void f4063(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-129);*r1p=r1;*r0p=r0;}
+static void f4064(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,256);*r1p=r1;*r0p=r0;}
+static void f4065(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-256);*r1p=r1;*r0p=r0;}
+static void f4066(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,255);*r1p=r1;*r0p=r0;}
+static void f4067(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-257);*r1p=r1;*r0p=r0;}
+static void f4068(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,512);*r1p=r1;*r0p=r0;}
+static void f4069(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-512);*r1p=r1;*r0p=r0;}
+static void f4070(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,511);*r1p=r1;*r0p=r0;}
+static void f4071(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-513);*r1p=r1;*r0p=r0;}
+static void f4072(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,1024);*r1p=r1;*r0p=r0;}
+static void f4073(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-1024);*r1p=r1;*r0p=r0;}
+static void f4074(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,1023);*r1p=r1;*r0p=r0;}
+static void f4075(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-1025);*r1p=r1;*r0p=r0;}
+static void f4076(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,2048);*r1p=r1;*r0p=r0;}
+static void f4077(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-2048);*r1p=r1;*r0p=r0;}
+static void f4078(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,2047);*r1p=r1;*r0p=r0;}
+static void f4079(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-2049);*r1p=r1;*r0p=r0;}
+static void f4080(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,4096);*r1p=r1;*r0p=r0;}
+static void f4081(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-4096);*r1p=r1;*r0p=r0;}
+static void f4082(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,4095);*r1p=r1;*r0p=r0;}
+static void f4083(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-4097);*r1p=r1;*r0p=r0;}
+static void f4084(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,8192);*r1p=r1;*r0p=r0;}
+static void f4085(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-8192);*r1p=r1;*r0p=r0;}
+static void f4086(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,8191);*r1p=r1;*r0p=r0;}
+static void f4087(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-8193);*r1p=r1;*r0p=r0;}
+static void f4088(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,16384);*r1p=r1;*r0p=r0;}
+static void f4089(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-16384);*r1p=r1;*r0p=r0;}
+static void f4090(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,16383);*r1p=r1;*r0p=r0;}
+static void f4091(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-16385);*r1p=r1;*r0p=r0;}
+static void f4092(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,32768);*r1p=r1;*r0p=r0;}
+static void f4093(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-32768);*r1p=r1;*r0p=r0;}
+static void f4094(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,32767);*r1p=r1;*r0p=r0;}
+static void f4095(mp_limb_t*r1p,mp_limb_t*r0p){mp_limb_t r1,r0;sub_ddmmss(r1,r0,0,-32769,0,-32769);*r1p=r1;*r0p=r0;}
+typedef void (*func_t) (mp_limb_t*, mp_limb_t*);
+static const func_t funcs[4096] = {
+f0,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,
+f16,f17,f18,f19,f20,f21,f22,f23,f24,f25,f26,f27,f28,f29,f30,f31,
+f32,f33,f34,f35,f36,f37,f38,f39,f40,f41,f42,f43,f44,f45,f46,f47,
+f48,f49,f50,f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,
+f64,f65,f66,f67,f68,f69,f70,f71,f72,f73,f74,f75,f76,f77,f78,f79,
+f80,f81,f82,f83,f84,f85,f86,f87,f88,f89,f90,f91,f92,f93,f94,f95,
+f96,f97,f98,f99,f100,f101,f102,f103,f104,f105,f106,f107,f108,f109,f110,f111,
+f112,f113,f114,f115,f116,f117,f118,f119,f120,f121,f122,f123,f124,f125,f126,f127,
+f128,f129,f130,f131,f132,f133,f134,f135,f136,f137,f138,f139,f140,f141,f142,f143,
+f144,f145,f146,f147,f148,f149,f150,f151,f152,f153,f154,f155,f156,f157,f158,f159,
+f160,f161,f162,f163,f164,f165,f166,f167,f168,f169,f170,f171,f172,f173,f174,f175,
+f176,f177,f178,f179,f180,f181,f182,f183,f184,f185,f186,f187,f188,f189,f190,f191,
+f192,f193,f194,f195,f196,f197,f198,f199,f200,f201,f202,f203,f204,f205,f206,f207,
+f208,f209,f210,f211,f212,f213,f214,f215,f216,f217,f218,f219,f220,f221,f222,f223,
+f224,f225,f226,f227,f228,f229,f230,f231,f232,f233,f234,f235,f236,f237,f238,f239,
+f240,f241,f242,f243,f244,f245,f246,f247,f248,f249,f250,f251,f252,f253,f254,f255,
+f256,f257,f258,f259,f260,f261,f262,f263,f264,f265,f266,f267,f268,f269,f270,f271,
+f272,f273,f274,f275,f276,f277,f278,f279,f280,f281,f282,f283,f284,f285,f286,f287,
+f288,f289,f290,f291,f292,f293,f294,f295,f296,f297,f298,f299,f300,f301,f302,f303,
+f304,f305,f306,f307,f308,f309,f310,f311,f312,f313,f314,f315,f316,f317,f318,f319,
+f320,f321,f322,f323,f324,f325,f326,f327,f328,f329,f330,f331,f332,f333,f334,f335,
+f336,f337,f338,f339,f340,f341,f342,f343,f344,f345,f346,f347,f348,f349,f350,f351,
+f352,f353,f354,f355,f356,f357,f358,f359,f360,f361,f362,f363,f364,f365,f366,f367,
+f368,f369,f370,f371,f372,f373,f374,f375,f376,f377,f378,f379,f380,f381,f382,f383,
+f384,f385,f386,f387,f388,f389,f390,f391,f392,f393,f394,f395,f396,f397,f398,f399,
+f400,f401,f402,f403,f404,f405,f406,f407,f408,f409,f410,f411,f412,f413,f414,f415,
+f416,f417,f418,f419,f420,f421,f422,f423,f424,f425,f426,f427,f428,f429,f430,f431,
+f432,f433,f434,f435,f436,f437,f438,f439,f440,f441,f442,f443,f444,f445,f446,f447,
+f448,f449,f450,f451,f452,f453,f454,f455,f456,f457,f458,f459,f460,f461,f462,f463,
+f464,f465,f466,f467,f468,f469,f470,f471,f472,f473,f474,f475,f476,f477,f478,f479,
+f480,f481,f482,f483,f484,f485,f486,f487,f488,f489,f490,f491,f492,f493,f494,f495,
+f496,f497,f498,f499,f500,f501,f502,f503,f504,f505,f506,f507,f508,f509,f510,f511,
+f512,f513,f514,f515,f516,f517,f518,f519,f520,f521,f522,f523,f524,f525,f526,f527,
+f528,f529,f530,f531,f532,f533,f534,f535,f536,f537,f538,f539,f540,f541,f542,f543,
+f544,f545,f546,f547,f548,f549,f550,f551,f552,f553,f554,f555,f556,f557,f558,f559,
+f560,f561,f562,f563,f564,f565,f566,f567,f568,f569,f570,f571,f572,f573,f574,f575,
+f576,f577,f578,f579,f580,f581,f582,f583,f584,f585,f586,f587,f588,f589,f590,f591,
+f592,f593,f594,f595,f596,f597,f598,f599,f600,f601,f602,f603,f604,f605,f606,f607,
+f608,f609,f610,f611,f612,f613,f614,f615,f616,f617,f618,f619,f620,f621,f622,f623,
+f624,f625,f626,f627,f628,f629,f630,f631,f632,f633,f634,f635,f636,f637,f638,f639,
+f640,f641,f642,f643,f644,f645,f646,f647,f648,f649,f650,f651,f652,f653,f654,f655,
+f656,f657,f658,f659,f660,f661,f662,f663,f664,f665,f666,f667,f668,f669,f670,f671,
+f672,f673,f674,f675,f676,f677,f678,f679,f680,f681,f682,f683,f684,f685,f686,f687,
+f688,f689,f690,f691,f692,f693,f694,f695,f696,f697,f698,f699,f700,f701,f702,f703,
+f704,f705,f706,f707,f708,f709,f710,f711,f712,f713,f714,f715,f716,f717,f718,f719,
+f720,f721,f722,f723,f724,f725,f726,f727,f728,f729,f730,f731,f732,f733,f734,f735,
+f736,f737,f738,f739,f740,f741,f742,f743,f744,f745,f746,f747,f748,f749,f750,f751,
+f752,f753,f754,f755,f756,f757,f758,f759,f760,f761,f762,f763,f764,f765,f766,f767,
+f768,f769,f770,f771,f772,f773,f774,f775,f776,f777,f778,f779,f780,f781,f782,f783,
+f784,f785,f786,f787,f788,f789,f790,f791,f792,f793,f794,f795,f796,f797,f798,f799,
+f800,f801,f802,f803,f804,f805,f806,f807,f808,f809,f810,f811,f812,f813,f814,f815,
+f816,f817,f818,f819,f820,f821,f822,f823,f824,f825,f826,f827,f828,f829,f830,f831,
+f832,f833,f834,f835,f836,f837,f838,f839,f840,f841,f842,f843,f844,f845,f846,f847,
+f848,f849,f850,f851,f852,f853,f854,f855,f856,f857,f858,f859,f860,f861,f862,f863,
+f864,f865,f866,f867,f868,f869,f870,f871,f872,f873,f874,f875,f876,f877,f878,f879,
+f880,f881,f882,f883,f884,f885,f886,f887,f888,f889,f890,f891,f892,f893,f894,f895,
+f896,f897,f898,f899,f900,f901,f902,f903,f904,f905,f906,f907,f908,f909,f910,f911,
+f912,f913,f914,f915,f916,f917,f918,f919,f920,f921,f922,f923,f924,f925,f926,f927,
+f928,f929,f930,f931,f932,f933,f934,f935,f936,f937,f938,f939,f940,f941,f942,f943,
+f944,f945,f946,f947,f948,f949,f950,f951,f952,f953,f954,f955,f956,f957,f958,f959,
+f960,f961,f962,f963,f964,f965,f966,f967,f968,f969,f970,f971,f972,f973,f974,f975,
+f976,f977,f978,f979,f980,f981,f982,f983,f984,f985,f986,f987,f988,f989,f990,f991,
+f992,f993,f994,f995,f996,f997,f998,f999,f1000,f1001,f1002,f1003,f1004,f1005,f1006,f1007,
+f1008,f1009,f1010,f1011,f1012,f1013,f1014,f1015,f1016,f1017,f1018,f1019,f1020,f1021,f1022,f1023,
+f1024,f1025,f1026,f1027,f1028,f1029,f1030,f1031,f1032,f1033,f1034,f1035,f1036,f1037,f1038,f1039,
+f1040,f1041,f1042,f1043,f1044,f1045,f1046,f1047,f1048,f1049,f1050,f1051,f1052,f1053,f1054,f1055,
+f1056,f1057,f1058,f1059,f1060,f1061,f1062,f1063,f1064,f1065,f1066,f1067,f1068,f1069,f1070,f1071,
+f1072,f1073,f1074,f1075,f1076,f1077,f1078,f1079,f1080,f1081,f1082,f1083,f1084,f1085,f1086,f1087,
+f1088,f1089,f1090,f1091,f1092,f1093,f1094,f1095,f1096,f1097,f1098,f1099,f1100,f1101,f1102,f1103,
+f1104,f1105,f1106,f1107,f1108,f1109,f1110,f1111,f1112,f1113,f1114,f1115,f1116,f1117,f1118,f1119,
+f1120,f1121,f1122,f1123,f1124,f1125,f1126,f1127,f1128,f1129,f1130,f1131,f1132,f1133,f1134,f1135,
+f1136,f1137,f1138,f1139,f1140,f1141,f1142,f1143,f1144,f1145,f1146,f1147,f1148,f1149,f1150,f1151,
+f1152,f1153,f1154,f1155,f1156,f1157,f1158,f1159,f1160,f1161,f1162,f1163,f1164,f1165,f1166,f1167,
+f1168,f1169,f1170,f1171,f1172,f1173,f1174,f1175,f1176,f1177,f1178,f1179,f1180,f1181,f1182,f1183,
+f1184,f1185,f1186,f1187,f1188,f1189,f1190,f1191,f1192,f1193,f1194,f1195,f1196,f1197,f1198,f1199,
+f1200,f1201,f1202,f1203,f1204,f1205,f1206,f1207,f1208,f1209,f1210,f1211,f1212,f1213,f1214,f1215,
+f1216,f1217,f1218,f1219,f1220,f1221,f1222,f1223,f1224,f1225,f1226,f1227,f1228,f1229,f1230,f1231,
+f1232,f1233,f1234,f1235,f1236,f1237,f1238,f1239,f1240,f1241,f1242,f1243,f1244,f1245,f1246,f1247,
+f1248,f1249,f1250,f1251,f1252,f1253,f1254,f1255,f1256,f1257,f1258,f1259,f1260,f1261,f1262,f1263,
+f1264,f1265,f1266,f1267,f1268,f1269,f1270,f1271,f1272,f1273,f1274,f1275,f1276,f1277,f1278,f1279,
+f1280,f1281,f1282,f1283,f1284,f1285,f1286,f1287,f1288,f1289,f1290,f1291,f1292,f1293,f1294,f1295,
+f1296,f1297,f1298,f1299,f1300,f1301,f1302,f1303,f1304,f1305,f1306,f1307,f1308,f1309,f1310,f1311,
+f1312,f1313,f1314,f1315,f1316,f1317,f1318,f1319,f1320,f1321,f1322,f1323,f1324,f1325,f1326,f1327,
+f1328,f1329,f1330,f1331,f1332,f1333,f1334,f1335,f1336,f1337,f1338,f1339,f1340,f1341,f1342,f1343,
+f1344,f1345,f1346,f1347,f1348,f1349,f1350,f1351,f1352,f1353,f1354,f1355,f1356,f1357,f1358,f1359,
+f1360,f1361,f1362,f1363,f1364,f1365,f1366,f1367,f1368,f1369,f1370,f1371,f1372,f1373,f1374,f1375,
+f1376,f1377,f1378,f1379,f1380,f1381,f1382,f1383,f1384,f1385,f1386,f1387,f1388,f1389,f1390,f1391,
+f1392,f1393,f1394,f1395,f1396,f1397,f1398,f1399,f1400,f1401,f1402,f1403,f1404,f1405,f1406,f1407,
+f1408,f1409,f1410,f1411,f1412,f1413,f1414,f1415,f1416,f1417,f1418,f1419,f1420,f1421,f1422,f1423,
+f1424,f1425,f1426,f1427,f1428,f1429,f1430,f1431,f1432,f1433,f1434,f1435,f1436,f1437,f1438,f1439,
+f1440,f1441,f1442,f1443,f1444,f1445,f1446,f1447,f1448,f1449,f1450,f1451,f1452,f1453,f1454,f1455,
+f1456,f1457,f1458,f1459,f1460,f1461,f1462,f1463,f1464,f1465,f1466,f1467,f1468,f1469,f1470,f1471,
+f1472,f1473,f1474,f1475,f1476,f1477,f1478,f1479,f1480,f1481,f1482,f1483,f1484,f1485,f1486,f1487,
+f1488,f1489,f1490,f1491,f1492,f1493,f1494,f1495,f1496,f1497,f1498,f1499,f1500,f1501,f1502,f1503,
+f1504,f1505,f1506,f1507,f1508,f1509,f1510,f1511,f1512,f1513,f1514,f1515,f1516,f1517,f1518,f1519,
+f1520,f1521,f1522,f1523,f1524,f1525,f1526,f1527,f1528,f1529,f1530,f1531,f1532,f1533,f1534,f1535,
+f1536,f1537,f1538,f1539,f1540,f1541,f1542,f1543,f1544,f1545,f1546,f1547,f1548,f1549,f1550,f1551,
+f1552,f1553,f1554,f1555,f1556,f1557,f1558,f1559,f1560,f1561,f1562,f1563,f1564,f1565,f1566,f1567,
+f1568,f1569,f1570,f1571,f1572,f1573,f1574,f1575,f1576,f1577,f1578,f1579,f1580,f1581,f1582,f1583,
+f1584,f1585,f1586,f1587,f1588,f1589,f1590,f1591,f1592,f1593,f1594,f1595,f1596,f1597,f1598,f1599,
+f1600,f1601,f1602,f1603,f1604,f1605,f1606,f1607,f1608,f1609,f1610,f1611,f1612,f1613,f1614,f1615,
+f1616,f1617,f1618,f1619,f1620,f1621,f1622,f1623,f1624,f1625,f1626,f1627,f1628,f1629,f1630,f1631,
+f1632,f1633,f1634,f1635,f1636,f1637,f1638,f1639,f1640,f1641,f1642,f1643,f1644,f1645,f1646,f1647,
+f1648,f1649,f1650,f1651,f1652,f1653,f1654,f1655,f1656,f1657,f1658,f1659,f1660,f1661,f1662,f1663,
+f1664,f1665,f1666,f1667,f1668,f1669,f1670,f1671,f1672,f1673,f1674,f1675,f1676,f1677,f1678,f1679,
+f1680,f1681,f1682,f1683,f1684,f1685,f1686,f1687,f1688,f1689,f1690,f1691,f1692,f1693,f1694,f1695,
+f1696,f1697,f1698,f1699,f1700,f1701,f1702,f1703,f1704,f1705,f1706,f1707,f1708,f1709,f1710,f1711,
+f1712,f1713,f1714,f1715,f1716,f1717,f1718,f1719,f1720,f1721,f1722,f1723,f1724,f1725,f1726,f1727,
+f1728,f1729,f1730,f1731,f1732,f1733,f1734,f1735,f1736,f1737,f1738,f1739,f1740,f1741,f1742,f1743,
+f1744,f1745,f1746,f1747,f1748,f1749,f1750,f1751,f1752,f1753,f1754,f1755,f1756,f1757,f1758,f1759,
+f1760,f1761,f1762,f1763,f1764,f1765,f1766,f1767,f1768,f1769,f1770,f1771,f1772,f1773,f1774,f1775,
+f1776,f1777,f1778,f1779,f1780,f1781,f1782,f1783,f1784,f1785,f1786,f1787,f1788,f1789,f1790,f1791,
+f1792,f1793,f1794,f1795,f1796,f1797,f1798,f1799,f1800,f1801,f1802,f1803,f1804,f1805,f1806,f1807,
+f1808,f1809,f1810,f1811,f1812,f1813,f1814,f1815,f1816,f1817,f1818,f1819,f1820,f1821,f1822,f1823,
+f1824,f1825,f1826,f1827,f1828,f1829,f1830,f1831,f1832,f1833,f1834,f1835,f1836,f1837,f1838,f1839,
+f1840,f1841,f1842,f1843,f1844,f1845,f1846,f1847,f1848,f1849,f1850,f1851,f1852,f1853,f1854,f1855,
+f1856,f1857,f1858,f1859,f1860,f1861,f1862,f1863,f1864,f1865,f1866,f1867,f1868,f1869,f1870,f1871,
+f1872,f1873,f1874,f1875,f1876,f1877,f1878,f1879,f1880,f1881,f1882,f1883,f1884,f1885,f1886,f1887,
+f1888,f1889,f1890,f1891,f1892,f1893,f1894,f1895,f1896,f1897,f1898,f1899,f1900,f1901,f1902,f1903,
+f1904,f1905,f1906,f1907,f1908,f1909,f1910,f1911,f1912,f1913,f1914,f1915,f1916,f1917,f1918,f1919,
+f1920,f1921,f1922,f1923,f1924,f1925,f1926,f1927,f1928,f1929,f1930,f1931,f1932,f1933,f1934,f1935,
+f1936,f1937,f1938,f1939,f1940,f1941,f1942,f1943,f1944,f1945,f1946,f1947,f1948,f1949,f1950,f1951,
+f1952,f1953,f1954,f1955,f1956,f1957,f1958,f1959,f1960,f1961,f1962,f1963,f1964,f1965,f1966,f1967,
+f1968,f1969,f1970,f1971,f1972,f1973,f1974,f1975,f1976,f1977,f1978,f1979,f1980,f1981,f1982,f1983,
+f1984,f1985,f1986,f1987,f1988,f1989,f1990,f1991,f1992,f1993,f1994,f1995,f1996,f1997,f1998,f1999,
+f2000,f2001,f2002,f2003,f2004,f2005,f2006,f2007,f2008,f2009,f2010,f2011,f2012,f2013,f2014,f2015,
+f2016,f2017,f2018,f2019,f2020,f2021,f2022,f2023,f2024,f2025,f2026,f2027,f2028,f2029,f2030,f2031,
+f2032,f2033,f2034,f2035,f2036,f2037,f2038,f2039,f2040,f2041,f2042,f2043,f2044,f2045,f2046,f2047,
+f2048,f2049,f2050,f2051,f2052,f2053,f2054,f2055,f2056,f2057,f2058,f2059,f2060,f2061,f2062,f2063,
+f2064,f2065,f2066,f2067,f2068,f2069,f2070,f2071,f2072,f2073,f2074,f2075,f2076,f2077,f2078,f2079,
+f2080,f2081,f2082,f2083,f2084,f2085,f2086,f2087,f2088,f2089,f2090,f2091,f2092,f2093,f2094,f2095,
+f2096,f2097,f2098,f2099,f2100,f2101,f2102,f2103,f2104,f2105,f2106,f2107,f2108,f2109,f2110,f2111,
+f2112,f2113,f2114,f2115,f2116,f2117,f2118,f2119,f2120,f2121,f2122,f2123,f2124,f2125,f2126,f2127,
+f2128,f2129,f2130,f2131,f2132,f2133,f2134,f2135,f2136,f2137,f2138,f2139,f2140,f2141,f2142,f2143,
+f2144,f2145,f2146,f2147,f2148,f2149,f2150,f2151,f2152,f2153,f2154,f2155,f2156,f2157,f2158,f2159,
+f2160,f2161,f2162,f2163,f2164,f2165,f2166,f2167,f2168,f2169,f2170,f2171,f2172,f2173,f2174,f2175,
+f2176,f2177,f2178,f2179,f2180,f2181,f2182,f2183,f2184,f2185,f2186,f2187,f2188,f2189,f2190,f2191,
+f2192,f2193,f2194,f2195,f2196,f2197,f2198,f2199,f2200,f2201,f2202,f2203,f2204,f2205,f2206,f2207,
+f2208,f2209,f2210,f2211,f2212,f2213,f2214,f2215,f2216,f2217,f2218,f2219,f2220,f2221,f2222,f2223,
+f2224,f2225,f2226,f2227,f2228,f2229,f2230,f2231,f2232,f2233,f2234,f2235,f2236,f2237,f2238,f2239,
+f2240,f2241,f2242,f2243,f2244,f2245,f2246,f2247,f2248,f2249,f2250,f2251,f2252,f2253,f2254,f2255,
+f2256,f2257,f2258,f2259,f2260,f2261,f2262,f2263,f2264,f2265,f2266,f2267,f2268,f2269,f2270,f2271,
+f2272,f2273,f2274,f2275,f2276,f2277,f2278,f2279,f2280,f2281,f2282,f2283,f2284,f2285,f2286,f2287,
+f2288,f2289,f2290,f2291,f2292,f2293,f2294,f2295,f2296,f2297,f2298,f2299,f2300,f2301,f2302,f2303,
+f2304,f2305,f2306,f2307,f2308,f2309,f2310,f2311,f2312,f2313,f2314,f2315,f2316,f2317,f2318,f2319,
+f2320,f2321,f2322,f2323,f2324,f2325,f2326,f2327,f2328,f2329,f2330,f2331,f2332,f2333,f2334,f2335,
+f2336,f2337,f2338,f2339,f2340,f2341,f2342,f2343,f2344,f2345,f2346,f2347,f2348,f2349,f2350,f2351,
+f2352,f2353,f2354,f2355,f2356,f2357,f2358,f2359,f2360,f2361,f2362,f2363,f2364,f2365,f2366,f2367,
+f2368,f2369,f2370,f2371,f2372,f2373,f2374,f2375,f2376,f2377,f2378,f2379,f2380,f2381,f2382,f2383,
+f2384,f2385,f2386,f2387,f2388,f2389,f2390,f2391,f2392,f2393,f2394,f2395,f2396,f2397,f2398,f2399,
+f2400,f2401,f2402,f2403,f2404,f2405,f2406,f2407,f2408,f2409,f2410,f2411,f2412,f2413,f2414,f2415,
+f2416,f2417,f2418,f2419,f2420,f2421,f2422,f2423,f2424,f2425,f2426,f2427,f2428,f2429,f2430,f2431,
+f2432,f2433,f2434,f2435,f2436,f2437,f2438,f2439,f2440,f2441,f2442,f2443,f2444,f2445,f2446,f2447,
+f2448,f2449,f2450,f2451,f2452,f2453,f2454,f2455,f2456,f2457,f2458,f2459,f2460,f2461,f2462,f2463,
+f2464,f2465,f2466,f2467,f2468,f2469,f2470,f2471,f2472,f2473,f2474,f2475,f2476,f2477,f2478,f2479,
+f2480,f2481,f2482,f2483,f2484,f2485,f2486,f2487,f2488,f2489,f2490,f2491,f2492,f2493,f2494,f2495,
+f2496,f2497,f2498,f2499,f2500,f2501,f2502,f2503,f2504,f2505,f2506,f2507,f2508,f2509,f2510,f2511,
+f2512,f2513,f2514,f2515,f2516,f2517,f2518,f2519,f2520,f2521,f2522,f2523,f2524,f2525,f2526,f2527,
+f2528,f2529,f2530,f2531,f2532,f2533,f2534,f2535,f2536,f2537,f2538,f2539,f2540,f2541,f2542,f2543,
+f2544,f2545,f2546,f2547,f2548,f2549,f2550,f2551,f2552,f2553,f2554,f2555,f2556,f2557,f2558,f2559,
+f2560,f2561,f2562,f2563,f2564,f2565,f2566,f2567,f2568,f2569,f2570,f2571,f2572,f2573,f2574,f2575,
+f2576,f2577,f2578,f2579,f2580,f2581,f2582,f2583,f2584,f2585,f2586,f2587,f2588,f2589,f2590,f2591,
+f2592,f2593,f2594,f2595,f2596,f2597,f2598,f2599,f2600,f2601,f2602,f2603,f2604,f2605,f2606,f2607,
+f2608,f2609,f2610,f2611,f2612,f2613,f2614,f2615,f2616,f2617,f2618,f2619,f2620,f2621,f2622,f2623,
+f2624,f2625,f2626,f2627,f2628,f2629,f2630,f2631,f2632,f2633,f2634,f2635,f2636,f2637,f2638,f2639,
+f2640,f2641,f2642,f2643,f2644,f2645,f2646,f2647,f2648,f2649,f2650,f2651,f2652,f2653,f2654,f2655,
+f2656,f2657,f2658,f2659,f2660,f2661,f2662,f2663,f2664,f2665,f2666,f2667,f2668,f2669,f2670,f2671,
+f2672,f2673,f2674,f2675,f2676,f2677,f2678,f2679,f2680,f2681,f2682,f2683,f2684,f2685,f2686,f2687,
+f2688,f2689,f2690,f2691,f2692,f2693,f2694,f2695,f2696,f2697,f2698,f2699,f2700,f2701,f2702,f2703,
+f2704,f2705,f2706,f2707,f2708,f2709,f2710,f2711,f2712,f2713,f2714,f2715,f2716,f2717,f2718,f2719,
+f2720,f2721,f2722,f2723,f2724,f2725,f2726,f2727,f2728,f2729,f2730,f2731,f2732,f2733,f2734,f2735,
+f2736,f2737,f2738,f2739,f2740,f2741,f2742,f2743,f2744,f2745,f2746,f2747,f2748,f2749,f2750,f2751,
+f2752,f2753,f2754,f2755,f2756,f2757,f2758,f2759,f2760,f2761,f2762,f2763,f2764,f2765,f2766,f2767,
+f2768,f2769,f2770,f2771,f2772,f2773,f2774,f2775,f2776,f2777,f2778,f2779,f2780,f2781,f2782,f2783,
+f2784,f2785,f2786,f2787,f2788,f2789,f2790,f2791,f2792,f2793,f2794,f2795,f2796,f2797,f2798,f2799,
+f2800,f2801,f2802,f2803,f2804,f2805,f2806,f2807,f2808,f2809,f2810,f2811,f2812,f2813,f2814,f2815,
+f2816,f2817,f2818,f2819,f2820,f2821,f2822,f2823,f2824,f2825,f2826,f2827,f2828,f2829,f2830,f2831,
+f2832,f2833,f2834,f2835,f2836,f2837,f2838,f2839,f2840,f2841,f2842,f2843,f2844,f2845,f2846,f2847,
+f2848,f2849,f2850,f2851,f2852,f2853,f2854,f2855,f2856,f2857,f2858,f2859,f2860,f2861,f2862,f2863,
+f2864,f2865,f2866,f2867,f2868,f2869,f2870,f2871,f2872,f2873,f2874,f2875,f2876,f2877,f2878,f2879,
+f2880,f2881,f2882,f2883,f2884,f2885,f2886,f2887,f2888,f2889,f2890,f2891,f2892,f2893,f2894,f2895,
+f2896,f2897,f2898,f2899,f2900,f2901,f2902,f2903,f2904,f2905,f2906,f2907,f2908,f2909,f2910,f2911,
+f2912,f2913,f2914,f2915,f2916,f2917,f2918,f2919,f2920,f2921,f2922,f2923,f2924,f2925,f2926,f2927,
+f2928,f2929,f2930,f2931,f2932,f2933,f2934,f2935,f2936,f2937,f2938,f2939,f2940,f2941,f2942,f2943,
+f2944,f2945,f2946,f2947,f2948,f2949,f2950,f2951,f2952,f2953,f2954,f2955,f2956,f2957,f2958,f2959,
+f2960,f2961,f2962,f2963,f2964,f2965,f2966,f2967,f2968,f2969,f2970,f2971,f2972,f2973,f2974,f2975,
+f2976,f2977,f2978,f2979,f2980,f2981,f2982,f2983,f2984,f2985,f2986,f2987,f2988,f2989,f2990,f2991,
+f2992,f2993,f2994,f2995,f2996,f2997,f2998,f2999,f3000,f3001,f3002,f3003,f3004,f3005,f3006,f3007,
+f3008,f3009,f3010,f3011,f3012,f3013,f3014,f3015,f3016,f3017,f3018,f3019,f3020,f3021,f3022,f3023,
+f3024,f3025,f3026,f3027,f3028,f3029,f3030,f3031,f3032,f3033,f3034,f3035,f3036,f3037,f3038,f3039,
+f3040,f3041,f3042,f3043,f3044,f3045,f3046,f3047,f3048,f3049,f3050,f3051,f3052,f3053,f3054,f3055,
+f3056,f3057,f3058,f3059,f3060,f3061,f3062,f3063,f3064,f3065,f3066,f3067,f3068,f3069,f3070,f3071,
+f3072,f3073,f3074,f3075,f3076,f3077,f3078,f3079,f3080,f3081,f3082,f3083,f3084,f3085,f3086,f3087,
+f3088,f3089,f3090,f3091,f3092,f3093,f3094,f3095,f3096,f3097,f3098,f3099,f3100,f3101,f3102,f3103,
+f3104,f3105,f3106,f3107,f3108,f3109,f3110,f3111,f3112,f3113,f3114,f3115,f3116,f3117,f3118,f3119,
+f3120,f3121,f3122,f3123,f3124,f3125,f3126,f3127,f3128,f3129,f3130,f3131,f3132,f3133,f3134,f3135,
+f3136,f3137,f3138,f3139,f3140,f3141,f3142,f3143,f3144,f3145,f3146,f3147,f3148,f3149,f3150,f3151,
+f3152,f3153,f3154,f3155,f3156,f3157,f3158,f3159,f3160,f3161,f3162,f3163,f3164,f3165,f3166,f3167,
+f3168,f3169,f3170,f3171,f3172,f3173,f3174,f3175,f3176,f3177,f3178,f3179,f3180,f3181,f3182,f3183,
+f3184,f3185,f3186,f3187,f3188,f3189,f3190,f3191,f3192,f3193,f3194,f3195,f3196,f3197,f3198,f3199,
+f3200,f3201,f3202,f3203,f3204,f3205,f3206,f3207,f3208,f3209,f3210,f3211,f3212,f3213,f3214,f3215,
+f3216,f3217,f3218,f3219,f3220,f3221,f3222,f3223,f3224,f3225,f3226,f3227,f3228,f3229,f3230,f3231,
+f3232,f3233,f3234,f3235,f3236,f3237,f3238,f3239,f3240,f3241,f3242,f3243,f3244,f3245,f3246,f3247,
+f3248,f3249,f3250,f3251,f3252,f3253,f3254,f3255,f3256,f3257,f3258,f3259,f3260,f3261,f3262,f3263,
+f3264,f3265,f3266,f3267,f3268,f3269,f3270,f3271,f3272,f3273,f3274,f3275,f3276,f3277,f3278,f3279,
+f3280,f3281,f3282,f3283,f3284,f3285,f3286,f3287,f3288,f3289,f3290,f3291,f3292,f3293,f3294,f3295,
+f3296,f3297,f3298,f3299,f3300,f3301,f3302,f3303,f3304,f3305,f3306,f3307,f3308,f3309,f3310,f3311,
+f3312,f3313,f3314,f3315,f3316,f3317,f3318,f3319,f3320,f3321,f3322,f3323,f3324,f3325,f3326,f3327,
+f3328,f3329,f3330,f3331,f3332,f3333,f3334,f3335,f3336,f3337,f3338,f3339,f3340,f3341,f3342,f3343,
+f3344,f3345,f3346,f3347,f3348,f3349,f3350,f3351,f3352,f3353,f3354,f3355,f3356,f3357,f3358,f3359,
+f3360,f3361,f3362,f3363,f3364,f3365,f3366,f3367,f3368,f3369,f3370,f3371,f3372,f3373,f3374,f3375,
+f3376,f3377,f3378,f3379,f3380,f3381,f3382,f3383,f3384,f3385,f3386,f3387,f3388,f3389,f3390,f3391,
+f3392,f3393,f3394,f3395,f3396,f3397,f3398,f3399,f3400,f3401,f3402,f3403,f3404,f3405,f3406,f3407,
+f3408,f3409,f3410,f3411,f3412,f3413,f3414,f3415,f3416,f3417,f3418,f3419,f3420,f3421,f3422,f3423,
+f3424,f3425,f3426,f3427,f3428,f3429,f3430,f3431,f3432,f3433,f3434,f3435,f3436,f3437,f3438,f3439,
+f3440,f3441,f3442,f3443,f3444,f3445,f3446,f3447,f3448,f3449,f3450,f3451,f3452,f3453,f3454,f3455,
+f3456,f3457,f3458,f3459,f3460,f3461,f3462,f3463,f3464,f3465,f3466,f3467,f3468,f3469,f3470,f3471,
+f3472,f3473,f3474,f3475,f3476,f3477,f3478,f3479,f3480,f3481,f3482,f3483,f3484,f3485,f3486,f3487,
+f3488,f3489,f3490,f3491,f3492,f3493,f3494,f3495,f3496,f3497,f3498,f3499,f3500,f3501,f3502,f3503,
+f3504,f3505,f3506,f3507,f3508,f3509,f3510,f3511,f3512,f3513,f3514,f3515,f3516,f3517,f3518,f3519,
+f3520,f3521,f3522,f3523,f3524,f3525,f3526,f3527,f3528,f3529,f3530,f3531,f3532,f3533,f3534,f3535,
+f3536,f3537,f3538,f3539,f3540,f3541,f3542,f3543,f3544,f3545,f3546,f3547,f3548,f3549,f3550,f3551,
+f3552,f3553,f3554,f3555,f3556,f3557,f3558,f3559,f3560,f3561,f3562,f3563,f3564,f3565,f3566,f3567,
+f3568,f3569,f3570,f3571,f3572,f3573,f3574,f3575,f3576,f3577,f3578,f3579,f3580,f3581,f3582,f3583,
+f3584,f3585,f3586,f3587,f3588,f3589,f3590,f3591,f3592,f3593,f3594,f3595,f3596,f3597,f3598,f3599,
+f3600,f3601,f3602,f3603,f3604,f3605,f3606,f3607,f3608,f3609,f3610,f3611,f3612,f3613,f3614,f3615,
+f3616,f3617,f3618,f3619,f3620,f3621,f3622,f3623,f3624,f3625,f3626,f3627,f3628,f3629,f3630,f3631,
+f3632,f3633,f3634,f3635,f3636,f3637,f3638,f3639,f3640,f3641,f3642,f3643,f3644,f3645,f3646,f3647,
+f3648,f3649,f3650,f3651,f3652,f3653,f3654,f3655,f3656,f3657,f3658,f3659,f3660,f3661,f3662,f3663,
+f3664,f3665,f3666,f3667,f3668,f3669,f3670,f3671,f3672,f3673,f3674,f3675,f3676,f3677,f3678,f3679,
+f3680,f3681,f3682,f3683,f3684,f3685,f3686,f3687,f3688,f3689,f3690,f3691,f3692,f3693,f3694,f3695,
+f3696,f3697,f3698,f3699,f3700,f3701,f3702,f3703,f3704,f3705,f3706,f3707,f3708,f3709,f3710,f3711,
+f3712,f3713,f3714,f3715,f3716,f3717,f3718,f3719,f3720,f3721,f3722,f3723,f3724,f3725,f3726,f3727,
+f3728,f3729,f3730,f3731,f3732,f3733,f3734,f3735,f3736,f3737,f3738,f3739,f3740,f3741,f3742,f3743,
+f3744,f3745,f3746,f3747,f3748,f3749,f3750,f3751,f3752,f3753,f3754,f3755,f3756,f3757,f3758,f3759,
+f3760,f3761,f3762,f3763,f3764,f3765,f3766,f3767,f3768,f3769,f3770,f3771,f3772,f3773,f3774,f3775,
+f3776,f3777,f3778,f3779,f3780,f3781,f3782,f3783,f3784,f3785,f3786,f3787,f3788,f3789,f3790,f3791,
+f3792,f3793,f3794,f3795,f3796,f3797,f3798,f3799,f3800,f3801,f3802,f3803,f3804,f3805,f3806,f3807,
+f3808,f3809,f3810,f3811,f3812,f3813,f3814,f3815,f3816,f3817,f3818,f3819,f3820,f3821,f3822,f3823,
+f3824,f3825,f3826,f3827,f3828,f3829,f3830,f3831,f3832,f3833,f3834,f3835,f3836,f3837,f3838,f3839,
+f3840,f3841,f3842,f3843,f3844,f3845,f3846,f3847,f3848,f3849,f3850,f3851,f3852,f3853,f3854,f3855,
+f3856,f3857,f3858,f3859,f3860,f3861,f3862,f3863,f3864,f3865,f3866,f3867,f3868,f3869,f3870,f3871,
+f3872,f3873,f3874,f3875,f3876,f3877,f3878,f3879,f3880,f3881,f3882,f3883,f3884,f3885,f3886,f3887,
+f3888,f3889,f3890,f3891,f3892,f3893,f3894,f3895,f3896,f3897,f3898,f3899,f3900,f3901,f3902,f3903,
+f3904,f3905,f3906,f3907,f3908,f3909,f3910,f3911,f3912,f3913,f3914,f3915,f3916,f3917,f3918,f3919,
+f3920,f3921,f3922,f3923,f3924,f3925,f3926,f3927,f3928,f3929,f3930,f3931,f3932,f3933,f3934,f3935,
+f3936,f3937,f3938,f3939,f3940,f3941,f3942,f3943,f3944,f3945,f3946,f3947,f3948,f3949,f3950,f3951,
+f3952,f3953,f3954,f3955,f3956,f3957,f3958,f3959,f3960,f3961,f3962,f3963,f3964,f3965,f3966,f3967,
+f3968,f3969,f3970,f3971,f3972,f3973,f3974,f3975,f3976,f3977,f3978,f3979,f3980,f3981,f3982,f3983,
+f3984,f3985,f3986,f3987,f3988,f3989,f3990,f3991,f3992,f3993,f3994,f3995,f3996,f3997,f3998,f3999,
+f4000,f4001,f4002,f4003,f4004,f4005,f4006,f4007,f4008,f4009,f4010,f4011,f4012,f4013,f4014,f4015,
+f4016,f4017,f4018,f4019,f4020,f4021,f4022,f4023,f4024,f4025,f4026,f4027,f4028,f4029,f4030,f4031,
+f4032,f4033,f4034,f4035,f4036,f4037,f4038,f4039,f4040,f4041,f4042,f4043,f4044,f4045,f4046,f4047,
+f4048,f4049,f4050,f4051,f4052,f4053,f4054,f4055,f4056,f4057,f4058,f4059,f4060,f4061,f4062,f4063,
+f4064,f4065,f4066,f4067,f4068,f4069,f4070,f4071,f4072,f4073,f4074,f4075,f4076,f4077,f4078,f4079,
+f4080,f4081,f4082,f4083,f4084,f4085,f4086,f4087,f4088,f4089,f4090,f4091,f4092,f4093,f4094,f4095,
+};
+static const int ref[4096][2] = {
+{     0, 0},
+{     2,-1},{     1, 0},{     3,-1},{    -1,-1},{     3,-1},{     0, 0},{     4,-1},{    -3,-1},
+{     5,-1},{    -2,-1},{     6,-1},{    -7,-1},{     9,-1},{    -6,-1},{    10,-1},{   -15,-1},
+{    17,-1},{   -14,-1},{    18,-1},{   -31,-1},{    33,-1},{   -30,-1},{    34,-1},{   -63,-1},
+{    65,-1},{   -62,-1},{    66,-1},{  -127,-1},{   129,-1},{  -126,-1},{   130,-1},{  -255,-1},
+{   257,-1},{  -254,-1},{   258,-1},{  -511,-1},{   513,-1},{  -510,-1},{   514,-1},{ -1023,-1},
+{  1025,-1},{ -1022,-1},{  1026,-1},{ -2047,-1},{  2049,-1},{ -2046,-1},{  2050,-1},{ -4095,-1},
+{  4097,-1},{ -4094,-1},{  4098,-1},{ -8191,-1},{  8193,-1},{ -8190,-1},{  8194,-1},{-16383,-1},
+{ 16385,-1},{-16382,-1},{ 16386,-1},{-32767,-1},{ 32769,-1},{-32766,-1},{ 32770,-1},{    -2, 0},
+{     0, 0},{    -1, 0},{     1, 0},{    -3, 0},{     1, 0},{    -2, 0},{     2, 0},{    -5, 0},
+{     3, 0},{    -4, 0},{     4, 0},{    -9, 0},{     7, 0},{    -8, 0},{     8, 0},{   -17, 0},
+{    15, 0},{   -16, 0},{    16, 0},{   -33, 0},{    31, 0},{   -32, 0},{    32, 0},{   -65, 0},
+{    63, 0},{   -64, 0},{    64, 0},{  -129, 0},{   127, 0},{  -128, 0},{   128, 0},{  -257, 0},
+{   255, 0},{  -256, 0},{   256, 0},{  -513, 0},{   511, 0},{  -512, 0},{   512, 0},{ -1025, 0},
+{  1023, 0},{ -1024, 0},{  1024, 0},{ -2049, 0},{  2047, 0},{ -2048, 0},{  2048, 0},{ -4097, 0},
+{  4095, 0},{ -4096, 0},{  4096, 0},{ -8193, 0},{  8191, 0},{ -8192, 0},{  8192, 0},{-16385, 0},
+{ 16383, 0},{-16384, 0},{ 16384, 0},{-32769, 0},{ 32767, 0},{-32768, 0},{ 32768, 0},{    -1,-1},
+{     1,-1},{     0, 0},{     2,-1},{    -2,-1},{     2,-1},{    -1,-1},{     3,-1},{    -4,-1},
+{     4,-1},{    -3,-1},{     5,-1},{    -8,-1},{     8,-1},{    -7,-1},{     9,-1},{   -16,-1},
+{    16,-1},{   -15,-1},{    17,-1},{   -32,-1},{    32,-1},{   -31,-1},{    33,-1},{   -64,-1},
+{    64,-1},{   -63,-1},{    65,-1},{  -128,-1},{   128,-1},{  -127,-1},{   129,-1},{  -256,-1},
+{   256,-1},{  -255,-1},{   257,-1},{  -512,-1},{   512,-1},{  -511,-1},{   513,-1},{ -1024,-1},
+{  1024,-1},{ -1023,-1},{  1025,-1},{ -2048,-1},{  2048,-1},{ -2047,-1},{  2049,-1},{ -4096,-1},
+{  4096,-1},{ -4095,-1},{  4097,-1},{ -8192,-1},{  8192,-1},{ -8191,-1},{  8193,-1},{-16384,-1},
+{ 16384,-1},{-16383,-1},{ 16385,-1},{-32768,-1},{ 32768,-1},{-32767,-1},{ 32769,-1},{    -3, 0},
+{    -1,-1},{    -2, 0},{     0, 0},{    -4, 0},{     0, 0},{    -3, 0},{     1, 0},{    -6, 0},
+{     2, 0},{    -5, 0},{     3, 0},{   -10, 0},{     6, 0},{    -9, 0},{     7, 0},{   -18, 0},
+{    14, 0},{   -17, 0},{    15, 0},{   -34, 0},{    30, 0},{   -33, 0},{    31, 0},{   -66, 0},
+{    62, 0},{   -65, 0},{    63, 0},{  -130, 0},{   126, 0},{  -129, 0},{   127, 0},{  -258, 0},
+{   254, 0},{  -257, 0},{   255, 0},{  -514, 0},{   510, 0},{  -513, 0},{   511, 0},{ -1026, 0},
+{  1022, 0},{ -1025, 0},{  1023, 0},{ -2050, 0},{  2046, 0},{ -2049, 0},{  2047, 0},{ -4098, 0},
+{  4094, 0},{ -4097, 0},{  4095, 0},{ -8194, 0},{  8190, 0},{ -8193, 0},{  8191, 0},{-16386, 0},
+{ 16382, 0},{-16385, 0},{ 16383, 0},{-32770, 0},{ 32766, 0},{-32769, 0},{ 32767, 0},{     1, 0},
+{     3,-1},{     2, 0},{     4,-1},{     0, 0},{     4,-1},{     1, 0},{     5,-1},{    -2,-1},
+{     6,-1},{    -1,-1},{     7,-1},{    -6,-1},{    10,-1},{    -5,-1},{    11,-1},{   -14,-1},
+{    18,-1},{   -13,-1},{    19,-1},{   -30,-1},{    34,-1},{   -29,-1},{    35,-1},{   -62,-1},
+{    66,-1},{   -61,-1},{    67,-1},{  -126,-1},{   130,-1},{  -125,-1},{   131,-1},{  -254,-1},
+{   258,-1},{  -253,-1},{   259,-1},{  -510,-1},{   514,-1},{  -509,-1},{   515,-1},{ -1022,-1},
+{  1026,-1},{ -1021,-1},{  1027,-1},{ -2046,-1},{  2050,-1},{ -2045,-1},{  2051,-1},{ -4094,-1},
+{  4098,-1},{ -4093,-1},{  4099,-1},{ -8190,-1},{  8194,-1},{ -8189,-1},{  8195,-1},{-16382,-1},
+{ 16386,-1},{-16381,-1},{ 16387,-1},{-32766,-1},{ 32770,-1},{-32765,-1},{ 32771,-1},{    -3, 0},
+{    -1,-1},{    -2, 0},{     0, 0},{    -4, 0},{     0, 0},{    -3, 0},{     1, 0},{    -6, 0},
+{     2, 0},{    -5, 0},{     3, 0},{   -10, 0},{     6, 0},{    -9, 0},{     7, 0},{   -18, 0},
+{    14, 0},{   -17, 0},{    15, 0},{   -34, 0},{    30, 0},{   -33, 0},{    31, 0},{   -66, 0},
+{    62, 0},{   -65, 0},{    63, 0},{  -130, 0},{   126, 0},{  -129, 0},{   127, 0},{  -258, 0},
+{   254, 0},{  -257, 0},{   255, 0},{  -514, 0},{   510, 0},{  -513, 0},{   511, 0},{ -1026, 0},
+{  1022, 0},{ -1025, 0},{  1023, 0},{ -2050, 0},{  2046, 0},{ -2049, 0},{  2047, 0},{ -4098, 0},
+{  4094, 0},{ -4097, 0},{  4095, 0},{ -8194, 0},{  8190, 0},{ -8193, 0},{  8191, 0},{-16386, 0},
+{ 16382, 0},{-16385, 0},{ 16383, 0},{-32770, 0},{ 32766, 0},{-32769, 0},{ 32767, 0},{     0, 0},
+{     2,-1},{     1, 0},{     3,-1},{    -1,-1},{     3,-1},{     0, 0},{     4,-1},{    -3,-1},
+{     5,-1},{    -2,-1},{     6,-1},{    -7,-1},{     9,-1},{    -6,-1},{    10,-1},{   -15,-1},
+{    17,-1},{   -14,-1},{    18,-1},{   -31,-1},{    33,-1},{   -30,-1},{    34,-1},{   -63,-1},
+{    65,-1},{   -62,-1},{    66,-1},{  -127,-1},{   129,-1},{  -126,-1},{   130,-1},{  -255,-1},
+{   257,-1},{  -254,-1},{   258,-1},{  -511,-1},{   513,-1},{  -510,-1},{   514,-1},{ -1023,-1},
+{  1025,-1},{ -1022,-1},{  1026,-1},{ -2047,-1},{  2049,-1},{ -2046,-1},{  2050,-1},{ -4095,-1},
+{  4097,-1},{ -4094,-1},{  4098,-1},{ -8191,-1},{  8193,-1},{ -8190,-1},{  8194,-1},{-16383,-1},
+{ 16385,-1},{-16382,-1},{ 16386,-1},{-32767,-1},{ 32769,-1},{-32766,-1},{ 32770,-1},{    -4, 0},
+{    -2,-1},{    -3, 0},{    -1,-1},{    -5, 0},{    -1,-1},{    -4, 0},{     0, 0},{    -7, 0},
+{     1, 0},{    -6, 0},{     2, 0},{   -11, 0},{     5, 0},{   -10, 0},{     6, 0},{   -19, 0},
+{    13, 0},{   -18, 0},{    14, 0},{   -35, 0},{    29, 0},{   -34, 0},{    30, 0},{   -67, 0},
+{    61, 0},{   -66, 0},{    62, 0},{  -131, 0},{   125, 0},{  -130, 0},{   126, 0},{  -259, 0},
+{   253, 0},{  -258, 0},{   254, 0},{  -515, 0},{   509, 0},{  -514, 0},{   510, 0},{ -1027, 0},
+{  1021, 0},{ -1026, 0},{  1022, 0},{ -2051, 0},{  2045, 0},{ -2050, 0},{  2046, 0},{ -4099, 0},
+{  4093, 0},{ -4098, 0},{  4094, 0},{ -8195, 0},{  8189, 0},{ -8194, 0},{  8190, 0},{-16387, 0},
+{ 16381, 0},{-16386, 0},{ 16382, 0},{-32771, 0},{ 32765, 0},{-32770, 0},{ 32766, 0},{     3, 0},
+{     5,-1},{     4, 0},{     6,-1},{     2, 0},{     6,-1},{     3, 0},{     7,-1},{     0, 0},
+{     8,-1},{     1, 0},{     9,-1},{    -4,-1},{    12,-1},{    -3,-1},{    13,-1},{   -12,-1},
+{    20,-1},{   -11,-1},{    21,-1},{   -28,-1},{    36,-1},{   -27,-1},{    37,-1},{   -60,-1},
+{    68,-1},{   -59,-1},{    69,-1},{  -124,-1},{   132,-1},{  -123,-1},{   133,-1},{  -252,-1},
+{   260,-1},{  -251,-1},{   261,-1},{  -508,-1},{   516,-1},{  -507,-1},{   517,-1},{ -1020,-1},
+{  1028,-1},{ -1019,-1},{  1029,-1},{ -2044,-1},{  2052,-1},{ -2043,-1},{  2053,-1},{ -4092,-1},
+{  4100,-1},{ -4091,-1},{  4101,-1},{ -8188,-1},{  8196,-1},{ -8187,-1},{  8197,-1},{-16380,-1},
+{ 16388,-1},{-16379,-1},{ 16389,-1},{-32764,-1},{ 32772,-1},{-32763,-1},{ 32773,-1},{    -5, 0},
+{    -3,-1},{    -4, 0},{    -2,-1},{    -6, 0},{    -2,-1},{    -5, 0},{    -1,-1},{    -8, 0},
+{     0, 0},{    -7, 0},{     1, 0},{   -12, 0},{     4, 0},{   -11, 0},{     5, 0},{   -20, 0},
+{    12, 0},{   -19, 0},{    13, 0},{   -36, 0},{    28, 0},{   -35, 0},{    29, 0},{   -68, 0},
+{    60, 0},{   -67, 0},{    61, 0},{  -132, 0},{   124, 0},{  -131, 0},{   125, 0},{  -260, 0},
+{   252, 0},{  -259, 0},{   253, 0},{  -516, 0},{   508, 0},{  -515, 0},{   509, 0},{ -1028, 0},
+{  1020, 0},{ -1027, 0},{  1021, 0},{ -2052, 0},{  2044, 0},{ -2051, 0},{  2045, 0},{ -4100, 0},
+{  4092, 0},{ -4099, 0},{  4093, 0},{ -8196, 0},{  8188, 0},{ -8195, 0},{  8189, 0},{-16388, 0},
+{ 16380, 0},{-16387, 0},{ 16381, 0},{-32772, 0},{ 32764, 0},{-32771, 0},{ 32765, 0},{     2, 0},
+{     4,-1},{     3, 0},{     5,-1},{     1, 0},{     5,-1},{     2, 0},{     6,-1},{    -1,-1},
+{     7,-1},{     0, 0},{     8,-1},{    -5,-1},{    11,-1},{    -4,-1},{    12,-1},{   -13,-1},
+{    19,-1},{   -12,-1},{    20,-1},{   -29,-1},{    35,-1},{   -28,-1},{    36,-1},{   -61,-1},
+{    67,-1},{   -60,-1},{    68,-1},{  -125,-1},{   131,-1},{  -124,-1},{   132,-1},{  -253,-1},
+{   259,-1},{  -252,-1},{   260,-1},{  -509,-1},{   515,-1},{  -508,-1},{   516,-1},{ -1021,-1},
+{  1027,-1},{ -1020,-1},{  1028,-1},{ -2045,-1},{  2051,-1},{ -2044,-1},{  2052,-1},{ -4093,-1},
+{  4099,-1},{ -4092,-1},{  4100,-1},{ -8189,-1},{  8195,-1},{ -8188,-1},{  8196,-1},{-16381,-1},
+{ 16387,-1},{-16380,-1},{ 16388,-1},{-32765,-1},{ 32771,-1},{-32764,-1},{ 32772,-1},{    -6, 0},
+{    -4,-1},{    -5, 0},{    -3,-1},{    -7, 0},{    -3,-1},{    -6, 0},{    -2,-1},{    -9, 0},
+{    -1,-1},{    -8, 0},{     0, 0},{   -13, 0},{     3, 0},{   -12, 0},{     4, 0},{   -21, 0},
+{    11, 0},{   -20, 0},{    12, 0},{   -37, 0},{    27, 0},{   -36, 0},{    28, 0},{   -69, 0},
+{    59, 0},{   -68, 0},{    60, 0},{  -133, 0},{   123, 0},{  -132, 0},{   124, 0},{  -261, 0},
+{   251, 0},{  -260, 0},{   252, 0},{  -517, 0},{   507, 0},{  -516, 0},{   508, 0},{ -1029, 0},
+{  1019, 0},{ -1028, 0},{  1020, 0},{ -2053, 0},{  2043, 0},{ -2052, 0},{  2044, 0},{ -4101, 0},
+{  4091, 0},{ -4100, 0},{  4092, 0},{ -8197, 0},{  8187, 0},{ -8196, 0},{  8188, 0},{-16389, 0},
+{ 16379, 0},{-16388, 0},{ 16380, 0},{-32773, 0},{ 32763, 0},{-32772, 0},{ 32764, 0},{     7, 0},
+{     9,-1},{     8, 0},{    10,-1},{     6, 0},{    10,-1},{     7, 0},{    11,-1},{     4, 0},
+{    12,-1},{     5, 0},{    13,-1},{     0, 0},{    16,-1},{     1, 0},{    17,-1},{    -8,-1},
+{    24,-1},{    -7,-1},{    25,-1},{   -24,-1},{    40,-1},{   -23,-1},{    41,-1},{   -56,-1},
+{    72,-1},{   -55,-1},{    73,-1},{  -120,-1},{   136,-1},{  -119,-1},{   137,-1},{  -248,-1},
+{   264,-1},{  -247,-1},{   265,-1},{  -504,-1},{   520,-1},{  -503,-1},{   521,-1},{ -1016,-1},
+{  1032,-1},{ -1015,-1},{  1033,-1},{ -2040,-1},{  2056,-1},{ -2039,-1},{  2057,-1},{ -4088,-1},
+{  4104,-1},{ -4087,-1},{  4105,-1},{ -8184,-1},{  8200,-1},{ -8183,-1},{  8201,-1},{-16376,-1},
+{ 16392,-1},{-16375,-1},{ 16393,-1},{-32760,-1},{ 32776,-1},{-32759,-1},{ 32777,-1},{    -9, 0},
+{    -7,-1},{    -8, 0},{    -6,-1},{   -10, 0},{    -6,-1},{    -9, 0},{    -5,-1},{   -12, 0},
+{    -4,-1},{   -11, 0},{    -3,-1},{   -16, 0},{     0, 0},{   -15, 0},{     1, 0},{   -24, 0},
+{     8, 0},{   -23, 0},{     9, 0},{   -40, 0},{    24, 0},{   -39, 0},{    25, 0},{   -72, 0},
+{    56, 0},{   -71, 0},{    57, 0},{  -136, 0},{   120, 0},{  -135, 0},{   121, 0},{  -264, 0},
+{   248, 0},{  -263, 0},{   249, 0},{  -520, 0},{   504, 0},{  -519, 0},{   505, 0},{ -1032, 0},
+{  1016, 0},{ -1031, 0},{  1017, 0},{ -2056, 0},{  2040, 0},{ -2055, 0},{  2041, 0},{ -4104, 0},
+{  4088, 0},{ -4103, 0},{  4089, 0},{ -8200, 0},{  8184, 0},{ -8199, 0},{  8185, 0},{-16392, 0},
+{ 16376, 0},{-16391, 0},{ 16377, 0},{-32776, 0},{ 32760, 0},{-32775, 0},{ 32761, 0},{     6, 0},
+{     8,-1},{     7, 0},{     9,-1},{     5, 0},{     9,-1},{     6, 0},{    10,-1},{     3, 0},
+{    11,-1},{     4, 0},{    12,-1},{    -1,-1},{    15,-1},{     0, 0},{    16,-1},{    -9,-1},
+{    23,-1},{    -8,-1},{    24,-1},{   -25,-1},{    39,-1},{   -24,-1},{    40,-1},{   -57,-1},
+{    71,-1},{   -56,-1},{    72,-1},{  -121,-1},{   135,-1},{  -120,-1},{   136,-1},{  -249,-1},
+{   263,-1},{  -248,-1},{   264,-1},{  -505,-1},{   519,-1},{  -504,-1},{   520,-1},{ -1017,-1},
+{  1031,-1},{ -1016,-1},{  1032,-1},{ -2041,-1},{  2055,-1},{ -2040,-1},{  2056,-1},{ -4089,-1},
+{  4103,-1},{ -4088,-1},{  4104,-1},{ -8185,-1},{  8199,-1},{ -8184,-1},{  8200,-1},{-16377,-1},
+{ 16391,-1},{-16376,-1},{ 16392,-1},{-32761,-1},{ 32775,-1},{-32760,-1},{ 32776,-1},{   -10, 0},
+{    -8,-1},{    -9, 0},{    -7,-1},{   -11, 0},{    -7,-1},{   -10, 0},{    -6,-1},{   -13, 0},
+{    -5,-1},{   -12, 0},{    -4,-1},{   -17, 0},{    -1,-1},{   -16, 0},{     0, 0},{   -25, 0},
+{     7, 0},{   -24, 0},{     8, 0},{   -41, 0},{    23, 0},{   -40, 0},{    24, 0},{   -73, 0},
+{    55, 0},{   -72, 0},{    56, 0},{  -137, 0},{   119, 0},{  -136, 0},{   120, 0},{  -265, 0},
+{   247, 0},{  -264, 0},{   248, 0},{  -521, 0},{   503, 0},{  -520, 0},{   504, 0},{ -1033, 0},
+{  1015, 0},{ -1032, 0},{  1016, 0},{ -2057, 0},{  2039, 0},{ -2056, 0},{  2040, 0},{ -4105, 0},
+{  4087, 0},{ -4104, 0},{  4088, 0},{ -8201, 0},{  8183, 0},{ -8200, 0},{  8184, 0},{-16393, 0},
+{ 16375, 0},{-16392, 0},{ 16376, 0},{-32777, 0},{ 32759, 0},{-32776, 0},{ 32760, 0},{    15, 0},
+{    17,-1},{    16, 0},{    18,-1},{    14, 0},{    18,-1},{    15, 0},{    19,-1},{    12, 0},
+{    20,-1},{    13, 0},{    21,-1},{     8, 0},{    24,-1},{     9, 0},{    25,-1},{     0, 0},
+{    32,-1},{     1, 0},{    33,-1},{   -16,-1},{    48,-1},{   -15,-1},{    49,-1},{   -48,-1},
+{    80,-1},{   -47,-1},{    81,-1},{  -112,-1},{   144,-1},{  -111,-1},{   145,-1},{  -240,-1},
+{   272,-1},{  -239,-1},{   273,-1},{  -496,-1},{   528,-1},{  -495,-1},{   529,-1},{ -1008,-1},
+{  1040,-1},{ -1007,-1},{  1041,-1},{ -2032,-1},{  2064,-1},{ -2031,-1},{  2065,-1},{ -4080,-1},
+{  4112,-1},{ -4079,-1},{  4113,-1},{ -8176,-1},{  8208,-1},{ -8175,-1},{  8209,-1},{-16368,-1},
+{ 16400,-1},{-16367,-1},{ 16401,-1},{-32752,-1},{ 32784,-1},{-32751,-1},{ 32785,-1},{   -17, 0},
+{   -15,-1},{   -16, 0},{   -14,-1},{   -18, 0},{   -14,-1},{   -17, 0},{   -13,-1},{   -20, 0},
+{   -12,-1},{   -19, 0},{   -11,-1},{   -24, 0},{    -8,-1},{   -23, 0},{    -7,-1},{   -32, 0},
+{     0, 0},{   -31, 0},{     1, 0},{   -48, 0},{    16, 0},{   -47, 0},{    17, 0},{   -80, 0},
+{    48, 0},{   -79, 0},{    49, 0},{  -144, 0},{   112, 0},{  -143, 0},{   113, 0},{  -272, 0},
+{   240, 0},{  -271, 0},{   241, 0},{  -528, 0},{   496, 0},{  -527, 0},{   497, 0},{ -1040, 0},
+{  1008, 0},{ -1039, 0},{  1009, 0},{ -2064, 0},{  2032, 0},{ -2063, 0},{  2033, 0},{ -4112, 0},
+{  4080, 0},{ -4111, 0},{  4081, 0},{ -8208, 0},{  8176, 0},{ -8207, 0},{  8177, 0},{-16400, 0},
+{ 16368, 0},{-16399, 0},{ 16369, 0},{-32784, 0},{ 32752, 0},{-32783, 0},{ 32753, 0},{    14, 0},
+{    16,-1},{    15, 0},{    17,-1},{    13, 0},{    17,-1},{    14, 0},{    18,-1},{    11, 0},
+{    19,-1},{    12, 0},{    20,-1},{     7, 0},{    23,-1},{     8, 0},{    24,-1},{    -1,-1},
+{    31,-1},{     0, 0},{    32,-1},{   -17,-1},{    47,-1},{   -16,-1},{    48,-1},{   -49,-1},
+{    79,-1},{   -48,-1},{    80,-1},{  -113,-1},{   143,-1},{  -112,-1},{   144,-1},{  -241,-1},
+{   271,-1},{  -240,-1},{   272,-1},{  -497,-1},{   527,-1},{  -496,-1},{   528,-1},{ -1009,-1},
+{  1039,-1},{ -1008,-1},{  1040,-1},{ -2033,-1},{  2063,-1},{ -2032,-1},{  2064,-1},{ -4081,-1},
+{  4111,-1},{ -4080,-1},{  4112,-1},{ -8177,-1},{  8207,-1},{ -8176,-1},{  8208,-1},{-16369,-1},
+{ 16399,-1},{-16368,-1},{ 16400,-1},{-32753,-1},{ 32783,-1},{-32752,-1},{ 32784,-1},{   -18, 0},
+{   -16,-1},{   -17, 0},{   -15,-1},{   -19, 0},{   -15,-1},{   -18, 0},{   -14,-1},{   -21, 0},
+{   -13,-1},{   -20, 0},{   -12,-1},{   -25, 0},{    -9,-1},{   -24, 0},{    -8,-1},{   -33, 0},
+{    -1,-1},{   -32, 0},{     0, 0},{   -49, 0},{    15, 0},{   -48, 0},{    16, 0},{   -81, 0},
+{    47, 0},{   -80, 0},{    48, 0},{  -145, 0},{   111, 0},{  -144, 0},{   112, 0},{  -273, 0},
+{   239, 0},{  -272, 0},{   240, 0},{  -529, 0},{   495, 0},{  -528, 0},{   496, 0},{ -1041, 0},
+{  1007, 0},{ -1040, 0},{  1008, 0},{ -2065, 0},{  2031, 0},{ -2064, 0},{  2032, 0},{ -4113, 0},
+{  4079, 0},{ -4112, 0},{  4080, 0},{ -8209, 0},{  8175, 0},{ -8208, 0},{  8176, 0},{-16401, 0},
+{ 16367, 0},{-16400, 0},{ 16368, 0},{-32785, 0},{ 32751, 0},{-32784, 0},{ 32752, 0},{    31, 0},
+{    33,-1},{    32, 0},{    34,-1},{    30, 0},{    34,-1},{    31, 0},{    35,-1},{    28, 0},
+{    36,-1},{    29, 0},{    37,-1},{    24, 0},{    40,-1},{    25, 0},{    41,-1},{    16, 0},
+{    48,-1},{    17, 0},{    49,-1},{     0, 0},{    64,-1},{     1, 0},{    65,-1},{   -32,-1},
+{    96,-1},{   -31,-1},{    97,-1},{   -96,-1},{   160,-1},{   -95,-1},{   161,-1},{  -224,-1},
+{   288,-1},{  -223,-1},{   289,-1},{  -480,-1},{   544,-1},{  -479,-1},{   545,-1},{  -992,-1},
+{  1056,-1},{  -991,-1},{  1057,-1},{ -2016,-1},{  2080,-1},{ -2015,-1},{  2081,-1},{ -4064,-1},
+{  4128,-1},{ -4063,-1},{  4129,-1},{ -8160,-1},{  8224,-1},{ -8159,-1},{  8225,-1},{-16352,-1},
+{ 16416,-1},{-16351,-1},{ 16417,-1},{-32736,-1},{ 32800,-1},{-32735,-1},{ 32801,-1},{   -33, 0},
+{   -31,-1},{   -32, 0},{   -30,-1},{   -34, 0},{   -30,-1},{   -33, 0},{   -29,-1},{   -36, 0},
+{   -28,-1},{   -35, 0},{   -27,-1},{   -40, 0},{   -24,-1},{   -39, 0},{   -23,-1},{   -48, 0},
+{   -16,-1},{   -47, 0},{   -15,-1},{   -64, 0},{     0, 0},{   -63, 0},{     1, 0},{   -96, 0},
+{    32, 0},{   -95, 0},{    33, 0},{  -160, 0},{    96, 0},{  -159, 0},{    97, 0},{  -288, 0},
+{   224, 0},{  -287, 0},{   225, 0},{  -544, 0},{   480, 0},{  -543, 0},{   481, 0},{ -1056, 0},
+{   992, 0},{ -1055, 0},{   993, 0},{ -2080, 0},{  2016, 0},{ -2079, 0},{  2017, 0},{ -4128, 0},
+{  4064, 0},{ -4127, 0},{  4065, 0},{ -8224, 0},{  8160, 0},{ -8223, 0},{  8161, 0},{-16416, 0},
+{ 16352, 0},{-16415, 0},{ 16353, 0},{-32800, 0},{ 32736, 0},{-32799, 0},{ 32737, 0},{    30, 0},
+{    32,-1},{    31, 0},{    33,-1},{    29, 0},{    33,-1},{    30, 0},{    34,-1},{    27, 0},
+{    35,-1},{    28, 0},{    36,-1},{    23, 0},{    39,-1},{    24, 0},{    40,-1},{    15, 0},
+{    47,-1},{    16, 0},{    48,-1},{    -1,-1},{    63,-1},{     0, 0},{    64,-1},{   -33,-1},
+{    95,-1},{   -32,-1},{    96,-1},{   -97,-1},{   159,-1},{   -96,-1},{   160,-1},{  -225,-1},
+{   287,-1},{  -224,-1},{   288,-1},{  -481,-1},{   543,-1},{  -480,-1},{   544,-1},{  -993,-1},
+{  1055,-1},{  -992,-1},{  1056,-1},{ -2017,-1},{  2079,-1},{ -2016,-1},{  2080,-1},{ -4065,-1},
+{  4127,-1},{ -4064,-1},{  4128,-1},{ -8161,-1},{  8223,-1},{ -8160,-1},{  8224,-1},{-16353,-1},
+{ 16415,-1},{-16352,-1},{ 16416,-1},{-32737,-1},{ 32799,-1},{-32736,-1},{ 32800,-1},{   -34, 0},
+{   -32,-1},{   -33, 0},{   -31,-1},{   -35, 0},{   -31,-1},{   -34, 0},{   -30,-1},{   -37, 0},
+{   -29,-1},{   -36, 0},{   -28,-1},{   -41, 0},{   -25,-1},{   -40, 0},{   -24,-1},{   -49, 0},
+{   -17,-1},{   -48, 0},{   -16,-1},{   -65, 0},{    -1,-1},{   -64, 0},{     0, 0},{   -97, 0},
+{    31, 0},{   -96, 0},{    32, 0},{  -161, 0},{    95, 0},{  -160, 0},{    96, 0},{  -289, 0},
+{   223, 0},{  -288, 0},{   224, 0},{  -545, 0},{   479, 0},{  -544, 0},{   480, 0},{ -1057, 0},
+{   991, 0},{ -1056, 0},{   992, 0},{ -2081, 0},{  2015, 0},{ -2080, 0},{  2016, 0},{ -4129, 0},
+{  4063, 0},{ -4128, 0},{  4064, 0},{ -8225, 0},{  8159, 0},{ -8224, 0},{  8160, 0},{-16417, 0},
+{ 16351, 0},{-16416, 0},{ 16352, 0},{-32801, 0},{ 32735, 0},{-32800, 0},{ 32736, 0},{    63, 0},
+{    65,-1},{    64, 0},{    66,-1},{    62, 0},{    66,-1},{    63, 0},{    67,-1},{    60, 0},
+{    68,-1},{    61, 0},{    69,-1},{    56, 0},{    72,-1},{    57, 0},{    73,-1},{    48, 0},
+{    80,-1},{    49, 0},{    81,-1},{    32, 0},{    96,-1},{    33, 0},{    97,-1},{     0, 0},
+{   128,-1},{     1, 0},{   129,-1},{   -64,-1},{   192,-1},{   -63,-1},{   193,-1},{  -192,-1},
+{   320,-1},{  -191,-1},{   321,-1},{  -448,-1},{   576,-1},{  -447,-1},{   577,-1},{  -960,-1},
+{  1088,-1},{  -959,-1},{  1089,-1},{ -1984,-1},{  2112,-1},{ -1983,-1},{  2113,-1},{ -4032,-1},
+{  4160,-1},{ -4031,-1},{  4161,-1},{ -8128,-1},{  8256,-1},{ -8127,-1},{  8257,-1},{-16320,-1},
+{ 16448,-1},{-16319,-1},{ 16449,-1},{-32704,-1},{ 32832,-1},{-32703,-1},{ 32833,-1},{   -65, 0},
+{   -63,-1},{   -64, 0},{   -62,-1},{   -66, 0},{   -62,-1},{   -65, 0},{   -61,-1},{   -68, 0},
+{   -60,-1},{   -67, 0},{   -59,-1},{   -72, 0},{   -56,-1},{   -71, 0},{   -55,-1},{   -80, 0},
+{   -48,-1},{   -79, 0},{   -47,-1},{   -96, 0},{   -32,-1},{   -95, 0},{   -31,-1},{  -128, 0},
+{     0, 0},{  -127, 0},{     1, 0},{  -192, 0},{    64, 0},{  -191, 0},{    65, 0},{  -320, 0},
+{   192, 0},{  -319, 0},{   193, 0},{  -576, 0},{   448, 0},{  -575, 0},{   449, 0},{ -1088, 0},
+{   960, 0},{ -1087, 0},{   961, 0},{ -2112, 0},{  1984, 0},{ -2111, 0},{  1985, 0},{ -4160, 0},
+{  4032, 0},{ -4159, 0},{  4033, 0},{ -8256, 0},{  8128, 0},{ -8255, 0},{  8129, 0},{-16448, 0},
+{ 16320, 0},{-16447, 0},{ 16321, 0},{-32832, 0},{ 32704, 0},{-32831, 0},{ 32705, 0},{    62, 0},
+{    64,-1},{    63, 0},{    65,-1},{    61, 0},{    65,-1},{    62, 0},{    66,-1},{    59, 0},
+{    67,-1},{    60, 0},{    68,-1},{    55, 0},{    71,-1},{    56, 0},{    72,-1},{    47, 0},
+{    79,-1},{    48, 0},{    80,-1},{    31, 0},{    95,-1},{    32, 0},{    96,-1},{    -1,-1},
+{   127,-1},{     0, 0},{   128,-1},{   -65,-1},{   191,-1},{   -64,-1},{   192,-1},{  -193,-1},
+{   319,-1},{  -192,-1},{   320,-1},{  -449,-1},{   575,-1},{  -448,-1},{   576,-1},{  -961,-1},
+{  1087,-1},{  -960,-1},{  1088,-1},{ -1985,-1},{  2111,-1},{ -1984,-1},{  2112,-1},{ -4033,-1},
+{  4159,-1},{ -4032,-1},{  4160,-1},{ -8129,-1},{  8255,-1},{ -8128,-1},{  8256,-1},{-16321,-1},
+{ 16447,-1},{-16320,-1},{ 16448,-1},{-32705,-1},{ 32831,-1},{-32704,-1},{ 32832,-1},{   -66, 0},
+{   -64,-1},{   -65, 0},{   -63,-1},{   -67, 0},{   -63,-1},{   -66, 0},{   -62,-1},{   -69, 0},
+{   -61,-1},{   -68, 0},{   -60,-1},{   -73, 0},{   -57,-1},{   -72, 0},{   -56,-1},{   -81, 0},
+{   -49,-1},{   -80, 0},{   -48,-1},{   -97, 0},{   -33,-1},{   -96, 0},{   -32,-1},{  -129, 0},
+{    -1,-1},{  -128, 0},{     0, 0},{  -193, 0},{    63, 0},{  -192, 0},{    64, 0},{  -321, 0},
+{   191, 0},{  -320, 0},{   192, 0},{  -577, 0},{   447, 0},{  -576, 0},{   448, 0},{ -1089, 0},
+{   959, 0},{ -1088, 0},{   960, 0},{ -2113, 0},{  1983, 0},{ -2112, 0},{  1984, 0},{ -4161, 0},
+{  4031, 0},{ -4160, 0},{  4032, 0},{ -8257, 0},{  8127, 0},{ -8256, 0},{  8128, 0},{-16449, 0},
+{ 16319, 0},{-16448, 0},{ 16320, 0},{-32833, 0},{ 32703, 0},{-32832, 0},{ 32704, 0},{   127, 0},
+{   129,-1},{   128, 0},{   130,-1},{   126, 0},{   130,-1},{   127, 0},{   131,-1},{   124, 0},
+{   132,-1},{   125, 0},{   133,-1},{   120, 0},{   136,-1},{   121, 0},{   137,-1},{   112, 0},
+{   144,-1},{   113, 0},{   145,-1},{    96, 0},{   160,-1},{    97, 0},{   161,-1},{    64, 0},
+{   192,-1},{    65, 0},{   193,-1},{     0, 0},{   256,-1},{     1, 0},{   257,-1},{  -128,-1},
+{   384,-1},{  -127,-1},{   385,-1},{  -384,-1},{   640,-1},{  -383,-1},{   641,-1},{  -896,-1},
+{  1152,-1},{  -895,-1},{  1153,-1},{ -1920,-1},{  2176,-1},{ -1919,-1},{  2177,-1},{ -3968,-1},
+{  4224,-1},{ -3967,-1},{  4225,-1},{ -8064,-1},{  8320,-1},{ -8063,-1},{  8321,-1},{-16256,-1},
+{ 16512,-1},{-16255,-1},{ 16513,-1},{-32640,-1},{ 32896,-1},{-32639,-1},{ 32897,-1},{  -129, 0},
+{  -127,-1},{  -128, 0},{  -126,-1},{  -130, 0},{  -126,-1},{  -129, 0},{  -125,-1},{  -132, 0},
+{  -124,-1},{  -131, 0},{  -123,-1},{  -136, 0},{  -120,-1},{  -135, 0},{  -119,-1},{  -144, 0},
+{  -112,-1},{  -143, 0},{  -111,-1},{  -160, 0},{   -96,-1},{  -159, 0},{   -95,-1},{  -192, 0},
+{   -64,-1},{  -191, 0},{   -63,-1},{  -256, 0},{     0, 0},{  -255, 0},{     1, 0},{  -384, 0},
+{   128, 0},{  -383, 0},{   129, 0},{  -640, 0},{   384, 0},{  -639, 0},{   385, 0},{ -1152, 0},
+{   896, 0},{ -1151, 0},{   897, 0},{ -2176, 0},{  1920, 0},{ -2175, 0},{  1921, 0},{ -4224, 0},
+{  3968, 0},{ -4223, 0},{  3969, 0},{ -8320, 0},{  8064, 0},{ -8319, 0},{  8065, 0},{-16512, 0},
+{ 16256, 0},{-16511, 0},{ 16257, 0},{-32896, 0},{ 32640, 0},{-32895, 0},{ 32641, 0},{   126, 0},
+{   128,-1},{   127, 0},{   129,-1},{   125, 0},{   129,-1},{   126, 0},{   130,-1},{   123, 0},
+{   131,-1},{   124, 0},{   132,-1},{   119, 0},{   135,-1},{   120, 0},{   136,-1},{   111, 0},
+{   143,-1},{   112, 0},{   144,-1},{    95, 0},{   159,-1},{    96, 0},{   160,-1},{    63, 0},
+{   191,-1},{    64, 0},{   192,-1},{    -1,-1},{   255,-1},{     0, 0},{   256,-1},{  -129,-1},
+{   383,-1},{  -128,-1},{   384,-1},{  -385,-1},{   639,-1},{  -384,-1},{   640,-1},{  -897,-1},
+{  1151,-1},{  -896,-1},{  1152,-1},{ -1921,-1},{  2175,-1},{ -1920,-1},{  2176,-1},{ -3969,-1},
+{  4223,-1},{ -3968,-1},{  4224,-1},{ -8065,-1},{  8319,-1},{ -8064,-1},{  8320,-1},{-16257,-1},
+{ 16511,-1},{-16256,-1},{ 16512,-1},{-32641,-1},{ 32895,-1},{-32640,-1},{ 32896,-1},{  -130, 0},
+{  -128,-1},{  -129, 0},{  -127,-1},{  -131, 0},{  -127,-1},{  -130, 0},{  -126,-1},{  -133, 0},
+{  -125,-1},{  -132, 0},{  -124,-1},{  -137, 0},{  -121,-1},{  -136, 0},{  -120,-1},{  -145, 0},
+{  -113,-1},{  -144, 0},{  -112,-1},{  -161, 0},{   -97,-1},{  -160, 0},{   -96,-1},{  -193, 0},
+{   -65,-1},{  -192, 0},{   -64,-1},{  -257, 0},{    -1,-1},{  -256, 0},{     0, 0},{  -385, 0},
+{   127, 0},{  -384, 0},{   128, 0},{  -641, 0},{   383, 0},{  -640, 0},{   384, 0},{ -1153, 0},
+{   895, 0},{ -1152, 0},{   896, 0},{ -2177, 0},{  1919, 0},{ -2176, 0},{  1920, 0},{ -4225, 0},
+{  3967, 0},{ -4224, 0},{  3968, 0},{ -8321, 0},{  8063, 0},{ -8320, 0},{  8064, 0},{-16513, 0},
+{ 16255, 0},{-16512, 0},{ 16256, 0},{-32897, 0},{ 32639, 0},{-32896, 0},{ 32640, 0},{   255, 0},
+{   257,-1},{   256, 0},{   258,-1},{   254, 0},{   258,-1},{   255, 0},{   259,-1},{   252, 0},
+{   260,-1},{   253, 0},{   261,-1},{   248, 0},{   264,-1},{   249, 0},{   265,-1},{   240, 0},
+{   272,-1},{   241, 0},{   273,-1},{   224, 0},{   288,-1},{   225, 0},{   289,-1},{   192, 0},
+{   320,-1},{   193, 0},{   321,-1},{   128, 0},{   384,-1},{   129, 0},{   385,-1},{     0, 0},
+{   512,-1},{     1, 0},{   513,-1},{  -256,-1},{   768,-1},{  -255,-1},{   769,-1},{  -768,-1},
+{  1280,-1},{  -767,-1},{  1281,-1},{ -1792,-1},{  2304,-1},{ -1791,-1},{  2305,-1},{ -3840,-1},
+{  4352,-1},{ -3839,-1},{  4353,-1},{ -7936,-1},{  8448,-1},{ -7935,-1},{  8449,-1},{-16128,-1},
+{ 16640,-1},{-16127,-1},{ 16641,-1},{-32512,-1},{ 33024,-1},{-32511,-1},{ 33025,-1},{  -257, 0},
+{  -255,-1},{  -256, 0},{  -254,-1},{  -258, 0},{  -254,-1},{  -257, 0},{  -253,-1},{  -260, 0},
+{  -252,-1},{  -259, 0},{  -251,-1},{  -264, 0},{  -248,-1},{  -263, 0},{  -247,-1},{  -272, 0},
+{  -240,-1},{  -271, 0},{  -239,-1},{  -288, 0},{  -224,-1},{  -287, 0},{  -223,-1},{  -320, 0},
+{  -192,-1},{  -319, 0},{  -191,-1},{  -384, 0},{  -128,-1},{  -383, 0},{  -127,-1},{  -512, 0},
+{     0, 0},{  -511, 0},{     1, 0},{  -768, 0},{   256, 0},{  -767, 0},{   257, 0},{ -1280, 0},
+{   768, 0},{ -1279, 0},{   769, 0},{ -2304, 0},{  1792, 0},{ -2303, 0},{  1793, 0},{ -4352, 0},
+{  3840, 0},{ -4351, 0},{  3841, 0},{ -8448, 0},{  7936, 0},{ -8447, 0},{  7937, 0},{-16640, 0},
+{ 16128, 0},{-16639, 0},{ 16129, 0},{-33024, 0},{ 32512, 0},{-33023, 0},{ 32513, 0},{   254, 0},
+{   256,-1},{   255, 0},{   257,-1},{   253, 0},{   257,-1},{   254, 0},{   258,-1},{   251, 0},
+{   259,-1},{   252, 0},{   260,-1},{   247, 0},{   263,-1},{   248, 0},{   264,-1},{   239, 0},
+{   271,-1},{   240, 0},{   272,-1},{   223, 0},{   287,-1},{   224, 0},{   288,-1},{   191, 0},
+{   319,-1},{   192, 0},{   320,-1},{   127, 0},{   383,-1},{   128, 0},{   384,-1},{    -1,-1},
+{   511,-1},{     0, 0},{   512,-1},{  -257,-1},{   767,-1},{  -256,-1},{   768,-1},{  -769,-1},
+{  1279,-1},{  -768,-1},{  1280,-1},{ -1793,-1},{  2303,-1},{ -1792,-1},{  2304,-1},{ -3841,-1},
+{  4351,-1},{ -3840,-1},{  4352,-1},{ -7937,-1},{  8447,-1},{ -7936,-1},{  8448,-1},{-16129,-1},
+{ 16639,-1},{-16128,-1},{ 16640,-1},{-32513,-1},{ 33023,-1},{-32512,-1},{ 33024,-1},{  -258, 0},
+{  -256,-1},{  -257, 0},{  -255,-1},{  -259, 0},{  -255,-1},{  -258, 0},{  -254,-1},{  -261, 0},
+{  -253,-1},{  -260, 0},{  -252,-1},{  -265, 0},{  -249,-1},{  -264, 0},{  -248,-1},{  -273, 0},
+{  -241,-1},{  -272, 0},{  -240,-1},{  -289, 0},{  -225,-1},{  -288, 0},{  -224,-1},{  -321, 0},
+{  -193,-1},{  -320, 0},{  -192,-1},{  -385, 0},{  -129,-1},{  -384, 0},{  -128,-1},{  -513, 0},
+{    -1,-1},{  -512, 0},{     0, 0},{  -769, 0},{   255, 0},{  -768, 0},{   256, 0},{ -1281, 0},
+{   767, 0},{ -1280, 0},{   768, 0},{ -2305, 0},{  1791, 0},{ -2304, 0},{  1792, 0},{ -4353, 0},
+{  3839, 0},{ -4352, 0},{  3840, 0},{ -8449, 0},{  7935, 0},{ -8448, 0},{  7936, 0},{-16641, 0},
+{ 16127, 0},{-16640, 0},{ 16128, 0},{-33025, 0},{ 32511, 0},{-33024, 0},{ 32512, 0},{   511, 0},
+{   513,-1},{   512, 0},{   514,-1},{   510, 0},{   514,-1},{   511, 0},{   515,-1},{   508, 0},
+{   516,-1},{   509, 0},{   517,-1},{   504, 0},{   520,-1},{   505, 0},{   521,-1},{   496, 0},
+{   528,-1},{   497, 0},{   529,-1},{   480, 0},{   544,-1},{   481, 0},{   545,-1},{   448, 0},
+{   576,-1},{   449, 0},{   577,-1},{   384, 0},{   640,-1},{   385, 0},{   641,-1},{   256, 0},
+{   768,-1},{   257, 0},{   769,-1},{     0, 0},{  1024,-1},{     1, 0},{  1025,-1},{  -512,-1},
+{  1536,-1},{  -511,-1},{  1537,-1},{ -1536,-1},{  2560,-1},{ -1535,-1},{  2561,-1},{ -3584,-1},
+{  4608,-1},{ -3583,-1},{  4609,-1},{ -7680,-1},{  8704,-1},{ -7679,-1},{  8705,-1},{-15872,-1},
+{ 16896,-1},{-15871,-1},{ 16897,-1},{-32256,-1},{ 33280,-1},{-32255,-1},{ 33281,-1},{  -513, 0},
+{  -511,-1},{  -512, 0},{  -510,-1},{  -514, 0},{  -510,-1},{  -513, 0},{  -509,-1},{  -516, 0},
+{  -508,-1},{  -515, 0},{  -507,-1},{  -520, 0},{  -504,-1},{  -519, 0},{  -503,-1},{  -528, 0},
+{  -496,-1},{  -527, 0},{  -495,-1},{  -544, 0},{  -480,-1},{  -543, 0},{  -479,-1},{  -576, 0},
+{  -448,-1},{  -575, 0},{  -447,-1},{  -640, 0},{  -384,-1},{  -639, 0},{  -383,-1},{  -768, 0},
+{  -256,-1},{  -767, 0},{  -255,-1},{ -1024, 0},{     0, 0},{ -1023, 0},{     1, 0},{ -1536, 0},
+{   512, 0},{ -1535, 0},{   513, 0},{ -2560, 0},{  1536, 0},{ -2559, 0},{  1537, 0},{ -4608, 0},
+{  3584, 0},{ -4607, 0},{  3585, 0},{ -8704, 0},{  7680, 0},{ -8703, 0},{  7681, 0},{-16896, 0},
+{ 15872, 0},{-16895, 0},{ 15873, 0},{-33280, 0},{ 32256, 0},{-33279, 0},{ 32257, 0},{   510, 0},
+{   512,-1},{   511, 0},{   513,-1},{   509, 0},{   513,-1},{   510, 0},{   514,-1},{   507, 0},
+{   515,-1},{   508, 0},{   516,-1},{   503, 0},{   519,-1},{   504, 0},{   520,-1},{   495, 0},
+{   527,-1},{   496, 0},{   528,-1},{   479, 0},{   543,-1},{   480, 0},{   544,-1},{   447, 0},
+{   575,-1},{   448, 0},{   576,-1},{   383, 0},{   639,-1},{   384, 0},{   640,-1},{   255, 0},
+{   767,-1},{   256, 0},{   768,-1},{    -1,-1},{  1023,-1},{     0, 0},{  1024,-1},{  -513,-1},
+{  1535,-1},{  -512,-1},{  1536,-1},{ -1537,-1},{  2559,-1},{ -1536,-1},{  2560,-1},{ -3585,-1},
+{  4607,-1},{ -3584,-1},{  4608,-1},{ -7681,-1},{  8703,-1},{ -7680,-1},{  8704,-1},{-15873,-1},
+{ 16895,-1},{-15872,-1},{ 16896,-1},{-32257,-1},{ 33279,-1},{-32256,-1},{ 33280,-1},{  -514, 0},
+{  -512,-1},{  -513, 0},{  -511,-1},{  -515, 0},{  -511,-1},{  -514, 0},{  -510,-1},{  -517, 0},
+{  -509,-1},{  -516, 0},{  -508,-1},{  -521, 0},{  -505,-1},{  -520, 0},{  -504,-1},{  -529, 0},
+{  -497,-1},{  -528, 0},{  -496,-1},{  -545, 0},{  -481,-1},{  -544, 0},{  -480,-1},{  -577, 0},
+{  -449,-1},{  -576, 0},{  -448,-1},{  -641, 0},{  -385,-1},{  -640, 0},{  -384,-1},{  -769, 0},
+{  -257,-1},{  -768, 0},{  -256,-1},{ -1025, 0},{    -1,-1},{ -1024, 0},{     0, 0},{ -1537, 0},
+{   511, 0},{ -1536, 0},{   512, 0},{ -2561, 0},{  1535, 0},{ -2560, 0},{  1536, 0},{ -4609, 0},
+{  3583, 0},{ -4608, 0},{  3584, 0},{ -8705, 0},{  7679, 0},{ -8704, 0},{  7680, 0},{-16897, 0},
+{ 15871, 0},{-16896, 0},{ 15872, 0},{-33281, 0},{ 32255, 0},{-33280, 0},{ 32256, 0},{  1023, 0},
+{  1025,-1},{  1024, 0},{  1026,-1},{  1022, 0},{  1026,-1},{  1023, 0},{  1027,-1},{  1020, 0},
+{  1028,-1},{  1021, 0},{  1029,-1},{  1016, 0},{  1032,-1},{  1017, 0},{  1033,-1},{  1008, 0},
+{  1040,-1},{  1009, 0},{  1041,-1},{   992, 0},{  1056,-1},{   993, 0},{  1057,-1},{   960, 0},
+{  1088,-1},{   961, 0},{  1089,-1},{   896, 0},{  1152,-1},{   897, 0},{  1153,-1},{   768, 0},
+{  1280,-1},{   769, 0},{  1281,-1},{   512, 0},{  1536,-1},{   513, 0},{  1537,-1},{     0, 0},
+{  2048,-1},{     1, 0},{  2049,-1},{ -1024,-1},{  3072,-1},{ -1023,-1},{  3073,-1},{ -3072,-1},
+{  5120,-1},{ -3071,-1},{  5121,-1},{ -7168,-1},{  9216,-1},{ -7167,-1},{  9217,-1},{-15360,-1},
+{ 17408,-1},{-15359,-1},{ 17409,-1},{-31744,-1},{ 33792,-1},{-31743,-1},{ 33793,-1},{ -1025, 0},
+{ -1023,-1},{ -1024, 0},{ -1022,-1},{ -1026, 0},{ -1022,-1},{ -1025, 0},{ -1021,-1},{ -1028, 0},
+{ -1020,-1},{ -1027, 0},{ -1019,-1},{ -1032, 0},{ -1016,-1},{ -1031, 0},{ -1015,-1},{ -1040, 0},
+{ -1008,-1},{ -1039, 0},{ -1007,-1},{ -1056, 0},{  -992,-1},{ -1055, 0},{  -991,-1},{ -1088, 0},
+{  -960,-1},{ -1087, 0},{  -959,-1},{ -1152, 0},{  -896,-1},{ -1151, 0},{  -895,-1},{ -1280, 0},
+{  -768,-1},{ -1279, 0},{  -767,-1},{ -1536, 0},{  -512,-1},{ -1535, 0},{  -511,-1},{ -2048, 0},
+{     0, 0},{ -2047, 0},{     1, 0},{ -3072, 0},{  1024, 0},{ -3071, 0},{  1025, 0},{ -5120, 0},
+{  3072, 0},{ -5119, 0},{  3073, 0},{ -9216, 0},{  7168, 0},{ -9215, 0},{  7169, 0},{-17408, 0},
+{ 15360, 0},{-17407, 0},{ 15361, 0},{-33792, 0},{ 31744, 0},{-33791, 0},{ 31745, 0},{  1022, 0},
+{  1024,-1},{  1023, 0},{  1025,-1},{  1021, 0},{  1025,-1},{  1022, 0},{  1026,-1},{  1019, 0},
+{  1027,-1},{  1020, 0},{  1028,-1},{  1015, 0},{  1031,-1},{  1016, 0},{  1032,-1},{  1007, 0},
+{  1039,-1},{  1008, 0},{  1040,-1},{   991, 0},{  1055,-1},{   992, 0},{  1056,-1},{   959, 0},
+{  1087,-1},{   960, 0},{  1088,-1},{   895, 0},{  1151,-1},{   896, 0},{  1152,-1},{   767, 0},
+{  1279,-1},{   768, 0},{  1280,-1},{   511, 0},{  1535,-1},{   512, 0},{  1536,-1},{    -1,-1},
+{  2047,-1},{     0, 0},{  2048,-1},{ -1025,-1},{  3071,-1},{ -1024,-1},{  3072,-1},{ -3073,-1},
+{  5119,-1},{ -3072,-1},{  5120,-1},{ -7169,-1},{  9215,-1},{ -7168,-1},{  9216,-1},{-15361,-1},
+{ 17407,-1},{-15360,-1},{ 17408,-1},{-31745,-1},{ 33791,-1},{-31744,-1},{ 33792,-1},{ -1026, 0},
+{ -1024,-1},{ -1025, 0},{ -1023,-1},{ -1027, 0},{ -1023,-1},{ -1026, 0},{ -1022,-1},{ -1029, 0},
+{ -1021,-1},{ -1028, 0},{ -1020,-1},{ -1033, 0},{ -1017,-1},{ -1032, 0},{ -1016,-1},{ -1041, 0},
+{ -1009,-1},{ -1040, 0},{ -1008,-1},{ -1057, 0},{  -993,-1},{ -1056, 0},{  -992,-1},{ -1089, 0},
+{  -961,-1},{ -1088, 0},{  -960,-1},{ -1153, 0},{  -897,-1},{ -1152, 0},{  -896,-1},{ -1281, 0},
+{  -769,-1},{ -1280, 0},{  -768,-1},{ -1537, 0},{  -513,-1},{ -1536, 0},{  -512,-1},{ -2049, 0},
+{    -1,-1},{ -2048, 0},{     0, 0},{ -3073, 0},{  1023, 0},{ -3072, 0},{  1024, 0},{ -5121, 0},
+{  3071, 0},{ -5120, 0},{  3072, 0},{ -9217, 0},{  7167, 0},{ -9216, 0},{  7168, 0},{-17409, 0},
+{ 15359, 0},{-17408, 0},{ 15360, 0},{-33793, 0},{ 31743, 0},{-33792, 0},{ 31744, 0},{  2047, 0},
+{  2049,-1},{  2048, 0},{  2050,-1},{  2046, 0},{  2050,-1},{  2047, 0},{  2051,-1},{  2044, 0},
+{  2052,-1},{  2045, 0},{  2053,-1},{  2040, 0},{  2056,-1},{  2041, 0},{  2057,-1},{  2032, 0},
+{  2064,-1},{  2033, 0},{  2065,-1},{  2016, 0},{  2080,-1},{  2017, 0},{  2081,-1},{  1984, 0},
+{  2112,-1},{  1985, 0},{  2113,-1},{  1920, 0},{  2176,-1},{  1921, 0},{  2177,-1},{  1792, 0},
+{  2304,-1},{  1793, 0},{  2305,-1},{  1536, 0},{  2560,-1},{  1537, 0},{  2561,-1},{  1024, 0},
+{  3072,-1},{  1025, 0},{  3073,-1},{     0, 0},{  4096,-1},{     1, 0},{  4097,-1},{ -2048,-1},
+{  6144,-1},{ -2047,-1},{  6145,-1},{ -6144,-1},{ 10240,-1},{ -6143,-1},{ 10241,-1},{-14336,-1},
+{ 18432,-1},{-14335,-1},{ 18433,-1},{-30720,-1},{ 34816,-1},{-30719,-1},{ 34817,-1},{ -2049, 0},
+{ -2047,-1},{ -2048, 0},{ -2046,-1},{ -2050, 0},{ -2046,-1},{ -2049, 0},{ -2045,-1},{ -2052, 0},
+{ -2044,-1},{ -2051, 0},{ -2043,-1},{ -2056, 0},{ -2040,-1},{ -2055, 0},{ -2039,-1},{ -2064, 0},
+{ -2032,-1},{ -2063, 0},{ -2031,-1},{ -2080, 0},{ -2016,-1},{ -2079, 0},{ -2015,-1},{ -2112, 0},
+{ -1984,-1},{ -2111, 0},{ -1983,-1},{ -2176, 0},{ -1920,-1},{ -2175, 0},{ -1919,-1},{ -2304, 0},
+{ -1792,-1},{ -2303, 0},{ -1791,-1},{ -2560, 0},{ -1536,-1},{ -2559, 0},{ -1535,-1},{ -3072, 0},
+{ -1024,-1},{ -3071, 0},{ -1023,-1},{ -4096, 0},{     0, 0},{ -4095, 0},{     1, 0},{ -6144, 0},
+{  2048, 0},{ -6143, 0},{  2049, 0},{-10240, 0},{  6144, 0},{-10239, 0},{  6145, 0},{-18432, 0},
+{ 14336, 0},{-18431, 0},{ 14337, 0},{-34816, 0},{ 30720, 0},{-34815, 0},{ 30721, 0},{  2046, 0},
+{  2048,-1},{  2047, 0},{  2049,-1},{  2045, 0},{  2049,-1},{  2046, 0},{  2050,-1},{  2043, 0},
+{  2051,-1},{  2044, 0},{  2052,-1},{  2039, 0},{  2055,-1},{  2040, 0},{  2056,-1},{  2031, 0},
+{  2063,-1},{  2032, 0},{  2064,-1},{  2015, 0},{  2079,-1},{  2016, 0},{  2080,-1},{  1983, 0},
+{  2111,-1},{  1984, 0},{  2112,-1},{  1919, 0},{  2175,-1},{  1920, 0},{  2176,-1},{  1791, 0},
+{  2303,-1},{  1792, 0},{  2304,-1},{  1535, 0},{  2559,-1},{  1536, 0},{  2560,-1},{  1023, 0},
+{  3071,-1},{  1024, 0},{  3072,-1},{    -1,-1},{  4095,-1},{     0, 0},{  4096,-1},{ -2049,-1},
+{  6143,-1},{ -2048,-1},{  6144,-1},{ -6145,-1},{ 10239,-1},{ -6144,-1},{ 10240,-1},{-14337,-1},
+{ 18431,-1},{-14336,-1},{ 18432,-1},{-30721,-1},{ 34815,-1},{-30720,-1},{ 34816,-1},{ -2050, 0},
+{ -2048,-1},{ -2049, 0},{ -2047,-1},{ -2051, 0},{ -2047,-1},{ -2050, 0},{ -2046,-1},{ -2053, 0},
+{ -2045,-1},{ -2052, 0},{ -2044,-1},{ -2057, 0},{ -2041,-1},{ -2056, 0},{ -2040,-1},{ -2065, 0},
+{ -2033,-1},{ -2064, 0},{ -2032,-1},{ -2081, 0},{ -2017,-1},{ -2080, 0},{ -2016,-1},{ -2113, 0},
+{ -1985,-1},{ -2112, 0},{ -1984,-1},{ -2177, 0},{ -1921,-1},{ -2176, 0},{ -1920,-1},{ -2305, 0},
+{ -1793,-1},{ -2304, 0},{ -1792,-1},{ -2561, 0},{ -1537,-1},{ -2560, 0},{ -1536,-1},{ -3073, 0},
+{ -1025,-1},{ -3072, 0},{ -1024,-1},{ -4097, 0},{    -1,-1},{ -4096, 0},{     0, 0},{ -6145, 0},
+{  2047, 0},{ -6144, 0},{  2048, 0},{-10241, 0},{  6143, 0},{-10240, 0},{  6144, 0},{-18433, 0},
+{ 14335, 0},{-18432, 0},{ 14336, 0},{-34817, 0},{ 30719, 0},{-34816, 0},{ 30720, 0},{  4095, 0},
+{  4097,-1},{  4096, 0},{  4098,-1},{  4094, 0},{  4098,-1},{  4095, 0},{  4099,-1},{  4092, 0},
+{  4100,-1},{  4093, 0},{  4101,-1},{  4088, 0},{  4104,-1},{  4089, 0},{  4105,-1},{  4080, 0},
+{  4112,-1},{  4081, 0},{  4113,-1},{  4064, 0},{  4128,-1},{  4065, 0},{  4129,-1},{  4032, 0},
+{  4160,-1},{  4033, 0},{  4161,-1},{  3968, 0},{  4224,-1},{  3969, 0},{  4225,-1},{  3840, 0},
+{  4352,-1},{  3841, 0},{  4353,-1},{  3584, 0},{  4608,-1},{  3585, 0},{  4609,-1},{  3072, 0},
+{  5120,-1},{  3073, 0},{  5121,-1},{  2048, 0},{  6144,-1},{  2049, 0},{  6145,-1},{     0, 0},
+{  8192,-1},{     1, 0},{  8193,-1},{ -4096,-1},{ 12288,-1},{ -4095,-1},{ 12289,-1},{-12288,-1},
+{ 20480,-1},{-12287,-1},{ 20481,-1},{-28672,-1},{ 36864,-1},{-28671,-1},{ 36865,-1},{ -4097, 0},
+{ -4095,-1},{ -4096, 0},{ -4094,-1},{ -4098, 0},{ -4094,-1},{ -4097, 0},{ -4093,-1},{ -4100, 0},
+{ -4092,-1},{ -4099, 0},{ -4091,-1},{ -4104, 0},{ -4088,-1},{ -4103, 0},{ -4087,-1},{ -4112, 0},
+{ -4080,-1},{ -4111, 0},{ -4079,-1},{ -4128, 0},{ -4064,-1},{ -4127, 0},{ -4063,-1},{ -4160, 0},
+{ -4032,-1},{ -4159, 0},{ -4031,-1},{ -4224, 0},{ -3968,-1},{ -4223, 0},{ -3967,-1},{ -4352, 0},
+{ -3840,-1},{ -4351, 0},{ -3839,-1},{ -4608, 0},{ -3584,-1},{ -4607, 0},{ -3583,-1},{ -5120, 0},
+{ -3072,-1},{ -5119, 0},{ -3071,-1},{ -6144, 0},{ -2048,-1},{ -6143, 0},{ -2047,-1},{ -8192, 0},
+{     0, 0},{ -8191, 0},{     1, 0},{-12288, 0},{  4096, 0},{-12287, 0},{  4097, 0},{-20480, 0},
+{ 12288, 0},{-20479, 0},{ 12289, 0},{-36864, 0},{ 28672, 0},{-36863, 0},{ 28673, 0},{  4094, 0},
+{  4096,-1},{  4095, 0},{  4097,-1},{  4093, 0},{  4097,-1},{  4094, 0},{  4098,-1},{  4091, 0},
+{  4099,-1},{  4092, 0},{  4100,-1},{  4087, 0},{  4103,-1},{  4088, 0},{  4104,-1},{  4079, 0},
+{  4111,-1},{  4080, 0},{  4112,-1},{  4063, 0},{  4127,-1},{  4064, 0},{  4128,-1},{  4031, 0},
+{  4159,-1},{  4032, 0},{  4160,-1},{  3967, 0},{  4223,-1},{  3968, 0},{  4224,-1},{  3839, 0},
+{  4351,-1},{  3840, 0},{  4352,-1},{  3583, 0},{  4607,-1},{  3584, 0},{  4608,-1},{  3071, 0},
+{  5119,-1},{  3072, 0},{  5120,-1},{  2047, 0},{  6143,-1},{  2048, 0},{  6144,-1},{    -1,-1},
+{  8191,-1},{     0, 0},{  8192,-1},{ -4097,-1},{ 12287,-1},{ -4096,-1},{ 12288,-1},{-12289,-1},
+{ 20479,-1},{-12288,-1},{ 20480,-1},{-28673,-1},{ 36863,-1},{-28672,-1},{ 36864,-1},{ -4098, 0},
+{ -4096,-1},{ -4097, 0},{ -4095,-1},{ -4099, 0},{ -4095,-1},{ -4098, 0},{ -4094,-1},{ -4101, 0},
+{ -4093,-1},{ -4100, 0},{ -4092,-1},{ -4105, 0},{ -4089,-1},{ -4104, 0},{ -4088,-1},{ -4113, 0},
+{ -4081,-1},{ -4112, 0},{ -4080,-1},{ -4129, 0},{ -4065,-1},{ -4128, 0},{ -4064,-1},{ -4161, 0},
+{ -4033,-1},{ -4160, 0},{ -4032,-1},{ -4225, 0},{ -3969,-1},{ -4224, 0},{ -3968,-1},{ -4353, 0},
+{ -3841,-1},{ -4352, 0},{ -3840,-1},{ -4609, 0},{ -3585,-1},{ -4608, 0},{ -3584,-1},{ -5121, 0},
+{ -3073,-1},{ -5120, 0},{ -3072,-1},{ -6145, 0},{ -2049,-1},{ -6144, 0},{ -2048,-1},{ -8193, 0},
+{    -1,-1},{ -8192, 0},{     0, 0},{-12289, 0},{  4095, 0},{-12288, 0},{  4096, 0},{-20481, 0},
+{ 12287, 0},{-20480, 0},{ 12288, 0},{-36865, 0},{ 28671, 0},{-36864, 0},{ 28672, 0},{  8191, 0},
+{  8193,-1},{  8192, 0},{  8194,-1},{  8190, 0},{  8194,-1},{  8191, 0},{  8195,-1},{  8188, 0},
+{  8196,-1},{  8189, 0},{  8197,-1},{  8184, 0},{  8200,-1},{  8185, 0},{  8201,-1},{  8176, 0},
+{  8208,-1},{  8177, 0},{  8209,-1},{  8160, 0},{  8224,-1},{  8161, 0},{  8225,-1},{  8128, 0},
+{  8256,-1},{  8129, 0},{  8257,-1},{  8064, 0},{  8320,-1},{  8065, 0},{  8321,-1},{  7936, 0},
+{  8448,-1},{  7937, 0},{  8449,-1},{  7680, 0},{  8704,-1},{  7681, 0},{  8705,-1},{  7168, 0},
+{  9216,-1},{  7169, 0},{  9217,-1},{  6144, 0},{ 10240,-1},{  6145, 0},{ 10241,-1},{  4096, 0},
+{ 12288,-1},{  4097, 0},{ 12289,-1},{     0, 0},{ 16384,-1},{     1, 0},{ 16385,-1},{ -8192,-1},
+{ 24576,-1},{ -8191,-1},{ 24577,-1},{-24576,-1},{ 40960,-1},{-24575,-1},{ 40961,-1},{ -8193, 0},
+{ -8191,-1},{ -8192, 0},{ -8190,-1},{ -8194, 0},{ -8190,-1},{ -8193, 0},{ -8189,-1},{ -8196, 0},
+{ -8188,-1},{ -8195, 0},{ -8187,-1},{ -8200, 0},{ -8184,-1},{ -8199, 0},{ -8183,-1},{ -8208, 0},
+{ -8176,-1},{ -8207, 0},{ -8175,-1},{ -8224, 0},{ -8160,-1},{ -8223, 0},{ -8159,-1},{ -8256, 0},
+{ -8128,-1},{ -8255, 0},{ -8127,-1},{ -8320, 0},{ -8064,-1},{ -8319, 0},{ -8063,-1},{ -8448, 0},
+{ -7936,-1},{ -8447, 0},{ -7935,-1},{ -8704, 0},{ -7680,-1},{ -8703, 0},{ -7679,-1},{ -9216, 0},
+{ -7168,-1},{ -9215, 0},{ -7167,-1},{-10240, 0},{ -6144,-1},{-10239, 0},{ -6143,-1},{-12288, 0},
+{ -4096,-1},{-12287, 0},{ -4095,-1},{-16384, 0},{     0, 0},{-16383, 0},{     1, 0},{-24576, 0},
+{  8192, 0},{-24575, 0},{  8193, 0},{-40960, 0},{ 24576, 0},{-40959, 0},{ 24577, 0},{  8190, 0},
+{  8192,-1},{  8191, 0},{  8193,-1},{  8189, 0},{  8193,-1},{  8190, 0},{  8194,-1},{  8187, 0},
+{  8195,-1},{  8188, 0},{  8196,-1},{  8183, 0},{  8199,-1},{  8184, 0},{  8200,-1},{  8175, 0},
+{  8207,-1},{  8176, 0},{  8208,-1},{  8159, 0},{  8223,-1},{  8160, 0},{  8224,-1},{  8127, 0},
+{  8255,-1},{  8128, 0},{  8256,-1},{  8063, 0},{  8319,-1},{  8064, 0},{  8320,-1},{  7935, 0},
+{  8447,-1},{  7936, 0},{  8448,-1},{  7679, 0},{  8703,-1},{  7680, 0},{  8704,-1},{  7167, 0},
+{  9215,-1},{  7168, 0},{  9216,-1},{  6143, 0},{ 10239,-1},{  6144, 0},{ 10240,-1},{  4095, 0},
+{ 12287,-1},{  4096, 0},{ 12288,-1},{    -1,-1},{ 16383,-1},{     0, 0},{ 16384,-1},{ -8193,-1},
+{ 24575,-1},{ -8192,-1},{ 24576,-1},{-24577,-1},{ 40959,-1},{-24576,-1},{ 40960,-1},{ -8194, 0},
+{ -8192,-1},{ -8193, 0},{ -8191,-1},{ -8195, 0},{ -8191,-1},{ -8194, 0},{ -8190,-1},{ -8197, 0},
+{ -8189,-1},{ -8196, 0},{ -8188,-1},{ -8201, 0},{ -8185,-1},{ -8200, 0},{ -8184,-1},{ -8209, 0},
+{ -8177,-1},{ -8208, 0},{ -8176,-1},{ -8225, 0},{ -8161,-1},{ -8224, 0},{ -8160,-1},{ -8257, 0},
+{ -8129,-1},{ -8256, 0},{ -8128,-1},{ -8321, 0},{ -8065,-1},{ -8320, 0},{ -8064,-1},{ -8449, 0},
+{ -7937,-1},{ -8448, 0},{ -7936,-1},{ -8705, 0},{ -7681,-1},{ -8704, 0},{ -7680,-1},{ -9217, 0},
+{ -7169,-1},{ -9216, 0},{ -7168,-1},{-10241, 0},{ -6145,-1},{-10240, 0},{ -6144,-1},{-12289, 0},
+{ -4097,-1},{-12288, 0},{ -4096,-1},{-16385, 0},{    -1,-1},{-16384, 0},{     0, 0},{-24577, 0},
+{  8191, 0},{-24576, 0},{  8192, 0},{-40961, 0},{ 24575, 0},{-40960, 0},{ 24576, 0},{ 16383, 0},
+{ 16385,-1},{ 16384, 0},{ 16386,-1},{ 16382, 0},{ 16386,-1},{ 16383, 0},{ 16387,-1},{ 16380, 0},
+{ 16388,-1},{ 16381, 0},{ 16389,-1},{ 16376, 0},{ 16392,-1},{ 16377, 0},{ 16393,-1},{ 16368, 0},
+{ 16400,-1},{ 16369, 0},{ 16401,-1},{ 16352, 0},{ 16416,-1},{ 16353, 0},{ 16417,-1},{ 16320, 0},
+{ 16448,-1},{ 16321, 0},{ 16449,-1},{ 16256, 0},{ 16512,-1},{ 16257, 0},{ 16513,-1},{ 16128, 0},
+{ 16640,-1},{ 16129, 0},{ 16641,-1},{ 15872, 0},{ 16896,-1},{ 15873, 0},{ 16897,-1},{ 15360, 0},
+{ 17408,-1},{ 15361, 0},{ 17409,-1},{ 14336, 0},{ 18432,-1},{ 14337, 0},{ 18433,-1},{ 12288, 0},
+{ 20480,-1},{ 12289, 0},{ 20481,-1},{  8192, 0},{ 24576,-1},{  8193, 0},{ 24577,-1},{     0, 0},
+{ 32768,-1},{     1, 0},{ 32769,-1},{-16384,-1},{ 49152,-1},{-16383,-1},{ 49153,-1},{-16385, 0},
+{-16383,-1},{-16384, 0},{-16382,-1},{-16386, 0},{-16382,-1},{-16385, 0},{-16381,-1},{-16388, 0},
+{-16380,-1},{-16387, 0},{-16379,-1},{-16392, 0},{-16376,-1},{-16391, 0},{-16375,-1},{-16400, 0},
+{-16368,-1},{-16399, 0},{-16367,-1},{-16416, 0},{-16352,-1},{-16415, 0},{-16351,-1},{-16448, 0},
+{-16320,-1},{-16447, 0},{-16319,-1},{-16512, 0},{-16256,-1},{-16511, 0},{-16255,-1},{-16640, 0},
+{-16128,-1},{-16639, 0},{-16127,-1},{-16896, 0},{-15872,-1},{-16895, 0},{-15871,-1},{-17408, 0},
+{-15360,-1},{-17407, 0},{-15359,-1},{-18432, 0},{-14336,-1},{-18431, 0},{-14335,-1},{-20480, 0},
+{-12288,-1},{-20479, 0},{-12287,-1},{-24576, 0},{ -8192,-1},{-24575, 0},{ -8191,-1},{-32768, 0},
+{     0, 0},{-32767, 0},{     1, 0},{-49152, 0},{ 16384, 0},{-49151, 0},{ 16385, 0},{ 16382, 0},
+{ 16384,-1},{ 16383, 0},{ 16385,-1},{ 16381, 0},{ 16385,-1},{ 16382, 0},{ 16386,-1},{ 16379, 0},
+{ 16387,-1},{ 16380, 0},{ 16388,-1},{ 16375, 0},{ 16391,-1},{ 16376, 0},{ 16392,-1},{ 16367, 0},
+{ 16399,-1},{ 16368, 0},{ 16400,-1},{ 16351, 0},{ 16415,-1},{ 16352, 0},{ 16416,-1},{ 16319, 0},
+{ 16447,-1},{ 16320, 0},{ 16448,-1},{ 16255, 0},{ 16511,-1},{ 16256, 0},{ 16512,-1},{ 16127, 0},
+{ 16639,-1},{ 16128, 0},{ 16640,-1},{ 15871, 0},{ 16895,-1},{ 15872, 0},{ 16896,-1},{ 15359, 0},
+{ 17407,-1},{ 15360, 0},{ 17408,-1},{ 14335, 0},{ 18431,-1},{ 14336, 0},{ 18432,-1},{ 12287, 0},
+{ 20479,-1},{ 12288, 0},{ 20480,-1},{  8191, 0},{ 24575,-1},{  8192, 0},{ 24576,-1},{    -1,-1},
+{ 32767,-1},{     0, 0},{ 32768,-1},{-16385,-1},{ 49151,-1},{-16384,-1},{ 49152,-1},{-16386, 0},
+{-16384,-1},{-16385, 0},{-16383,-1},{-16387, 0},{-16383,-1},{-16386, 0},{-16382,-1},{-16389, 0},
+{-16381,-1},{-16388, 0},{-16380,-1},{-16393, 0},{-16377,-1},{-16392, 0},{-16376,-1},{-16401, 0},
+{-16369,-1},{-16400, 0},{-16368,-1},{-16417, 0},{-16353,-1},{-16416, 0},{-16352,-1},{-16449, 0},
+{-16321,-1},{-16448, 0},{-16320,-1},{-16513, 0},{-16257,-1},{-16512, 0},{-16256,-1},{-16641, 0},
+{-16129,-1},{-16640, 0},{-16128,-1},{-16897, 0},{-15873,-1},{-16896, 0},{-15872,-1},{-17409, 0},
+{-15361,-1},{-17408, 0},{-15360,-1},{-18433, 0},{-14337,-1},{-18432, 0},{-14336,-1},{-20481, 0},
+{-12289,-1},{-20480, 0},{-12288,-1},{-24577, 0},{ -8193,-1},{-24576, 0},{ -8192,-1},{-32769, 0},
+{    -1,-1},{-32768, 0},{     0, 0},{-49153, 0},{ 16383, 0},{-49152, 0},{ 16384, 0},{ 32767, 0},
+{ 32769,-1},{ 32768, 0},{ 32770,-1},{ 32766, 0},{ 32770,-1},{ 32767, 0},{ 32771,-1},{ 32764, 0},
+{ 32772,-1},{ 32765, 0},{ 32773,-1},{ 32760, 0},{ 32776,-1},{ 32761, 0},{ 32777,-1},{ 32752, 0},
+{ 32784,-1},{ 32753, 0},{ 32785,-1},{ 32736, 0},{ 32800,-1},{ 32737, 0},{ 32801,-1},{ 32704, 0},
+{ 32832,-1},{ 32705, 0},{ 32833,-1},{ 32640, 0},{ 32896,-1},{ 32641, 0},{ 32897,-1},{ 32512, 0},
+{ 33024,-1},{ 32513, 0},{ 33025,-1},{ 32256, 0},{ 33280,-1},{ 32257, 0},{ 33281,-1},{ 31744, 0},
+{ 33792,-1},{ 31745, 0},{ 33793,-1},{ 30720, 0},{ 34816,-1},{ 30721, 0},{ 34817,-1},{ 28672, 0},
+{ 36864,-1},{ 28673, 0},{ 36865,-1},{ 24576, 0},{ 40960,-1},{ 24577, 0},{ 40961,-1},{ 16384, 0},
+{ 49152,-1},{ 16385, 0},{ 49153,-1},{     0, 0},{ 65536,-1},{     1, 0},{ 65537,-1},{-32769, 0},
+{-32767,-1},{-32768, 0},{-32766,-1},{-32770, 0},{-32766,-1},{-32769, 0},{-32765,-1},{-32772, 0},
+{-32764,-1},{-32771, 0},{-32763,-1},{-32776, 0},{-32760,-1},{-32775, 0},{-32759,-1},{-32784, 0},
+{-32752,-1},{-32783, 0},{-32751,-1},{-32800, 0},{-32736,-1},{-32799, 0},{-32735,-1},{-32832, 0},
+{-32704,-1},{-32831, 0},{-32703,-1},{-32896, 0},{-32640,-1},{-32895, 0},{-32639,-1},{-33024, 0},
+{-32512,-1},{-33023, 0},{-32511,-1},{-33280, 0},{-32256,-1},{-33279, 0},{-32255,-1},{-33792, 0},
+{-31744,-1},{-33791, 0},{-31743,-1},{-34816, 0},{-30720,-1},{-34815, 0},{-30719,-1},{-36864, 0},
+{-28672,-1},{-36863, 0},{-28671,-1},{-40960, 0},{-24576,-1},{-40959, 0},{-24575,-1},{-49152, 0},
+{-16384,-1},{-49151, 0},{-16383,-1},{-65536, 0},{     0, 0},{-65535, 0},{     1, 0},{ 32766, 0},
+{ 32768,-1},{ 32767, 0},{ 32769,-1},{ 32765, 0},{ 32769,-1},{ 32766, 0},{ 32770,-1},{ 32763, 0},
+{ 32771,-1},{ 32764, 0},{ 32772,-1},{ 32759, 0},{ 32775,-1},{ 32760, 0},{ 32776,-1},{ 32751, 0},
+{ 32783,-1},{ 32752, 0},{ 32784,-1},{ 32735, 0},{ 32799,-1},{ 32736, 0},{ 32800,-1},{ 32703, 0},
+{ 32831,-1},{ 32704, 0},{ 32832,-1},{ 32639, 0},{ 32895,-1},{ 32640, 0},{ 32896,-1},{ 32511, 0},
+{ 33023,-1},{ 32512, 0},{ 33024,-1},{ 32255, 0},{ 33279,-1},{ 32256, 0},{ 33280,-1},{ 31743, 0},
+{ 33791,-1},{ 31744, 0},{ 33792,-1},{ 30719, 0},{ 34815,-1},{ 30720, 0},{ 34816,-1},{ 28671, 0},
+{ 36863,-1},{ 28672, 0},{ 36864,-1},{ 24575, 0},{ 40959,-1},{ 24576, 0},{ 40960,-1},{ 16383, 0},
+{ 49151,-1},{ 16384, 0},{ 49152,-1},{    -1,-1},{ 65535,-1},{     0, 0},{ 65536,-1},{-32770, 0},
+{-32768,-1},{-32769, 0},{-32767,-1},{-32771, 0},{-32767,-1},{-32770, 0},{-32766,-1},{-32773, 0},
+{-32765,-1},{-32772, 0},{-32764,-1},{-32777, 0},{-32761,-1},{-32776, 0},{-32760,-1},{-32785, 0},
+{-32753,-1},{-32784, 0},{-32752,-1},{-32801, 0},{-32737,-1},{-32800, 0},{-32736,-1},{-32833, 0},
+{-32705,-1},{-32832, 0},{-32704,-1},{-32897, 0},{-32641,-1},{-32896, 0},{-32640,-1},{-33025, 0},
+{-32513,-1},{-33024, 0},{-32512,-1},{-33281, 0},{-32257,-1},{-33280, 0},{-32256,-1},{-33793, 0},
+{-31745,-1},{-33792, 0},{-31744,-1},{-34817, 0},{-30721,-1},{-34816, 0},{-30720,-1},{-36865, 0},
+{-28673,-1},{-36864, 0},{-28672,-1},{-40961, 0},{-24577,-1},{-40960, 0},{-24576,-1},{-49153, 0},
+{-16385,-1},{-49152, 0},{-16384,-1},{-65537, 0},{    -1,-1},{-65536, 0},{     0, 0},};
+int main ()
+{
+  mp_limb_t r1, r0;
+  int err = 0;
+  size_t ind = 0;
+  for (size_t i = 0; i < 4096; i++)
+    {
+      int ii = i / 64, jj = i % 64;
+      funcs[i](&r1, &r0);
+      if (r0 != (mp_limb_signed_t) ref[ind][0] || r1 != (mp_limb_signed_t) ref[ind][1]) {
+         printf ("error for f%zu(%d,%d): want (%d,%d) got (%d,%d)\n", i, (int) ops[ii], (int) ops[jj], ref[ind][1], ref[ind][0], (int) r1, (int) r0);
+         err++;
+       }
+      ind++;
+    }
+  return err != 0;
+}
diff --git a/tests/devel/try.c b/tests/devel/try.c
new file mode 100644
index 0000000..f8f4a1c
--- /dev/null
+++ b/tests/devel/try.c
@@ -0,0 +1,3658 @@
+/* Run some tests on various mpn routines.
+
+   THIS IS A TEST PROGRAM USED ONLY FOR DEVELOPMENT.  IT'S ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE VERSIONS OF GMP.
+
+Copyright 2000-2006, 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: try [options] <function>...
+
+   For example, "./try mpn_add_n" to run tests of that function.
+
+   Combinations of alignments and overlaps are tested, with redzones above
+   or below the destinations, and with the sources write-protected.
+
+   The number of tests performed becomes ridiculously large with all the
+   combinations, and for that reason this can't be a part of a "make check",
+   it's meant only for development.  The code isn't very pretty either.
+
+   During development it can help to disable the redzones, since seeing the
+   rest of the destination written can show where the wrong part is, or if
+   the dst pointers are off by 1 or whatever.  The magic DEADVAL initial
+   fill (see below) will show locations never written.
+
+   The -s option can be used to test only certain size operands, which is
+   useful if some new code doesn't yet support say sizes less than the
+   unrolling, or whatever.
+
+   When a problem occurs it'll of course be necessary to run the program
+   under gdb to find out quite where, how and why it's going wrong.  Disable
+   the spinner with the -W option when doing this, or single stepping won't
+   work.  Using the "-1" option to run with simple data can be useful.
+
+   New functions to test can be added in try_array[].  If a new TYPE is
+   required then add it to the existing constants, set up its parameters in
+   param_init(), and add it to the call() function.  Extra parameter fields
+   can be added if necessary, or further interpretations given to existing
+   fields.
+
+
+   Portability:
+
+   This program is not designed for use on Cray vector systems under Unicos,
+   it will fail to compile due to missing _SC_PAGE_SIZE.  Those systems
+   don't really have pages or mprotect.  We could arrange to run the tests
+   without the redzones, but we haven't bothered currently.
+
+
+   Enhancements:
+
+   umul_ppmm support is not very good, lots of source data is generated
+   whereas only two limbs are needed.
+
+   Make a little scheme for interpreting the "SIZE" selections uniformly.
+
+   Make tr->size==SIZE_2 work, for the benefit of find_a which wants just 2
+   source limbs.  Possibly increase the default repetitions in that case.
+
+   Automatically detect gdb and disable the spinner (use -W for now).
+
+   Make a way to re-run a failing case in the debugger.  Have an option to
+   snapshot each test case before it's run so the data is available if a
+   segv occurs.  (This should be more reliable than the current print_all()
+   in the signal handler.)
+
+   When alignment means a dst isn't hard against the redzone, check the
+   space in between remains unchanged.
+
+   When a source overlaps a destination, don't run both s[i].high 0 and 1,
+   as s[i].high has no effect.  Maybe encode s[i].high into overlap->s[i].
+
+   When partial overlaps aren't done, don't loop over source alignments
+   during overlaps.
+
+   Try to make the looping code a bit less horrible.  Right now it's pretty
+   hard to see what iterations are actually done.
+
+   Perhaps specific setups and loops for each style of function under test
+   would be clearer than a parameterized general loop.  There's lots of
+   stuff common to all functions, but the exceptions get messy.
+
+   When there's no overlap, run with both src>dst and src<dst.  A subtle
+   calling-conventions violation occurred in a P6 copy which depended on the
+   relative location of src and dst.
+
+   multiplier_N is more or less a third source region for the addmul_N
+   routines, and could be done with the redzoned region scheme.
+
+*/
+
+
+/* always do assertion checking */
+#define WANT_ASSERT 1
+
+#include "config.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#if ! HAVE_DECL_SYS_NERR
+extern int sys_nerr;
+#endif
+
+#if ! HAVE_DECL_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+
+#if ! HAVE_STRERROR
+char *
+strerror (int n)
+{
+  if (n < 0 || n >= sys_nerr)
+    return "errno out of range";
+  else
+    return sys_errlist[n];
+}
+#endif
+
+/* Rumour has it some systems lack a define of PROT_NONE. */
+#ifndef PROT_NONE
+#define PROT_NONE   0
+#endif
+
+/* Dummy defines for when mprotect doesn't exist. */
+#ifndef PROT_READ
+#define PROT_READ   0
+#endif
+#ifndef PROT_WRITE
+#define PROT_WRITE  0
+#endif
+
+/* _SC_PAGESIZE is standard, but hpux 9 and possibly other systems have
+   _SC_PAGE_SIZE instead. */
+#if defined (_SC_PAGE_SIZE) && ! defined (_SC_PAGESIZE)
+#define _SC_PAGESIZE  _SC_PAGE_SIZE
+#endif
+
+
+#ifdef EXTRA_PROTOS
+EXTRA_PROTOS
+#endif
+#ifdef EXTRA_PROTOS2
+EXTRA_PROTOS2
+#endif
+
+
+#define DEFAULT_REPETITIONS  10
+
+int  option_repetitions = DEFAULT_REPETITIONS;
+int  option_spinner = 1;
+int  option_redzones = 1;
+int  option_firstsize = 0;
+int  option_lastsize = 500;
+int  option_firstsize2 = 0;
+
+#define ALIGNMENTS          4
+#define OVERLAPS            4
+#define CARRY_RANDOMS       5
+#define MULTIPLIER_RANDOMS  5
+#define DIVISOR_RANDOMS     5
+#define FRACTION_COUNT      4
+
+int  option_print = 0;
+
+#define DATA_TRAND  0
+#define DATA_ZEROS  1
+#define DATA_SEQ    2
+#define DATA_FFS    3
+#define DATA_2FD    4
+int  option_data = DATA_TRAND;
+
+
+mp_size_t  pagesize;
+#define PAGESIZE_LIMBS  (pagesize / GMP_LIMB_BYTES)
+
+/* must be a multiple of the page size */
+#define REDZONE_BYTES   (pagesize * 16)
+#define REDZONE_LIMBS   (REDZONE_BYTES / GMP_LIMB_BYTES)
+
+
+#define MAX3(x,y,z)   (MAX (x, MAX (y, z)))
+
+#if GMP_LIMB_BITS == 32
+#define DEADVAL  CNST_LIMB(0xDEADBEEF)
+#else
+#define DEADVAL  CNST_LIMB(0xDEADBEEFBADDCAFE)
+#endif
+
+
+struct region_t {
+  mp_ptr     ptr;
+  mp_size_t  size;
+};
+
+
+#define TRAP_NOWHERE 0
+#define TRAP_REF     1
+#define TRAP_FUN     2
+#define TRAP_SETUPS  3
+int trap_location = TRAP_NOWHERE;
+
+
+#define NUM_SOURCES  5
+#define NUM_DESTS    2
+
+struct source_t {
+  struct region_t  region;
+  int        high;
+  mp_size_t  align;
+  mp_ptr     p;
+};
+
+struct source_t  s[NUM_SOURCES];
+
+struct dest_t {
+  int        high;
+  mp_size_t  align;
+  mp_size_t  size;
+};
+
+struct dest_t  d[NUM_DESTS];
+
+struct source_each_t {
+  mp_ptr     p;
+};
+
+struct dest_each_t {
+  struct region_t  region;
+  mp_ptr     p;
+};
+
+mp_size_t       size;
+mp_size_t       size2;
+unsigned long   shift;
+mp_limb_t       carry;
+mp_limb_t       divisor;
+mp_limb_t       multiplier;
+mp_limb_t       multiplier_N[8];
+
+struct each_t {
+  const char  *name;
+  struct dest_each_t    d[NUM_DESTS];
+  struct source_each_t  s[NUM_SOURCES];
+  mp_limb_t  retval;
+};
+
+struct each_t  ref = { "Ref" };
+struct each_t  fun = { "Fun" };
+
+#define SRC_SIZE(n)  ((n) == 1 && tr->size2 ? size2 : size)
+
+void validate_fail (void);
+
+
+#if HAVE_TRY_NEW_C
+#include "try-new.c"
+#endif
+
+
+typedef mp_limb_t (*tryfun_t) (ANYARGS);
+
+struct try_t {
+  char  retval;
+
+  char  src[NUM_SOURCES];
+  char  dst[NUM_DESTS];
+
+#define SIZE_YES          1
+#define SIZE_ALLOW_ZERO   2
+#define SIZE_1            3  /* 1 limb  */
+#define SIZE_2            4  /* 2 limbs */
+#define SIZE_3            5  /* 3 limbs */
+#define SIZE_4            6  /* 4 limbs */
+#define SIZE_6            7  /* 6 limbs */
+#define SIZE_FRACTION     8  /* size2 is fraction for divrem etc */
+#define SIZE_SIZE2        9
+#define SIZE_PLUS_1      10
+#define SIZE_SUM         11
+#define SIZE_DIFF        12
+#define SIZE_DIFF_PLUS_1 13
+#define SIZE_DIFF_PLUS_3 14
+#define SIZE_RETVAL      15
+#define SIZE_CEIL_HALF   16
+#define SIZE_GET_STR     17
+#define SIZE_PLUS_MSIZE_SUB_1 18  /* size+msize-1 */
+#define SIZE_ODD         19
+  char  size;
+  char  size2;
+  char  dst_size[NUM_DESTS];
+
+  /* multiplier_N size in limbs */
+  mp_size_t  msize;
+
+  char  dst_bytes[NUM_DESTS];
+
+  char  dst0_from_src1;
+
+#define CARRY_BIT     1  /* single bit 0 or 1 */
+#define CARRY_3       2  /* 0, 1, 2 */
+#define CARRY_4       3  /* 0 to 3 */
+#define CARRY_LIMB    4  /* any limb value */
+#define CARRY_DIVISOR 5  /* carry<divisor */
+  char  carry;
+
+  /* a fudge to tell the output when to print negatives */
+  char  carry_sign;
+
+  char  multiplier;
+  char  shift;
+
+#define DIVISOR_LIMB  1
+#define DIVISOR_NORM  2
+#define DIVISOR_ODD   3
+  char  divisor;
+
+#define DATA_NON_ZERO         1
+#define DATA_GCD              2
+#define DATA_SRC0_ODD         3
+#define DATA_SRC0_HIGHBIT     4
+#define DATA_SRC1_ODD         5
+#define DATA_SRC1_ODD_PRIME   6
+#define DATA_SRC1_HIGHBIT     7
+#define DATA_MULTIPLE_DIVISOR 8
+#define DATA_UDIV_QRNND       9
+#define DATA_DIV_QR_1        10
+  char  data;
+
+/* Default is allow full overlap. */
+#define OVERLAP_NONE         1
+#define OVERLAP_LOW_TO_HIGH  2
+#define OVERLAP_HIGH_TO_LOW  3
+#define OVERLAP_NOT_SRCS     4
+#define OVERLAP_NOT_SRC2     8
+#define OVERLAP_NOT_DST2     16
+  char  overlap;
+
+  tryfun_t    reference;
+  const char  *reference_name;
+
+  void        (*validate) (void);
+  const char  *validate_name;
+};
+
+struct try_t  *tr;
+
+
+void
+validate_mod_34lsub1 (void)
+{
+#define CNST_34LSUB1   ((CNST_LIMB(1) << (3 * (GMP_NUMB_BITS / 4))) - 1)
+
+  mp_srcptr  ptr = s[0].p;
+  int        error = 0;
+  mp_limb_t  got, got_mod, want, want_mod;
+
+  ASSERT (size >= 1);
+
+  got = fun.retval;
+  got_mod = got % CNST_34LSUB1;
+
+  want = refmpn_mod_34lsub1 (ptr, size);
+  want_mod = want % CNST_34LSUB1;
+
+  if (got_mod != want_mod)
+    {
+      gmp_printf ("got   0x%MX reduced from 0x%MX\n", got_mod, got);
+      gmp_printf ("want  0x%MX reduced from 0x%MX\n", want_mod, want);
+      error = 1;
+    }
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_divexact_1 (void)
+{
+  mp_srcptr  src = s[0].p;
+  mp_srcptr  dst = fun.d[0].p;
+  int  error = 0;
+
+  ASSERT (size >= 1);
+
+  {
+    mp_ptr     tp = refmpn_malloc_limbs (size);
+    mp_limb_t  rem;
+
+    rem = refmpn_divrem_1 (tp, 0, src, size, divisor);
+    if (rem != 0)
+      {
+	gmp_printf ("Remainder a%%d == 0x%MX, mpn_divexact_1 undefined\n", rem);
+	error = 1;
+      }
+    if (! refmpn_equal_anynail (tp, dst, size))
+      {
+	printf ("Quotient a/d wrong\n");
+	mpn_trace ("fun ", dst, size);
+	mpn_trace ("want", tp, size);
+	error = 1;
+      }
+    free (tp);
+  }
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_bdiv_q_1
+ (void)
+{
+  mp_srcptr  src = s[0].p;
+  mp_srcptr  dst = fun.d[0].p;
+  int  error = 0;
+
+  ASSERT (size >= 1);
+
+  {
+    mp_ptr     tp = refmpn_malloc_limbs (size + 1);
+
+    refmpn_mul_1 (tp, dst, size, divisor);
+    /* Set ignored low bits */
+    tp[0] |= (src[0] & LOW_ZEROS_MASK (divisor));
+    if (! refmpn_equal_anynail (tp, src, size))
+      {
+	printf ("Bdiv wrong: res * divisor != src (mod B^size)\n");
+	mpn_trace ("res ", dst, size);
+	mpn_trace ("src ", src, size);
+	error = 1;
+      }
+    free (tp);
+  }
+
+  if (error)
+    validate_fail ();
+}
+
+
+void
+validate_modexact_1c_odd (void)
+{
+  mp_srcptr  ptr = s[0].p;
+  mp_limb_t  r = fun.retval;
+  int  error = 0;
+
+  ASSERT (size >= 1);
+  ASSERT (divisor & 1);
+
+  if ((r & GMP_NAIL_MASK) != 0)
+    printf ("r has non-zero nail\n");
+
+  if (carry < divisor)
+    {
+      if (! (r < divisor))
+	{
+	  printf ("Don't have r < divisor\n");
+	  error = 1;
+	}
+    }
+  else /* carry >= divisor */
+    {
+      if (! (r <= divisor))
+	{
+	  printf ("Don't have r <= divisor\n");
+	  error = 1;
+	}
+    }
+
+  {
+    mp_limb_t  c = carry % divisor;
+    mp_ptr     tp = refmpn_malloc_limbs (size+1);
+    mp_size_t  k;
+
+    for (k = size-1; k <= size; k++)
+      {
+	/* set {tp,size+1} to r*b^k + a - c */
+	refmpn_copyi (tp, ptr, size);
+	tp[size] = 0;
+	ASSERT_NOCARRY (refmpn_add_1 (tp+k, tp+k, size+1-k, r));
+	if (refmpn_sub_1 (tp, tp, size+1, c))
+	  ASSERT_CARRY (mpn_add_1 (tp, tp, size+1, divisor));
+
+	if (refmpn_mod_1 (tp, size+1, divisor) == 0)
+	  goto good_remainder;
+      }
+    printf ("Remainder matches neither r*b^(size-1) nor r*b^size\n");
+    error = 1;
+
+  good_remainder:
+    free (tp);
+  }
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_modexact_1_odd (void)
+{
+  carry = 0;
+  validate_modexact_1c_odd ();
+}
+
+void
+validate_div_qr_1_pi1 (void)
+{
+  mp_srcptr up = ref.s[0].p;
+  mp_size_t un = size;
+  mp_size_t uh = ref.s[1].p[0];
+  mp_srcptr qp = fun.d[0].p;
+  mp_limb_t r = fun.retval;
+  mp_limb_t cy;
+  int cmp;
+  mp_ptr tp;
+  if (r >= divisor)
+    {
+      gmp_printf ("Bad remainder %Md, d = %Md\n", r, divisor);
+      validate_fail ();
+    }
+  tp = refmpn_malloc_limbs (un);
+  cy = refmpn_mul_1 (tp, qp, un, divisor);
+  cy += refmpn_add_1 (tp, tp, un, r);
+  if (cy != uh || refmpn_cmp (tp, up, un) != 0)
+    {
+      gmp_printf ("Incorrect result, size %ld.\n"
+		  "d = %Mx, u = %Mx, %Nx\n"
+		  "got: r = %Mx, q = %Nx\n"
+		  "q d + r = %Mx, %Nx",
+		  (long) un,
+		  divisor, uh, up, un,
+		  r, qp, un,
+		  cy, tp, un);
+      validate_fail ();
+    }
+  free (tp);
+}
+
+
+void
+validate_sqrtrem (void)
+{
+  mp_srcptr  orig_ptr = s[0].p;
+  mp_size_t  orig_size = size;
+  mp_size_t  root_size = (size+1)/2;
+  mp_srcptr  root_ptr = fun.d[0].p;
+  mp_size_t  rem_size = fun.retval;
+  mp_srcptr  rem_ptr = fun.d[1].p;
+  mp_size_t  prod_size = 2*root_size;
+  mp_ptr     p;
+  int  error = 0;
+
+  if (rem_size < 0 || rem_size > size)
+    {
+      printf ("Bad remainder size retval %ld\n", (long) rem_size);
+      validate_fail ();
+    }
+
+  p = refmpn_malloc_limbs (prod_size);
+
+  p[root_size] = refmpn_lshift (p, root_ptr, root_size, 1);
+  if (refmpn_cmp_twosizes (p,root_size+1, rem_ptr,rem_size) < 0)
+    {
+      printf ("Remainder bigger than 2*root\n");
+      error = 1;
+    }
+
+  refmpn_sqr (p, root_ptr, root_size);
+  if (rem_size != 0)
+    refmpn_add (p, p, prod_size, rem_ptr, rem_size);
+  if (refmpn_cmp_twosizes (p,prod_size, orig_ptr,orig_size) != 0)
+    {
+      printf ("root^2+rem != original\n");
+      mpn_trace ("prod", p, prod_size);
+      error = 1;
+    }
+  free (p);
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_sqrt (void)
+{
+  mp_srcptr  orig_ptr = s[0].p;
+  mp_size_t  orig_size = size;
+  mp_size_t  root_size = (size+1)/2;
+  mp_srcptr  root_ptr = fun.d[0].p;
+  int        perf_pow = (fun.retval == 0);
+  mp_size_t  prod_size = 2*root_size;
+  mp_ptr     p;
+  int  error = 0;
+
+  p = refmpn_malloc_limbs (prod_size);
+
+  refmpn_sqr (p, root_ptr, root_size);
+  MPN_NORMALIZE (p, prod_size);
+  if (refmpn_cmp_twosizes (p,prod_size, orig_ptr,orig_size) != - !perf_pow)
+    {
+      printf ("root^2 bigger than original, or wrong return value.\n");
+      mpn_trace ("prod...", p, prod_size);
+      error = 1;
+    }
+
+  refmpn_sub (p, orig_ptr,orig_size, p,prod_size);
+  MPN_NORMALIZE (p, prod_size);
+  if (prod_size >= root_size &&
+      refmpn_sub (p, p,prod_size, root_ptr, root_size) == 0 &&
+      refmpn_cmp_twosizes (p, prod_size, root_ptr, root_size) > 0)
+    {
+      printf ("(root+1)^2 smaller than original.\n");
+      mpn_trace ("prod", p, prod_size);
+      error = 1;
+    }
+  free (p);
+
+  if (error)
+    validate_fail ();
+}
+
+
+/* These types are indexes into the param[] array and are arbitrary so long
+   as they're all distinct and within the size of param[].  Renumber
+   whenever necessary or desired.  */
+
+enum {
+  TYPE_ADD = 1, TYPE_ADD_N, TYPE_ADD_NC, TYPE_SUB, TYPE_SUB_N, TYPE_SUB_NC,
+
+  TYPE_ADD_ERR1_N, TYPE_ADD_ERR2_N, TYPE_ADD_ERR3_N,
+  TYPE_SUB_ERR1_N, TYPE_SUB_ERR2_N, TYPE_SUB_ERR3_N,
+
+  TYPE_MUL_1, TYPE_MUL_1C,
+
+  TYPE_MUL_2, TYPE_MUL_3, TYPE_MUL_4, TYPE_MUL_5, TYPE_MUL_6,
+
+  TYPE_ADDMUL_1, TYPE_ADDMUL_1C, TYPE_SUBMUL_1, TYPE_SUBMUL_1C,
+
+  TYPE_ADDMUL_2, TYPE_ADDMUL_3, TYPE_ADDMUL_4, TYPE_ADDMUL_5, TYPE_ADDMUL_6,
+  TYPE_ADDMUL_7, TYPE_ADDMUL_8,
+
+  TYPE_ADDSUB_N, TYPE_ADDSUB_NC,
+
+  TYPE_RSHIFT, TYPE_LSHIFT, TYPE_LSHIFTC,
+
+  TYPE_COPY, TYPE_COPYI, TYPE_COPYD, TYPE_COM,
+
+  TYPE_ADDLSH1_N, TYPE_ADDLSH2_N, TYPE_ADDLSH_N,
+  TYPE_ADDLSH1_N_IP1, TYPE_ADDLSH2_N_IP1, TYPE_ADDLSH_N_IP1,
+  TYPE_ADDLSH1_N_IP2, TYPE_ADDLSH2_N_IP2, TYPE_ADDLSH_N_IP2,
+  TYPE_SUBLSH1_N, TYPE_SUBLSH2_N, TYPE_SUBLSH_N,
+  TYPE_SUBLSH1_N_IP1, TYPE_SUBLSH2_N_IP1, TYPE_SUBLSH_N_IP1,
+  TYPE_RSBLSH1_N, TYPE_RSBLSH2_N, TYPE_RSBLSH_N,
+  TYPE_RSH1ADD_N, TYPE_RSH1SUB_N,
+
+  TYPE_ADDLSH1_NC, TYPE_ADDLSH2_NC, TYPE_ADDLSH_NC,
+  TYPE_SUBLSH1_NC, TYPE_SUBLSH2_NC, TYPE_SUBLSH_NC,
+  TYPE_RSBLSH1_NC, TYPE_RSBLSH2_NC, TYPE_RSBLSH_NC,
+
+  TYPE_ADDCND_N, TYPE_SUBCND_N,
+
+  TYPE_MOD_1, TYPE_MOD_1C, TYPE_DIVMOD_1, TYPE_DIVMOD_1C, TYPE_DIVREM_1,
+  TYPE_DIVREM_1C, TYPE_PREINV_DIVREM_1, TYPE_DIVREM_2, TYPE_PREINV_MOD_1,
+  TYPE_DIV_QR_1N_PI1,
+  TYPE_MOD_34LSUB1, TYPE_UDIV_QRNND, TYPE_UDIV_QRNND_R,
+
+  TYPE_DIVEXACT_1, TYPE_BDIV_Q_1, TYPE_DIVEXACT_BY3, TYPE_DIVEXACT_BY3C,
+  TYPE_MODEXACT_1_ODD, TYPE_MODEXACT_1C_ODD,
+
+  TYPE_INVERT, TYPE_BINVERT,
+
+  TYPE_GCD, TYPE_GCD_1, TYPE_GCD_FINDA, TYPE_MPZ_JACOBI, TYPE_MPZ_KRONECKER,
+  TYPE_MPZ_KRONECKER_UI, TYPE_MPZ_KRONECKER_SI, TYPE_MPZ_UI_KRONECKER,
+  TYPE_MPZ_SI_KRONECKER, TYPE_MPZ_LEGENDRE,
+
+  TYPE_AND_N, TYPE_NAND_N, TYPE_ANDN_N, TYPE_IOR_N, TYPE_IORN_N, TYPE_NIOR_N,
+  TYPE_XOR_N, TYPE_XNOR_N,
+
+  TYPE_MUL_MN, TYPE_MUL_N, TYPE_SQR, TYPE_UMUL_PPMM, TYPE_UMUL_PPMM_R,
+  TYPE_MULLO_N, TYPE_SQRLO, TYPE_MULMID_MN, TYPE_MULMID_N,
+
+  TYPE_SBPI1_DIV_QR, TYPE_TDIV_QR,
+
+  TYPE_SQRTREM, TYPE_SQRT, TYPE_ZERO, TYPE_GET_STR, TYPE_POPCOUNT, TYPE_HAMDIST,
+
+  TYPE_EXTRA
+};
+
+struct try_t  param[TYPE_EXTRA];
+
+
+void
+param_init (void)
+{
+  struct try_t  *p;
+
+#define COPY(index)  memcpy (p, &param[index], sizeof (*p))
+
+#define REFERENCE(fun)                  \
+  p->reference = (tryfun_t) fun;        \
+  p->reference_name = #fun
+#define VALIDATE(fun)           \
+  p->validate = fun;            \
+  p->validate_name = #fun
+
+
+  p = &param[TYPE_ADD_N];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  REFERENCE (refmpn_add_n);
+
+  p = &param[TYPE_ADD_NC];
+  COPY (TYPE_ADD_N);
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpn_add_nc);
+
+  p = &param[TYPE_SUB_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_sub_n);
+
+  p = &param[TYPE_SUB_NC];
+  COPY (TYPE_ADD_NC);
+  REFERENCE (refmpn_sub_nc);
+
+  p = &param[TYPE_ADD];
+  COPY (TYPE_ADD_N);
+  p->size = SIZE_ALLOW_ZERO;
+  p->size2 = 1;
+  REFERENCE (refmpn_add);
+
+  p = &param[TYPE_SUB];
+  COPY (TYPE_ADD);
+  REFERENCE (refmpn_sub);
+
+
+  p = &param[TYPE_ADD_ERR1_N];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->src[2] = 1;
+  p->dst_size[1] = SIZE_2;
+  p->carry = CARRY_BIT;
+  p->overlap = OVERLAP_NOT_DST2;
+  REFERENCE (refmpn_add_err1_n);
+
+  p = &param[TYPE_SUB_ERR1_N];
+  COPY (TYPE_ADD_ERR1_N);
+  REFERENCE (refmpn_sub_err1_n);
+
+  p = &param[TYPE_ADD_ERR2_N];
+  COPY (TYPE_ADD_ERR1_N);
+  p->src[3] = 1;
+  p->dst_size[1] = SIZE_4;
+  REFERENCE (refmpn_add_err2_n);
+
+  p = &param[TYPE_SUB_ERR2_N];
+  COPY (TYPE_ADD_ERR2_N);
+  REFERENCE (refmpn_sub_err2_n);
+
+  p = &param[TYPE_ADD_ERR3_N];
+  COPY (TYPE_ADD_ERR2_N);
+  p->src[4] = 1;
+  p->dst_size[1] = SIZE_6;
+  REFERENCE (refmpn_add_err3_n);
+
+  p = &param[TYPE_SUB_ERR3_N];
+  COPY (TYPE_ADD_ERR3_N);
+  REFERENCE (refmpn_sub_err3_n);
+
+  p = &param[TYPE_ADDCND_N];
+  COPY (TYPE_ADD_N);
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpn_cnd_add_n);
+
+  p = &param[TYPE_SUBCND_N];
+  COPY (TYPE_ADD_N);
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpn_cnd_sub_n);
+
+
+  p = &param[TYPE_MUL_1];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->multiplier = 1;
+  p->overlap = OVERLAP_LOW_TO_HIGH;
+  REFERENCE (refmpn_mul_1);
+
+  p = &param[TYPE_MUL_1C];
+  COPY (TYPE_MUL_1);
+  p->carry = CARRY_LIMB;
+  REFERENCE (refmpn_mul_1c);
+
+
+  p = &param[TYPE_MUL_2];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_PLUS_MSIZE_SUB_1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->msize = 2;
+  p->overlap = OVERLAP_NOT_SRC2;
+  REFERENCE (refmpn_mul_2);
+
+  p = &param[TYPE_MUL_3];
+  COPY (TYPE_MUL_2);
+  p->msize = 3;
+  REFERENCE (refmpn_mul_3);
+
+  p = &param[TYPE_MUL_4];
+  COPY (TYPE_MUL_2);
+  p->msize = 4;
+  REFERENCE (refmpn_mul_4);
+
+  p = &param[TYPE_MUL_5];
+  COPY (TYPE_MUL_2);
+  p->msize = 5;
+  REFERENCE (refmpn_mul_5);
+
+  p = &param[TYPE_MUL_6];
+  COPY (TYPE_MUL_2);
+  p->msize = 6;
+  REFERENCE (refmpn_mul_6);
+
+
+  p = &param[TYPE_ADDMUL_1];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->multiplier = 1;
+  p->dst0_from_src1 = 1;
+  REFERENCE (refmpn_addmul_1);
+
+  p = &param[TYPE_ADDMUL_1C];
+  COPY (TYPE_ADDMUL_1);
+  p->carry = CARRY_LIMB;
+  REFERENCE (refmpn_addmul_1c);
+
+  p = &param[TYPE_SUBMUL_1];
+  COPY (TYPE_ADDMUL_1);
+  REFERENCE (refmpn_submul_1);
+
+  p = &param[TYPE_SUBMUL_1C];
+  COPY (TYPE_ADDMUL_1C);
+  REFERENCE (refmpn_submul_1c);
+
+
+  p = &param[TYPE_ADDMUL_2];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_PLUS_MSIZE_SUB_1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->msize = 2;
+  p->dst0_from_src1 = 1;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_addmul_2);
+
+  p = &param[TYPE_ADDMUL_3];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 3;
+  REFERENCE (refmpn_addmul_3);
+
+  p = &param[TYPE_ADDMUL_4];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 4;
+  REFERENCE (refmpn_addmul_4);
+
+  p = &param[TYPE_ADDMUL_5];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 5;
+  REFERENCE (refmpn_addmul_5);
+
+  p = &param[TYPE_ADDMUL_6];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 6;
+  REFERENCE (refmpn_addmul_6);
+
+  p = &param[TYPE_ADDMUL_7];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 7;
+  REFERENCE (refmpn_addmul_7);
+
+  p = &param[TYPE_ADDMUL_8];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 8;
+  REFERENCE (refmpn_addmul_8);
+
+
+  p = &param[TYPE_AND_N];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  REFERENCE (refmpn_and_n);
+
+  p = &param[TYPE_ANDN_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_andn_n);
+
+  p = &param[TYPE_NAND_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_nand_n);
+
+  p = &param[TYPE_IOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_ior_n);
+
+  p = &param[TYPE_IORN_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_iorn_n);
+
+  p = &param[TYPE_NIOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_nior_n);
+
+  p = &param[TYPE_XOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_xor_n);
+
+  p = &param[TYPE_XNOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_xnor_n);
+
+
+  p = &param[TYPE_ADDSUB_N];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  REFERENCE (refmpn_add_n_sub_n);
+
+  p = &param[TYPE_ADDSUB_NC];
+  COPY (TYPE_ADDSUB_N);
+  p->carry = CARRY_4;
+  REFERENCE (refmpn_add_n_sub_nc);
+
+
+  p = &param[TYPE_COPY];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->overlap = OVERLAP_NONE;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_copy);
+
+  p = &param[TYPE_COPYI];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->overlap = OVERLAP_LOW_TO_HIGH;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_copyi);
+
+  p = &param[TYPE_COPYD];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->overlap = OVERLAP_HIGH_TO_LOW;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_copyd);
+
+  p = &param[TYPE_COM];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  REFERENCE (refmpn_com);
+
+
+  p = &param[TYPE_ADDLSH1_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_addlsh1_n);
+
+  p = &param[TYPE_ADDLSH2_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_addlsh2_n);
+
+  p = &param[TYPE_ADDLSH_N];
+  COPY (TYPE_ADD_N);
+  p->shift = 1;
+  REFERENCE (refmpn_addlsh_n);
+
+  p = &param[TYPE_ADDLSH1_N_IP1];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->dst0_from_src1 = 1;
+  REFERENCE (refmpn_addlsh1_n_ip1);
+
+  p = &param[TYPE_ADDLSH2_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_addlsh2_n_ip1);
+
+  p = &param[TYPE_ADDLSH_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  p->shift = 1;
+  REFERENCE (refmpn_addlsh_n_ip1);
+
+  p = &param[TYPE_ADDLSH1_N_IP2];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_addlsh1_n_ip2);
+
+  p = &param[TYPE_ADDLSH2_N_IP2];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_addlsh2_n_ip2);
+
+  p = &param[TYPE_ADDLSH_N_IP2];
+  COPY (TYPE_ADDLSH_N_IP1);
+  REFERENCE (refmpn_addlsh_n_ip2);
+
+  p = &param[TYPE_SUBLSH1_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_sublsh1_n);
+
+  p = &param[TYPE_SUBLSH2_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_sublsh2_n);
+
+  p = &param[TYPE_SUBLSH_N];
+  COPY (TYPE_ADDLSH_N);
+  REFERENCE (refmpn_sublsh_n);
+
+  p = &param[TYPE_SUBLSH1_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_sublsh1_n_ip1);
+
+  p = &param[TYPE_SUBLSH2_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_sublsh2_n_ip1);
+
+  p = &param[TYPE_SUBLSH_N_IP1];
+  COPY (TYPE_ADDLSH_N_IP1);
+  REFERENCE (refmpn_sublsh_n_ip1);
+
+  p = &param[TYPE_RSBLSH1_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsblsh1_n);
+
+  p = &param[TYPE_RSBLSH2_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsblsh2_n);
+
+  p = &param[TYPE_RSBLSH_N];
+  COPY (TYPE_ADDLSH_N);
+  REFERENCE (refmpn_rsblsh_n);
+
+  p = &param[TYPE_RSH1ADD_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsh1add_n);
+
+  p = &param[TYPE_RSH1SUB_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsh1sub_n);
+
+
+  p = &param[TYPE_ADDLSH1_NC];
+  COPY (TYPE_ADDLSH1_N);
+  p->carry = CARRY_3;
+  REFERENCE (refmpn_addlsh1_nc);
+
+  p = &param[TYPE_ADDLSH2_NC];
+  COPY (TYPE_ADDLSH2_N);
+  p->carry = CARRY_4; /* FIXME */
+  REFERENCE (refmpn_addlsh2_nc);
+
+  p = &param[TYPE_ADDLSH_NC];
+  COPY (TYPE_ADDLSH_N);
+  p->carry = CARRY_BIT; /* FIXME */
+  REFERENCE (refmpn_addlsh_nc);
+
+  p = &param[TYPE_SUBLSH1_NC];
+  COPY (TYPE_ADDLSH1_NC);
+  REFERENCE (refmpn_sublsh1_nc);
+
+  p = &param[TYPE_SUBLSH2_NC];
+  COPY (TYPE_ADDLSH2_NC);
+  REFERENCE (refmpn_sublsh2_nc);
+
+  p = &param[TYPE_SUBLSH_NC];
+  COPY (TYPE_ADDLSH_NC);
+  REFERENCE (refmpn_sublsh_nc);
+
+  p = &param[TYPE_RSBLSH1_NC];
+  COPY (TYPE_RSBLSH1_N);
+  p->carry = CARRY_BIT; /* FIXME */
+  REFERENCE (refmpn_rsblsh1_nc);
+
+  p = &param[TYPE_RSBLSH2_NC];
+  COPY (TYPE_RSBLSH2_N);
+  p->carry = CARRY_4; /* FIXME */
+  REFERENCE (refmpn_rsblsh2_nc);
+
+  p = &param[TYPE_RSBLSH_NC];
+  COPY (TYPE_RSBLSH_N);
+  p->carry = CARRY_BIT; /* FIXME */
+  REFERENCE (refmpn_rsblsh_nc);
+
+
+  p = &param[TYPE_MOD_1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->divisor = DIVISOR_LIMB;
+  REFERENCE (refmpn_mod_1);
+
+  p = &param[TYPE_MOD_1C];
+  COPY (TYPE_MOD_1);
+  p->carry = CARRY_DIVISOR;
+  REFERENCE (refmpn_mod_1c);
+
+  p = &param[TYPE_DIVMOD_1];
+  COPY (TYPE_MOD_1);
+  p->dst[0] = 1;
+  REFERENCE (refmpn_divmod_1);
+
+  p = &param[TYPE_DIVMOD_1C];
+  COPY (TYPE_DIVMOD_1);
+  p->carry = CARRY_DIVISOR;
+  REFERENCE (refmpn_divmod_1c);
+
+  p = &param[TYPE_DIVREM_1];
+  COPY (TYPE_DIVMOD_1);
+  p->size2 = SIZE_FRACTION;
+  p->dst_size[0] = SIZE_SUM;
+  REFERENCE (refmpn_divrem_1);
+
+  p = &param[TYPE_DIVREM_1C];
+  COPY (TYPE_DIVREM_1);
+  p->carry = CARRY_DIVISOR;
+  REFERENCE (refmpn_divrem_1c);
+
+  p = &param[TYPE_PREINV_DIVREM_1];
+  COPY (TYPE_DIVREM_1);
+  p->size = SIZE_YES; /* ie. no size==0 */
+  REFERENCE (refmpn_preinv_divrem_1);
+
+  p = &param[TYPE_DIV_QR_1N_PI1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  /* SIZE_1 not supported. Always uses low limb only. */
+  p->size2 = 1;
+  p->dst[0] = 1;
+  p->divisor = DIVISOR_NORM;
+  p->data = DATA_DIV_QR_1;
+  VALIDATE (validate_div_qr_1_pi1);
+
+  p = &param[TYPE_PREINV_MOD_1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_NORM;
+  REFERENCE (refmpn_preinv_mod_1);
+
+  p = &param[TYPE_MOD_34LSUB1];
+  p->retval = 1;
+  p->src[0] = 1;
+  VALIDATE (validate_mod_34lsub1);
+
+  p = &param[TYPE_UDIV_QRNND];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_1;
+  p->divisor = UDIV_NEEDS_NORMALIZATION ? DIVISOR_NORM : DIVISOR_LIMB;
+  p->data = DATA_UDIV_QRNND;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_udiv_qrnnd);
+
+  p = &param[TYPE_UDIV_QRNND_R];
+  COPY (TYPE_UDIV_QRNND);
+  REFERENCE (refmpn_udiv_qrnnd_r);
+
+
+  p = &param[TYPE_DIVEXACT_1];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_LIMB;
+  p->data = DATA_MULTIPLE_DIVISOR;
+  VALIDATE (validate_divexact_1);
+  REFERENCE (refmpn_divmod_1);
+
+  p = &param[TYPE_BDIV_Q_1];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_LIMB;
+  VALIDATE (validate_bdiv_q_1);
+
+  p = &param[TYPE_DIVEXACT_BY3];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  REFERENCE (refmpn_divexact_by3);
+
+  p = &param[TYPE_DIVEXACT_BY3C];
+  COPY (TYPE_DIVEXACT_BY3);
+  p->carry = CARRY_3;
+  REFERENCE (refmpn_divexact_by3c);
+
+
+  p = &param[TYPE_MODEXACT_1_ODD];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_ODD;
+  VALIDATE (validate_modexact_1_odd);
+
+  p = &param[TYPE_MODEXACT_1C_ODD];
+  COPY (TYPE_MODEXACT_1_ODD);
+  p->carry = CARRY_LIMB;
+  VALIDATE (validate_modexact_1c_odd);
+
+
+  p = &param[TYPE_GCD_1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->data = DATA_NON_ZERO;
+  p->divisor = DIVISOR_LIMB;
+  REFERENCE (refmpn_gcd_1);
+
+  p = &param[TYPE_GCD];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->size2 = 1;
+  p->dst_size[0] = SIZE_RETVAL;
+  p->overlap = OVERLAP_NOT_SRCS;
+  p->data = DATA_GCD;
+  REFERENCE (refmpn_gcd);
+
+
+  p = &param[TYPE_MPZ_LEGENDRE];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->src[1] = 1;
+  p->data = DATA_SRC1_ODD_PRIME;
+  p->size2 = 1;
+  p->carry = CARRY_BIT;
+  p->carry_sign = 1;
+  REFERENCE (refmpz_legendre);
+
+  p = &param[TYPE_MPZ_JACOBI];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->src[1] = 1;
+  p->data = DATA_SRC1_ODD;
+  p->size2 = 1;
+  p->carry = CARRY_BIT;
+  p->carry_sign = 1;
+  REFERENCE (refmpz_jacobi);
+
+  p = &param[TYPE_MPZ_KRONECKER];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->src[1] = 1;
+  p->data = 0;
+  p->size2 = 1;
+  p->carry = CARRY_4;
+  p->carry_sign = 1;
+  REFERENCE (refmpz_kronecker);
+
+
+  p = &param[TYPE_MPZ_KRONECKER_UI];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->multiplier = 1;
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpz_kronecker_ui);
+
+  p = &param[TYPE_MPZ_KRONECKER_SI];
+  COPY (TYPE_MPZ_KRONECKER_UI);
+  REFERENCE (refmpz_kronecker_si);
+
+  p = &param[TYPE_MPZ_UI_KRONECKER];
+  COPY (TYPE_MPZ_KRONECKER_UI);
+  REFERENCE (refmpz_ui_kronecker);
+
+  p = &param[TYPE_MPZ_SI_KRONECKER];
+  COPY (TYPE_MPZ_KRONECKER_UI);
+  REFERENCE (refmpz_si_kronecker);
+
+
+  p = &param[TYPE_SQR];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->dst_size[0] = SIZE_SUM;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_sqr);
+
+  p = &param[TYPE_MUL_N];
+  COPY (TYPE_SQR);
+  p->src[1] = 1;
+  REFERENCE (refmpn_mul_n);
+
+  p = &param[TYPE_MULLO_N];
+  COPY (TYPE_MUL_N);
+  p->dst_size[0] = 0;
+  REFERENCE (refmpn_mullo_n);
+
+  p = &param[TYPE_SQRLO];
+  COPY (TYPE_SQR);
+  p->dst_size[0] = 0;
+  REFERENCE (refmpn_sqrlo);
+
+  p = &param[TYPE_MUL_MN];
+  COPY (TYPE_MUL_N);
+  p->size2 = 1;
+  REFERENCE (refmpn_mul_basecase);
+
+  p = &param[TYPE_MULMID_MN];
+  COPY (TYPE_MUL_MN);
+  p->dst_size[0] = SIZE_DIFF_PLUS_3;
+  REFERENCE (refmpn_mulmid_basecase);
+
+  p = &param[TYPE_MULMID_N];
+  COPY (TYPE_MUL_N);
+  p->size = SIZE_ODD;
+  p->size2 = SIZE_CEIL_HALF;
+  p->dst_size[0] = SIZE_DIFF_PLUS_3;
+  REFERENCE (refmpn_mulmid_n);
+
+  p = &param[TYPE_UMUL_PPMM];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_1;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_umul_ppmm);
+
+  p = &param[TYPE_UMUL_PPMM_R];
+  COPY (TYPE_UMUL_PPMM);
+  REFERENCE (refmpn_umul_ppmm_r);
+
+
+  p = &param[TYPE_RSHIFT];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->shift = 1;
+  p->overlap = OVERLAP_LOW_TO_HIGH;
+  REFERENCE (refmpn_rshift);
+
+  p = &param[TYPE_LSHIFT];
+  COPY (TYPE_RSHIFT);
+  p->overlap = OVERLAP_HIGH_TO_LOW;
+  REFERENCE (refmpn_lshift);
+
+  p = &param[TYPE_LSHIFTC];
+  COPY (TYPE_RSHIFT);
+  p->overlap = OVERLAP_HIGH_TO_LOW;
+  REFERENCE (refmpn_lshiftc);
+
+
+  p = &param[TYPE_POPCOUNT];
+  p->retval = 1;
+  p->src[0] = 1;
+  REFERENCE (refmpn_popcount);
+
+  p = &param[TYPE_HAMDIST];
+  COPY (TYPE_POPCOUNT);
+  p->src[1] = 1;
+  REFERENCE (refmpn_hamdist);
+
+
+  p = &param[TYPE_SBPI1_DIV_QR];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->data = DATA_SRC1_HIGHBIT;
+  p->size2 = 1;
+  p->dst_size[0] = SIZE_DIFF;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_sb_div_qr);
+
+  p = &param[TYPE_TDIV_QR];
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->size2 = 1;
+  p->dst_size[0] = SIZE_DIFF_PLUS_1;
+  p->dst_size[1] = SIZE_SIZE2;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_tdiv_qr);
+
+  p = &param[TYPE_SQRTREM];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->dst_size[0] = SIZE_CEIL_HALF;
+  p->dst_size[1] = SIZE_RETVAL;
+  p->overlap = OVERLAP_NONE;
+  VALIDATE (validate_sqrtrem);
+  REFERENCE (refmpn_sqrtrem);
+
+  p = &param[TYPE_SQRT];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 0;
+  p->src[0] = 1;
+  p->dst_size[0] = SIZE_CEIL_HALF;
+  p->overlap = OVERLAP_NONE;
+  VALIDATE (validate_sqrt);
+
+  p = &param[TYPE_ZERO];
+  p->dst[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_zero);
+
+  p = &param[TYPE_GET_STR];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->dst_size[0] = SIZE_GET_STR;
+  p->dst_bytes[0] = 1;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_get_str);
+
+  p = &param[TYPE_BINVERT];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->data = DATA_SRC0_ODD;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_binvert);
+
+  p = &param[TYPE_INVERT];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->data = DATA_SRC0_HIGHBIT;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_invert);
+
+#ifdef EXTRA_PARAM_INIT
+  EXTRA_PARAM_INIT
+#endif
+}
+
+
+/* The following are macros if there's no native versions, so wrap them in
+   functions that can be in try_array[]. */
+
+void
+MPN_COPY_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ MPN_COPY (rp, sp, size); }
+
+void
+MPN_COPY_INCR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ MPN_COPY_INCR (rp, sp, size); }
+
+void
+MPN_COPY_DECR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ MPN_COPY_DECR (rp, sp, size); }
+
+void
+__GMPN_COPY_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ __GMPN_COPY (rp, sp, size); }
+
+#ifdef __GMPN_COPY_INCR
+void
+__GMPN_COPY_INCR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ __GMPN_COPY_INCR (rp, sp, size); }
+#endif
+
+void
+mpn_com_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ mpn_com (rp, sp, size); }
+
+void
+mpn_and_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_and_n (rp, s1, s2, size); }
+
+void
+mpn_andn_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_andn_n (rp, s1, s2, size); }
+
+void
+mpn_nand_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_nand_n (rp, s1, s2, size); }
+
+void
+mpn_ior_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_ior_n (rp, s1, s2, size); }
+
+void
+mpn_iorn_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_iorn_n (rp, s1, s2, size); }
+
+void
+mpn_nior_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_nior_n (rp, s1, s2, size); }
+
+void
+mpn_xor_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_xor_n (rp, s1, s2, size); }
+
+void
+mpn_xnor_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_xnor_n (rp, s1, s2, size); }
+
+mp_limb_t
+udiv_qrnnd_fun (mp_limb_t *remptr, mp_limb_t n1, mp_limb_t n0, mp_limb_t d)
+{
+  mp_limb_t  q;
+  udiv_qrnnd (q, *remptr, n1, n0, d);
+  return q;
+}
+
+mp_limb_t
+mpn_divexact_by3_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_divexact_by3 (rp, sp, size);
+}
+
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+mp_limb_t
+mpn_addlsh1_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh1_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+mp_limb_t
+mpn_addlsh2_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh2_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip1
+mp_limb_t
+mpn_addlsh_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned int sh)
+{
+  return mpn_addlsh_n_ip1 (rp, sp, size, sh);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip2
+mp_limb_t
+mpn_addlsh1_n_ip2_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh1_n_ip2 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip2
+mp_limb_t
+mpn_addlsh2_n_ip2_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh2_n_ip2 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip2
+mp_limb_t
+mpn_addlsh_n_ip2_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned int sh)
+{
+  return mpn_addlsh_n_ip2 (rp, sp, size, sh);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n_ip1
+mp_limb_t
+mpn_sublsh1_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_sublsh1_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+mp_limb_t
+mpn_sublsh2_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_sublsh2_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n_ip1
+mp_limb_t
+mpn_sublsh_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned int sh)
+{
+  return mpn_sublsh_n_ip1 (rp, sp, size, sh);
+}
+#endif
+
+mp_limb_t
+mpn_modexact_1_odd_fun (mp_srcptr ptr, mp_size_t size, mp_limb_t divisor)
+{
+  return mpn_modexact_1_odd (ptr, size, divisor);
+}
+
+void
+mpn_toom22_mul_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2, mp_size_t size)
+{
+  mp_ptr  tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom22_mul_itch (size, size));
+  mpn_toom22_mul (dst, src1, size, src2, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom2_sqr_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom2_sqr_itch (size));
+  mpn_toom2_sqr (dst, src, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom33_mul_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2, mp_size_t size)
+{
+  mp_ptr  tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom33_mul_itch (size, size));
+  mpn_toom33_mul (dst, src1, size, src2, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom3_sqr_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom3_sqr_itch (size));
+  mpn_toom3_sqr (dst, src, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom44_mul_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2, mp_size_t size)
+{
+  mp_ptr  tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom44_mul_itch (size, size));
+  mpn_toom44_mul (dst, src1, size, src2, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom4_sqr_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom4_sqr_itch (size));
+  mpn_toom4_sqr (dst, src, size, tspace);
+  TMP_FREE;
+}
+
+void
+mpn_toom42_mulmid_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+		       mp_size_t size)
+{
+  mp_ptr  tspace;
+  mp_size_t n;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (size));
+  mpn_toom42_mulmid (dst, src1, src2, size, tspace);
+  TMP_FREE;
+}
+
+mp_limb_t
+umul_ppmm_fun (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2)
+{
+  mp_limb_t  high;
+  umul_ppmm (high, *lowptr, m1, m2);
+  return high;
+}
+
+void
+MPN_ZERO_fun (mp_ptr ptr, mp_size_t size)
+{ MPN_ZERO (ptr, size); }
+
+mp_size_t
+mpn_sqrt_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{ return mpn_sqrtrem (dst, NULL, src, size); }
+
+struct choice_t {
+  const char  *name;
+  tryfun_t    function;
+  int         type;
+  mp_size_t   minsize;
+};
+
+#define TRY(fun)        #fun, (tryfun_t) fun
+#define TRY_FUNFUN(fun) #fun, (tryfun_t) fun##_fun
+
+const struct choice_t choice_array[] = {
+  { TRY(mpn_add),       TYPE_ADD    },
+  { TRY(mpn_sub),       TYPE_SUB    },
+
+  { TRY(mpn_add_n),     TYPE_ADD_N  },
+  { TRY(mpn_sub_n),     TYPE_SUB_N  },
+
+#if HAVE_NATIVE_mpn_add_nc
+  { TRY(mpn_add_nc),    TYPE_ADD_NC },
+#endif
+#if HAVE_NATIVE_mpn_sub_nc
+  { TRY(mpn_sub_nc),    TYPE_SUB_NC },
+#endif
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  { TRY(mpn_add_n_sub_n),  TYPE_ADDSUB_N  },
+#endif
+#if HAVE_NATIVE_mpn_add_n_sub_nc
+  { TRY(mpn_add_n_sub_nc), TYPE_ADDSUB_NC },
+#endif
+
+  { TRY(mpn_add_err1_n),  TYPE_ADD_ERR1_N  },
+  { TRY(mpn_sub_err1_n),  TYPE_SUB_ERR1_N  },
+  { TRY(mpn_add_err2_n),  TYPE_ADD_ERR2_N  },
+  { TRY(mpn_sub_err2_n),  TYPE_SUB_ERR2_N  },
+  { TRY(mpn_add_err3_n),  TYPE_ADD_ERR3_N  },
+  { TRY(mpn_sub_err3_n),  TYPE_SUB_ERR3_N  },
+
+  { TRY(mpn_addmul_1),  TYPE_ADDMUL_1  },
+  { TRY(mpn_submul_1),  TYPE_SUBMUL_1  },
+#if HAVE_NATIVE_mpn_addmul_1c
+  { TRY(mpn_addmul_1c), TYPE_ADDMUL_1C },
+#endif
+#if HAVE_NATIVE_mpn_submul_1c
+  { TRY(mpn_submul_1c), TYPE_SUBMUL_1C },
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2
+  { TRY(mpn_addmul_2), TYPE_ADDMUL_2, 2 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_3
+  { TRY(mpn_addmul_3), TYPE_ADDMUL_3, 3 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_4
+  { TRY(mpn_addmul_4), TYPE_ADDMUL_4, 4 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_5
+  { TRY(mpn_addmul_5), TYPE_ADDMUL_5, 5 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_6
+  { TRY(mpn_addmul_6), TYPE_ADDMUL_6, 6 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_7
+  { TRY(mpn_addmul_7), TYPE_ADDMUL_7, 7 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_8
+  { TRY(mpn_addmul_8), TYPE_ADDMUL_8, 8 },
+#endif
+
+  { TRY_FUNFUN(mpn_com),  TYPE_COM },
+
+  { TRY_FUNFUN(MPN_COPY),      TYPE_COPY },
+  { TRY_FUNFUN(MPN_COPY_INCR), TYPE_COPYI },
+  { TRY_FUNFUN(MPN_COPY_DECR), TYPE_COPYD },
+
+  { TRY_FUNFUN(__GMPN_COPY),      TYPE_COPY },
+#ifdef __GMPN_COPY_INCR
+  { TRY_FUNFUN(__GMPN_COPY_INCR), TYPE_COPYI },
+#endif
+
+#if HAVE_NATIVE_mpn_copyi
+  { TRY(mpn_copyi), TYPE_COPYI },
+#endif
+#if HAVE_NATIVE_mpn_copyd
+  { TRY(mpn_copyd), TYPE_COPYD },
+#endif
+
+  { TRY(mpn_cnd_add_n), TYPE_ADDCND_N },
+  { TRY(mpn_cnd_sub_n), TYPE_SUBCND_N },
+#if HAVE_NATIVE_mpn_addlsh1_n == 1
+  { TRY(mpn_addlsh1_n), TYPE_ADDLSH1_N },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n == 1
+  { TRY(mpn_addlsh2_n), TYPE_ADDLSH2_N },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n
+  { TRY(mpn_addlsh_n), TYPE_ADDLSH_N },
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+  { TRY_FUNFUN(mpn_addlsh1_n_ip1), TYPE_ADDLSH1_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+  { TRY_FUNFUN(mpn_addlsh2_n_ip1), TYPE_ADDLSH2_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip1
+  { TRY_FUNFUN(mpn_addlsh_n_ip1), TYPE_ADDLSH_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip2
+  { TRY_FUNFUN(mpn_addlsh1_n_ip2), TYPE_ADDLSH1_N_IP2 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip2
+  { TRY_FUNFUN(mpn_addlsh2_n_ip2), TYPE_ADDLSH2_N_IP2 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip2
+  { TRY_FUNFUN(mpn_addlsh_n_ip2), TYPE_ADDLSH_N_IP2 },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n == 1
+  { TRY(mpn_sublsh1_n), TYPE_SUBLSH1_N },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n == 1
+  { TRY(mpn_sublsh2_n), TYPE_SUBLSH2_N },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n
+  { TRY(mpn_sublsh_n), TYPE_SUBLSH_N },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n_ip1
+  { TRY_FUNFUN(mpn_sublsh1_n_ip1), TYPE_SUBLSH1_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+  { TRY_FUNFUN(mpn_sublsh2_n_ip1), TYPE_SUBLSH2_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n_ip1
+  { TRY_FUNFUN(mpn_sublsh_n_ip1), TYPE_SUBLSH_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh1_n == 1
+  { TRY(mpn_rsblsh1_n), TYPE_RSBLSH1_N },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh2_n == 1
+  { TRY(mpn_rsblsh2_n), TYPE_RSBLSH2_N },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh_n
+  { TRY(mpn_rsblsh_n), TYPE_RSBLSH_N },
+#endif
+#if HAVE_NATIVE_mpn_rsh1add_n
+  { TRY(mpn_rsh1add_n), TYPE_RSH1ADD_N },
+#endif
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  { TRY(mpn_rsh1sub_n), TYPE_RSH1SUB_N },
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_nc == 1
+  { TRY(mpn_addlsh1_nc), TYPE_ADDLSH1_NC },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_nc == 1
+  { TRY(mpn_addlsh2_nc), TYPE_ADDLSH2_NC },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_nc
+  { TRY(mpn_addlsh_nc), TYPE_ADDLSH_NC },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_nc == 1
+  { TRY(mpn_sublsh1_nc), TYPE_SUBLSH1_NC },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_nc == 1
+  { TRY(mpn_sublsh2_nc), TYPE_SUBLSH2_NC },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_nc
+  { TRY(mpn_sublsh_nc), TYPE_SUBLSH_NC },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh1_nc
+  { TRY(mpn_rsblsh1_nc), TYPE_RSBLSH1_NC },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh2_nc
+  { TRY(mpn_rsblsh2_nc), TYPE_RSBLSH2_NC },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh_nc
+  { TRY(mpn_rsblsh_nc), TYPE_RSBLSH_NC },
+#endif
+
+  { TRY_FUNFUN(mpn_and_n),  TYPE_AND_N  },
+  { TRY_FUNFUN(mpn_andn_n), TYPE_ANDN_N },
+  { TRY_FUNFUN(mpn_nand_n), TYPE_NAND_N },
+  { TRY_FUNFUN(mpn_ior_n),  TYPE_IOR_N  },
+  { TRY_FUNFUN(mpn_iorn_n), TYPE_IORN_N },
+  { TRY_FUNFUN(mpn_nior_n), TYPE_NIOR_N },
+  { TRY_FUNFUN(mpn_xor_n),  TYPE_XOR_N  },
+  { TRY_FUNFUN(mpn_xnor_n), TYPE_XNOR_N },
+
+  { TRY(mpn_divrem_1),     TYPE_DIVREM_1 },
+#if USE_PREINV_DIVREM_1
+  { TRY(mpn_preinv_divrem_1), TYPE_PREINV_DIVREM_1 },
+#endif
+  { TRY(mpn_mod_1),        TYPE_MOD_1 },
+#if USE_PREINV_MOD_1
+  { TRY(mpn_preinv_mod_1), TYPE_PREINV_MOD_1 },
+#endif
+#if HAVE_NATIVE_mpn_divrem_1c
+  { TRY(mpn_divrem_1c),    TYPE_DIVREM_1C },
+#endif
+#if HAVE_NATIVE_mpn_mod_1c
+  { TRY(mpn_mod_1c),       TYPE_MOD_1C },
+#endif
+  { TRY(mpn_div_qr_1n_pi1), TYPE_DIV_QR_1N_PI1 },
+#if GMP_NUMB_BITS % 4 == 0
+  { TRY(mpn_mod_34lsub1),  TYPE_MOD_34LSUB1 },
+#endif
+
+  { TRY_FUNFUN(udiv_qrnnd), TYPE_UDIV_QRNND, 2 },
+#if HAVE_NATIVE_mpn_udiv_qrnnd
+  { TRY(mpn_udiv_qrnnd),    TYPE_UDIV_QRNND, 2 },
+#endif
+#if HAVE_NATIVE_mpn_udiv_qrnnd_r
+  { TRY(mpn_udiv_qrnnd_r),  TYPE_UDIV_QRNND_R, 2 },
+#endif
+
+  { TRY(mpn_divexact_1),          TYPE_DIVEXACT_1 },
+  { TRY(mpn_bdiv_q_1),            TYPE_BDIV_Q_1 },
+  { TRY_FUNFUN(mpn_divexact_by3), TYPE_DIVEXACT_BY3 },
+  { TRY(mpn_divexact_by3c),       TYPE_DIVEXACT_BY3C },
+
+  { TRY_FUNFUN(mpn_modexact_1_odd), TYPE_MODEXACT_1_ODD },
+  { TRY(mpn_modexact_1c_odd),       TYPE_MODEXACT_1C_ODD },
+
+
+  { TRY(mpn_sbpi1_div_qr), TYPE_SBPI1_DIV_QR, 3},
+  { TRY(mpn_tdiv_qr),      TYPE_TDIV_QR },
+
+  { TRY(mpn_mul_1),      TYPE_MUL_1 },
+#if HAVE_NATIVE_mpn_mul_1c
+  { TRY(mpn_mul_1c),     TYPE_MUL_1C },
+#endif
+#if HAVE_NATIVE_mpn_mul_2
+  { TRY(mpn_mul_2),      TYPE_MUL_2, 2 },
+#endif
+#if HAVE_NATIVE_mpn_mul_3
+  { TRY(mpn_mul_3),      TYPE_MUL_3, 3 },
+#endif
+#if HAVE_NATIVE_mpn_mul_4
+  { TRY(mpn_mul_4),      TYPE_MUL_4, 4 },
+#endif
+#if HAVE_NATIVE_mpn_mul_5
+  { TRY(mpn_mul_5),      TYPE_MUL_5, 5 },
+#endif
+#if HAVE_NATIVE_mpn_mul_6
+  { TRY(mpn_mul_6),      TYPE_MUL_6, 6 },
+#endif
+
+  { TRY(mpn_rshift),     TYPE_RSHIFT },
+  { TRY(mpn_lshift),     TYPE_LSHIFT },
+  { TRY(mpn_lshiftc),    TYPE_LSHIFTC },
+
+
+  { TRY(mpn_mul_basecase), TYPE_MUL_MN },
+  { TRY(mpn_mulmid_basecase), TYPE_MULMID_MN },
+  { TRY(mpn_mullo_basecase), TYPE_MULLO_N },
+  { TRY(mpn_sqrlo_basecase), TYPE_SQRLO },
+  { TRY(mpn_sqrlo), TYPE_SQRLO },
+#if SQR_TOOM2_THRESHOLD > 0
+  { TRY(mpn_sqr_basecase), TYPE_SQR },
+#endif
+
+  { TRY(mpn_mul),    TYPE_MUL_MN },
+  { TRY(mpn_mul_n),  TYPE_MUL_N },
+  { TRY(mpn_sqr),    TYPE_SQR },
+
+  { TRY_FUNFUN(umul_ppmm), TYPE_UMUL_PPMM, 2 },
+#if HAVE_NATIVE_mpn_umul_ppmm
+  { TRY(mpn_umul_ppmm),    TYPE_UMUL_PPMM, 2 },
+#endif
+#if HAVE_NATIVE_mpn_umul_ppmm_r
+  { TRY(mpn_umul_ppmm_r),  TYPE_UMUL_PPMM_R, 2 },
+#endif
+
+  { TRY_FUNFUN(mpn_toom22_mul),  TYPE_MUL_N,  MPN_TOOM22_MUL_MINSIZE },
+  { TRY_FUNFUN(mpn_toom2_sqr),   TYPE_SQR,    MPN_TOOM2_SQR_MINSIZE },
+  { TRY_FUNFUN(mpn_toom33_mul),  TYPE_MUL_N,  MPN_TOOM33_MUL_MINSIZE },
+  { TRY_FUNFUN(mpn_toom3_sqr),   TYPE_SQR,    MPN_TOOM3_SQR_MINSIZE },
+  { TRY_FUNFUN(mpn_toom44_mul),  TYPE_MUL_N,  MPN_TOOM44_MUL_MINSIZE },
+  { TRY_FUNFUN(mpn_toom4_sqr),   TYPE_SQR,    MPN_TOOM4_SQR_MINSIZE },
+
+  { TRY(mpn_mulmid_n),  TYPE_MULMID_N, 1 },
+  { TRY(mpn_mulmid),  TYPE_MULMID_MN, 1 },
+  { TRY_FUNFUN(mpn_toom42_mulmid),  TYPE_MULMID_N,
+    (2 * MPN_TOOM42_MULMID_MINSIZE - 1) },
+
+  { TRY(mpn_gcd_1),        TYPE_GCD_1            },
+  { TRY(mpn_gcd),          TYPE_GCD              },
+  { TRY(mpz_legendre),     TYPE_MPZ_LEGENDRE     },
+  { TRY(mpz_jacobi),       TYPE_MPZ_JACOBI       },
+  { TRY(mpz_kronecker),    TYPE_MPZ_KRONECKER    },
+  { TRY(mpz_kronecker_ui), TYPE_MPZ_KRONECKER_UI },
+  { TRY(mpz_kronecker_si), TYPE_MPZ_KRONECKER_SI },
+  { TRY(mpz_ui_kronecker), TYPE_MPZ_UI_KRONECKER },
+  { TRY(mpz_si_kronecker), TYPE_MPZ_SI_KRONECKER },
+
+  { TRY(mpn_popcount),   TYPE_POPCOUNT },
+  { TRY(mpn_hamdist),    TYPE_HAMDIST },
+
+  { TRY(mpn_sqrtrem),     TYPE_SQRTREM },
+  { TRY_FUNFUN(mpn_sqrt), TYPE_SQRT },
+
+  { TRY_FUNFUN(MPN_ZERO), TYPE_ZERO },
+
+  { TRY(mpn_get_str),    TYPE_GET_STR },
+
+  { TRY(mpn_binvert),    TYPE_BINVERT },
+  { TRY(mpn_invert),     TYPE_INVERT  },
+
+#ifdef EXTRA_ROUTINES
+  EXTRA_ROUTINES
+#endif
+};
+
+const struct choice_t *choice = NULL;
+
+
+void
+mprotect_maybe (void *addr, size_t len, int prot)
+{
+  if (!option_redzones)
+    return;
+
+#if HAVE_MPROTECT
+  if (mprotect (addr, len, prot) != 0)
+    {
+      fprintf (stderr, "Cannot mprotect %p 0x%X 0x%X: %s\n",
+	       addr, (unsigned) len, prot, strerror (errno));
+      exit (1);
+    }
+#else
+  {
+    static int  warned = 0;
+    if (!warned)
+      {
+	fprintf (stderr,
+		 "mprotect not available, bounds testing not performed\n");
+	warned = 1;
+      }
+  }
+#endif
+}
+
+/* round "a" up to a multiple of "m" */
+size_t
+round_up_multiple (size_t a, size_t m)
+{
+  unsigned long  r;
+
+  r = a % m;
+  if (r == 0)
+    return a;
+  else
+    return a + (m - r);
+}
+
+
+/* On some systems it seems that only an mmap'ed region can be mprotect'ed,
+   for instance HP-UX 10.
+
+   mmap will almost certainly return a pointer already aligned to a page
+   boundary, but it's easy enough to share the alignment handling with the
+   malloc case. */
+
+void
+malloc_region (struct region_t *r, mp_size_t n)
+{
+  mp_ptr  p;
+  size_t  nbytes;
+
+  ASSERT ((pagesize % GMP_LIMB_BYTES) == 0);
+
+  n = round_up_multiple (n, PAGESIZE_LIMBS);
+  r->size = n;
+
+  nbytes = n*GMP_LIMB_BYTES + 2*REDZONE_BYTES + pagesize;
+
+#if defined (MAP_ANONYMOUS) && ! defined (MAP_ANON)
+#define MAP_ANON  MAP_ANONYMOUS
+#endif
+
+#if HAVE_MMAP && defined (MAP_ANON)
+  /* note must pass fd=-1 for MAP_ANON on BSD */
+  p = (mp_ptr) mmap (NULL, nbytes, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+  if (p == (void *) -1)
+    {
+      fprintf (stderr, "Cannot mmap %#x anon bytes: %s\n",
+	       (unsigned) nbytes, strerror (errno));
+      exit (1);
+    }
+#else
+  p = (mp_ptr) malloc (nbytes);
+  ASSERT_ALWAYS (p != NULL);
+#endif
+
+  p = (mp_ptr) align_pointer (p, pagesize);
+
+  mprotect_maybe (p, REDZONE_BYTES, PROT_NONE);
+  p += REDZONE_LIMBS;
+  r->ptr = p;
+
+  mprotect_maybe (p + n, REDZONE_BYTES, PROT_NONE);
+}
+
+void
+mprotect_region (const struct region_t *r, int prot)
+{
+  mprotect_maybe (r->ptr, r->size, prot);
+}
+
+
+/* First four entries must be 0,1,2,3 for the benefit of CARRY_BIT, CARRY_3,
+   and CARRY_4 */
+mp_limb_t  carry_array[] = {
+  0, 1, 2, 3,
+  4,
+  CNST_LIMB(1) << 8,
+  CNST_LIMB(1) << 16,
+  GMP_NUMB_MAX
+};
+int        carry_index;
+
+#define CARRY_COUNT                                             \
+  ((tr->carry == CARRY_BIT) ? 2                                 \
+   : tr->carry == CARRY_3   ? 3                                 \
+   : tr->carry == CARRY_4   ? 4                                 \
+   : (tr->carry == CARRY_LIMB || tr->carry == CARRY_DIVISOR)    \
+     ? numberof(carry_array) + CARRY_RANDOMS                    \
+   : 1)
+
+#define MPN_RANDOM_ALT(index,dst,size) \
+  (((index) & 1) ? refmpn_random (dst, size) : refmpn_random2 (dst, size))
+
+/* The dummy value after MPN_RANDOM_ALT ensures both sides of the ":" have
+   the same type */
+#define CARRY_ITERATION                                                 \
+  for (carry_index = 0;                                                 \
+       (carry_index < numberof (carry_array)                            \
+	? (carry = carry_array[carry_index])                            \
+	: (MPN_RANDOM_ALT (carry_index, &carry, 1), (mp_limb_t) 0)),    \
+	 (tr->carry == CARRY_DIVISOR ? carry %= divisor : 0),           \
+	 carry_index < CARRY_COUNT;                                     \
+       carry_index++)
+
+
+mp_limb_t  multiplier_array[] = {
+  0, 1, 2, 3,
+  CNST_LIMB(1) << 8,
+  CNST_LIMB(1) << 16,
+  GMP_NUMB_MAX - 2,
+  GMP_NUMB_MAX - 1,
+  GMP_NUMB_MAX
+};
+int        multiplier_index;
+
+mp_limb_t  divisor_array[] = {
+  1, 2, 3,
+  CNST_LIMB(1) << 8,
+  CNST_LIMB(1) << 16,
+  CNST_LIMB(1) << (GMP_NUMB_BITS/2 - 1),
+  GMP_NUMB_MAX >> (GMP_NUMB_BITS/2),
+  GMP_NUMB_HIGHBIT,
+  GMP_NUMB_HIGHBIT + 1,
+  GMP_NUMB_MAX - 2,
+  GMP_NUMB_MAX - 1,
+  GMP_NUMB_MAX
+};
+
+int        divisor_index;
+
+/* The dummy value after MPN_RANDOM_ALT ensures both sides of the ":" have
+   the same type */
+#define ARRAY_ITERATION(var, index, limit, array, randoms, cond)        \
+  for (index = 0;                                                       \
+       (index < numberof (array)                                        \
+	? (var = array[index])                                          \
+	: (MPN_RANDOM_ALT (index, &var, 1), (mp_limb_t) 0)),            \
+       index < limit;                                                   \
+       index++)
+
+#define MULTIPLIER_COUNT                                \
+  (tr->multiplier                                       \
+    ? numberof (multiplier_array) + MULTIPLIER_RANDOMS  \
+    : 1)
+
+#define MULTIPLIER_ITERATION                                            \
+  ARRAY_ITERATION(multiplier, multiplier_index, MULTIPLIER_COUNT,       \
+		  multiplier_array, MULTIPLIER_RANDOMS, TRY_MULTIPLIER)
+
+#define DIVISOR_COUNT                           \
+  (tr->divisor                                  \
+   ? numberof (divisor_array) + DIVISOR_RANDOMS \
+   : 1)
+
+#define DIVISOR_ITERATION                                               \
+  ARRAY_ITERATION(divisor, divisor_index, DIVISOR_COUNT, divisor_array, \
+		  DIVISOR_RANDOMS, TRY_DIVISOR)
+
+
+/* overlap_array[].s[i] is where s[i] should be, 0 or 1 means overlapping
+   d[0] or d[1] respectively, -1 means a separate (write-protected)
+   location. */
+
+struct overlap_t {
+  int  s[NUM_SOURCES];
+} overlap_array[] = {
+  { { -1, -1, -1, -1, -1 } },
+  { {  0, -1, -1, -1, -1 } },
+  { { -1,  0, -1, -1, -1 } },
+  { {  0,  0, -1, -1, -1 } },
+  { {  1, -1, -1, -1, -1 } },
+  { { -1,  1, -1, -1, -1 } },
+  { {  1,  1, -1, -1, -1 } },
+  { {  0,  1, -1, -1, -1 } },
+  { {  1,  0, -1, -1, -1 } },
+};
+
+struct overlap_t  *overlap, *overlap_limit;
+
+#define OVERLAP_COUNT                   \
+  (tr->overlap & OVERLAP_NONE       ? 1 \
+   : tr->overlap & OVERLAP_NOT_SRCS ? 3 \
+   : tr->overlap & OVERLAP_NOT_SRC2 ? 2 \
+   : tr->overlap & OVERLAP_NOT_DST2 ? 4	\
+   : tr->dst[1]                     ? 9 \
+   : tr->src[1]                     ? 4 \
+   : tr->dst[0]                     ? 2 \
+   : 1)
+
+#define OVERLAP_ITERATION                               \
+  for (overlap = &overlap_array[0],                     \
+    overlap_limit = &overlap_array[OVERLAP_COUNT];      \
+    overlap < overlap_limit;                            \
+    overlap++)
+
+
+int  base = 10;
+
+#define T_RAND_COUNT  2
+int  t_rand;
+
+void
+t_random (mp_ptr ptr, mp_size_t n)
+{
+  if (n == 0)
+    return;
+
+  switch (option_data) {
+  case DATA_TRAND:
+    switch (t_rand) {
+    case 0: refmpn_random (ptr, n); break;
+    case 1: refmpn_random2 (ptr, n); break;
+    default: abort();
+    }
+    break;
+  case DATA_SEQ:
+    {
+      static mp_limb_t  counter = 0;
+      mp_size_t  i;
+      for (i = 0; i < n; i++)
+	ptr[i] = ++counter;
+    }
+    break;
+  case DATA_ZEROS:
+    refmpn_zero (ptr, n);
+    break;
+  case DATA_FFS:
+    refmpn_fill (ptr, n, GMP_NUMB_MAX);
+    break;
+  case DATA_2FD:
+    /* Special value 0x2FFF...FFFD, which divided by 3 gives 0xFFF...FFF,
+       inducing the q1_ff special case in the mul-by-inverse part of some
+       versions of divrem_1 and mod_1. */
+    refmpn_fill (ptr, n, (mp_limb_t) -1);
+    ptr[n-1] = 2;
+    ptr[0] -= 2;
+    break;
+
+  default:
+    abort();
+  }
+}
+#define T_RAND_ITERATION \
+  for (t_rand = 0; t_rand < T_RAND_COUNT; t_rand++)
+
+
+void
+print_each (const struct each_t *e)
+{
+  int  i;
+
+  printf ("%s %s\n", e->name, e == &ref ? tr->reference_name : choice->name);
+  if (tr->retval)
+    mpn_trace ("   retval", &e->retval, 1);
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      if (tr->dst[i])
+	{
+	  if (tr->dst_bytes[i])
+	    byte_tracen ("   d[%d]", i, e->d[i].p, d[i].size);
+	  else
+	    mpn_tracen ("   d[%d]", i, e->d[i].p, d[i].size);
+	  printf ("        located %p\n", (void *) (e->d[i].p));
+	}
+    }
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    if (tr->src[i])
+      printf ("   s[%d] located %p\n", i, (void *)  (e->s[i].p));
+}
+
+
+void
+print_all (void)
+{
+  int  i;
+
+  printf ("\n");
+  printf ("size  %ld\n", (long) size);
+  if (tr->size2)
+    printf ("size2 %ld\n", (long) size2);
+
+  for (i = 0; i < NUM_DESTS; i++)
+    if (d[i].size != size)
+      printf ("d[%d].size %ld\n", i, (long) d[i].size);
+
+  if (tr->multiplier)
+    mpn_trace ("   multiplier", &multiplier, 1);
+  if (tr->divisor)
+    mpn_trace ("   divisor", &divisor, 1);
+  if (tr->shift)
+    printf ("   shift %lu\n", shift);
+  if (tr->carry)
+    mpn_trace ("   carry", &carry, 1);
+  if (tr->msize)
+    mpn_trace ("   multiplier_N", multiplier_N, tr->msize);
+
+  for (i = 0; i < NUM_DESTS; i++)
+    if (tr->dst[i])
+      printf ("   d[%d] %s, align %ld, size %ld\n",
+	      i, d[i].high ? "high" : "low",
+	      (long) d[i].align, (long) d[i].size);
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (tr->src[i])
+	{
+	  printf ("   s[%d] %s, align %ld, ",
+		  i, s[i].high ? "high" : "low", (long) s[i].align);
+	  switch (overlap->s[i]) {
+	  case -1:
+	    printf ("no overlap\n");
+	    break;
+	  default:
+	    printf ("==d[%d]%s\n",
+		    overlap->s[i],
+		    tr->overlap == OVERLAP_LOW_TO_HIGH ? "+a"
+		    : tr->overlap == OVERLAP_HIGH_TO_LOW ? "-a"
+		    : "");
+	    break;
+	  }
+	  printf ("   s[%d]=", i);
+	  if (tr->carry_sign && (carry & (1 << i)))
+	    printf ("-");
+	  mpn_trace (NULL, s[i].p, SRC_SIZE(i));
+	}
+    }
+
+  if (tr->dst0_from_src1)
+    mpn_trace ("   d[0]", s[1].region.ptr, size);
+
+  if (tr->reference)
+    print_each (&ref);
+  print_each (&fun);
+}
+
+void
+compare (void)
+{
+  int  error = 0;
+  int  i;
+
+  if (tr->retval && ref.retval != fun.retval)
+    {
+      gmp_printf ("Different return values (%Mu, %Mu)\n",
+		  ref.retval, fun.retval);
+      error = 1;
+    }
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      switch (tr->dst_size[i]) {
+      case SIZE_RETVAL:
+      case SIZE_GET_STR:
+	d[i].size = ref.retval;
+	break;
+      }
+    }
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      if (! tr->dst[i])
+	continue;
+
+      if (tr->dst_bytes[i])
+	{
+	  if (memcmp (ref.d[i].p, fun.d[i].p, d[i].size) != 0)
+	    {
+	      printf ("Different d[%d] data results, low diff at %ld, high diff at %ld\n",
+		      i,
+		      (long) byte_diff_lowest (ref.d[i].p, fun.d[i].p, d[i].size),
+		      (long) byte_diff_highest (ref.d[i].p, fun.d[i].p, d[i].size));
+	      error = 1;
+	    }
+	}
+      else
+	{
+	  if (d[i].size != 0
+	      && ! refmpn_equal_anynail (ref.d[i].p, fun.d[i].p, d[i].size))
+	    {
+	      printf ("Different d[%d] data results, low diff at %ld, high diff at %ld\n",
+		      i,
+		      (long) mpn_diff_lowest (ref.d[i].p, fun.d[i].p, d[i].size),
+		      (long) mpn_diff_highest (ref.d[i].p, fun.d[i].p, d[i].size));
+	      error = 1;
+	    }
+	}
+    }
+
+  if (error)
+    {
+      print_all();
+      abort();
+    }
+}
+
+
+/* The functions are cast if the return value should be a long rather than
+   the default mp_limb_t.  This is necessary under _LONG_LONG_LIMB.  This
+   might not be enough if some actual calling conventions checking is
+   implemented on a long long limb system.  */
+
+void
+call (struct each_t *e, tryfun_t function)
+{
+  switch (choice->type) {
+  case TYPE_ADD:
+  case TYPE_SUB:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, e->s[1].p, size2);
+    break;
+
+  case TYPE_ADD_N:
+  case TYPE_SUB_N:
+  case TYPE_ADDLSH1_N:
+  case TYPE_ADDLSH2_N:
+  case TYPE_SUBLSH1_N:
+  case TYPE_SUBLSH2_N:
+  case TYPE_RSBLSH1_N:
+  case TYPE_RSBLSH2_N:
+  case TYPE_RSH1ADD_N:
+  case TYPE_RSH1SUB_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_ADDLSH_N:
+  case TYPE_SUBLSH_N:
+  case TYPE_RSBLSH_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size, shift);
+    break;
+  case TYPE_ADDLSH_NC:
+  case TYPE_SUBLSH_NC:
+  case TYPE_RSBLSH_NC:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size, shift, carry);
+    break;
+  case TYPE_ADDLSH1_NC:
+  case TYPE_ADDLSH2_NC:
+  case TYPE_SUBLSH1_NC:
+  case TYPE_SUBLSH2_NC:
+  case TYPE_RSBLSH1_NC:
+  case TYPE_RSBLSH2_NC:
+  case TYPE_ADD_NC:
+  case TYPE_SUB_NC:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size, carry);
+    break;
+  case TYPE_ADDCND_N:
+  case TYPE_SUBCND_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (carry, e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_ADD_ERR1_N:
+  case TYPE_SUB_ERR1_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, e->d[1].p, e->s[2].p, size, carry);
+    break;
+  case TYPE_ADD_ERR2_N:
+  case TYPE_SUB_ERR2_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, e->d[1].p, e->s[2].p, e->s[3].p, size, carry);
+    break;
+  case TYPE_ADD_ERR3_N:
+  case TYPE_SUB_ERR3_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, e->d[1].p, e->s[2].p, e->s[3].p, e->s[4].p, size, carry);
+    break;
+
+  case TYPE_MUL_1:
+  case TYPE_ADDMUL_1:
+  case TYPE_SUBMUL_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier);
+    break;
+  case TYPE_MUL_1C:
+  case TYPE_ADDMUL_1C:
+  case TYPE_SUBMUL_1C:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier, carry);
+    break;
+
+  case TYPE_MUL_2:
+  case TYPE_MUL_3:
+  case TYPE_MUL_4:
+  case TYPE_MUL_5:
+  case TYPE_MUL_6:
+    if (size == 1)
+      abort ();
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier_N);
+    break;
+
+  case TYPE_ADDMUL_2:
+  case TYPE_ADDMUL_3:
+  case TYPE_ADDMUL_4:
+  case TYPE_ADDMUL_5:
+  case TYPE_ADDMUL_6:
+  case TYPE_ADDMUL_7:
+  case TYPE_ADDMUL_8:
+    if (size == 1)
+      abort ();
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier_N);
+    break;
+
+  case TYPE_AND_N:
+  case TYPE_ANDN_N:
+  case TYPE_NAND_N:
+  case TYPE_IOR_N:
+  case TYPE_IORN_N:
+  case TYPE_NIOR_N:
+  case TYPE_XOR_N:
+  case TYPE_XNOR_N:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+
+  case TYPE_ADDSUB_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->d[1].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_ADDSUB_NC:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->d[1].p, e->s[0].p, e->s[1].p, size, carry);
+    break;
+
+  case TYPE_COPY:
+  case TYPE_COPYI:
+  case TYPE_COPYD:
+  case TYPE_COM:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
+    break;
+
+  case TYPE_ADDLSH1_N_IP1:
+  case TYPE_ADDLSH2_N_IP1:
+  case TYPE_ADDLSH1_N_IP2:
+  case TYPE_ADDLSH2_N_IP2:
+  case TYPE_SUBLSH1_N_IP1:
+  case TYPE_SUBLSH2_N_IP1:
+  case TYPE_DIVEXACT_BY3:
+    e->retval = CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
+    break;
+  case TYPE_DIVEXACT_BY3C:
+    e->retval = CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size,
+						carry);
+    break;
+
+
+  case TYPE_DIVMOD_1:
+  case TYPE_DIVEXACT_1:
+  case TYPE_BDIV_Q_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, divisor);
+    break;
+  case TYPE_DIVMOD_1C:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, divisor, carry);
+    break;
+  case TYPE_DIVREM_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, size2, e->s[0].p, size, divisor);
+    break;
+  case TYPE_DIVREM_1C:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, size2, e->s[0].p, size, divisor, carry);
+    break;
+  case TYPE_PREINV_DIVREM_1:
+    {
+      mp_limb_t  dinv;
+      unsigned   shift;
+      shift = refmpn_count_leading_zeros (divisor);
+      dinv = refmpn_invert_limb (divisor << shift);
+      e->retval = CALLING_CONVENTIONS (function)
+	(e->d[0].p, size2, e->s[0].p, size, divisor, dinv, shift);
+    }
+    break;
+  case TYPE_MOD_1:
+  case TYPE_MODEXACT_1_ODD:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p, size, divisor);
+    break;
+  case TYPE_MOD_1C:
+  case TYPE_MODEXACT_1C_ODD:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p, size, divisor, carry);
+    break;
+  case TYPE_PREINV_MOD_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p, size, divisor, refmpn_invert_limb (divisor));
+    break;
+  case TYPE_DIV_QR_1N_PI1:
+    {
+      mp_limb_t dinv = refmpn_invert_limb (divisor);
+      e->retval = CALLING_CONVENTIONS (function)
+	(e->d[0].p, e->s[0].p, size, e->s[1].p[0], divisor, dinv);
+      break;
+    }
+
+  case TYPE_MOD_34LSUB1:
+    e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, size);
+    break;
+
+  case TYPE_UDIV_QRNND:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p[1], e->s[0].p[0], divisor);
+    break;
+  case TYPE_UDIV_QRNND_R:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p[1], e->s[0].p[0], divisor, e->d[0].p);
+    break;
+
+  case TYPE_SBPI1_DIV_QR:
+    {
+      gmp_pi1_t dinv;
+      invert_pi1 (dinv, e->s[1].p[size2-1], e->s[1].p[size2-2]); /* FIXME: use refinvert_pi1 */
+      refmpn_copyi (e->d[1].p, e->s[0].p, size);        /* dividend */
+      refmpn_fill (e->d[0].p, size-size2, 0x98765432);  /* quotient */
+      e->retval = CALLING_CONVENTIONS (function)
+	(e->d[0].p, e->d[1].p, size, e->s[1].p, size2, dinv.inv32);
+      refmpn_zero (e->d[1].p+size2, size-size2);    /* excess over remainder */
+    }
+    break;
+
+  case TYPE_TDIV_QR:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->d[1].p, 0,
+				    e->s[0].p, size, e->s[1].p, size2);
+    break;
+
+  case TYPE_GCD_1:
+    /* Must have a non-zero src, but this probably isn't the best way to do
+       it. */
+    if (refmpn_zero_p (e->s[0].p, size))
+      e->retval = 0;
+    else
+      e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, size, divisor);
+    break;
+
+  case TYPE_GCD:
+    /* Sources are destroyed, so they're saved and replaced, but a general
+       approach to this might be better.  Note that it's still e->s[0].p and
+       e->s[1].p that are passed, to get the desired alignments. */
+    {
+      mp_ptr  s0 = refmpn_malloc_limbs (size);
+      mp_ptr  s1 = refmpn_malloc_limbs (size2);
+      refmpn_copyi (s0, e->s[0].p, size);
+      refmpn_copyi (s1, e->s[1].p, size2);
+
+      mprotect_region (&s[0].region, PROT_READ|PROT_WRITE);
+      mprotect_region (&s[1].region, PROT_READ|PROT_WRITE);
+      e->retval = CALLING_CONVENTIONS (function) (e->d[0].p,
+						  e->s[0].p, size,
+						  e->s[1].p, size2);
+      refmpn_copyi (e->s[0].p, s0, size);
+      refmpn_copyi (e->s[1].p, s1, size2);
+      free (s0);
+      free (s1);
+    }
+    break;
+
+  case TYPE_GCD_FINDA:
+    {
+      /* FIXME: do this with a flag */
+      mp_limb_t  c[2];
+      c[0] = e->s[0].p[0];
+      c[0] += (c[0] == 0);
+      c[1] = e->s[0].p[0];
+      c[1] += (c[1] == 0);
+      e->retval = CALLING_CONVENTIONS (function) (c);
+    }
+    break;
+
+  case TYPE_MPZ_LEGENDRE:
+  case TYPE_MPZ_JACOBI:
+    {
+      mpz_t  a, b;
+      PTR(a) = e->s[0].p; SIZ(a) = (carry==0 ? size : -size);
+      PTR(b) = e->s[1].p; SIZ(b) = size2;
+      e->retval = CALLING_CONVENTIONS (function) (a, b);
+    }
+    break;
+  case TYPE_MPZ_KRONECKER:
+    {
+      mpz_t  a, b;
+      PTR(a) = e->s[0].p; SIZ(a) = ((carry&1)==0 ? size : -size);
+      PTR(b) = e->s[1].p; SIZ(b) = ((carry&2)==0 ? size2 : -size2);
+      e->retval = CALLING_CONVENTIONS (function) (a, b);
+    }
+    break;
+  case TYPE_MPZ_KRONECKER_UI:
+    {
+      mpz_t  a;
+      PTR(a) = e->s[0].p; SIZ(a) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS(function) (a, (unsigned long)multiplier);
+    }
+    break;
+  case TYPE_MPZ_KRONECKER_SI:
+    {
+      mpz_t  a;
+      PTR(a) = e->s[0].p; SIZ(a) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS (function) (a, (long) multiplier);
+    }
+    break;
+  case TYPE_MPZ_UI_KRONECKER:
+    {
+      mpz_t  b;
+      PTR(b) = e->s[0].p; SIZ(b) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS(function) ((unsigned long)multiplier, b);
+    }
+    break;
+  case TYPE_MPZ_SI_KRONECKER:
+    {
+      mpz_t  b;
+      PTR(b) = e->s[0].p; SIZ(b) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS (function) ((long) multiplier, b);
+    }
+    break;
+
+  case TYPE_MUL_MN:
+  case TYPE_MULMID_MN:
+    CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, e->s[1].p, size2);
+    break;
+  case TYPE_MUL_N:
+  case TYPE_MULLO_N:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_MULMID_N:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p,
+				    (size + 1) / 2);
+    break;
+  case TYPE_SQR:
+  case TYPE_SQRLO:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
+    break;
+
+  case TYPE_UMUL_PPMM:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p[0], e->s[0].p[1]);
+    break;
+  case TYPE_UMUL_PPMM_R:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p[0], e->s[0].p[1], e->d[0].p);
+    break;
+
+  case TYPE_ADDLSH_N_IP1:
+  case TYPE_ADDLSH_N_IP2:
+  case TYPE_SUBLSH_N_IP1:
+  case TYPE_LSHIFT:
+  case TYPE_LSHIFTC:
+  case TYPE_RSHIFT:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, shift);
+    break;
+
+  case TYPE_POPCOUNT:
+    e->retval = (* (unsigned long (*)(ANYARGS))
+		 CALLING_CONVENTIONS (function)) (e->s[0].p, size);
+    break;
+  case TYPE_HAMDIST:
+    e->retval = (* (unsigned long (*)(ANYARGS))
+		 CALLING_CONVENTIONS (function)) (e->s[0].p, e->s[1].p, size);
+    break;
+
+  case TYPE_SQRTREM:
+    e->retval = (* (long (*)(ANYARGS)) CALLING_CONVENTIONS (function))
+      (e->d[0].p, e->d[1].p, e->s[0].p, size);
+    break;
+
+  case TYPE_SQRT:
+    e->retval = (* (long (*)(ANYARGS)) CALLING_CONVENTIONS (function))
+      (e->d[0].p, e->s[0].p, size);
+    break;
+
+  case TYPE_ZERO:
+    CALLING_CONVENTIONS (function) (e->d[0].p, size);
+    break;
+
+  case TYPE_GET_STR:
+    {
+      size_t  sizeinbase, fill;
+      char    *dst;
+      MPN_SIZEINBASE (sizeinbase, e->s[0].p, size, base);
+      ASSERT_ALWAYS (sizeinbase <= d[0].size);
+      fill = d[0].size - sizeinbase;
+      if (d[0].high)
+	{
+	  memset (e->d[0].p, 0xBA, fill);
+	  dst = (char *) e->d[0].p + fill;
+	}
+      else
+	{
+	  dst = (char *) e->d[0].p;
+	  memset (dst + sizeinbase, 0xBA, fill);
+	}
+      if (POW2_P (base))
+	{
+	  e->retval = CALLING_CONVENTIONS (function) (dst, base,
+						      e->s[0].p, size);
+	}
+      else
+	{
+	  refmpn_copy (e->d[1].p, e->s[0].p, size);
+	  e->retval = CALLING_CONVENTIONS (function) (dst, base,
+						      e->d[1].p, size);
+	}
+      refmpn_zero (e->d[1].p, size);  /* clobbered or unused */
+    }
+    break;
+
+ case TYPE_INVERT:
+    {
+      mp_ptr scratch;
+      TMP_DECL;
+      TMP_MARK;
+      scratch = TMP_ALLOC_LIMBS (mpn_invert_itch (size));
+      CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size, scratch);
+      TMP_FREE;
+    }
+    break;
+  case TYPE_BINVERT:
+    {
+      mp_ptr scratch;
+      TMP_DECL;
+      TMP_MARK;
+      scratch = TMP_ALLOC_LIMBS (mpn_binvert_itch (size));
+      CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size, scratch);
+      TMP_FREE;
+    }
+    break;
+
+#ifdef EXTRA_CALL
+    EXTRA_CALL
+#endif
+
+  default:
+    printf ("Unknown routine type %d\n", choice->type);
+    abort ();
+    break;
+  }
+}
+
+
+void
+pointer_setup (struct each_t *e)
+{
+  int  i, j;
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      switch (tr->dst_size[i]) {
+      case 0:
+      case SIZE_RETVAL: /* will be adjusted later */
+	d[i].size = size;
+	break;
+
+      case SIZE_1:
+	d[i].size = 1;
+	break;
+      case SIZE_2:
+	d[i].size = 2;
+	break;
+      case SIZE_3:
+	d[i].size = 3;
+	break;
+      case SIZE_4:
+	d[i].size = 4;
+	break;
+      case SIZE_6:
+	d[i].size = 6;
+	break;
+
+      case SIZE_PLUS_1:
+	d[i].size = size+1;
+	break;
+      case SIZE_PLUS_MSIZE_SUB_1:
+	d[i].size = size + tr->msize - 1;
+	break;
+
+      case SIZE_SUM:
+	if (tr->size2)
+	  d[i].size = size + size2;
+	else
+	  d[i].size = 2*size;
+	break;
+
+      case SIZE_SIZE2:
+	d[i].size = size2;
+	break;
+
+      case SIZE_DIFF:
+	d[i].size = size - size2;
+	break;
+
+      case SIZE_DIFF_PLUS_1:
+	d[i].size = size - size2 + 1;
+	break;
+
+      case SIZE_DIFF_PLUS_3:
+	d[i].size = size - size2 + 3;
+	break;
+
+      case SIZE_CEIL_HALF:
+	d[i].size = (size+1)/2;
+	break;
+
+      case SIZE_GET_STR:
+	{
+	  mp_limb_t ff = GMP_NUMB_MAX;
+	  MPN_SIZEINBASE (d[i].size, &ff - (size-1), size, base);
+	}
+	break;
+
+      default:
+	printf ("Unrecognised dst_size type %d\n", tr->dst_size[i]);
+	abort ();
+      }
+    }
+
+  /* establish e->d[].p destinations */
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      mp_size_t  offset = 0;
+
+      /* possible room for overlapping sources */
+      for (j = 0; j < numberof (overlap->s); j++)
+	if (overlap->s[j] == i)
+	  offset = MAX (offset, s[j].align);
+
+      if (d[i].high)
+	{
+	  if (tr->dst_bytes[i])
+	    {
+	      e->d[i].p = (mp_ptr)
+		((char *) (e->d[i].region.ptr + e->d[i].region.size)
+		 - d[i].size - d[i].align);
+	    }
+	  else
+	    {
+	      e->d[i].p = e->d[i].region.ptr + e->d[i].region.size
+		- d[i].size - d[i].align;
+	      if (tr->overlap == OVERLAP_LOW_TO_HIGH)
+		e->d[i].p -= offset;
+	    }
+	}
+      else
+	{
+	  if (tr->dst_bytes[i])
+	    {
+	      e->d[i].p = (mp_ptr) ((char *) e->d[i].region.ptr + d[i].align);
+	    }
+	  else
+	    {
+	      e->d[i].p = e->d[i].region.ptr + d[i].align;
+	      if (tr->overlap == OVERLAP_HIGH_TO_LOW)
+		e->d[i].p += offset;
+	    }
+	}
+    }
+
+  /* establish e->s[].p sources */
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      int  o = overlap->s[i];
+      switch (o) {
+      case -1:
+	/* no overlap */
+	e->s[i].p = s[i].p;
+	break;
+      case 0:
+      case 1:
+	/* overlap with d[o] */
+	if (tr->overlap == OVERLAP_HIGH_TO_LOW)
+	  e->s[i].p = e->d[o].p - s[i].align;
+	else if (tr->overlap == OVERLAP_LOW_TO_HIGH)
+	  e->s[i].p = e->d[o].p + s[i].align;
+	else if (tr->size2 == SIZE_FRACTION)
+	  e->s[i].p = e->d[o].p + size2;
+	else
+	  e->s[i].p = e->d[o].p;
+	break;
+      default:
+	abort();
+	break;
+      }
+    }
+}
+
+
+void
+validate_fail (void)
+{
+  if (tr->reference)
+    {
+      trap_location = TRAP_REF;
+      call (&ref, tr->reference);
+      trap_location = TRAP_NOWHERE;
+    }
+
+  print_all();
+  abort();
+}
+
+
+void
+try_one (void)
+{
+  int  i;
+
+  if (option_spinner)
+    spinner();
+  spinner_count++;
+
+  trap_location = TRAP_SETUPS;
+
+  if (tr->divisor == DIVISOR_NORM)
+    divisor |= GMP_NUMB_HIGHBIT;
+  if (tr->divisor == DIVISOR_ODD)
+    divisor |= 1;
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (s[i].high)
+	s[i].p = s[i].region.ptr + s[i].region.size - SRC_SIZE(i) - s[i].align;
+      else
+	s[i].p = s[i].region.ptr + s[i].align;
+    }
+
+  pointer_setup (&ref);
+  pointer_setup (&fun);
+
+  ref.retval = 0x04152637;
+  fun.retval = 0x8C9DAEBF;
+
+  t_random (multiplier_N, tr->msize);
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (! tr->src[i])
+	continue;
+
+      mprotect_region (&s[i].region, PROT_READ|PROT_WRITE);
+      t_random (s[i].p, SRC_SIZE(i));
+
+      switch (tr->data) {
+      case DATA_NON_ZERO:
+	if (refmpn_zero_p (s[i].p, SRC_SIZE(i)))
+	  s[i].p[0] = 1;
+	break;
+
+      case DATA_MULTIPLE_DIVISOR:
+	/* same number of low zero bits as divisor */
+	s[i].p[0] &= ~ LOW_ZEROS_MASK (divisor);
+	refmpn_sub_1 (s[i].p, s[i].p, size,
+		      refmpn_mod_1 (s[i].p, size, divisor));
+	break;
+
+      case DATA_GCD:
+	/* s[1] no more bits than s[0] */
+	if (i == 1 && size2 == size)
+	  s[1].p[size-1] &= refmpn_msbone_mask (s[0].p[size-1]);
+
+	/* high limb non-zero */
+	s[i].p[SRC_SIZE(i)-1] += (s[i].p[SRC_SIZE(i)-1] == 0);
+
+	/* odd */
+	s[i].p[0] |= 1;
+	break;
+
+      case DATA_SRC0_ODD:
+	if (i == 0)
+	  s[i].p[0] |= 1;
+	break;
+
+      case DATA_SRC1_ODD:
+	if (i == 1)
+	  s[i].p[0] |= 1;
+	break;
+
+      case DATA_SRC1_ODD_PRIME:
+	if (i == 1)
+	  {
+	    if (refmpn_zero_p (s[i].p+1, SRC_SIZE(i)-1)
+		&& s[i].p[0] <=3)
+	      s[i].p[0] = 3;
+	    else
+	      {
+		mpz_t p;
+		mpz_init (p);
+		for (;;)
+		  {
+		    _mpz_realloc (p, SRC_SIZE(i));
+		    MPN_COPY (PTR(p), s[i].p, SRC_SIZE(i));
+		    SIZ(p) = SRC_SIZE(i);
+		    MPN_NORMALIZE (PTR(p), SIZ(p));
+		    mpz_nextprime (p, p);
+		    if (mpz_size (p) <= SRC_SIZE(i))
+		      break;
+
+		    t_random (s[i].p, SRC_SIZE(i));
+		  }
+		MPN_COPY (s[i].p, PTR(p), SIZ(p));
+		if (SIZ(p) < SRC_SIZE(i))
+		  MPN_ZERO (s[i].p + SIZ(p), SRC_SIZE(i) - SIZ(p));
+		mpz_clear (p);
+	      }
+	  }
+	break;
+
+      case DATA_SRC1_HIGHBIT:
+	if (i == 1)
+	  {
+	    if (tr->size2)
+	      s[i].p[size2-1] |= GMP_NUMB_HIGHBIT;
+	    else
+	      s[i].p[size-1] |= GMP_NUMB_HIGHBIT;
+	  }
+	break;
+
+      case DATA_SRC0_HIGHBIT:
+       if (i == 0)
+	 {
+	   s[i].p[size-1] |= GMP_NUMB_HIGHBIT;
+	 }
+       break;
+
+      case DATA_UDIV_QRNND:
+	s[i].p[1] %= divisor;
+	break;
+      case DATA_DIV_QR_1:
+	if (i == 1)
+	  s[i].p[0] %= divisor;
+	break;
+      }
+
+      mprotect_region (&s[i].region, PROT_READ);
+    }
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      if (! tr->dst[i])
+	continue;
+
+      if (tr->dst0_from_src1 && i==0)
+	{
+	  mp_size_t  copy = MIN (d[0].size, SRC_SIZE(1));
+	  mp_size_t  fill = MAX (0, d[0].size - copy);
+	  MPN_COPY (fun.d[0].p, s[1].region.ptr, copy);
+	  MPN_COPY (ref.d[0].p, s[1].region.ptr, copy);
+	  refmpn_fill (fun.d[0].p + copy, fill, DEADVAL);
+	  refmpn_fill (ref.d[0].p + copy, fill, DEADVAL);
+	}
+      else if (tr->dst_bytes[i])
+	{
+	  memset (ref.d[i].p, 0xBA, d[i].size);
+	  memset (fun.d[i].p, 0xBA, d[i].size);
+	}
+      else
+	{
+	  refmpn_fill (ref.d[i].p, d[i].size, DEADVAL);
+	  refmpn_fill (fun.d[i].p, d[i].size, DEADVAL);
+	}
+    }
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (! tr->src[i])
+	continue;
+
+      if (ref.s[i].p != s[i].p)
+	{
+	  refmpn_copyi (ref.s[i].p, s[i].p, SRC_SIZE(i));
+	  refmpn_copyi (fun.s[i].p, s[i].p, SRC_SIZE(i));
+	}
+    }
+
+  if (option_print)
+    print_all();
+
+  if (tr->validate != NULL)
+    {
+      trap_location = TRAP_FUN;
+      call (&fun, choice->function);
+      trap_location = TRAP_NOWHERE;
+
+      if (! CALLING_CONVENTIONS_CHECK ())
+	{
+	  print_all();
+	  abort();
+	}
+
+      (*tr->validate) ();
+    }
+  else
+    {
+      trap_location = TRAP_REF;
+      call (&ref, tr->reference);
+      trap_location = TRAP_FUN;
+      call (&fun, choice->function);
+      trap_location = TRAP_NOWHERE;
+
+      if (! CALLING_CONVENTIONS_CHECK ())
+	{
+	  print_all();
+	  abort();
+	}
+
+      compare ();
+    }
+}
+
+
+#define SIZE_ITERATION                                          \
+  for (size = MAX3 (option_firstsize,                           \
+		    choice->minsize,                            \
+		    (tr->size == SIZE_ALLOW_ZERO) ? 0 : 1),	\
+	 size += (tr->size == SIZE_ODD) && !(size & 1);		\
+       size <= option_lastsize;                                 \
+       size += (tr->size == SIZE_ODD) ? 2 : 1)
+
+#define SIZE2_FIRST                                     \
+  (tr->size2 == SIZE_2 ? 2                              \
+   : tr->size2 == SIZE_FRACTION ? option_firstsize2     \
+   : tr->size2 == SIZE_CEIL_HALF ? ((size + 1) / 2)	\
+   : tr->size2 ?                                        \
+   MAX (choice->minsize, (option_firstsize2 != 0        \
+			  ? option_firstsize2 : 1))     \
+   : 0)
+
+#define SIZE2_LAST                                      \
+  (tr->size2 == SIZE_2 ? 2                              \
+   : tr->size2 == SIZE_FRACTION ? FRACTION_COUNT-1      \
+   : tr->size2 == SIZE_CEIL_HALF ? ((size + 1) / 2)	\
+   : tr->size2 ? size                                   \
+   : 0)
+
+#define SIZE2_ITERATION \
+  for (size2 = SIZE2_FIRST; size2 <= SIZE2_LAST; size2++)
+
+#define ALIGN_COUNT(cond)  ((cond) ? ALIGNMENTS : 1)
+#define ALIGN_ITERATION(w,n,cond) \
+  for (w[n].align = 0; w[n].align < ALIGN_COUNT(cond); w[n].align++)
+
+#define HIGH_LIMIT(cond)  ((cond) != 0)
+#define HIGH_COUNT(cond)  (HIGH_LIMIT (cond) + 1)
+#define HIGH_ITERATION(w,n,cond) \
+  for (w[n].high = 0; w[n].high <= HIGH_LIMIT(cond); w[n].high++)
+
+#define SHIFT_LIMIT                                     \
+  ((unsigned long) (tr->shift ? GMP_NUMB_BITS -1 : 1))
+
+#define SHIFT_ITERATION                                 \
+  for (shift = 1; shift <= SHIFT_LIMIT; shift++)
+
+
+void
+try_many (void)
+{
+  int   i;
+
+  {
+    unsigned long  total = 1;
+
+    total *= option_repetitions;
+    total *= option_lastsize;
+    if (tr->size2 == SIZE_FRACTION) total *= FRACTION_COUNT;
+    else if (tr->size2)             total *= (option_lastsize+1)/2;
+
+    total *= SHIFT_LIMIT;
+    total *= MULTIPLIER_COUNT;
+    total *= DIVISOR_COUNT;
+    total *= CARRY_COUNT;
+    total *= T_RAND_COUNT;
+
+    total *= HIGH_COUNT (tr->dst[0]);
+    total *= HIGH_COUNT (tr->dst[1]);
+    total *= HIGH_COUNT (tr->src[0]);
+    total *= HIGH_COUNT (tr->src[1]);
+
+    total *= ALIGN_COUNT (tr->dst[0]);
+    total *= ALIGN_COUNT (tr->dst[1]);
+    total *= ALIGN_COUNT (tr->src[0]);
+    total *= ALIGN_COUNT (tr->src[1]);
+
+    total *= OVERLAP_COUNT;
+
+    printf ("%s %lu\n", choice->name, total);
+  }
+
+  spinner_count = 0;
+
+  for (i = 0; i < option_repetitions; i++)
+    SIZE_ITERATION
+      SIZE2_ITERATION
+
+      SHIFT_ITERATION
+      MULTIPLIER_ITERATION
+      DIVISOR_ITERATION
+      CARRY_ITERATION /* must be after divisor */
+      T_RAND_ITERATION
+
+      HIGH_ITERATION(d,0, tr->dst[0])
+      HIGH_ITERATION(d,1, tr->dst[1])
+      HIGH_ITERATION(s,0, tr->src[0])
+      HIGH_ITERATION(s,1, tr->src[1])
+
+      ALIGN_ITERATION(d,0, tr->dst[0])
+      ALIGN_ITERATION(d,1, tr->dst[1])
+      ALIGN_ITERATION(s,0, tr->src[0])
+      ALIGN_ITERATION(s,1, tr->src[1])
+
+      OVERLAP_ITERATION
+      try_one();
+
+  printf("\n");
+}
+
+
+/* Usually print_all() doesn't show much, but it might give a hint as to
+   where the function was up to when it died. */
+void
+trap (int sig)
+{
+  const char *name = "noname";
+
+  switch (sig) {
+  case SIGILL:  name = "SIGILL";  break;
+#ifdef SIGBUS
+  case SIGBUS:  name = "SIGBUS";  break;
+#endif
+  case SIGSEGV: name = "SIGSEGV"; break;
+  case SIGFPE:  name = "SIGFPE";  break;
+  }
+
+  printf ("\n\nSIGNAL TRAP: %s\n", name);
+
+  switch (trap_location) {
+  case TRAP_REF:
+    printf ("  in reference function: %s\n", tr->reference_name);
+    break;
+  case TRAP_FUN:
+    printf ("  in test function: %s\n", choice->name);
+    print_all ();
+    break;
+  case TRAP_SETUPS:
+    printf ("  in parameter setups\n");
+    print_all ();
+    break;
+  default:
+    printf ("  somewhere unknown\n");
+    break;
+  }
+  exit (1);
+}
+
+
+void
+try_init (void)
+{
+#if HAVE_GETPAGESIZE
+  /* Prefer getpagesize() over sysconf(), since on SunOS 4 sysconf() doesn't
+     know _SC_PAGESIZE. */
+  pagesize = getpagesize ();
+#else
+#if HAVE_SYSCONF
+  if ((pagesize = sysconf (_SC_PAGESIZE)) == -1)
+    {
+      /* According to the linux man page, sysconf doesn't set errno */
+      fprintf (stderr, "Cannot get sysconf _SC_PAGESIZE\n");
+      exit (1);
+    }
+#else
+Error, error, cannot get page size
+#endif
+#endif
+
+  printf ("pagesize is 0x%lX bytes\n", pagesize);
+
+  signal (SIGILL,  trap);
+#ifdef SIGBUS
+  signal (SIGBUS,  trap);
+#endif
+  signal (SIGSEGV, trap);
+  signal (SIGFPE,  trap);
+
+  {
+    int  i;
+
+    for (i = 0; i < NUM_SOURCES; i++)
+      {
+	malloc_region (&s[i].region, 2*option_lastsize+ALIGNMENTS-1);
+	printf ("s[%d] %p to %p (0x%lX bytes)\n",
+		i, (void *) (s[i].region.ptr),
+		(void *) (s[i].region.ptr + s[i].region.size),
+		(long) s[i].region.size * GMP_LIMB_BYTES);
+      }
+
+#define INIT_EACH(e,es)                                                 \
+    for (i = 0; i < NUM_DESTS; i++)                                     \
+      {                                                                 \
+	malloc_region (&e.d[i].region, 2*option_lastsize+ALIGNMENTS-1); \
+	printf ("%s d[%d] %p to %p (0x%lX bytes)\n",                    \
+		es, i, (void *) (e.d[i].region.ptr),			\
+		(void *)  (e.d[i].region.ptr + e.d[i].region.size),	\
+		(long) e.d[i].region.size * GMP_LIMB_BYTES);         \
+      }
+
+    INIT_EACH(ref, "ref");
+    INIT_EACH(fun, "fun");
+  }
+}
+
+int
+strmatch_wild (const char *pattern, const char *str)
+{
+  size_t  plen, slen;
+
+  /* wildcard at start */
+  if (pattern[0] == '*')
+    {
+      pattern++;
+      plen = strlen (pattern);
+      slen = strlen (str);
+      return (plen == 0
+	      || (slen >= plen && memcmp (pattern, str+slen-plen, plen) == 0));
+    }
+
+  /* wildcard at end */
+  plen = strlen (pattern);
+  if (plen >= 1 && pattern[plen-1] == '*')
+    return (memcmp (pattern, str, plen-1) == 0);
+
+  /* no wildcards */
+  return (strcmp (pattern, str) == 0);
+}
+
+void
+try_name (const char *name)
+{
+  int  found = 0;
+  int  i;
+
+  for (i = 0; i < numberof (choice_array); i++)
+    {
+      if (strmatch_wild (name, choice_array[i].name))
+	{
+	  choice = &choice_array[i];
+	  tr = &param[choice->type];
+	  try_many ();
+	  found = 1;
+	}
+    }
+
+  if (!found)
+    {
+      printf ("%s unknown\n", name);
+      /* exit (1); */
+    }
+}
+
+
+void
+usage (const char *prog)
+{
+  int  col = 0;
+  int  i;
+
+  printf ("Usage: %s [options] function...\n", prog);
+  printf ("    -1        use limb data 1,2,3,etc\n");
+  printf ("    -9        use limb data all 0xFF..FFs\n");
+  printf ("    -a zeros  use limb data all zeros\n");
+  printf ("    -a ffs    use limb data all 0xFF..FFs (same as -9)\n");
+  printf ("    -a 2fd    use data 0x2FFF...FFFD\n");
+  printf ("    -p        print each case tried (try this if seg faulting)\n");
+  printf ("    -R        seed random numbers from time()\n");
+  printf ("    -r reps   set repetitions (default %d)\n", DEFAULT_REPETITIONS);
+  printf ("    -s size   starting size to test\n");
+  printf ("    -S size2  starting size2 to test\n");
+  printf ("    -s s1-s2  range of sizes to test\n");
+  printf ("    -W        don't show the spinner (use this in gdb)\n");
+  printf ("    -z        disable mprotect() redzones\n");
+  printf ("Default data is refmpn_random() and refmpn_random2().\n");
+  printf ("\n");
+  printf ("Functions that can be tested:\n");
+
+  for (i = 0; i < numberof (choice_array); i++)
+    {
+      if (col + 1 + strlen (choice_array[i].name) > 79)
+	{
+	  printf ("\n");
+	  col = 0;
+	}
+      printf (" %s", choice_array[i].name);
+      col += 1 + strlen (choice_array[i].name);
+    }
+  printf ("\n");
+
+  exit(1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+
+  /* unbuffered output */
+  setbuf (stdout, NULL);
+  setbuf (stderr, NULL);
+
+  /* default trace in hex, and in upper-case so can paste into bc */
+  mp_trace_base = -16;
+
+  param_init ();
+
+  {
+    unsigned long  seed = 123;
+    int   opt;
+
+    while ((opt = getopt(argc, argv, "19a:b:E:pRr:S:s:Wz")) != EOF)
+      {
+	switch (opt) {
+	case '1':
+	  /* use limb data values 1, 2, 3, ... etc */
+	  option_data = DATA_SEQ;
+	  break;
+	case '9':
+	  /* use limb data values 0xFFF...FFF always */
+	  option_data = DATA_FFS;
+	  break;
+	case 'a':
+	  if (strcmp (optarg, "zeros") == 0)     option_data = DATA_ZEROS;
+	  else if (strcmp (optarg, "seq") == 0)  option_data = DATA_SEQ;
+	  else if (strcmp (optarg, "ffs") == 0)  option_data = DATA_FFS;
+	  else if (strcmp (optarg, "2fd") == 0)  option_data = DATA_2FD;
+	  else
+	    {
+	      fprintf (stderr, "unrecognised data option: %s\n", optarg);
+	      exit (1);
+	    }
+	  break;
+	case 'b':
+	  mp_trace_base = atoi (optarg);
+	  break;
+	case 'E':
+	  /* re-seed */
+	  sscanf (optarg, "%lu", &seed);
+	  printf ("Re-seeding with %lu\n", seed);
+	  break;
+	case 'p':
+	  option_print = 1;
+	  break;
+	case 'R':
+	  /* randomize */
+	  seed = time (NULL);
+	  printf ("Seeding with %lu, re-run using \"-E %lu\"\n", seed, seed);
+	  break;
+	case 'r':
+	  option_repetitions = atoi (optarg);
+	  break;
+	case 's':
+	  {
+	    char  *p;
+	    option_firstsize = strtol (optarg, 0, 0);
+	    if ((p = strchr (optarg, '-')) != NULL)
+	      option_lastsize = strtol (p+1, 0, 0);
+	  }
+	  break;
+	case 'S':
+	  /* -S <size> sets the starting size for the second of a two size
+	     routine (like mpn_mul_basecase) */
+	  option_firstsize2 = strtol (optarg, 0, 0);
+	  break;
+	case 'W':
+	  /* use this when running in the debugger */
+	  option_spinner = 0;
+	  break;
+	case 'z':
+	  /* disable redzones */
+	  option_redzones = 0;
+	  break;
+	case '?':
+	  usage (argv[0]);
+	  break;
+	}
+      }
+
+    gmp_randinit_default (__gmp_rands);
+    __gmp_rands_initialized = 1;
+    gmp_randseed_ui (__gmp_rands, seed);
+  }
+
+  try_init();
+
+  if (argc <= optind)
+    usage (argv[0]);
+
+  for (i = optind; i < argc; i++)
+    try_name (argv[i]);
+
+  return 0;
+}
diff --git a/tests/memory.c b/tests/memory.c
new file mode 100644
index 0000000..4ab54b7
--- /dev/null
+++ b/tests/memory.c
@@ -0,0 +1,246 @@
+/* Memory allocation used during tests.
+
+Copyright 2001, 2002, 2007, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>		/* for abort */
+#include <string.h>		/* for memcpy, memcmp */
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if GMP_LIMB_BITS == 64
+#define PATTERN1 CNST_LIMB(0xcafebabedeadbeef)
+#define PATTERN2 CNST_LIMB(0xabacadabaedeedab)
+#else
+#define PATTERN1 CNST_LIMB(0xcafebabe)
+#define PATTERN2 CNST_LIMB(0xdeadbeef)
+#endif
+
+#if HAVE_INTPTR_T
+#define PTRLIMB(p)  ((mp_limb_t) (intptr_t) p)
+#else
+#define PTRLIMB(p)  ((mp_limb_t) (size_t) p)
+#endif
+
+/* Each block allocated is a separate malloc, for the benefit of a redzoning
+   malloc debugger during development or when bug hunting.
+
+   Sizes passed when reallocating or freeing are checked (the default
+   routines don't care about these).
+
+   Memory leaks are checked by requiring that all blocks have been freed
+   when tests_memory_end() is called.  Test programs must be sure to have
+   "clear"s for all temporary variables used.  */
+
+
+struct header {
+  void           *ptr;
+  size_t         size;
+  struct header  *next;
+};
+
+struct header  *tests_memory_list = NULL;
+
+/* Return a pointer to a pointer to the found block (so it can be updated
+   when unlinking). */
+struct header **
+tests_memory_find (void *ptr)
+{
+  struct header  **hp;
+
+  for (hp = &tests_memory_list; *hp != NULL; hp = &((*hp)->next))
+    if ((*hp)->ptr == ptr)
+      return hp;
+
+  return NULL;
+}
+
+int
+tests_memory_valid (void *ptr)
+{
+  return (tests_memory_find (ptr) != NULL);
+}
+
+void *
+tests_allocate (size_t size)
+{
+  struct header  *h;
+  void *rptr, *ptr;
+  mp_limb_t PATTERN2_var;
+
+  if (size == 0)
+    {
+      fprintf (stderr, "tests_allocate(): attempt to allocate 0 bytes\n");
+      abort ();
+    }
+
+  h = (struct header *) __gmp_default_allocate (sizeof (*h));
+  h->next = tests_memory_list;
+  tests_memory_list = h;
+
+  rptr = __gmp_default_allocate (size + 2 * sizeof (mp_limb_t));
+  ptr = (void *) ((gmp_intptr_t) rptr + sizeof (mp_limb_t));
+
+  *((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+    = PATTERN1 - PTRLIMB (ptr);
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  memcpy ((void *) ((gmp_intptr_t) ptr + size), &PATTERN2_var, sizeof (mp_limb_t));
+
+  h->size = size;
+  h->ptr = ptr;
+  return h->ptr;
+}
+
+void *
+tests_reallocate (void *ptr, size_t old_size, size_t new_size)
+{
+  struct header  **hp, *h;
+  void *rptr;
+  mp_limb_t PATTERN2_var;
+
+  if (new_size == 0)
+    {
+      fprintf (stderr, "tests_reallocate(): attempt to reallocate %p to 0 bytes\n",
+	       ptr);
+      abort ();
+    }
+
+  hp = tests_memory_find (ptr);
+  if (hp == NULL)
+    {
+      fprintf (stderr, "tests_reallocate(): attempt to reallocate bad pointer %p\n",
+	       ptr);
+      abort ();
+    }
+  h = *hp;
+
+  if (h->size != old_size)
+    {
+      fprintf (stderr, "tests_reallocate(): bad old size %lu, should be %lu\n",
+	       (unsigned long) old_size, (unsigned long) h->size);
+      abort ();
+    }
+
+  if (*((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+      != PATTERN1 - PTRLIMB (ptr))
+    {
+      fprintf (stderr, "in realloc: redzone clobbered before block\n");
+      abort ();
+    }
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  if (memcmp ((void *) ((gmp_intptr_t) ptr + h->size), &PATTERN2_var, sizeof (mp_limb_t)))
+    {
+      fprintf (stderr, "in realloc: redzone clobbered after block\n");
+      abort ();
+    }
+
+  rptr = __gmp_default_reallocate ((void *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)),
+				 old_size + 2 * sizeof (mp_limb_t),
+				 new_size + 2 * sizeof (mp_limb_t));
+  ptr = (void *) ((gmp_intptr_t) rptr + sizeof (mp_limb_t));
+
+  *((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+    = PATTERN1 - PTRLIMB (ptr);
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  memcpy ((void *) ((gmp_intptr_t) ptr + new_size), &PATTERN2_var, sizeof (mp_limb_t));
+
+  h->size = new_size;
+  h->ptr = ptr;
+  return h->ptr;
+}
+
+struct header **
+tests_free_find (void *ptr)
+{
+  struct header  **hp = tests_memory_find (ptr);
+  if (hp == NULL)
+    {
+      fprintf (stderr, "tests_free(): attempt to free bad pointer %p\n",
+	       ptr);
+      abort ();
+    }
+  return hp;
+}
+
+void
+tests_free_nosize (void *ptr)
+{
+  struct header  **hp = tests_free_find (ptr);
+  struct header  *h = *hp;
+  mp_limb_t PATTERN2_var;
+
+  *hp = h->next;  /* unlink */
+
+  if (*((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+      != PATTERN1 - PTRLIMB (ptr))
+    {
+      fprintf (stderr, "in free: redzone clobbered before block\n");
+      abort ();
+    }
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  if (memcmp ((void *) ((gmp_intptr_t) ptr + h->size), &PATTERN2_var, sizeof (mp_limb_t)))
+    {
+      fprintf (stderr, "in free: redzone clobbered after block\n");
+      abort ();
+    }
+
+  __gmp_default_free ((void *) ((gmp_intptr_t) ptr - sizeof(mp_limb_t)),
+		      h->size + 2 * sizeof (mp_limb_t));
+  __gmp_default_free (h, sizeof (*h));
+}
+
+void
+tests_free (void *ptr, size_t size)
+{
+  struct header  **hp = tests_free_find (ptr);
+  struct header  *h = *hp;
+
+  if (h->size != size)
+    {
+      fprintf (stderr, "tests_free(): bad size %lu, should be %lu\n",
+	       (unsigned long) size, (unsigned long) h->size);
+      abort ();
+    }
+
+  tests_free_nosize (ptr);
+}
+
+void
+tests_memory_start (void)
+{
+  mp_set_memory_functions (tests_allocate, tests_reallocate, tests_free);
+}
+
+void
+tests_memory_end (void)
+{
+  if (tests_memory_list != NULL)
+    {
+      struct header  *h;
+      unsigned  count;
+
+      fprintf (stderr, "tests_memory_end(): not all memory freed\n");
+
+      count = 0;
+      for (h = tests_memory_list; h != NULL; h = h->next)
+	count++;
+
+      fprintf (stderr, "    %u blocks remaining\n", count);
+      abort ();
+    }
+}
diff --git a/tests/misc.c b/tests/misc.c
new file mode 100644
index 0000000..6c40d78
--- /dev/null
+++ b/tests/misc.c
@@ -0,0 +1,608 @@
+/* Miscellaneous test program support routines.
+
+Copyright 2000-2003, 2005, 2013, 2015, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>     /* for getenv */
+#include <string.h>
+
+#if HAVE_FLOAT_H
+#include <float.h>      /* for DBL_MANT_DIG */
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>  /* for struct timeval */
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* The various tests setups and final checks, collected up together. */
+void
+tests_start (void)
+{
+  char version[10];
+  snprintf (version, 10, "%u.%u.%u",
+	    __GNU_MP_VERSION,
+	    __GNU_MP_VERSION_MINOR,
+	    __GNU_MP_VERSION_PATCHLEVEL);
+
+  if (strcmp (gmp_version, version) != 0)
+    {
+      fprintf (stderr, "tests are not linked to the newly compiled library\n");
+      fprintf (stderr, "  local version is: %s\n", version);
+      fprintf (stderr, "  linked version is: %s\n", gmp_version);
+      abort ();
+    }
+
+  /* don't buffer, so output is not lost if a test causes a segv etc */
+  setbuf (stdout, NULL);
+  setbuf (stderr, NULL);
+
+  tests_memory_start ();
+  tests_rand_start ();
+}
+void
+tests_end (void)
+{
+  tests_rand_end ();
+  tests_memory_end ();
+}
+
+static void
+seed_from_tod (gmp_randstate_ptr  rands)
+{
+  unsigned long seed;
+#if HAVE_GETTIMEOFDAY
+  struct timeval  tv;
+  gettimeofday (&tv, NULL);
+  seed = tv.tv_sec ^ ((unsigned long) tv.tv_usec << 12);
+  seed &= 0xffffffff;
+#else
+  time_t  tv;
+  time (&tv);
+  seed = tv;
+#endif
+  gmp_randseed_ui (rands, seed);
+  printf ("Seed GMP_CHECK_RANDOMIZE=%lu (include this in bug reports)\n", seed);
+}
+
+static void
+seed_from_urandom (gmp_randstate_ptr rands, FILE *fs)
+{
+  mpz_t seed;
+  unsigned char buf[6];
+  fread (buf, 1, 6, fs);
+  mpz_init (seed);
+  mpz_import (seed, 6, 1, 1, 0, 0, buf);
+  gmp_randseed (rands, seed);
+  gmp_printf ("Seed GMP_CHECK_RANDOMIZE=%Zd (include this in bug reports)\n", seed);
+  mpz_clear (seed);
+}
+
+void
+tests_rand_start (void)
+{
+  gmp_randstate_ptr  rands;
+  char           *seed_string;
+
+  if (__gmp_rands_initialized)
+    {
+      printf ("Please let tests_start() initialize the global __gmp_rands.\n");
+      printf ("ie. ensure that function is called before the first use of RANDS.\n");
+      abort ();
+    }
+
+  gmp_randinit_default (__gmp_rands);
+  __gmp_rands_initialized = 1;
+  rands = __gmp_rands;
+
+  seed_string = getenv ("GMP_CHECK_RANDOMIZE");
+  if (seed_string != NULL)
+    {
+      if (strcmp (seed_string, "0") != 0 &&
+	  strcmp (seed_string, "1") != 0)
+        {
+	  mpz_t seed;
+	  mpz_init_set_str (seed, seed_string, 0);
+          gmp_printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%Zd\n", seed);
+          gmp_randseed (rands, seed);
+	  mpz_clear (seed);
+        }
+      else
+        {
+	  FILE *fs = fopen ("/dev/urandom", "r");
+	  if (fs != NULL)
+	    {
+	      seed_from_urandom (rands, fs);
+	      fclose (fs);
+	    }
+	  else
+	    seed_from_tod (rands);
+        }
+      fflush (stdout);
+    }
+}
+void
+tests_rand_end (void)
+{
+  RANDS_CLEAR ();
+}
+
+
+/* Only used if CPU calling conventions checking is available. */
+mp_limb_t (*calling_conventions_function) (ANYARGS);
+
+
+/* Return p advanced to the next multiple of "align" bytes.  "align" must be
+   a power of 2.  Care is taken not to assume sizeof(int)==sizeof(pointer).
+   Using "unsigned long" avoids a warning on hpux.  */
+void *
+align_pointer (void *p, size_t align)
+{
+  gmp_intptr_t d;
+  d = ((gmp_intptr_t) p) & (align-1);
+  d = (d != 0 ? align-d : 0);
+  return (void *) (((char *) p) + d);
+}
+
+
+/* Note that memory allocated with this function can never be freed, because
+   the start address of the block allocated is lost. */
+void *
+__gmp_allocate_func_aligned (size_t bytes, size_t align)
+{
+  return align_pointer ((*__gmp_allocate_func) (bytes + align-1), align);
+}
+
+
+void *
+__gmp_allocate_or_reallocate (void *ptr, size_t oldsize, size_t newsize)
+{
+  if (ptr == NULL)
+    return (*__gmp_allocate_func) (newsize);
+  else
+    return (*__gmp_reallocate_func) (ptr, oldsize, newsize);
+}
+
+char *
+__gmp_allocate_strdup (const char *s)
+{
+  size_t  len;
+  char    *t;
+  len = strlen (s);
+  t = (char *) (*__gmp_allocate_func) (len+1);
+  memcpy (t, s, len+1);
+  return t;
+}
+
+
+char *
+strtoupper (char *s_orig)
+{
+  char  *s;
+  for (s = s_orig; *s != '\0'; s++)
+    if (islower (*s))
+      *s = toupper (*s);
+  return s_orig;
+}
+
+
+void
+mpz_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
+{
+  ASSERT (size >= 0);
+  MPN_NORMALIZE (p, size);
+  MPZ_REALLOC (z, size);
+  MPN_COPY (PTR(z), p, size);
+  SIZ(z) = size;
+}
+
+void
+mpz_init_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
+{
+  ASSERT (size >= 0);
+
+  MPN_NORMALIZE (p, size);
+  ALLOC(z) = MAX (size, 1);
+  PTR(z) = __GMP_ALLOCATE_FUNC_LIMBS (ALLOC(z));
+  SIZ(z) = size;
+  MPN_COPY (PTR(z), p, size);
+}
+
+
+/* Find least significant limb position where p1,size and p2,size differ.  */
+mp_size_t
+mpn_diff_lowest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = 0; i < size; i++)
+    if (p1[i] != p2[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+/* Find most significant limb position where p1,size and p2,size differ.  */
+mp_size_t
+mpn_diff_highest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = size-1; i >= 0; i--)
+    if (p1[i] != p2[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+/* Find least significant byte position where p1,size and p2,size differ.  */
+mp_size_t
+byte_diff_lowest (const void *p1, const void *p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = 0; i < size; i++)
+    if (((const char *) p1)[i] != ((const char *) p2)[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+/* Find most significant byte position where p1,size and p2,size differ.  */
+mp_size_t
+byte_diff_highest (const void *p1, const void *p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = size-1; i >= 0; i--)
+    if (((const char *) p1)[i] != ((const char *) p2)[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+void
+mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
+{
+  if (mpz_set_str (z, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR: mpz_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+void
+mpq_set_str_or_abort (mpq_ptr q, const char *str, int base)
+{
+  if (mpq_set_str (q, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR: mpq_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+void
+mpf_set_str_or_abort (mpf_ptr f, const char *str, int base)
+{
+  if (mpf_set_str (f, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR mpf_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+
+/* Whether the absolute value of z is a power of 2. */
+int
+mpz_pow2abs_p (mpz_srcptr z)
+{
+  mp_size_t  size, i;
+  mp_srcptr  ptr;
+
+  size = SIZ (z);
+  if (size == 0)
+    return 0;  /* zero is not a power of 2 */
+  size = ABS (size);
+
+  ptr = PTR (z);
+  for (i = 0; i < size-1; i++)
+    if (ptr[i] != 0)
+      return 0;  /* non-zero low limb means not a power of 2 */
+
+  return POW2_P (ptr[i]);  /* high limb power of 2 */
+}
+
+
+/* Exponentially distributed between 0 and 2^nbits-1, meaning the number of
+   bits in the result is uniformly distributed between 0 and nbits-1.
+
+   FIXME: This is not a proper exponential distribution, since the
+   probability function will have a stepped shape due to using a uniform
+   distribution after choosing how many bits.  */
+
+void
+mpz_erandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_urandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
+}
+
+void
+mpz_erandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_erandomb (rop, rstate, nbits);
+  if (mpz_sgn (rop) == 0)
+    mpz_set_ui (rop, 1L);
+}
+
+void
+mpz_errandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_rrandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
+}
+
+void
+mpz_errandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_errandomb (rop, rstate, nbits);
+  if (mpz_sgn (rop) == 0)
+    mpz_set_ui (rop, 1L);
+}
+
+void
+mpz_negrandom (mpz_ptr rop, gmp_randstate_t rstate)
+{
+  mp_limb_t  n;
+  _gmp_rand (&n, rstate, 1);
+  if (n != 0)
+    mpz_neg (rop, rop);
+}
+
+void
+mpz_clobber(mpz_ptr rop)
+{
+  MPN_ZERO(PTR(rop), ALLOC(rop));
+  PTR(rop)[0] = 0xDEADBEEF;
+  SIZ(rop) = 0xDEFACE;
+}
+
+mp_limb_t
+urandom (void)
+{
+#if GMP_NAIL_BITS == 0
+  mp_limb_t  n;
+  _gmp_rand (&n, RANDS, GMP_LIMB_BITS);
+  return n;
+#else
+  mp_limb_t n[2];
+  _gmp_rand (n, RANDS, GMP_LIMB_BITS);
+  return n[0] + (n[1] << GMP_NUMB_BITS);
+#endif
+}
+
+
+/* Call (*func)() with various random number generators. */
+void
+call_rand_algs (void (*func) (const char *, gmp_randstate_ptr))
+{
+  gmp_randstate_t  rstate;
+  mpz_t            a;
+
+  mpz_init (a);
+
+  gmp_randinit_default (rstate);
+  (*func) ("gmp_randinit_default", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_mt (rstate);
+  (*func) ("gmp_randinit_mt", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_lc_2exp_size (rstate, 8L);
+  (*func) ("gmp_randinit_lc_2exp_size 8", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_lc_2exp_size (rstate, 16L);
+  (*func) ("gmp_randinit_lc_2exp_size 16", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_lc_2exp_size (rstate, 128L);
+  (*func) ("gmp_randinit_lc_2exp_size 128", rstate);
+  gmp_randclear (rstate);
+
+  /* degenerate always zeros */
+  mpz_set_ui (a, 0L);
+  gmp_randinit_lc_2exp (rstate, a, 0L, 8L);
+  (*func) ("gmp_randinit_lc_2exp a=0 c=0 m=8", rstate);
+  gmp_randclear (rstate);
+
+  /* degenerate always FFs */
+  mpz_set_ui (a, 0L);
+  gmp_randinit_lc_2exp (rstate, a, 0xFFL, 8L);
+  (*func) ("gmp_randinit_lc_2exp a=0 c=0xFF m=8", rstate);
+  gmp_randclear (rstate);
+
+  mpz_clear (a);
+}
+
+
+/* Return +infinity if available, or 0 if not.
+   We don't want to use libm, so INFINITY or other system values are not
+   used here.  */
+double
+tests_infinity_d (void)
+{
+#if _GMP_IEEE_FLOATS
+  union ieee_double_extract x;
+  x.s.exp = 2047;
+  x.s.manl = 0;
+  x.s.manh = 0;
+  x.s.sig = 0;
+  return x.d;
+#else
+  return 0;
+#endif
+}
+
+
+/* Return non-zero if d is an infinity (either positive or negative).
+   Don't want libm, so don't use isinf() or other system tests.  */
+int
+tests_isinf (double d)
+{
+#if _GMP_IEEE_FLOATS
+  union ieee_double_extract x;
+  x.d = d;
+  return (x.s.exp == 2047 && x.s.manl == 0 && x.s.manh == 0);
+#else
+  return 0;
+#endif
+}
+
+
+/* Set the hardware floating point rounding mode.  Same mode values as mpfr,
+   namely 0=nearest, 1=tozero, 2=up, 3=down.  Return 1 if successful, 0 if
+   not.  */
+int
+tests_hardware_setround (int mode)
+{
+#if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
+  int  rc;
+  switch (mode) {
+  case 0: rc = 0; break;  /* nearest */
+  case 1: rc = 3; break;  /* tozero  */
+  case 2: rc = 2; break;  /* up      */
+  case 3: rc = 1; break;  /* down    */
+  default:
+    return 0;
+  }
+  x86_fldcw ((x86_fstcw () & ~0xC00) | (rc << 10));
+  return 1;
+#endif
+
+  return 0;
+}
+
+/* Return the hardware floating point rounding mode, or -1 if unknown. */
+int
+tests_hardware_getround (void)
+{
+#if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
+  switch ((x86_fstcw () & ~0xC00) >> 10) {
+  case 0: return 0; break;  /* nearest */
+  case 1: return 3; break;  /* down    */
+  case 2: return 2; break;  /* up      */
+  case 3: return 1; break;  /* tozero  */
+  }
+#endif
+
+  return -1;
+}
+
+
+/* tests_dbl_mant_bits() determines by experiment the number of bits in the
+   mantissa of a "double".  If it's not possible to find a value (perhaps
+   due to the compiler optimizing too aggressively), then return 0.
+
+   This code is used rather than DBL_MANT_DIG from <float.h> since ancient
+   systems like SunOS don't have that file, and since one GNU/Linux ARM
+   system was seen where the float emulation seemed to have only 32 working
+   bits, not the 53 float.h claimed.  */
+
+int
+tests_dbl_mant_bits (void)
+{
+  static int n = -1;
+  volatile double x, y, d;
+
+  if (n != -1)
+    return n;
+
+  n = 1;
+  x = 2.0;
+  for (;;)
+    {
+      /* see if 2^(n+1)+1 can be formed without rounding, if so then
+         continue, if not then "n" is the answer */
+      y = x + 1.0;
+      d = y - x;
+      if (d != 1.0)
+        {
+#if defined (DBL_MANT_DIG) && DBL_RADIX == 2
+          if (n != DBL_MANT_DIG)
+            printf ("Warning, tests_dbl_mant_bits got %d but DBL_MANT_DIG says %d\n", n, DBL_MANT_DIG);
+#endif
+          break;
+        }
+
+      x *= 2;
+      n++;
+
+      if (n > 1000)
+        {
+          printf ("Oops, tests_dbl_mant_bits can't determine mantissa size\n");
+          n = 0;
+          break;
+        }
+    }
+  return n;
+}
+
+
+/* See tests_setjmp_sigfpe in tests.h. */
+
+jmp_buf    tests_sigfpe_target;
+
+RETSIGTYPE
+tests_sigfpe_handler (int sig)
+{
+  longjmp (tests_sigfpe_target, 1);
+}
+
+void
+tests_sigfpe_done (void)
+{
+  signal (SIGFPE, SIG_DFL);
+}
diff --git a/tests/misc/t-locale.c b/tests/misc/t-locale.c
new file mode 100644
index 0000000..c5b0b3c
--- /dev/null
+++ b/tests/misc/t-locale.c
@@ -0,0 +1,197 @@
+/* Test locale support, or attempt to do so.
+
+Copyright 2001, 2002, 2011, 2014, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in glibc langinfo.h */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_NL_TYPES_H
+#include <nl_types.h>  /* for nl_item (on netbsd 1.4.1 at least) */
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for lconv */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+const char *decimal_point;
+
+/* Replace the libc localeconv with one we can manipulate. */
+#if HAVE_LOCALECONV && ! defined __MINGW32__
+struct lconv *
+localeconv (void)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+  static struct lconv  l;
+  l.decimal_point = (char *) decimal_point;
+  return &l;
+}
+#endif
+
+/* Replace the libc nl_langinfo with one we can manipulate. */
+#if HAVE_NL_LANGINFO && ! defined __TERMUX__
+char *
+nl_langinfo (nl_item n)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+#if defined (DECIMAL_POINT)
+  if (n == DECIMAL_POINT)
+    return (char *) decimal_point;
+#endif
+#if defined (RADIXCHAR)
+  if (n == RADIXCHAR)
+    return (char *) decimal_point;
+#endif
+  return (char *) "";
+}
+#endif
+
+void
+check_input (void)
+{
+  static const char *point[] = {
+    ".", ",", "WU", "STR", "ZTV***"
+  };
+
+  static const struct {
+    const char  *str;
+    double      d;
+  } data[] = {
+
+    { "1%s",   1.0 },
+    { "1%s0",  1.0 },
+    { "1%s00", 1.0 },
+
+    { "%s5",    0.5 },
+    { "0%s5",   0.5 },
+    { "00%s5",  0.5 },
+    { "00%s50", 0.5 },
+
+    { "1%s5",    1.5 },
+    { "1%s5e1", 15.0 },
+  };
+
+  int     i, j, neg, ret;
+  char    str[128];
+  mpf_t   f;
+  double  d;
+
+  mpf_init (f);
+
+  for (i = 0; i < numberof (point); i++)
+    {
+      decimal_point = (const char *) point[i];
+
+      for (neg = 0; neg <= 1; neg++)
+        {
+          for (j = 0; j < numberof (data); j++)
+            {
+              strcpy (str, neg ? "-" : "");
+              sprintf (str+strlen(str), data[j].str, decimal_point);
+
+              d = data[j].d;
+              if (neg)
+                d = -d;
+
+              mpf_set_d (f, 123.0);
+              if (mpf_set_str (f, str, 10) != 0)
+                {
+                  printf ("mpf_set_str error\n");
+                  printf ("  point  %s\n", decimal_point);
+                  printf ("  str    %s\n", str);
+                  abort ();
+                }
+              if (mpf_cmp_d (f, d) != 0)
+                {
+                  printf    ("mpf_set_str wrong result\n");
+                  printf    ("  point  %s\n", decimal_point);
+                  printf    ("  str    %s\n", str);
+                  mpf_trace ("  f", f);
+                  printf    ("  d=%g\n", d);
+                  abort ();
+                }
+
+              mpf_set_d (f, 123.0);
+              ret = gmp_sscanf (str, "%Ff", f);
+              if (ret != 1)
+                {
+                  printf ("gmp_sscanf wrong return value\n");
+                  printf ("  point  %s\n", decimal_point);
+                  printf ("  str    %s\n", str);
+                  printf ("  ret    %d\n", ret);
+                  abort ();
+                }
+              if (mpf_cmp_d (f, d) != 0)
+                {
+                  printf    ("gmp_sscanf wrong result\n");
+                  printf    ("  point  %s\n", decimal_point);
+                  printf    ("  str    %s\n", str);
+                  mpf_trace ("  f", f);
+                  printf    ("  d=%g\n", d);
+                  abort ();
+                }
+            }
+        }
+    }
+  mpf_clear (f);
+}
+
+int
+main (void)
+{
+  /* The localeconv replacement breaks printf "%lu" on SunOS 4, so we can't
+     print the seed in tests_rand_start().  Nothing random is used in this
+     program though, so just use the memory tests alone.  */
+  tests_memory_start ();
+
+  {
+    mpf_t  f;
+    char   buf[128];
+    mpf_init (f);
+    decimal_point = ",";
+    mpf_set_d (f, 1.5);
+    gmp_snprintf (buf, sizeof(buf), "%.1Ff", f);
+    mpf_clear (f);
+    if (strcmp (buf, "1,5") != 0)
+      {
+        printf ("Test skipped, replacing localeconv/nl_langinfo doesn't work\n");
+        goto done;
+      }
+  }
+
+  check_input ();
+
+ done:
+  tests_memory_end ();
+  exit (0);
+}
diff --git a/tests/misc/t-printf.c b/tests/misc/t-printf.c
new file mode 100644
index 0000000..e13a23e
--- /dev/null
+++ b/tests/misc/t-printf.c
@@ -0,0 +1,955 @@
+/* Test gmp_printf and related functions.
+
+Copyright 2001-2003, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: t-printf [-s]
+
+   -s  Check the data against the system printf, where possible.  This is
+       only an option since we don't want to fail if the system printf is
+       faulty or strange.  */
+
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+#include <stddef.h>    /* for ptrdiff_t */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_OBSTACK_VPRINTF
+#define obstack_chunk_alloc tests_allocate
+#define obstack_chunk_free  tests_free_nosize
+#include <obstack.h>
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+int   option_check_printf = 0;
+
+
+#define CHECK_VFPRINTF_FILENAME  "/tmp/t-printf.tmp"
+FILE  *check_vfprintf_fp;
+
+
+/* From any of the tests run here. */
+#define MAX_OUTPUT  1024
+
+
+void
+check_plain (const char *want, const char *fmt_orig, ...)
+{
+  char        got[MAX_OUTPUT];
+  int         got_len, want_len;
+  size_t      fmtsize;
+  char        *fmt, *q;
+  const char  *p;
+  va_list     ap;
+  va_start (ap, fmt_orig);
+
+  if (! option_check_printf)
+    return;
+
+  fmtsize = strlen (fmt_orig) + 1;
+  fmt = (char *) (*__gmp_allocate_func) (fmtsize);
+
+  for (p = fmt_orig, q = fmt; *p != '\0'; p++)
+    {
+      switch (*p) {
+      case 'a':
+      case 'A':
+	/* The exact value of the exponent isn't guaranteed in glibc, and it
+	   and gmp_printf do slightly different things, so don't compare
+	   directly. */
+	goto done;
+      case 'F':
+	if (p > fmt_orig && *(p-1) == '.')
+	  goto done;  /* don't test the "all digits" cases */
+	/* discard 'F' type */
+	break;
+      case 'Z':
+	/* transmute */
+	*q++ = 'l';
+	break;
+      default:
+	*q++ = *p;
+	break;
+      }
+    }
+  *q = '\0';
+
+  want_len = strlen (want);
+  ASSERT_ALWAYS (want_len < sizeof(got));
+
+  got_len = vsprintf (got, fmt, ap);
+
+  if (got_len != want_len || strcmp (got, want) != 0)
+    {
+      printf ("wanted data doesn't match plain vsprintf\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+
+ done:
+  (*__gmp_free_func) (fmt, fmtsize);
+}
+
+void
+check_vsprintf (const char *want, const char *fmt, va_list ap)
+{
+  char  got[MAX_OUTPUT];
+  int   got_len, want_len;
+
+  want_len = strlen (want);
+  got_len = gmp_vsprintf (got, fmt, ap);
+
+  if (got_len != want_len || strcmp (got, want) != 0)
+    {
+      printf ("gmp_vsprintf wrong\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+}
+
+void
+check_vfprintf (const char *want, const char *fmt, va_list ap)
+{
+  char  got[MAX_OUTPUT];
+  int   got_len, want_len, fread_len;
+  long  ftell_len;
+
+  want_len = strlen (want);
+
+  rewind (check_vfprintf_fp);
+  got_len = gmp_vfprintf (check_vfprintf_fp, fmt, ap);
+  ASSERT_ALWAYS (got_len != -1);
+  ASSERT_ALWAYS (fflush (check_vfprintf_fp) == 0);
+
+  ftell_len = ftell (check_vfprintf_fp);
+  ASSERT_ALWAYS (ftell_len != -1);
+
+  rewind (check_vfprintf_fp);
+  ASSERT_ALWAYS (ftell_len <= sizeof(got));
+  fread_len = fread (got, 1, ftell_len, check_vfprintf_fp);
+
+  if (got_len != want_len
+      || ftell_len != want_len
+      || fread_len != want_len
+      || memcmp (got, want, want_len) != 0)
+    {
+      printf ("gmp_vfprintf wrong\n");
+      printf ("  fmt       |%s|\n", fmt);
+      printf ("  got       |%.*s|\n", fread_len, got);
+      printf ("  want      |%s|\n", want);
+      printf ("  got_len   %d\n", got_len);
+      printf ("  ftell_len %ld\n", ftell_len);
+      printf ("  fread_len %d\n", fread_len);
+      printf ("  want_len  %d\n", want_len);
+      abort ();
+    }
+}
+
+void
+check_vsnprintf (const char *want, const char *fmt, va_list ap)
+{
+  char    got[MAX_OUTPUT+1];
+  int     ret, got_len, want_len;
+  size_t  bufsize;
+
+  want_len = strlen (want);
+
+  bufsize = -1;
+  for (;;)
+    {
+      /* do 0 to 5, then want-5 to want+5 */
+      bufsize++;
+      if (bufsize > 5 && bufsize < want_len-5)
+	bufsize = want_len-5;
+      if (bufsize > want_len + 5)
+	break;
+      ASSERT_ALWAYS (bufsize+1 <= sizeof (got));
+
+      got[bufsize] = '!';
+      ret = gmp_vsnprintf (got, bufsize, fmt, ap);
+
+      got_len = MIN (MAX(1,bufsize)-1, want_len);
+
+      if (got[bufsize] != '!')
+	{
+	  printf ("gmp_vsnprintf overwrote bufsize sentinel\n");
+	  goto error;
+	}
+
+      if (ret != want_len)
+	{
+	  printf ("gmp_vsnprintf return value wrong\n");
+	  goto error;
+	}
+
+      if (bufsize > 0)
+	{
+	  if (memcmp (got, want, got_len) != 0 || got[got_len] != '\0')
+	    {
+	      printf ("gmp_vsnprintf wrong result string\n");
+	    error:
+	      printf ("  fmt       |%s|\n", fmt);
+	      printf ("  bufsize   %lu\n", (unsigned long) bufsize);
+	      printf ("  got       |%s|\n", got);
+	      printf ("  want      |%.*s|\n", got_len, want);
+	      printf ("  want full |%s|\n", want);
+	      printf ("  ret       %d\n", ret);
+	      printf ("  want_len  %d\n", want_len);
+	      abort ();
+	    }
+	}
+    }
+}
+
+void
+check_vasprintf (const char *want, const char *fmt, va_list ap)
+{
+  char  *got;
+  int   got_len, want_len;
+
+  want_len = strlen (want);
+  got_len = gmp_vasprintf (&got, fmt, ap);
+
+  if (got_len != want_len || strcmp (got, want) != 0)
+    {
+      printf ("gmp_vasprintf wrong\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+  (*__gmp_free_func) (got, strlen(got)+1);
+}
+
+void
+check_obstack_vprintf (const char *want, const char *fmt, va_list ap)
+{
+#if HAVE_OBSTACK_VPRINTF
+  struct obstack  ob;
+  int   got_len, want_len, ob_len;
+  char  *got;
+
+  want_len = strlen (want);
+
+  obstack_init (&ob);
+  got_len = gmp_obstack_vprintf (&ob, fmt, ap);
+  got = (char *) obstack_base (&ob);
+  ob_len = obstack_object_size (&ob);
+
+  if (got_len != want_len
+      || ob_len != want_len
+      || memcmp (got, want, want_len) != 0)
+    {
+      printf ("gmp_obstack_vprintf wrong\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  ob_len   %d\n", ob_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+  obstack_free (&ob, NULL);
+#endif
+}
+
+
+void
+check_one (const char *want, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+
+  /* simplest first */
+  check_vsprintf (want, fmt, ap);
+  check_vfprintf (want, fmt, ap);
+  check_vsnprintf (want, fmt, ap);
+  check_vasprintf (want, fmt, ap);
+  check_obstack_vprintf (want, fmt, ap);
+}
+
+
+#define hex_or_octal_p(fmt)             \
+  (strchr (fmt, 'x') != NULL            \
+   || strchr (fmt, 'X') != NULL         \
+   || strchr (fmt, 'o') != NULL)
+
+void
+check_z (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *z;
+    const char  *want;
+  } data[] = {
+    { "%Zd", "0",    "0" },
+    { "%Zd", "1",    "1" },
+    { "%Zd", "123",  "123" },
+    { "%Zd", "-1",   "-1" },
+    { "%Zd", "-123", "-123" },
+
+    { "%+Zd", "0",      "+0" },
+    { "%+Zd", "123",  "+123" },
+    { "%+Zd", "-123", "-123" },
+
+    { "%Zx",  "123",   "7b" },
+    { "%ZX",  "123",   "7B" },
+    { "%Zx", "-123",  "-7b" },
+    { "%ZX", "-123",  "-7B" },
+    { "%Zo",  "123",  "173" },
+    { "%Zo", "-123", "-173" },
+
+    { "%#Zx",    "0",     "0" },
+    { "%#ZX",    "0",     "0" },
+    { "%#Zx",  "123",  "0x7b" },
+    { "%#ZX",  "123",  "0X7B" },
+    { "%#Zx", "-123", "-0x7b" },
+    { "%#ZX", "-123", "-0X7B" },
+
+    { "%#Zo",    "0",     "0" },
+    { "%#Zo",  "123",  "0173" },
+    { "%#Zo", "-123", "-0173" },
+
+    { "%10Zd",      "0", "         0" },
+    { "%10Zd",    "123", "       123" },
+    { "%10Zd",   "-123", "      -123" },
+
+    { "%-10Zd",     "0", "0         " },
+    { "%-10Zd",   "123", "123       " },
+    { "%-10Zd",  "-123", "-123      " },
+
+    { "%+10Zd",   "123", "      +123" },
+    { "%+-10Zd",  "123", "+123      " },
+    { "%+10Zd",  "-123", "      -123" },
+    { "%+-10Zd", "-123", "-123      " },
+
+    { "%08Zd",    "0", "00000000" },
+    { "%08Zd",  "123", "00000123" },
+    { "%08Zd", "-123", "-0000123" },
+
+    { "%+08Zd",    "0", "+0000000" },
+    { "%+08Zd",  "123", "+0000123" },
+    { "%+08Zd", "-123", "-0000123" },
+
+    { "%#08Zx",    "0", "00000000" },
+    { "%#08Zx",  "123", "0x00007b" },
+    { "%#08Zx", "-123", "-0x0007b" },
+
+    { "%+#08Zx",    "0", "+0000000" },
+    { "%+#08Zx",  "123", "+0x0007b" },
+    { "%+#08Zx", "-123", "-0x0007b" },
+
+    { "%.0Zd", "0", "" },
+    { "%.1Zd", "0", "0" },
+    { "%.2Zd", "0", "00" },
+    { "%.3Zd", "0", "000" },
+  };
+
+  int        i, j;
+  mpz_t      z;
+  char       *nfmt;
+  mp_size_t  nsize, zeros;
+
+  mpz_init (z);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (z, data[i].z, 0);
+
+      /* don't try negatives or forced sign in hex or octal */
+      if (mpz_fits_slong_p (z)
+	  && ! (hex_or_octal_p (data[i].fmt)
+		&& (strchr (data[i].fmt, '+') != NULL || mpz_sgn(z) < 0)))
+	{
+	  check_plain (data[i].want, data[i].fmt, mpz_get_si (z));
+	}
+
+      check_one (data[i].want, data[i].fmt, z);
+
+      /* Same again, with %N and possibly some high zero limbs */
+      nfmt = __gmp_allocate_strdup (data[i].fmt);
+      for (j = 0; nfmt[j] != '\0'; j++)
+	if (nfmt[j] == 'Z')
+	  nfmt[j] = 'N';
+      for (zeros = 0; zeros <= 3; zeros++)
+	{
+	  nsize = ABSIZ(z)+zeros;
+	  MPZ_REALLOC (z, nsize);
+	  nsize = (SIZ(z) >= 0 ? nsize : -nsize);
+	  refmpn_zero (PTR(z)+ABSIZ(z), zeros);
+	  check_one (data[i].want, nfmt, PTR(z), nsize);
+	}
+      __gmp_free_func (nfmt, strlen(nfmt)+1);
+    }
+
+  mpz_clear (z);
+}
+
+void
+check_q (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *q;
+    const char  *want;
+  } data[] = {
+    { "%Qd",    "0",    "0" },
+    { "%Qd",    "1",    "1" },
+    { "%Qd",  "123",  "123" },
+    { "%Qd",   "-1",   "-1" },
+    { "%Qd", "-123", "-123" },
+    { "%Qd",  "3/2",  "3/2" },
+    { "%Qd", "-3/2", "-3/2" },
+
+    { "%+Qd", "0",      "+0" },
+    { "%+Qd", "123",  "+123" },
+    { "%+Qd", "-123", "-123" },
+    { "%+Qd", "5/8",  "+5/8" },
+    { "%+Qd", "-5/8", "-5/8" },
+
+    { "%Qx",  "123",   "7b" },
+    { "%QX",  "123",   "7B" },
+    { "%Qx",  "15/16", "f/10" },
+    { "%QX",  "15/16", "F/10" },
+    { "%Qx", "-123",  "-7b" },
+    { "%QX", "-123",  "-7B" },
+    { "%Qx", "-15/16", "-f/10" },
+    { "%QX", "-15/16", "-F/10" },
+    { "%Qo",  "123",  "173" },
+    { "%Qo", "-123", "-173" },
+    { "%Qo",  "16/17",  "20/21" },
+    { "%Qo", "-16/17", "-20/21" },
+
+    { "%#Qx",    "0",     "0" },
+    { "%#QX",    "0",     "0" },
+    { "%#Qx",  "123",  "0x7b" },
+    { "%#QX",  "123",  "0X7B" },
+    { "%#Qx",  "5/8",  "0x5/0x8" },
+    { "%#QX",  "5/8",  "0X5/0X8" },
+    { "%#Qx", "-123", "-0x7b" },
+    { "%#QX", "-123", "-0X7B" },
+    { "%#Qx", "-5/8", "-0x5/0x8" },
+    { "%#QX", "-5/8", "-0X5/0X8" },
+    { "%#Qo",    "0",     "0" },
+    { "%#Qo",  "123",  "0173" },
+    { "%#Qo", "-123", "-0173" },
+    { "%#Qo",  "5/7",  "05/07" },
+    { "%#Qo", "-5/7", "-05/07" },
+
+    /* zero denominator and showbase */
+    { "%#10Qo", "0/0",     "       0/0" },
+    { "%#10Qd", "0/0",     "       0/0" },
+    { "%#10Qx", "0/0",     "       0/0" },
+    { "%#10Qo", "123/0",   "    0173/0" },
+    { "%#10Qd", "123/0",   "     123/0" },
+    { "%#10Qx", "123/0",   "    0x7b/0" },
+    { "%#10QX", "123/0",   "    0X7B/0" },
+    { "%#10Qo", "-123/0",  "   -0173/0" },
+    { "%#10Qd", "-123/0",  "    -123/0" },
+    { "%#10Qx", "-123/0",  "   -0x7b/0" },
+    { "%#10QX", "-123/0",  "   -0X7B/0" },
+
+    { "%10Qd",      "0", "         0" },
+    { "%-10Qd",     "0", "0         " },
+    { "%10Qd",    "123", "       123" },
+    { "%-10Qd",   "123", "123       " },
+    { "%10Qd",   "-123", "      -123" },
+    { "%-10Qd",  "-123", "-123      " },
+
+    { "%+10Qd",   "123", "      +123" },
+    { "%+-10Qd",  "123", "+123      " },
+    { "%+10Qd",  "-123", "      -123" },
+    { "%+-10Qd", "-123", "-123      " },
+
+    { "%08Qd",    "0", "00000000" },
+    { "%08Qd",  "123", "00000123" },
+    { "%08Qd", "-123", "-0000123" },
+
+    { "%+08Qd",    "0", "+0000000" },
+    { "%+08Qd",  "123", "+0000123" },
+    { "%+08Qd", "-123", "-0000123" },
+
+    { "%#08Qx",    "0", "00000000" },
+    { "%#08Qx",  "123", "0x00007b" },
+    { "%#08Qx", "-123", "-0x0007b" },
+
+    { "%+#08Qx",    "0", "+0000000" },
+    { "%+#08Qx",  "123", "+0x0007b" },
+    { "%+#08Qx", "-123", "-0x0007b" },
+  };
+
+  int    i;
+  mpq_t  q;
+
+  mpq_init (q);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (q, data[i].q, 0);
+      check_one (data[i].want, data[i].fmt, q);
+    }
+
+  mpq_clear (q);
+}
+
+void
+check_f (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *f;
+    const char  *want;
+
+  } data[] = {
+
+    { "%Ff",    "0",    "0.000000" },
+    { "%Ff",  "123",  "123.000000" },
+    { "%Ff", "-123", "-123.000000" },
+
+    { "%+Ff",    "0",   "+0.000000" },
+    { "%+Ff",  "123", "+123.000000" },
+    { "%+Ff", "-123", "-123.000000" },
+
+    { "%.0Ff",    "0",    "0" },
+    { "%.0Ff",  "123",  "123" },
+    { "%.0Ff", "-123", "-123" },
+
+    { "%8.0Ff",    "0", "       0" },
+    { "%8.0Ff",  "123", "     123" },
+    { "%8.0Ff", "-123", "    -123" },
+
+    { "%08.0Ff",    "0", "00000000" },
+    { "%08.0Ff",  "123", "00000123" },
+    { "%08.0Ff", "-123", "-0000123" },
+
+    { "%10.2Ff",       "0", "      0.00" },
+    { "%10.2Ff",    "0.25", "      0.25" },
+    { "%10.2Ff",  "123.25", "    123.25" },
+    { "%10.2Ff", "-123.25", "   -123.25" },
+
+    { "%-10.2Ff",       "0", "0.00      " },
+    { "%-10.2Ff",    "0.25", "0.25      " },
+    { "%-10.2Ff",  "123.25", "123.25    " },
+    { "%-10.2Ff", "-123.25", "-123.25   " },
+
+    { "%.2Ff", "0.00000000000001", "0.00" },
+    { "%.2Ff", "0.002",            "0.00" },
+    { "%.2Ff", "0.008",            "0.01" },
+
+    { "%.0Ff", "123.00000000000001", "123" },
+    { "%.0Ff", "123.2",              "123" },
+    { "%.0Ff", "123.8",              "124" },
+
+    { "%.0Ff",  "999999.9", "1000000" },
+    { "%.0Ff", "3999999.9", "4000000" },
+
+    { "%Fe",    "0",  "0.000000e+00" },
+    { "%Fe",    "1",  "1.000000e+00" },
+    { "%Fe",  "123",  "1.230000e+02" },
+
+    { "%FE",    "0",  "0.000000E+00" },
+    { "%FE",    "1",  "1.000000E+00" },
+    { "%FE",  "123",  "1.230000E+02" },
+
+    { "%Fe",    "0",  "0.000000e+00" },
+    { "%Fe",    "1",  "1.000000e+00" },
+
+    { "%.0Fe",     "10000000000",    "1e+10" },
+    { "%.0Fe",    "-10000000000",   "-1e+10" },
+
+    { "%.2Fe",     "10000000000",  "1.00e+10" },
+    { "%.2Fe",    "-10000000000", "-1.00e+10" },
+
+    { "%8.0Fe",    "10000000000", "   1e+10" },
+    { "%8.0Fe",   "-10000000000", "  -1e+10" },
+
+    { "%-8.0Fe",   "10000000000", "1e+10   " },
+    { "%-8.0Fe",  "-10000000000", "-1e+10  " },
+
+    { "%12.2Fe",   "10000000000", "    1.00e+10" },
+    { "%12.2Fe",  "-10000000000", "   -1.00e+10" },
+
+    { "%012.2Fe",  "10000000000", "00001.00e+10" },
+    { "%012.2Fe", "-10000000000", "-0001.00e+10" },
+
+    { "%Fg",   "0", "0" },
+    { "%Fg",   "1", "1" },
+    { "%Fg",   "-1", "-1" },
+
+    { "%.0Fg", "0", "0" },
+    { "%.0Fg", "1", "1" },
+    { "%.0Fg", "-1", "-1" },
+
+    { "%.1Fg", "100", "1e+02" },
+    { "%.2Fg", "100", "1e+02" },
+    { "%.3Fg", "100", "100" },
+    { "%.4Fg", "100", "100" },
+
+    { "%Fg", "0.001",    "0.001" },
+    { "%Fg", "0.0001",   "0.0001" },
+    { "%Fg", "0.00001",  "1e-05" },
+    { "%Fg", "0.000001", "1e-06" },
+
+    { "%.4Fg", "1.00000000000001", "1" },
+    { "%.4Fg", "100000000000001",  "1e+14" },
+
+    { "%.4Fg", "12345678", "1.235e+07" },
+
+    { "%Fa", "0","0x0p+0" },
+    { "%FA", "0","0X0P+0" },
+
+    { "%Fa", "1","0x1p+0" },
+    { "%Fa", "65535","0xf.fffp+12" },
+    { "%Fa", "65536","0x1p+16" },
+    { "%F.10a", "65536","0x1.0000000000p+16" },
+    { "%F.1a", "65535","0x1.0p+16" },
+    { "%F.0a", "65535","0x1p+16" },
+
+    { "%.2Ff", "0.99609375", "1.00" },
+    { "%.Ff",  "0.99609375", "0.99609375" },
+    { "%.Fe",  "0.99609375", "9.9609375e-01" },
+    { "%.Fg",  "0.99609375", "0.99609375" },
+    { "%.20Fg",  "1000000", "1000000" },
+    { "%.Fg",  "1000000", "1000000" },
+
+    { "%#.0Ff", "1", "1." },
+    { "%#.0Fe", "1", "1.e+00" },
+    { "%#.0Fg", "1", "1." },
+
+    { "%#.1Ff", "1", "1.0" },
+    { "%#.1Fe", "1", "1.0e+00" },
+    { "%#.1Fg", "1", "1." },
+
+    { "%#.4Ff", "1234", "1234.0000" },
+    { "%#.4Fe", "1234", "1.2340e+03" },
+    { "%#.4Fg", "1234", "1234." },
+
+    { "%#.8Ff", "1234", "1234.00000000" },
+    { "%#.8Fe", "1234", "1.23400000e+03" },
+    { "%#.8Fg", "1234", "1234.0000" },
+
+  };
+
+  int     i;
+  mpf_t   f;
+  double  d;
+
+  mpf_init2 (f, 256L);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      if (data[i].f[0] == '0' && data[i].f[1] == 'x')
+	mpf_set_str_or_abort (f, data[i].f, 16);
+      else
+	mpf_set_str_or_abort (f, data[i].f, 10);
+
+      /* if mpf->double doesn't truncate, then expect same result */
+      d = mpf_get_d (f);
+      if (mpf_cmp_d (f, d) == 0)
+	check_plain (data[i].want, data[i].fmt, d);
+
+      check_one (data[i].want, data[i].fmt, f);
+    }
+
+  mpf_clear (f);
+}
+
+
+void
+check_limb (void)
+{
+  int        i;
+  mp_limb_t  limb;
+  mpz_t      z;
+  char       *s;
+
+  check_one ("0", "%Md", CNST_LIMB(0));
+  check_one ("1", "%Md", CNST_LIMB(1));
+
+  /* "i" many 1 bits, tested against mpz_get_str in decimal and hex */
+  limb = 1;
+  mpz_init_set_ui (z, 1L);
+  for (i = 1; i <= GMP_LIMB_BITS; i++)
+    {
+      s = mpz_get_str (NULL, 10, z);
+      check_one (s, "%Mu", limb);
+      (*__gmp_free_func) (s, strlen (s) + 1);
+
+      s = mpz_get_str (NULL, 16, z);
+      check_one (s, "%Mx", limb);
+      (*__gmp_free_func) (s, strlen (s) + 1);
+
+      s = mpz_get_str (NULL, -16, z);
+      check_one (s, "%MX", limb);
+      (*__gmp_free_func) (s, strlen (s) + 1);
+
+      limb = 2*limb + 1;
+      mpz_mul_2exp (z, z, 1L);
+      mpz_add_ui (z, z, 1L);
+    }
+
+  mpz_clear (z);
+}
+
+
+void
+check_n (void)
+{
+  {
+    int  n = -1;
+    check_one ("blah", "%nblah", &n);
+    ASSERT_ALWAYS (n == 0);
+  }
+
+  {
+    int  n = -1;
+    check_one ("hello ", "hello %n", &n);
+    ASSERT_ALWAYS (n == 6);
+  }
+
+  {
+    int  n = -1;
+    check_one ("hello  world", "hello %n world", &n);
+    ASSERT_ALWAYS (n == 6);
+  }
+
+#define CHECK_N(type, string)                           \
+  do {                                                  \
+    type  x[2];                                         \
+    char  fmt[128];                                     \
+							\
+    x[0] = ~ (type) 0;                                  \
+    x[1] = ~ (type) 0;                                  \
+    sprintf (fmt, "%%d%%%sn%%d", string);               \
+    check_one ("123456", fmt, 123, &x[0], 456);         \
+							\
+    /* should write whole of x[0] and none of x[1] */   \
+    ASSERT_ALWAYS (x[0] == 3);                          \
+    ASSERT_ALWAYS (x[1] == (type) ~ (type) 0);		\
+							\
+  } while (0)
+
+  CHECK_N (mp_limb_t, "M");
+  CHECK_N (char,      "hh");
+  CHECK_N (long,      "l");
+#if HAVE_LONG_LONG
+  CHECK_N (long long, "L");
+#endif
+#if HAVE_INTMAX_T
+  CHECK_N (intmax_t,  "j");
+#endif
+#if HAVE_PTRDIFF_T
+  CHECK_N (ptrdiff_t, "t");
+#endif
+  CHECK_N (short,     "h");
+  CHECK_N (size_t,    "z");
+
+  {
+    mpz_t  x[2];
+    mpz_init_set_si (x[0], -987L);
+    mpz_init_set_si (x[1],  654L);
+    check_one ("123456", "%d%Zn%d", 123, x[0], 456);
+    MPZ_CHECK_FORMAT (x[0]);
+    MPZ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
+    mpz_clear (x[0]);
+    mpz_clear (x[1]);
+  }
+
+  {
+    mpq_t  x[2];
+    mpq_init (x[0]);
+    mpq_init (x[1]);
+    mpq_set_ui (x[0], 987L, 654L);
+    mpq_set_ui (x[1], 4115L, 226L);
+    check_one ("123456", "%d%Qn%d", 123, x[0], 456);
+    MPQ_CHECK_FORMAT (x[0]);
+    MPQ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
+    mpq_clear (x[0]);
+    mpq_clear (x[1]);
+  }
+
+  {
+    mpf_t  x[2];
+    mpf_init (x[0]);
+    mpf_init (x[1]);
+    mpf_set_ui (x[0], 987L);
+    mpf_set_ui (x[1], 654L);
+    check_one ("123456", "%d%Fn%d", 123, x[0], 456);
+    MPF_CHECK_FORMAT (x[0]);
+    MPF_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
+    mpf_clear (x[0]);
+    mpf_clear (x[1]);
+  }
+
+  {
+    mp_limb_t  a[5];
+    mp_limb_t  a_want[numberof(a)];
+    mp_size_t  i;
+
+    a[0] = 123;
+    check_one ("blah", "bl%Nnah", a, (mp_size_t) 0);
+    ASSERT_ALWAYS (a[0] == 123);
+
+    MPN_ZERO (a_want, numberof (a_want));
+    for (i = 1; i < numberof (a); i++)
+      {
+	check_one ("blah", "bl%Nnah", a, i);
+	a_want[0] = 2;
+	ASSERT_ALWAYS (mpn_cmp (a, a_want, i) == 0);
+      }
+  }
+}
+
+
+void
+check_misc (void)
+{
+  mpz_t  z;
+  mpf_t  f;
+
+  mpz_init (z);
+  mpf_init2 (f, 128L);
+
+  check_one ("!", "%c", '!');
+
+  check_one ("hello world", "hello %s", "world");
+  check_one ("hello:", "%s:", "hello");
+  mpz_set_ui (z, 0L);
+  check_one ("hello0", "%s%Zd", "hello", z, z);
+
+  {
+    static char  xs[801];
+    memset (xs, 'x', sizeof(xs)-1);
+    check_one (xs, "%s", xs);
+  }
+  {
+    char  *xs;
+    xs = (char *) (*__gmp_allocate_func) (MAX_OUTPUT * 2 - 12);
+    memset (xs, '%', MAX_OUTPUT * 2 - 14);
+    xs [MAX_OUTPUT * 2 - 13] = '\0';
+    xs [MAX_OUTPUT * 2 - 14] = 'x';
+    check_one (xs + MAX_OUTPUT - 7, xs, NULL);
+    (*__gmp_free_func) (xs, MAX_OUTPUT * 2 - 12);
+  }
+
+  mpz_set_ui (z, 12345L);
+  check_one ("     12345", "%*Zd", 10, z);
+  check_one ("0000012345", "%0*Zd", 10, z);
+  check_one ("12345     ", "%*Zd", -10, z);
+  check_one ("12345 and 678", "%Zd and %d", z, 678);
+  check_one ("12345,1,12345,2,12345", "%Zd,%d,%Zd,%d,%Zd", z, 1, z, 2, z);
+
+  /* from the glibc info docs */
+  mpz_set_si (z, 0L);
+  check_one ("|    0|0    |   +0|+0   |    0|00000|     |   00|0|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, 1L);
+  check_one ("|    1|1    |   +1|+1   |    1|00001|    1|   01|1|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, -1L);
+  check_one ("|   -1|-1   |   -1|-1   |   -1|-0001|   -1|  -01|-1|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, 100000L);
+  check_one ("|100000|100000|+100000|+100000| 100000|100000|100000|100000|100000|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, 0L);
+  check_one ("|    0|    0|    0|    0|    0|    0|  00000000|",
+	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
+	     /**/ z,   z,   z,    z,    z,    z,       z);
+  mpz_set_si (z, 1L);
+  check_one ("|    1|    1|    1|   01|  0x1|  0X1|0x00000001|",
+	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
+	     /**/ z,   z,   z,    z,    z,    z,       z);
+  mpz_set_si (z, 100000L);
+  check_one ("|303240|186a0|186A0|0303240|0x186a0|0X186A0|0x000186a0|",
+	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
+	     /**/ z,   z,   z,    z,    z,    z,       z);
+
+  /* %zd for size_t won't be available on old systems, and running something
+     to see if it works might be bad, so only try it on glibc, and only on a
+     new enough version (glibc 2.0 doesn't have %zd) */
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
+  mpz_set_ui (z, 789L);
+  check_one ("456 789 blah", "%zd %Zd blah", (size_t) 456, z);
+#endif
+
+  mpz_clear (z);
+  mpf_clear (f);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_check_printf = 1;
+
+  tests_start ();
+  check_vfprintf_fp = fopen (CHECK_VFPRINTF_FILENAME, "w+");
+  ASSERT_ALWAYS (check_vfprintf_fp != NULL);
+
+  check_z ();
+  check_q ();
+  check_f ();
+  check_limb ();
+  check_n ();
+  check_misc ();
+
+  ASSERT_ALWAYS (fclose (check_vfprintf_fp) == 0);
+  unlink (CHECK_VFPRINTF_FILENAME);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/misc/t-scanf.c b/tests/misc/t-scanf.c
new file mode 100644
index 0000000..8c25533
--- /dev/null
+++ b/tests/misc/t-scanf.c
@@ -0,0 +1,1615 @@
+/* Test gmp_scanf and related functions.
+
+Copyright 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: t-scanf [-s]
+
+   -s  Check the data against the system scanf, where possible.  This is
+       only an option since we don't want to fail if the system scanf is
+       faulty or strange.
+
+   There's some fairly unattractive repetition between check_z, check_q and
+   check_f, but enough differences to make a common loop or a set of macros
+   seem like too much trouble. */
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+
+#include <stddef.h>    /* for ptrdiff_t */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define TEMPFILE  "/tmp/t-scanf.tmp"
+
+int   option_libc_scanf = 0;
+
+typedef int (*fun_t) (const char *, const char *, void *, void *);
+
+
+/* This problem was seen on powerpc7450-apple-darwin7.0.0, sscanf returns 0
+   where it should return EOF.  A workaround in gmp_sscanf would be a bit
+   tedious, and since this is a rather obvious libc bug, quite likely
+   affecting other programs, we'll just suppress affected tests for now.  */
+int
+test_sscanf_eof_ok (void)
+{
+  static int  result = -1;
+
+  if (result == -1)
+    {
+      int  x;
+      if (sscanf ("", "%d", &x) == EOF)
+        {
+          result = 1;
+        }
+      else
+        {
+          printf ("Warning, sscanf(\"\",\"%%d\",&x) doesn't return EOF.\n");
+          printf ("This affects gmp_sscanf, tests involving it will be suppressed.\n");
+          printf ("You should try to get a fix for your libc.\n");
+          result = 0;
+        }
+    }
+  return result;
+}
+
+
+/* Convert fmt from a GMP scanf format string to an equivalent for a plain
+   libc scanf, for example "%Zd" becomes "%ld".  Return 1 if this succeeds,
+   0 if it cannot (or should not) be done.  */
+int
+libc_scanf_convert (char *fmt)
+{
+  char  *p = fmt;
+
+  if (! option_libc_scanf)
+    return 0;
+
+  for ( ; *fmt != '\0'; fmt++)
+    {
+      switch (*fmt) {
+      case 'F':
+      case 'Q':
+      case 'Z':
+        /* transmute */
+        *p++ = 'l';
+        break;
+      default:
+        *p++ = *fmt;
+        break;
+      }
+    }
+  *p = '\0';
+  return 1;
+}
+
+
+long  got_ftell;
+int   fromstring_next_c;
+
+/* Call gmp_fscanf, reading the "input" string data provided. */
+int
+fromstring_gmp_fscanf (const char *input, const char *fmt, ...)
+{
+  va_list  ap;
+  FILE     *fp;
+  int      ret;
+  va_start (ap, fmt);
+
+  fp = fopen (TEMPFILE, "w+");
+  ASSERT_ALWAYS (fp != NULL);
+  ASSERT_ALWAYS (fputs (input, fp) != EOF);
+  ASSERT_ALWAYS (fflush (fp) == 0);
+  rewind (fp);
+
+  ret = gmp_vfscanf (fp, fmt, ap);
+  got_ftell = ftell (fp);
+  ASSERT_ALWAYS (got_ftell != -1L);
+
+  fromstring_next_c = getc (fp);
+
+  ASSERT_ALWAYS (fclose (fp) == 0);
+  va_end (ap);
+  return ret;
+}
+
+
+int
+fun_gmp_sscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  if (a2 == NULL)
+    return gmp_sscanf (input, fmt, a1);
+  else
+    return gmp_sscanf (input, fmt, a1, a2);
+}
+
+int
+fun_gmp_fscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  if (a2 == NULL)
+    return fromstring_gmp_fscanf (input, fmt, a1);
+  else
+    return fromstring_gmp_fscanf (input, fmt, a1, a2);
+}
+
+
+int
+fun_fscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  FILE  *fp;
+  int   ret;
+
+  fp = fopen (TEMPFILE, "w+");
+  ASSERT_ALWAYS (fp != NULL);
+  ASSERT_ALWAYS (fputs (input, fp) != EOF);
+  ASSERT_ALWAYS (fflush (fp) == 0);
+  rewind (fp);
+
+  if (a2 == NULL)
+    ret = fscanf (fp, fmt, a1);
+  else
+    ret = fscanf (fp, fmt, a1, a2);
+
+  got_ftell = ftell (fp);
+  ASSERT_ALWAYS (got_ftell != -1L);
+
+  fromstring_next_c = getc (fp);
+
+  ASSERT_ALWAYS (fclose (fp) == 0);
+  return ret;
+}
+
+
+/* On various old systems, for instance HP-UX 9, the C library sscanf needs
+   to be able to write into the input string.  Ensure that this is possible,
+   when gcc is putting the test data into a read-only section.
+
+   Actually we ought to only need this under SSCANF_WRITABLE_INPUT from
+   configure, but it's just as easy to do it unconditionally, and in any
+   case this code is only executed under the -s option.  */
+
+int
+fun_sscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  char    *input_writable;
+  size_t  size;
+  int     ret;
+
+  size = strlen (input) + 1;
+  input_writable = (char *) (*__gmp_allocate_func) (size);
+  memcpy (input_writable, input, size);
+
+  if (a2 == NULL)
+    ret = sscanf (input_writable, fmt, a1);
+  else
+    ret = sscanf (input_writable, fmt, a1, a2);
+
+  (*__gmp_free_func) (input_writable, size);
+  return ret;
+}
+
+
+/* whether the format string consists entirely of ignored fields */
+int
+fmt_allignore (const char *fmt)
+{
+  int  saw_star = 1;
+  for ( ; *fmt != '\0'; fmt++)
+    {
+      switch (*fmt) {
+      case '%':
+        if (! saw_star)
+          return 0;
+        saw_star = 0;
+        break;
+      case '*':
+        saw_star = 1;
+        break;
+      }
+    }
+  return 1;
+}
+
+void
+check_z (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *input;
+    const char  *want;
+    int         want_ret;
+    long        want_ftell;
+    int         want_upto;
+    int         not_glibc;
+
+  } data[] = {
+
+    { "%Zd",    "0",    "0", 1, -1, -1 },
+    { "%Zd",    "1",    "1", 1, -1, -1 },
+    { "%Zd",  "123",  "123", 1, -1, -1 },
+    { "%Zd",   "+0",    "0", 1, -1, -1 },
+    { "%Zd",   "+1",    "1", 1, -1, -1 },
+    { "%Zd", "+123",  "123", 1, -1, -1 },
+    { "%Zd",   "-0",    "0", 1, -1, -1 },
+    { "%Zd",   "-1",   "-1", 1, -1, -1 },
+    { "%Zd", "-123", "-123", 1, -1, -1 },
+
+    { "%Zo",    "0",    "0", 1, -1, -1 },
+    { "%Zo",  "173",  "123", 1, -1, -1 },
+    { "%Zo",   "+0",    "0", 1, -1, -1 },
+    { "%Zo", "+173",  "123", 1, -1, -1 },
+    { "%Zo",   "-0",    "0", 1, -1, -1 },
+    { "%Zo", "-173", "-123", 1, -1, -1 },
+
+    { "%Zx",    "0",    "0", 1, -1, -1 },
+    { "%Zx",   "7b",  "123", 1, -1, -1 },
+    { "%Zx",   "7b",  "123", 1, -1, -1 },
+    { "%Zx",   "+0",    "0", 1, -1, -1 },
+    { "%Zx",  "+7b",  "123", 1, -1, -1 },
+    { "%Zx",  "+7b",  "123", 1, -1, -1 },
+    { "%Zx",   "-0",   "-0", 1, -1, -1 },
+    { "%Zx",  "-7b", "-123", 1, -1, -1 },
+    { "%Zx",  "-7b", "-123", 1, -1, -1 },
+    { "%ZX",    "0",    "0", 1, -1, -1 },
+    { "%ZX",   "7b",  "123", 1, -1, -1 },
+    { "%ZX",   "7b",  "123", 1, -1, -1 },
+    { "%ZX",   "+0",    "0", 1, -1, -1 },
+    { "%ZX",  "+7b",  "123", 1, -1, -1 },
+    { "%ZX",  "+7b",  "123", 1, -1, -1 },
+    { "%ZX",   "-0",   "-0", 1, -1, -1 },
+    { "%ZX",  "-7b", "-123", 1, -1, -1 },
+    { "%ZX",  "-7b", "-123", 1, -1, -1 },
+    { "%Zx",    "0",    "0", 1, -1, -1 },
+    { "%Zx",   "7B",  "123", 1, -1, -1 },
+    { "%Zx",   "7B",  "123", 1, -1, -1 },
+    { "%Zx",   "+0",    "0", 1, -1, -1 },
+    { "%Zx",  "+7B",  "123", 1, -1, -1 },
+    { "%Zx",  "+7B",  "123", 1, -1, -1 },
+    { "%Zx",   "-0",   "-0", 1, -1, -1 },
+    { "%Zx",  "-7B", "-123", 1, -1, -1 },
+    { "%Zx",  "-7B", "-123", 1, -1, -1 },
+    { "%ZX",    "0",    "0", 1, -1, -1 },
+    { "%ZX",   "7B",  "123", 1, -1, -1 },
+    { "%ZX",   "7B",  "123", 1, -1, -1 },
+    { "%ZX",   "+0",    "0", 1, -1, -1 },
+    { "%ZX",  "+7B",  "123", 1, -1, -1 },
+    { "%ZX",  "+7B",  "123", 1, -1, -1 },
+    { "%ZX",   "-0",   "-0", 1, -1, -1 },
+    { "%ZX",  "-7B", "-123", 1, -1, -1 },
+    { "%ZX",  "-7B", "-123", 1, -1, -1 },
+
+    { "%Zi",    "0",    "0", 1, -1, -1 },
+    { "%Zi",    "1",    "1", 1, -1, -1 },
+    { "%Zi",  "123",  "123", 1, -1, -1 },
+    { "%Zi",   "+0",    "0", 1, -1, -1 },
+    { "%Zi",   "+1",    "1", 1, -1, -1 },
+    { "%Zi", "+123",  "123", 1, -1, -1 },
+    { "%Zi",   "-0",    "0", 1, -1, -1 },
+    { "%Zi",   "-1",   "-1", 1, -1, -1 },
+    { "%Zi", "-123", "-123", 1, -1, -1 },
+
+    { "%Zi",    "00",    "0", 1, -1, -1 },
+    { "%Zi",  "0173",  "123", 1, -1, -1 },
+    { "%Zi",   "+00",    "0", 1, -1, -1 },
+    { "%Zi", "+0173",  "123", 1, -1, -1 },
+    { "%Zi",   "-00",    "0", 1, -1, -1 },
+    { "%Zi", "-0173", "-123", 1, -1, -1 },
+
+    { "%Zi",    "0x0",    "0", 1, -1, -1 },
+    { "%Zi",   "0x7b",  "123", 1, -1, -1 },
+    { "%Zi",   "0x7b",  "123", 1, -1, -1 },
+    { "%Zi",   "+0x0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0x7b",  "123", 1, -1, -1 },
+    { "%Zi",  "+0x7b",  "123", 1, -1, -1 },
+    { "%Zi",   "-0x0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0x7b", "-123", 1, -1, -1 },
+    { "%Zi",  "-0x7b", "-123", 1, -1, -1 },
+    { "%Zi",    "0X0",    "0", 1, -1, -1 },
+    { "%Zi",   "0X7b",  "123", 1, -1, -1 },
+    { "%Zi",   "0X7b",  "123", 1, -1, -1 },
+    { "%Zi",   "+0X0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0X7b",  "123", 1, -1, -1 },
+    { "%Zi",  "+0X7b",  "123", 1, -1, -1 },
+    { "%Zi",   "-0X0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0X7b", "-123", 1, -1, -1 },
+    { "%Zi",  "-0X7b", "-123", 1, -1, -1 },
+    { "%Zi",    "0x0",    "0", 1, -1, -1 },
+    { "%Zi",   "0x7B",  "123", 1, -1, -1 },
+    { "%Zi",   "0x7B",  "123", 1, -1, -1 },
+    { "%Zi",   "+0x0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0x7B",  "123", 1, -1, -1 },
+    { "%Zi",  "+0x7B",  "123", 1, -1, -1 },
+    { "%Zi",   "-0x0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0x7B", "-123", 1, -1, -1 },
+    { "%Zi",  "-0x7B", "-123", 1, -1, -1 },
+    { "%Zi",    "0X0",    "0", 1, -1, -1 },
+    { "%Zi",   "0X7B",  "123", 1, -1, -1 },
+    { "%Zi",   "0X7B",  "123", 1, -1, -1 },
+    { "%Zi",   "+0X0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0X7B",  "123", 1, -1, -1 },
+    { "%Zi",  "+0X7B",  "123", 1, -1, -1 },
+    { "%Zi",   "-0X0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0X7B", "-123", 1, -1, -1 },
+    { "%Zi",  "-0X7B", "-123", 1, -1, -1 },
+
+    { "%Zd",    " 0",    "0", 1, -1, -1 },
+    { "%Zd",   "  0",    "0", 1, -1, -1 },
+    { "%Zd",  "   0",    "0", 1, -1, -1 },
+    { "%Zd",   "\t0",    "0", 1, -1, -1 },
+    { "%Zd", "\t\t0",    "0", 1, -1, -1 },
+
+    { "hello%Zd",      "hello0",       "0", 1, -1, -1 },
+    { "hello%Zd",      "hello 0",      "0", 1, -1, -1 },
+    { "hello%Zd",      "hello \t0",    "0", 1, -1, -1 },
+    { "hello%Zdworld", "hello 0world", "0", 1, -1, -1 },
+
+    { "hello%*Zd",      "hello0",       "-999", 0, -1, -1 },
+    { "hello%*Zd",      "hello 0",      "-999", 0, -1, -1 },
+    { "hello%*Zd",      "hello \t0",    "-999", 0, -1, -1 },
+    { "hello%*Zdworld", "hello 0world", "-999", 0, -1, -1 },
+
+    { "%Zd",    "",     "-999", -1, -1, -555 },
+    { "%Zd",    " ",    "-999", -1, -1, -555 },
+    { " %Zd",   "",     "-999", -1, -1, -555 },
+    { "xyz%Zd", "",     "-999", -1, -1, -555 },
+
+    { "%*Zd",    "",     "-999", -1, -1, -555 },
+    { " %*Zd",   "",     "-999", -1, -1, -555 },
+    { "xyz%*Zd", "",     "-999", -1, -1, -555 },
+
+    { "%Zd",    "xyz",  "0",     0, 0, -555 },
+
+    /* match something, but invalid */
+    { "%Zd",    "-",    "-999",  0, 1, -555 },
+    { "%Zd",    "+",    "-999",  0, 1, -555 },
+    { "xyz%Zd", "xyz-", "-999",  0, 4, -555 },
+    { "xyz%Zd", "xyz+", "-999",  0, 4, -555 },
+    { "%Zi",    "0x",   "-999",  0, 2, -555 },
+    { "%Zi",    "0X",   "-999",  0, 2, -555 },
+    { "%Zi",    "0x-",  "-999",  0, 2, -555 },
+    { "%Zi",    "0X+",  "-999",  0, 2, -555 },
+    { "%Zi",    "-0x",  "-999",  0, 3, -555 },
+    { "%Zi",    "-0X",  "-999",  0, 3, -555 },
+    { "%Zi",    "+0x",  "-999",  0, 3, -555 },
+    { "%Zi",    "+0X",  "-999",  0, 3, -555 },
+
+    { "%1Zi",  "1234", "1",    1, 1, 1 },
+    { "%2Zi",  "1234", "12",   1, 2, 2 },
+    { "%3Zi",  "1234", "123",  1, 3, 3 },
+    { "%4Zi",  "1234", "1234", 1, 4, 4 },
+    { "%5Zi",  "1234", "1234", 1, 4, 4 },
+    { "%6Zi",  "1234", "1234", 1, 4, 4 },
+
+    { "%1Zi",  "01234", "0",     1, 1, 1 },
+    { "%2Zi",  "01234", "01",    1, 2, 2 },
+    { "%3Zi",  "01234", "012",   1, 3, 3 },
+    { "%4Zi",  "01234", "0123",  1, 4, 4 },
+    { "%5Zi",  "01234", "01234", 1, 5, 5 },
+    { "%6Zi",  "01234", "01234", 1, 5, 5 },
+    { "%7Zi",  "01234", "01234", 1, 5, 5 },
+
+    { "%1Zi",  "0x1234", "0",      1, 1, 1 },
+    { "%2Zi",  "0x1234", "-999",   0, 2, -555 },
+    { "%3Zi",  "0x1234", "0x1",    1, 3, 3 },
+    { "%4Zi",  "0x1234", "0x12",   1, 4, 4 },
+    { "%5Zi",  "0x1234", "0x123",  1, 5, 5 },
+    { "%6Zi",  "0x1234", "0x1234", 1, 6, 6 },
+    { "%7Zi",  "0x1234", "0x1234", 1, 6, 6 },
+    { "%8Zi",  "0x1234", "0x1234", 1, 6, 6 },
+
+    { "%%xyz%Zd",  "%xyz123",  "123", 1, -1, -1 },
+    { "12%%34%Zd", "12%34567", "567", 1, -1, -1 },
+    { "%%%%%Zd",   "%%123",    "123", 1, -1, -1 },
+
+    /* various subtle EOF cases */
+    { "x",       "",    "-999", EOF, 0, -555 },
+    { " x",      "",    "-999", EOF, 0, -555 },
+    { "xyz",     "",    "-999", EOF, 0, -555 },
+    { " ",       "",    "-999",   0, 0,    0 },
+    { " ",       " ",   "-999",   0, 1,    1 },
+    { "%*Zd%Zd", "",    "-999", EOF, 0, -555 },
+    { "%*Zd%Zd", "123", "-999", EOF, 3, -555 },
+    { "x",       "x",   "-999",   0, 1,    1 },
+    { "xyz",     "x",   "-999", EOF, 1, -555 },
+    { "xyz",     "xy",  "-999", EOF, 2, -555 },
+    { "xyz",     "xyz", "-999",   0, 3,    3 },
+    { "%Zn",     "",    "0",      0, 0,    0 },
+    { " %Zn",    "",    "0",      0, 0,    0 },
+    { " x%Zn",   "",    "-999", EOF, 0, -555 },
+    { "xyz%Zn",  "",    "-999", EOF, 0, -555 },
+    { " x%Zn",   "",    "-999", EOF, 0, -555 },
+    { " %Zn x",  " ",   "-999", EOF, 1, -555 },
+
+    /* these seem to tickle a bug in glibc 2.2.4 */
+    { " x",      " ",   "-999", EOF, 1, -555, 1 },
+    { " xyz",    " ",   "-999", EOF, 1, -555, 1 },
+    { " x%Zn",   " ",   "-999", EOF, 1, -555, 1 },
+  };
+
+  int         i, j, ignore;
+  int         got_ret, want_ret, got_upto, want_upto;
+  mpz_t       got, want;
+  long        got_l, want_ftell;
+  int         error = 0;
+  fun_t       fun;
+  const char  *name;
+  char        fmt[128];
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (want, data[i].want, 0);
+
+      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
+      strcpy (fmt, data[i].fmt);
+      strcat (fmt, "%n");
+
+      ignore = fmt_allignore (fmt);
+
+      for (j = 0; j <= 3; j++)
+        {
+          want_ret = data[i].want_ret;
+
+          want_ftell = data[i].want_ftell;
+          if (want_ftell == -1)
+            want_ftell = strlen (data[i].input);
+
+          want_upto = data[i].want_upto;
+          if (want_upto == -1)
+            want_upto = strlen (data[i].input);
+
+          switch (j) {
+          case 0:
+            name = "gmp_sscanf";
+            fun = fun_gmp_sscanf;
+            break;
+          case 1:
+            name = "gmp_fscanf";
+            fun = fun_gmp_fscanf;
+            break;
+          case 2:
+#ifdef __GLIBC__
+            if (data[i].not_glibc)
+              continue;
+#endif
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard sscanf";
+            fun = fun_sscanf;
+            break;
+          case 3:
+#ifdef __GLIBC__
+            if (data[i].not_glibc)
+              continue;
+#endif
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard fscanf";
+            fun = fun_fscanf;
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          got_upto = -555;
+          got_ftell = -1L;
+
+          switch (j) {
+          case 0:
+          case 1:
+            mpz_set_si (got, -999L);
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
+            break;
+          case 2:
+          case 3:
+            got_l = -999L;
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto);
+            mpz_set_si (got, got_l);
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          MPZ_CHECK_FORMAT (got);
+
+          if (got_ret != want_ret)
+            {
+              printf ("%s wrong return value\n", name);
+              error = 1;
+            }
+          if (want_ret == 1 && mpz_cmp (want, got) != 0)
+            {
+              printf ("%s wrong result\n", name);
+              error = 1;
+            }
+          if (got_upto != want_upto)
+            {
+              printf ("%s wrong upto\n", name);
+              error = 1;
+            }
+          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
+            {
+              printf ("%s wrong ftell\n", name);
+              error = 1;
+            }
+          if (error)
+            {
+              printf    ("  fmt   \"%s\"\n", data[i].fmt);
+              printf    ("  input \"%s\"\n", data[i].input);
+              printf    ("  ignore %d\n", ignore);
+              printf    ("  ret   want=%d\n", want_ret);
+              printf    ("        got =%d\n", got_ret);
+              mpz_trace ("  value want", want);
+              mpz_trace ("        got ", got);
+              printf    ("  upto  want =%d\n", want_upto);
+              printf    ("        got  =%d\n", got_upto);
+              if (got_ftell != -1)
+                {
+                  printf    ("  ftell want =%ld\n", want_ftell);
+                  printf    ("        got  =%ld\n", got_ftell);
+                }
+              abort ();
+            }
+        }
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+void
+check_q (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *input;
+    const char  *want;
+    int         ret;
+    long        ftell;
+
+  } data[] = {
+
+    { "%Qd",    "0",    "0", 1, -1 },
+    { "%Qd",    "1",    "1", 1, -1 },
+    { "%Qd",  "123",  "123", 1, -1 },
+    { "%Qd",   "+0",    "0", 1, -1 },
+    { "%Qd",   "+1",    "1", 1, -1 },
+    { "%Qd", "+123",  "123", 1, -1 },
+    { "%Qd",   "-0",    "0", 1, -1 },
+    { "%Qd",   "-1",   "-1", 1, -1 },
+    { "%Qd", "-123", "-123", 1, -1 },
+
+    { "%Qo",    "0",    "0", 1, -1 },
+    { "%Qo",  "173",  "123", 1, -1 },
+    { "%Qo",   "+0",    "0", 1, -1 },
+    { "%Qo", "+173",  "123", 1, -1 },
+    { "%Qo",   "-0",    "0", 1, -1 },
+    { "%Qo", "-173", "-123", 1, -1 },
+
+    { "%Qx",    "0",    "0", 1, -1 },
+    { "%Qx",   "7b",  "123", 1, -1 },
+    { "%Qx",   "7b",  "123", 1, -1 },
+    { "%Qx",   "+0",    "0", 1, -1 },
+    { "%Qx",  "+7b",  "123", 1, -1 },
+    { "%Qx",  "+7b",  "123", 1, -1 },
+    { "%Qx",   "-0",   "-0", 1, -1 },
+    { "%Qx",  "-7b", "-123", 1, -1 },
+    { "%Qx",  "-7b", "-123", 1, -1 },
+    { "%QX",    "0",    "0", 1, -1 },
+    { "%QX",   "7b",  "123", 1, -1 },
+    { "%QX",   "7b",  "123", 1, -1 },
+    { "%QX",   "+0",    "0", 1, -1 },
+    { "%QX",  "+7b",  "123", 1, -1 },
+    { "%QX",  "+7b",  "123", 1, -1 },
+    { "%QX",   "-0",   "-0", 1, -1 },
+    { "%QX",  "-7b", "-123", 1, -1 },
+    { "%QX",  "-7b", "-123", 1, -1 },
+    { "%Qx",    "0",    "0", 1, -1 },
+    { "%Qx",   "7B",  "123", 1, -1 },
+    { "%Qx",   "7B",  "123", 1, -1 },
+    { "%Qx",   "+0",    "0", 1, -1 },
+    { "%Qx",  "+7B",  "123", 1, -1 },
+    { "%Qx",  "+7B",  "123", 1, -1 },
+    { "%Qx",   "-0",   "-0", 1, -1 },
+    { "%Qx",  "-7B", "-123", 1, -1 },
+    { "%Qx",  "-7B", "-123", 1, -1 },
+    { "%QX",    "0",    "0", 1, -1 },
+    { "%QX",   "7B",  "123", 1, -1 },
+    { "%QX",   "7B",  "123", 1, -1 },
+    { "%QX",   "+0",    "0", 1, -1 },
+    { "%QX",  "+7B",  "123", 1, -1 },
+    { "%QX",  "+7B",  "123", 1, -1 },
+    { "%QX",   "-0",   "-0", 1, -1 },
+    { "%QX",  "-7B", "-123", 1, -1 },
+    { "%QX",  "-7B", "-123", 1, -1 },
+
+    { "%Qi",    "0",    "0", 1, -1 },
+    { "%Qi",    "1",    "1", 1, -1 },
+    { "%Qi",  "123",  "123", 1, -1 },
+    { "%Qi",   "+0",    "0", 1, -1 },
+    { "%Qi",   "+1",    "1", 1, -1 },
+    { "%Qi", "+123",  "123", 1, -1 },
+    { "%Qi",   "-0",    "0", 1, -1 },
+    { "%Qi",   "-1",   "-1", 1, -1 },
+    { "%Qi", "-123", "-123", 1, -1 },
+
+    { "%Qi",    "00",    "0", 1, -1 },
+    { "%Qi",  "0173",  "123", 1, -1 },
+    { "%Qi",   "+00",    "0", 1, -1 },
+    { "%Qi", "+0173",  "123", 1, -1 },
+    { "%Qi",   "-00",    "0", 1, -1 },
+    { "%Qi", "-0173", "-123", 1, -1 },
+
+    { "%Qi",    "0x0",    "0", 1, -1 },
+    { "%Qi",   "0x7b",  "123", 1, -1 },
+    { "%Qi",   "0x7b",  "123", 1, -1 },
+    { "%Qi",   "+0x0",    "0", 1, -1 },
+    { "%Qi",  "+0x7b",  "123", 1, -1 },
+    { "%Qi",  "+0x7b",  "123", 1, -1 },
+    { "%Qi",   "-0x0",   "-0", 1, -1 },
+    { "%Qi",  "-0x7b", "-123", 1, -1 },
+    { "%Qi",  "-0x7b", "-123", 1, -1 },
+    { "%Qi",    "0X0",    "0", 1, -1 },
+    { "%Qi",   "0X7b",  "123", 1, -1 },
+    { "%Qi",   "0X7b",  "123", 1, -1 },
+    { "%Qi",   "+0X0",    "0", 1, -1 },
+    { "%Qi",  "+0X7b",  "123", 1, -1 },
+    { "%Qi",  "+0X7b",  "123", 1, -1 },
+    { "%Qi",   "-0X0",   "-0", 1, -1 },
+    { "%Qi",  "-0X7b", "-123", 1, -1 },
+    { "%Qi",  "-0X7b", "-123", 1, -1 },
+    { "%Qi",    "0x0",    "0", 1, -1 },
+    { "%Qi",   "0x7B",  "123", 1, -1 },
+    { "%Qi",   "0x7B",  "123", 1, -1 },
+    { "%Qi",   "+0x0",    "0", 1, -1 },
+    { "%Qi",  "+0x7B",  "123", 1, -1 },
+    { "%Qi",  "+0x7B",  "123", 1, -1 },
+    { "%Qi",   "-0x0",   "-0", 1, -1 },
+    { "%Qi",  "-0x7B", "-123", 1, -1 },
+    { "%Qi",  "-0x7B", "-123", 1, -1 },
+    { "%Qi",    "0X0",    "0", 1, -1 },
+    { "%Qi",   "0X7B",  "123", 1, -1 },
+    { "%Qi",   "0X7B",  "123", 1, -1 },
+    { "%Qi",   "+0X0",    "0", 1, -1 },
+    { "%Qi",  "+0X7B",  "123", 1, -1 },
+    { "%Qi",  "+0X7B",  "123", 1, -1 },
+    { "%Qi",   "-0X0",   "-0", 1, -1 },
+    { "%Qi",  "-0X7B", "-123", 1, -1 },
+    { "%Qi",  "-0X7B", "-123", 1, -1 },
+
+    { "%Qd",    " 0",    "0", 1, -1 },
+    { "%Qd",   "  0",    "0", 1, -1 },
+    { "%Qd",  "   0",    "0", 1, -1 },
+    { "%Qd",   "\t0",    "0", 1, -1 },
+    { "%Qd", "\t\t0",    "0", 1, -1 },
+
+    { "%Qd",  "3/2",   "3/2", 1, -1 },
+    { "%Qd", "+3/2",   "3/2", 1, -1 },
+    { "%Qd", "-3/2",  "-3/2", 1, -1 },
+
+    { "%Qx",  "f/10", "15/16", 1, -1 },
+    { "%Qx",  "F/10", "15/16", 1, -1 },
+    { "%QX",  "f/10", "15/16", 1, -1 },
+    { "%QX",  "F/10", "15/16", 1, -1 },
+
+    { "%Qo",  "20/21",  "16/17", 1, -1 },
+    { "%Qo", "-20/21", "-16/17", 1, -1 },
+
+    { "%Qi",    "10/11",  "10/11", 1, -1 },
+    { "%Qi",   "+10/11",  "10/11", 1, -1 },
+    { "%Qi",   "-10/11", "-10/11", 1, -1 },
+    { "%Qi",   "010/11",   "8/11", 1, -1 },
+    { "%Qi",  "+010/11",   "8/11", 1, -1 },
+    { "%Qi",  "-010/11",  "-8/11", 1, -1 },
+    { "%Qi",  "0x10/11",  "16/11", 1, -1 },
+    { "%Qi", "+0x10/11",  "16/11", 1, -1 },
+    { "%Qi", "-0x10/11", "-16/11", 1, -1 },
+
+    { "%Qi",    "10/011",  "10/9", 1, -1 },
+    { "%Qi",   "+10/011",  "10/9", 1, -1 },
+    { "%Qi",   "-10/011", "-10/9", 1, -1 },
+    { "%Qi",   "010/011",   "8/9", 1, -1 },
+    { "%Qi",  "+010/011",   "8/9", 1, -1 },
+    { "%Qi",  "-010/011",  "-8/9", 1, -1 },
+    { "%Qi",  "0x10/011",  "16/9", 1, -1 },
+    { "%Qi", "+0x10/011",  "16/9", 1, -1 },
+    { "%Qi", "-0x10/011", "-16/9", 1, -1 },
+
+    { "%Qi",    "10/0x11",  "10/17", 1, -1 },
+    { "%Qi",   "+10/0x11",  "10/17", 1, -1 },
+    { "%Qi",   "-10/0x11", "-10/17", 1, -1 },
+    { "%Qi",   "010/0x11",   "8/17", 1, -1 },
+    { "%Qi",  "+010/0x11",   "8/17", 1, -1 },
+    { "%Qi",  "-010/0x11",  "-8/17", 1, -1 },
+    { "%Qi",  "0x10/0x11",  "16/17", 1, -1 },
+    { "%Qi", "+0x10/0x11",  "16/17", 1, -1 },
+    { "%Qi", "-0x10/0x11", "-16/17", 1, -1 },
+
+    { "hello%Qd",      "hello0",         "0", 1, -1 },
+    { "hello%Qd",      "hello 0",        "0", 1, -1 },
+    { "hello%Qd",      "hello \t0",      "0", 1, -1 },
+    { "hello%Qdworld", "hello 0world",   "0", 1, -1 },
+    { "hello%Qd",      "hello3/2",     "3/2", 1, -1 },
+
+    { "hello%*Qd",      "hello0",        "-999/121", 0, -1 },
+    { "hello%*Qd",      "hello 0",       "-999/121", 0, -1 },
+    { "hello%*Qd",      "hello \t0",     "-999/121", 0, -1 },
+    { "hello%*Qdworld", "hello 0world",  "-999/121", 0, -1 },
+    { "hello%*Qdworld", "hello3/2world", "-999/121", 0, -1 },
+
+    { "%Qd",    "",     "-999/121", -1, -1 },
+    { "%Qd",   " ",     "-999/121", -1, -1 },
+    { " %Qd",   "",     "-999/121", -1, -1 },
+    { "xyz%Qd", "",     "-999/121", -1, -1 },
+
+    { "%*Qd",    "",     "-999/121", -1, -1 },
+    { " %*Qd",   "",     "-999/121", -1, -1 },
+    { "xyz%*Qd", "",     "-999/121", -1, -1 },
+
+    /* match something, but invalid */
+    { "%Qd",    "-",     "-999/121",  0, 1 },
+    { "%Qd",    "+",     "-999/121",  0, 1 },
+    { "%Qd",    "/-",    "-999/121",  0, 1 },
+    { "%Qd",    "/+",    "-999/121",  0, 1 },
+    { "%Qd",    "-/",    "-999/121",  0, 1 },
+    { "%Qd",    "+/",    "-999/121",  0, 1 },
+    { "%Qd",    "-/-",   "-999/121",  0, 1 },
+    { "%Qd",    "-/+",   "-999/121",  0, 1 },
+    { "%Qd",    "+/+",   "-999/121",  0, 1 },
+    { "%Qd",    "/123",  "-999/121",  0, 1 },
+    { "%Qd",    "-/123", "-999/121",  0, 1 },
+    { "%Qd",    "+/123", "-999/121",  0, 1 },
+    { "%Qd",    "123/",  "-999/121",  0, 1 },
+    { "%Qd",    "123/-", "-999/121",  0, 1 },
+    { "%Qd",    "123/+", "-999/121",  0, 1 },
+    { "xyz%Qd", "xyz-",  "-999/121",  0, 4 },
+    { "xyz%Qd", "xyz+",  "-999/121",  0, 4 },
+
+    { "%1Qi",  "12/57", "1",        1, 1 },
+    { "%2Qi",  "12/57", "12",       1, 2 },
+    { "%3Qi",  "12/57", "-999/121", 0, -1 },
+    { "%4Qi",  "12/57", "12/5",     1, 4 },
+    { "%5Qi",  "12/57", "12/57",    1, 5 },
+    { "%6Qi",  "12/57", "12/57",    1, 5 },
+    { "%7Qi",  "12/57", "12/57",    1, 5 },
+
+    { "%1Qi",  "012/057", "0",        1, 1 },
+    { "%2Qi",  "012/057", "01",       1, 2 },
+    { "%3Qi",  "012/057", "012",      1, 3 },
+    { "%4Qi",  "012/057", "-999/121", 0, -1 },
+    { "%5Qi",  "012/057", "012/0",    1, 5 },
+    { "%6Qi",  "012/057", "012/5",    1, 6 },
+    { "%7Qi",  "012/057", "012/057",  1, 7 },
+    { "%8Qi",  "012/057", "012/057",  1, 7 },
+    { "%9Qi",  "012/057", "012/057",  1, 7 },
+
+    { "%1Qi",  "0x12/0x57", "0",         1, 1 },
+    { "%2Qi",  "0x12/0x57", "-999",      0, 2 },
+    { "%3Qi",  "0x12/0x57", "0x1",       1, 3 },
+    { "%4Qi",  "0x12/0x57", "0x12",      1, 4 },
+    { "%5Qi",  "0x12/0x57", "-999/121",  0, 5 },
+    { "%6Qi",  "0x12/0x57", "0x12/0",    1, 6 },
+    { "%7Qi",  "0x12/0x57", "-999/121",  0, 7 },
+    { "%8Qi",  "0x12/0x57", "0x12/0x5",  1, 8 },
+    { "%9Qi",  "0x12/0x57", "0x12/0x57", 1, 9 },
+    { "%10Qi", "0x12/0x57", "0x12/0x57", 1, 9 },
+    { "%11Qi", "0x12/0x57", "0x12/0x57", 1, 9 },
+
+    { "%Qd",  "xyz", "0", 0, 0 },
+  };
+
+  int         i, j, ignore, got_ret, want_ret, got_upto, want_upto;
+  mpq_t       got, want;
+  long        got_l, want_ftell;
+  int         error = 0;
+  fun_t       fun;
+  const char  *name;
+  char        fmt[128];
+
+  mpq_init (got);
+  mpq_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (want, data[i].want, 0);
+
+      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
+      strcpy (fmt, data[i].fmt);
+      strcat (fmt, "%n");
+
+      ignore = (strchr (fmt, '*') != NULL);
+
+      for (j = 0; j <= 3; j++)
+        {
+          want_ret = data[i].ret;
+
+          want_ftell = data[i].ftell;
+          if (want_ftell == -1)
+            want_ftell = strlen (data[i].input);
+          want_upto = want_ftell;
+
+          if (want_ret == -1 || (want_ret == 0 && ! ignore))
+            {
+              want_ftell = -1;
+              want_upto = -555;
+            }
+
+          switch (j) {
+          case 0:
+            name = "gmp_sscanf";
+            fun = fun_gmp_sscanf;
+            break;
+          case 1:
+            name = "gmp_fscanf";
+            fun = fun_gmp_fscanf;
+            break;
+          case 2:
+            if (strchr (data[i].input, '/') != NULL)
+              continue;
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard sscanf";
+            fun = fun_sscanf;
+            break;
+          case 3:
+            if (strchr (data[i].input, '/') != NULL)
+              continue;
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard fscanf";
+            fun = fun_fscanf;
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          got_upto = -555;
+          got_ftell = -1;
+
+          switch (j) {
+          case 0:
+          case 1:
+            mpq_set_si (got, -999L, 121L);
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
+            break;
+          case 2:
+          case 3:
+            got_l = -999L;
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto);
+            mpq_set_si (got, got_l, (got_l == -999L ? 121L : 1L));
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          MPZ_CHECK_FORMAT (mpq_numref (got));
+          MPZ_CHECK_FORMAT (mpq_denref (got));
+
+          if (got_ret != want_ret)
+            {
+              printf ("%s wrong return value\n", name);
+              error = 1;
+            }
+          /* use direct mpz compares, since some of the test data is
+             non-canonical and can trip ASSERTs in mpq_equal */
+          if (want_ret == 1
+              && ! (mpz_cmp (mpq_numref(want), mpq_numref(got)) == 0
+                    && mpz_cmp (mpq_denref(want), mpq_denref(got)) == 0))
+            {
+              printf ("%s wrong result\n", name);
+              error = 1;
+            }
+          if (got_upto != want_upto)
+            {
+              printf ("%s wrong upto\n", name);
+              error = 1;
+            }
+          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
+            {
+              printf ("%s wrong ftell\n", name);
+              error = 1;
+            }
+          if (error)
+            {
+              printf    ("  fmt   \"%s\"\n", data[i].fmt);
+              printf    ("  input \"%s\"\n", data[i].input);
+              printf    ("  ret   want=%d\n", want_ret);
+              printf    ("        got =%d\n", got_ret);
+              mpq_trace ("  value want", want);
+              mpq_trace ("        got ", got);
+              printf    ("  upto  want=%d\n", want_upto);
+              printf    ("        got =%d\n", got_upto);
+              if (got_ftell != -1)
+                {
+                  printf    ("  ftell want =%ld\n", want_ftell);
+                  printf    ("        got  =%ld\n", got_ftell);
+                }
+              abort ();
+            }
+        }
+    }
+
+  mpq_clear (got);
+  mpq_clear (want);
+}
+
+void
+check_f (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *input;
+    const char  *want;
+    int         ret;
+    long        ftell;    /* or -1 for length of input string */
+
+  } data[] = {
+
+    { "%Ff",    "0",    "0", 1, -1 },
+    { "%Fe",    "0",    "0", 1, -1 },
+    { "%FE",    "0",    "0", 1, -1 },
+    { "%Fg",    "0",    "0", 1, -1 },
+    { "%FG",    "0",    "0", 1, -1 },
+
+    { "%Ff",  "123",    "123", 1, -1 },
+    { "%Ff", "+123",    "123", 1, -1 },
+    { "%Ff", "-123",   "-123", 1, -1 },
+    { "%Ff",  "123.",   "123", 1, -1 },
+    { "%Ff", "+123.",   "123", 1, -1 },
+    { "%Ff", "-123.",  "-123", 1, -1 },
+    { "%Ff",  "123.0",  "123", 1, -1 },
+    { "%Ff", "+123.0",  "123", 1, -1 },
+    { "%Ff", "-123.0", "-123", 1, -1 },
+    { "%Ff",  "0123",   "123", 1, -1 },
+    { "%Ff", "-0123",  "-123", 1, -1 },
+
+    { "%Ff",  "123.456e3",   "123456", 1, -1 },
+    { "%Ff", "-123.456e3",  "-123456", 1, -1 },
+    { "%Ff",  "123.456e+3",  "123456", 1, -1 },
+    { "%Ff", "-123.456e+3", "-123456", 1, -1 },
+    { "%Ff",  "123000e-3",      "123", 1, -1 },
+    { "%Ff", "-123000e-3",     "-123", 1, -1 },
+    { "%Ff",  "123000.e-3",     "123", 1, -1 },
+    { "%Ff", "-123000.e-3",    "-123", 1, -1 },
+
+    { "%Ff",  "123.456E3",   "123456", 1, -1 },
+    { "%Ff", "-123.456E3",  "-123456", 1, -1 },
+    { "%Ff",  "123.456E+3",  "123456", 1, -1 },
+    { "%Ff", "-123.456E+3", "-123456", 1, -1 },
+    { "%Ff",  "123000E-3",      "123", 1, -1 },
+    { "%Ff", "-123000E-3",     "-123", 1, -1 },
+    { "%Ff",  "123000.E-3",     "123", 1, -1 },
+    { "%Ff", "-123000.E-3",    "-123", 1, -1 },
+
+    { "%Ff",  ".456e3",   "456", 1, -1 },
+    { "%Ff", "-.456e3",  "-456", 1, -1 },
+    { "%Ff",  ".456e+3",  "456", 1, -1 },
+    { "%Ff", "-.456e+3", "-456", 1, -1 },
+
+    { "%Ff",    " 0",    "0", 1, -1 },
+    { "%Ff",   "  0",    "0", 1, -1 },
+    { "%Ff",  "   0",    "0", 1, -1 },
+    { "%Ff",   "\t0",    "0", 1, -1 },
+    { "%Ff", "\t\t0",    "0", 1, -1 },
+
+    { "hello%Fg",      "hello0",       "0",   1, -1 },
+    { "hello%Fg",      "hello 0",      "0",   1, -1 },
+    { "hello%Fg",      "hello \t0",    "0",   1, -1 },
+    { "hello%Fgworld", "hello 0world", "0",   1, -1 },
+    { "hello%Fg",      "hello3.0",     "3.0", 1, -1 },
+
+    { "hello%*Fg",      "hello0",        "-999", 0, -1 },
+    { "hello%*Fg",      "hello 0",       "-999", 0, -1 },
+    { "hello%*Fg",      "hello \t0",     "-999", 0, -1 },
+    { "hello%*Fgworld", "hello 0world",  "-999", 0, -1 },
+    { "hello%*Fgworld", "hello3.0world", "-999", 0, -1 },
+
+    { "%Ff",     "",   "-999", -1, -1 },
+    { "%Ff",    " ",   "-999", -1, -1 },
+    { "%Ff",   "\t",   "-999", -1, -1 },
+    { "%Ff",  " \t",   "-999", -1, -1 },
+    { " %Ff",    "",   "-999", -1, -1 },
+    { "xyz%Ff",  "",   "-999", -1, -1 },
+
+    { "%*Ff",    "",   "-999", -1, -1 },
+    { " %*Ff",   "",   "-999", -1, -1 },
+    { "xyz%*Ff", "",   "-999", -1, -1 },
+
+    { "%Ff",    "xyz", "0", 0 },
+
+    /* various non-empty but invalid */
+    { "%Ff",    "-",      "-999",  0, 1 },
+    { "%Ff",    "+",      "-999",  0, 1 },
+    { "xyz%Ff", "xyz-",   "-999",  0, 4 },
+    { "xyz%Ff", "xyz+",   "-999",  0, 4 },
+    { "%Ff",    "-.",     "-999",  0, 2 },
+    { "%Ff",    "+.",     "-999",  0, 2 },
+    { "%Ff",    ".e",     "-999",  0, 1 },
+    { "%Ff",   "-.e",     "-999",  0, 2 },
+    { "%Ff",   "+.e",     "-999",  0, 2 },
+    { "%Ff",    ".E",     "-999",  0, 1 },
+    { "%Ff",   "-.E",     "-999",  0, 2 },
+    { "%Ff",   "+.E",     "-999",  0, 2 },
+    { "%Ff",    ".e123",  "-999",  0, 1 },
+    { "%Ff",   "-.e123",  "-999",  0, 2 },
+    { "%Ff",   "+.e123",  "-999",  0, 2 },
+    { "%Ff",    "123e",   "-999",  0, 4 },
+    { "%Ff",   "-123e",   "-999",  0, 5 },
+    { "%Ff",    "123e-",  "-999",  0, 5 },
+    { "%Ff",   "-123e-",  "-999",  0, 6 },
+    { "%Ff",    "123e+",  "-999",  0, 5 },
+    { "%Ff",   "-123e+",  "-999",  0, 6 },
+    { "%Ff",   "123e-Z",  "-999",  0, 5 },
+
+    /* hex floats */
+    { "%Ff", "0x123p0",       "291",  1, -1 },
+    { "%Ff", "0x123P0",       "291",  1, -1 },
+    { "%Ff", "0X123p0",       "291",  1, -1 },
+    { "%Ff", "0X123P0",       "291",  1, -1 },
+    { "%Ff", "-0x123p0",     "-291",  1, -1 },
+    { "%Ff", "+0x123p0",      "291",  1, -1 },
+    { "%Ff", "0x123.p0",      "291",  1, -1 },
+    { "%Ff", "0x12.3p4",      "291",  1, -1 },
+    { "%Ff", "-0x12.3p4",    "-291",  1, -1 },
+    { "%Ff", "+0x12.3p4",     "291",  1, -1 },
+    { "%Ff", "0x1230p-4",     "291",  1, -1 },
+    { "%Ff", "-0x1230p-4",   "-291",  1, -1 },
+    { "%Ff", "+0x1230p-4",    "291",  1, -1 },
+    { "%Ff", "+0x.1230p12",   "291",  1, -1 },
+    { "%Ff", "+0x123000p-12", "291",  1, -1 },
+    { "%Ff", "0x123 p12",     "291",  1, 5 },
+    { "%Ff", "0x9 9",           "9",  1, 3 },
+    { "%Ff", "0x01",            "1",  1, 4 },
+    { "%Ff", "0x23",           "35",  1, 4 },
+    { "%Ff", "0x45",           "69",  1, 4 },
+    { "%Ff", "0x67",          "103",  1, 4 },
+    { "%Ff", "0x89",          "137",  1, 4 },
+    { "%Ff", "0xAB",          "171",  1, 4 },
+    { "%Ff", "0xCD",          "205",  1, 4 },
+    { "%Ff", "0xEF",          "239",  1, 4 },
+    { "%Ff", "0xab",          "171",  1, 4 },
+    { "%Ff", "0xcd",          "205",  1, 4 },
+    { "%Ff", "0xef",          "239",  1, 4 },
+    { "%Ff", "0x100p0A",      "256",  1, 7 },
+    { "%Ff", "0x1p9",         "512",  1, -1 },
+
+    /* invalid hex floats */
+    { "%Ff", "0x",     "-999",  0, 2 },
+    { "%Ff", "-0x",    "-999",  0, 3 },
+    { "%Ff", "+0x",    "-999",  0, 3 },
+    { "%Ff", "0x-",    "-999",  0, 2 },
+    { "%Ff", "0x+",    "-999",  0, 2 },
+    { "%Ff", "0x.",    "-999",  0, 3 },
+    { "%Ff", "-0x.",   "-999",  0, 4 },
+    { "%Ff", "+0x.",   "-999",  0, 4 },
+    { "%Ff", "0x.p",   "-999",  0, 3 },
+    { "%Ff", "-0x.p",  "-999",  0, 4 },
+    { "%Ff", "+0x.p",  "-999",  0, 4 },
+    { "%Ff", "0x.P",   "-999",  0, 3 },
+    { "%Ff", "-0x.P",  "-999",  0, 4 },
+    { "%Ff", "+0x.P",  "-999",  0, 4 },
+    { "%Ff", ".p123",  "-999",  0, 1 },
+    { "%Ff", "-.p123", "-999",  0, 2 },
+    { "%Ff", "+.p123", "-999",  0, 2 },
+    { "%Ff", "0x1p",   "-999",  0, 4 },
+    { "%Ff", "0x1p-",  "-999",  0, 5 },
+    { "%Ff", "0x1p+",  "-999",  0, 5 },
+    { "%Ff", "0x123p 12", "291",  0, 6 },
+    { "%Ff", "0x 123p12", "291",  0, 2 },
+
+  };
+
+  int         i, j, ignore, got_ret, want_ret, got_upto, want_upto;
+  mpf_t       got, want;
+  double      got_d;
+  long        want_ftell;
+  int         error = 0;
+  fun_t       fun;
+  const char  *name;
+  char        fmt[128];
+
+  mpf_init (got);
+  mpf_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (want, data[i].want, 10);
+
+      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
+      strcpy (fmt, data[i].fmt);
+      strcat (fmt, "%n");
+
+      ignore = (strchr (fmt, '*') != NULL);
+
+      for (j = 0; j <= 3; j++)
+        {
+          want_ret = data[i].ret;
+
+          want_ftell = data[i].ftell;
+          if (want_ftell == -1)
+            want_ftell = strlen (data[i].input);
+          want_upto = want_ftell;
+
+          if (want_ret == -1 || (want_ret == 0 && ! ignore))
+            want_upto = -555;
+
+          switch (j) {
+          case 0:
+            name = "gmp_sscanf";
+            fun = fun_gmp_sscanf;
+            break;
+          case 1:
+            name = "gmp_fscanf";
+            fun = fun_gmp_fscanf;
+            break;
+          case 2:
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard sscanf";
+            fun = fun_sscanf;
+            break;
+          case 3:
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard fscanf";
+            fun = fun_fscanf;
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          got_upto = -555;
+          got_ftell = -1;
+
+          switch (j) {
+          case 0:
+          case 1:
+            mpf_set_si (got, -999L);
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
+            break;
+          case 2:
+          case 3:
+            got_d = -999L;
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, &got_d, &got_upto);
+            mpf_set_d (got, got_d);
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          MPF_CHECK_FORMAT (got);
+
+          if (got_ret != want_ret)
+            {
+              printf ("%s wrong return value\n", name);
+              error = 1;
+            }
+          if (want_ret == 1 && mpf_cmp (want, got) != 0)
+            {
+              printf ("%s wrong result\n", name);
+              error = 1;
+            }
+          if (got_upto != want_upto)
+            {
+              printf ("%s wrong upto\n", name);
+              error = 1;
+            }
+          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
+            {
+              printf ("%s wrong ftell\n", name);
+              error = 1;
+            }
+          if (error)
+            {
+              printf    ("  fmt   \"%s\"\n", data[i].fmt);
+              printf    ("  input \"%s\"\n", data[i].input);
+              printf    ("  ret   want=%d\n", want_ret);
+              printf    ("        got =%d\n", got_ret);
+              mpf_trace ("  value want", want);
+              mpf_trace ("        got ", got);
+              printf    ("  upto  want=%d\n", want_upto);
+              printf    ("        got =%d\n", got_upto);
+              if (got_ftell != -1)
+                {
+                  printf    ("  ftell want =%ld\n", want_ftell);
+                  printf    ("        got  =%ld\n", got_ftell);
+                }
+              abort ();
+            }
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+
+void
+check_n (void)
+{
+  int    ret;
+
+  /* %n suppressed */
+  {
+    int n = 123;
+    gmp_sscanf ("   ", " %*n", &n);
+    ASSERT_ALWAYS (n == 123);
+  }
+  {
+    int n = 123;
+    fromstring_gmp_fscanf ("   ", " %*n", &n);
+    ASSERT_ALWAYS (n == 123);
+  }
+
+
+#define CHECK_N(type, string)                           \
+  do {                                                  \
+    type  x[2];                                         \
+    char  fmt[128];                                     \
+    int   ret;                                          \
+                                                        \
+    x[0] = ~ (type) 0;                                  \
+    x[1] = ~ (type) 0;                                  \
+    sprintf (fmt, "abc%%%sn", string);                  \
+    ret = gmp_sscanf ("abc", fmt, &x[0]);               \
+                                                        \
+    ASSERT_ALWAYS (ret == 0);                           \
+                                                        \
+    /* should write whole of x[0] and none of x[1] */   \
+    ASSERT_ALWAYS (x[0] == 3);                          \
+    ASSERT_ALWAYS (x[1] == (type) ~ (type) 0);		\
+                                                        \
+  } while (0)
+
+  CHECK_N (char,      "hh");
+  CHECK_N (long,      "l");
+#if HAVE_LONG_LONG
+  CHECK_N (long long, "L");
+#endif
+#if HAVE_INTMAX_T
+  CHECK_N (intmax_t,  "j");
+#endif
+#if HAVE_PTRDIFF_T
+  CHECK_N (ptrdiff_t, "t");
+#endif
+  CHECK_N (short,     "h");
+  CHECK_N (size_t,    "z");
+
+  /* %Zn */
+  {
+    mpz_t  x[2];
+    mpz_init_set_si (x[0], -987L);
+    mpz_init_set_si (x[1],  654L);
+    ret = gmp_sscanf ("xyz   ", "xyz%Zn", x[0]);
+    MPZ_CHECK_FORMAT (x[0]);
+    MPZ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
+    mpz_clear (x[0]);
+    mpz_clear (x[1]);
+  }
+  {
+    mpz_t  x;
+    mpz_init (x);
+    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Zn", x);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x, 3L) == 0);
+    mpz_clear (x);
+  }
+
+  /* %Qn */
+  {
+    mpq_t  x[2];
+    mpq_init (x[0]);
+    mpq_init (x[1]);
+    mpq_set_ui (x[0], 987L, 654L);
+    mpq_set_ui (x[1], 4115L, 226L);
+    ret = gmp_sscanf ("xyz   ", "xyz%Qn", x[0]);
+    MPQ_CHECK_FORMAT (x[0]);
+    MPQ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
+    mpq_clear (x[0]);
+    mpq_clear (x[1]);
+  }
+  {
+    mpq_t  x;
+    mpq_init (x);
+    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Qn", x);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x, 3L, 1L) == 0);
+    mpq_clear (x);
+  }
+
+  /* %Fn */
+  {
+    mpf_t  x[2];
+    mpf_init (x[0]);
+    mpf_init (x[1]);
+    mpf_set_ui (x[0], 987L);
+    mpf_set_ui (x[1], 654L);
+    ret = gmp_sscanf ("xyz   ", "xyz%Fn", x[0]);
+    MPF_CHECK_FORMAT (x[0]);
+    MPF_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
+    mpf_clear (x[0]);
+    mpf_clear (x[1]);
+  }
+  {
+    mpf_t  x;
+    mpf_init (x);
+    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Fn", x);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x, 3L) == 0);
+    mpf_clear (x);
+  }
+}
+
+
+void
+check_misc (void)
+{
+  int  ret, cmp;
+  {
+    int  a=9, b=8, c=7, n=66;
+    mpz_t  z;
+    mpz_init (z);
+    ret = gmp_sscanf ("1 2 3 4", "%d %d %d %Zd%n",
+                      &a, &b, &c, z, &n);
+    ASSERT_ALWAYS (ret == 4);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (b == 2);
+    ASSERT_ALWAYS (c == 3);
+    ASSERT_ALWAYS (n == 7);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    mpz_clear (z);
+  }
+  {
+    int  a=9, b=8, c=7, n=66;
+    mpz_t  z;
+    mpz_init (z);
+    ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %d %d %Zd%n",
+                                 &a, &b, &c, z, &n);
+    ASSERT_ALWAYS (ret == 4);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (b == 2);
+    ASSERT_ALWAYS (c == 3);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    ASSERT_ALWAYS (n == 7);
+    ASSERT_ALWAYS (got_ftell == 7);
+    mpz_clear (z);
+  }
+
+  {
+    int  a=9, n=8;
+    mpz_t  z;
+    mpz_init (z);
+    ret = gmp_sscanf ("1 2 3 4", "%d %*d %*d %Zd%n", &a, z, &n);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    ASSERT_ALWAYS (n == 7);
+    mpz_clear (z);
+  }
+  {
+    int  a=9, n=8;
+    mpz_t  z;
+    mpz_init (z);
+    ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %*d %*d %Zd%n",
+                                 &a, z, &n);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    ASSERT_ALWAYS (n == 7);
+    ASSERT_ALWAYS (got_ftell == 7);
+    mpz_clear (z);
+  }
+
+  /* EOF for no matching */
+  {
+    char buf[128];
+    ret = gmp_sscanf ("   ", "%s", buf);
+    ASSERT_ALWAYS (ret == EOF);
+    ret = fromstring_gmp_fscanf ("   ", "%s", buf);
+    ASSERT_ALWAYS (ret == EOF);
+    if (option_libc_scanf)
+      {
+        ret = sscanf ("   ", "%s", buf);
+        ASSERT_ALWAYS (ret == EOF);
+        ret = fun_fscanf ("   ", "%s", buf, NULL);
+        ASSERT_ALWAYS (ret == EOF);
+      }
+  }
+
+  /* suppressed field, then eof */
+  {
+    int  x;
+    if (test_sscanf_eof_ok ())
+      {
+        ret = gmp_sscanf ("123", "%*d%d", &x);
+        ASSERT_ALWAYS (ret == EOF);
+      }
+    ret = fromstring_gmp_fscanf ("123", "%*d%d", &x);
+    ASSERT_ALWAYS (ret == EOF);
+    if (option_libc_scanf)
+      {
+        ret = sscanf ("123", "%*d%d", &x);
+        ASSERT_ALWAYS (ret == EOF);
+        ret = fun_fscanf ("123", "%*d%d", &x, NULL);
+        ASSERT_ALWAYS (ret == EOF);
+      }
+  }
+  {
+    mpz_t  x;
+    mpz_init (x);
+    ret = gmp_sscanf ("123", "%*Zd%Zd", x);
+    ASSERT_ALWAYS (ret == EOF);
+    ret = fromstring_gmp_fscanf ("123", "%*Zd%Zd", x);
+    ASSERT_ALWAYS (ret == EOF);
+    mpz_clear (x);
+  }
+
+  /* %[...], glibc only */
+#ifdef __GLIBC__
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("abcdefgh", "%[a-d]ef%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "abcd");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 6);
+  }
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("xyza", "%[^a]a%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "xyz");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 4);
+  }
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("ab]ab]", "%[]ab]%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "ab]ab]");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 6);
+  }
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("xyzb", "%[^]ab]b%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "xyz");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 4);
+  }
+#endif
+
+  /* %zd etc won't be accepted by sscanf on old systems, and running
+     something to see if they work might be bad, so only try it on glibc,
+     and only on a new enough version (glibc 2.0 doesn't have %zd) */
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
+  {
+    mpz_t   z;
+    size_t  s = -1;
+    mpz_init (z);
+    ret = gmp_sscanf ("456 789", "%zd %Zd", &s, z);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (s == 456);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
+    mpz_clear (z);
+  }
+  {
+    mpz_t      z;
+    ptrdiff_t  d = -1;
+    mpz_init (z);
+    ret = gmp_sscanf ("456 789", "%td %Zd", &d, z);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (d == 456);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
+    mpz_clear (z);
+  }
+  {
+    mpz_t      z;
+    long long  ll = -1;
+    mpz_init (z);
+    ret = gmp_sscanf ("456 789", "%Ld %Zd", &ll, z);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (ll == 456);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
+    mpz_clear (z);
+  }
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_libc_scanf = 1;
+
+  tests_start ();
+
+  mp_trace_base = 16;
+
+  check_z ();
+  check_q ();
+  check_f ();
+  check_n ();
+  check_misc ();
+
+  unlink (TEMPFILE);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/reuse.c b/tests/mpf/reuse.c
new file mode 100644
index 0000000..86db5b3
--- /dev/null
+++ b/tests/mpf/reuse.c
@@ -0,0 +1,218 @@
+/* Test that routines allow reusing a source variable as destination.
+
+Copyright 1996, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMP_LIBGMP_DLL
+
+/* FIXME: When linking to a DLL libgmp, mpf_add etc can't be used as
+   initializers for global variables because they're effectively global
+   variables (function pointers) themselves.  Perhaps calling a test
+   function successively with mpf_add etc would be better.  */
+
+int
+main (void)
+{
+  printf ("Test suppressed for windows DLL\n");
+  exit (0);
+}
+
+
+#else /* ! DLL_EXPORT */
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+#ifndef EXPO
+#define EXPO 32
+#endif
+
+void dump_abort (const char *, mpf_t, mpf_t);
+
+typedef void (*dss_func) (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+dss_func dss_funcs[] =
+{
+  mpf_div, mpf_add, mpf_mul, mpf_sub,
+};
+
+const char *dss_func_names[] =
+{
+  "mpf_div", "mpf_add", "mpf_mul", "mpf_sub",
+};
+
+typedef void (*dsi_func) (mpf_ptr, mpf_srcptr, unsigned long int);
+
+dsi_func dsi_funcs[] =
+{
+  mpf_div_ui, mpf_add_ui, mpf_mul_ui, mpf_sub_ui,
+  mpf_mul_2exp, mpf_div_2exp, mpf_pow_ui
+};
+
+const char *dsi_func_names[] =
+{
+  "mpf_div_ui", "mpf_add_ui", "mpf_mul_ui", "mpf_sub_ui",
+  "mpf_mul_2exp", "mpf_div_2exp", "mpf_pow_ui"
+};
+
+typedef void (*dis_func) (mpf_ptr, unsigned long int, mpf_srcptr);
+
+dis_func dis_funcs[] =
+{
+  mpf_ui_div, mpf_ui_sub,
+};
+
+const char *dis_func_names[] =
+{
+  "mpf_ui_div", "mpf_ui_sub",
+};
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  int pass, reps = 10000;
+  mpf_t in1, in2, out1;
+  unsigned long int in1i, in2i;
+  mpf_t res1, res2, res3;
+  mp_size_t bprec = 100;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init (in1);
+  mpf_init (in2);
+  mpf_init (out1);
+  mpf_init (res1);
+  mpf_init (res2);
+  mpf_init (res3);
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+      mpf_random2 (in1, urandom () % SIZE - SIZE/2, urandom () % EXPO);
+      mpf_random2 (in2, urandom () % SIZE - SIZE/2, urandom () % EXPO);
+
+      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
+	{
+	  /* Don't divide by 0.  */
+	  if (i == 0 && mpf_cmp_ui (in2, 0) == 0)
+	    continue;
+
+	  (dss_funcs[i]) (res1, in1, in2);
+
+	  mpf_set (out1, in1);
+	  (dss_funcs[i]) (out1, out1, in2);
+	  mpf_set (res2, out1);
+
+	  mpf_set (out1, in2);
+	  (dss_funcs[i]) (out1, in1, out1);
+	  mpf_set (res3, out1);
+
+	  if (mpf_cmp (res1, res2) != 0)
+	    dump_abort (dss_func_names[i], res1, res2);
+	  if (mpf_cmp (res1, res3) != 0)
+	    dump_abort (dss_func_names[i], res1, res3);
+	}
+
+      in2i = urandom ();
+      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
+	{
+	  unsigned long this_in2i = in2i;
+
+	  /* Don't divide by 0.  */
+	  if (i == 0 && this_in2i == 0) /* dsi_funcs[i] == mpf_div_ui */
+	    continue;
+
+	  /* Avoid overflow/underflow in the exponent.  */
+	  if (dsi_funcs[i] == mpf_mul_2exp || dsi_funcs[i] == mpf_div_2exp)
+	    this_in2i %= 0x100000;
+	  else if (dsi_funcs[i] == mpf_pow_ui)
+	    this_in2i %= 0x1000;
+
+	  (dsi_funcs[i]) (res1, in1, this_in2i);
+
+	  mpf_set (out1, in1);
+	  (dsi_funcs[i]) (out1, out1, this_in2i);
+	  mpf_set (res2, out1);
+
+	  if (mpf_cmp (res1, res2) != 0)
+	    dump_abort (dsi_func_names[i], res1, res2);
+	}
+
+      in1i = urandom ();
+      for (i = 0; i < sizeof (dis_funcs) / sizeof (dis_func); i++)
+	{
+	  /* Don't divide by 0.  */
+	  if (i == 0 /* dis_funcs[i] == mpf_ui_div */
+	      && mpf_cmp_ui (in2, 0) == 0)
+	    continue;
+
+	  (dis_funcs[i]) (res1, in1i, in2);
+
+	  mpf_set (out1, in2);
+	  (dis_funcs[i]) (out1, in1i, out1);
+	  mpf_set (res2, out1);
+
+	  if (mpf_cmp (res1, res2) != 0)
+	    dump_abort (dis_func_names[i], res1, res2);
+	}
+
+    }
+
+  mpf_clear (in1);
+  mpf_clear (in2);
+  mpf_clear (out1);
+  mpf_clear (res1);
+  mpf_clear (res2);
+  mpf_clear (res3);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *name, mpf_t res1, mpf_t res2)
+{
+  printf ("failure in %s:\n", name);
+  mpf_dump (res1);
+  mpf_dump (res2);
+  abort ();
+}
+
+#if 0
+void mpf_abs		(mpf_ptr, mpf_srcptr);
+void mpf_sqrt		(mpf_ptr, mpf_srcptr);
+void mpf_neg		(mpf_ptr, mpf_srcptr);
+#endif
+
+#endif /* ! DLL_EXPORT */
diff --git a/tests/mpf/t-add.c b/tests/mpf/t-add.c
new file mode 100644
index 0000000..eb8bbdc
--- /dev/null
+++ b/tests/mpf/t-add.c
@@ -0,0 +1,107 @@
+/* Test mpf_add.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 20000;
+  int i;
+  mpf_t u, v, w, wref;
+  mp_size_t bprec = 100;
+  mpf_t rerr, max_rerr, limit_rerr;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w);
+  mpf_init (wref);
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (u, size, exp);
+
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (v, size, exp);
+
+      mpf_add (w, u, v);
+      refmpf_add (wref, u, v);
+
+      mpf_reldiff (rerr, w, wref);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("wref = "); mpf_dump (wref);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w);
+  mpf_clear (wref);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-cmp_d.c b/tests/mpf/t-cmp_d.c
new file mode 100644
index 0000000..213c091
--- /dev/null
+++ b/tests/mpf/t-cmp_d.c
@@ -0,0 +1,103 @@
+/* Test mpf_cmp_d.
+
+Copyright 2001, 2003, 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define SGN(n)  ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
+
+void
+check_one (const char *name, mpf_srcptr x, double y, int cmp)
+{
+  int   got;
+
+  got = mpf_cmp_d (x, y);
+  if (SGN(got) != cmp)
+    {
+      int i;
+      printf    ("mpf_cmp_d wrong (from %s)\n", name);
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmp);
+      mpf_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      mp_trace_base=-16;
+      mpf_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      printf    ("  y");
+      for (i = 0; i < sizeof(y); i++)
+        printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
+      printf ("\n");
+      abort ();
+    }
+}
+
+void
+check_infinity (void)
+{
+  mpf_t   x;
+  double  y = tests_infinity_d ();
+  if (y == 0.0)
+    return;
+
+  mpf_init (x);
+
+  /* 0 cmp inf */
+  mpf_set_ui (x, 0L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* 123 cmp inf */
+  mpf_set_ui (x, 123L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* -123 cmp inf */
+  mpf_set_si (x, -123L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* 2^5000 cmp inf */
+  mpf_set_ui (x, 1L);
+  mpf_mul_2exp (x, x, 5000L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* -2^5000 cmp inf */
+  mpf_neg (x, x);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  mpf_clear (x);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_infinity ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-cmp_si.c b/tests/mpf/t-cmp_si.c
new file mode 100644
index 0000000..29f7cdb
--- /dev/null
+++ b/tests/mpf/t-cmp_si.c
@@ -0,0 +1,134 @@
+/* Test mpf_cmp_si and mpf_cmp_z.
+
+Copyright 2000, 2001, 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x)       ((x) < 0 ? -1 : (x) == 0 ? 0 : 1)
+
+void
+check_data (void)
+{
+  static const struct {
+    int         a_base;
+    const char  *a;
+    const char  *b;
+    int         want;
+  } data[] = {
+    { 10, "0",  "1", -1 },
+    { 10, "0",  "0",  0 },
+    { 10, "0", "-1",  1 },
+
+    { 10, "1",  "1", 0 },
+    { 10, "1",  "0", 1 },
+    { 10, "1", "-1", 1 },
+
+    { 10, "-1",  "1", -1 },
+    { 10, "-1",  "0", -1 },
+    { 10, "-1", "-1", 0 },
+
+    { 10, "1.5", "2", -1 },
+    { 10, "1.5", "1",  1 },
+    { 10, "0.5", "1", -1 },
+
+    { 10, "-1.5", "-2",  1 },
+    { 10, "-1.5", "-1", -1 },
+    { 10, "-0.5", "-1",  1 },
+
+    { 16,         "0", "-0x80000000",  1 },
+    { 16,  "80000000", "-0x80000000",  1 },
+    { 16,  "80000001", "-0x80000000",  1 },
+    { 16, "-80000000", "-0x80000000",  0 },
+    { 16, "-80000001", "-0x80000000", -1 },
+    { 16, "-FF0080000001", "-0x80000000", -1 },
+
+    { 16,                 "0", "-0x8000000000000000",  1 },
+    { 16,  "8000000000000000", "-0x8000000000000000",  1 },
+    { 16,  "8000000000000001", "-0x8000000000000000",  1 },
+    { 16, "-8000000000000000", "-0x8000000000000000",  0 },
+    { 16, "-8000000000000000.1", "-0x8000000000000000", -1 },
+    { 16, "-FF008000000000000001", "-0x8000000000000000", -1 },
+
+    { 16,                 "0", "-0x876543210FEDCBA9876543210000000",  1 },
+    { 16,  "876543210FEDCBA9876543210000000", "-0x876543210FEDCBA9876543210000000",  1 },
+    { 16,  "876543210FEDCBA9876543210000001", "-0x876543210FEDCBA9876543210000000",  1 },
+    { 16, "-876543210FEDCBA9876543210000000", "-0x876543210FEDCBA9876543210000000",  0 },
+    { 16, "-876543210FEDCBA9876543210000000.1", "-0x876543210FEDCBA9876543210000000", -1 },
+    { 16, "-FF00876543210FEDCBA9876543210000000", "-0x876543210FEDCBA9876543210000000", -1 },
+  };
+
+  mpf_t  a;
+  mpz_t  bz;
+  long   b;
+  int    got;
+  int    i;
+
+  mpf_init2 (a, 128);
+  mpz_init (bz);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (a, data[i].a, data[i].a_base);
+      mpz_set_str_or_abort (bz, data[i].b, 0);
+
+      if (mpz_fits_slong_p (bz))
+        {
+          b = mpz_get_si (bz);
+          got = mpf_cmp_si (a, b);
+          if (SGN (got) != data[i].want)
+            {
+              printf ("mpf_cmp_si wrong on data[%d]\n", i);
+              printf ("  a="); mpf_out_str (stdout, 10, 0, a);
+              printf (" (%s)\n", data[i].a);
+              printf ("  b=%ld (%s)\n", b, data[i].b);
+              printf ("  got=%d\n", got);
+              printf ("  want=%d\n", data[i].want);
+              abort();
+            }
+        }
+
+      got = mpf_cmp_z (a, bz);
+      if (SGN (got) != data[i].want)
+	{
+	  b = mpz_get_si (bz);
+	  printf ("mpf_cmp_z wrong on data[%d]\n", i);
+	  printf ("  a="); mpf_out_str (stdout, 10, 0, a);
+	  printf (" (%s)\n", data[i].a);
+	  printf ("  b=%ld (%s)\n", b, data[i].b);
+	  printf ("  got=%d\n", got);
+	  printf ("  want=%d\n", data[i].want);
+	  abort();
+	}
+    }
+
+  mpf_clear (a);
+  mpz_clear (bz);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-conv.c b/tests/mpf/t-conv.c
new file mode 100644
index 0000000..2f992af
--- /dev/null
+++ b/tests/mpf/t-conv.c
@@ -0,0 +1,261 @@
+/* Test mpf_get_str and mpf_set_str.
+
+Copyright 1996, 2000, 2001, 2008, 2019, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strlen */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 10
+#endif
+
+#ifndef EXPO
+#define EXPO 200
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mpf_t x, y;
+  int reps = 20000;
+  int i;
+  mp_size_t bprec = 100;
+  mpf_t d, rerr, max_rerr, limit_rerr;
+  char *str;
+  mp_exp_t bexp;
+  long size, exp;
+  int base;
+  char buf[SIZE * GMP_LIMB_BITS + 5];
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (x);
+  mpf_init (y);
+  mpf_init (d);
+
+  /* First test some specific values.  */
+
+  mpf_set_str (y, "1.23456", 0);
+  mpf_set_str (x, "1.23456", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000000000000000000000001.23456", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000123456e40", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".000000000000000000000000000000000000000123456e40", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000.00000000000000000000123456e21", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "1.23456e1000", 0);
+  mpf_set_str (x, "1.23456e1000", 10);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "1.23456e+1000", 0);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "1.23456e+1000", 10);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000000000000000000000001.23456e+1000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000123456e+1040", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".000000000000000000000000000000000000000123456e+1040", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000.00000000000000000000123456e+1021", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "1.23456", 16);
+  mpf_set_str (x, "00000000000000000000000000000000000000001.23456", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000123456@28", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".000000000000000000000000000000000000000123456@28", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000.00000000000000000000123456@15", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "   0", 10);
+  mpf_set_str (x, "00000000000000000000000000000000000000000000000000000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0000000000000000000000000000000000000000000000000000.", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "000000000000000000000000000000000000000000000000000.0", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".0000000000000000000000000000000000000000000000000000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000000000000000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (x, "00000000000000000000000000000000000000000000000000000", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0000000000000000000000000000000000000000000000000000.", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "000000000000000000000000000000000000000000000000000.0", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".0000000000000000000000000000000000000000000000000000", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000000000000000", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "+00000000000000000000000000000000000000000000000000000e-345", 9);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "-0000000000000000000000000000000000000000000000000000.@AB", 26);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "000000000000000000000000000000000000000000000000000.0@78", 19);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "+.0000000000000000000000000000000000000000000000000000e555", 6);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "-0.000000000000000000000000000000000000000000000000000@-AAAAAAAAAAAAAAAAAAAAAAAA", 17);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  /* Now test random values.  */
+
+  for (i = 0; i < reps; i++)
+    {
+      if (i == 0)
+        {
+          /* exercise the special case in get_str for for x==0 */
+          mpf_set_ui (x, 0L);
+          base = 0;
+        }
+      else
+        {
+          size = urandom () % (2 * SIZE) - SIZE;
+          exp = urandom () % EXPO;
+          mpf_random2 (x, size, exp);
+          base = urandom () % 62;
+          base += base > 0;
+        }
+
+      str = mpf_get_str (0, &bexp, base, 0, x);
+
+      if (str[0] == '-')
+	sprintf (buf, "-0.%s@%ld", str + 1, bexp);
+      else
+	sprintf (buf, "0.%s@%ld", str, bexp);
+
+      mpf_set_str_or_abort (y, buf, -base);
+      (*__gmp_free_func) (str, strlen (str) + 1);
+
+      mpf_reldiff (rerr, x, y);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("base = %d\n", base);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   y = "); mpf_dump (y);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (x);
+  mpf_clear (y);
+  mpf_clear (d);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-div.c b/tests/mpf/t-div.c
new file mode 100644
index 0000000..3214592
--- /dev/null
+++ b/tests/mpf/t-div.c
@@ -0,0 +1,185 @@
+/* Test mpf_div.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (const char *desc, mpf_ptr got, mpf_srcptr u, mpf_srcptr v)
+{
+  if (! refmpf_validate_division ("mpf_div", got, u, v))
+    {
+      mp_trace_base = -16;
+      mpf_trace ("  u", u);
+      mpf_trace ("  v", v);
+      printf    ("  %s\n", desc);
+      abort ();
+    }
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  prec;
+  mpf_t  got, u, v;
+  int    i;
+
+  mpf_init (got);
+  mpf_init (u);
+  mpf_init (v);
+
+  /* separate */
+  for (i = 0; i < 100; i++)
+    {
+      /* got precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* u */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (u, prec);
+      do {
+        mpf_random2 (u, PREC(u), (mp_exp_t) 20);
+      } while (SIZ(u) == 0);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (u, u);
+
+      /* v */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (v, prec);
+      do {
+        mpf_random2 (v, PREC(v), (mp_exp_t) 20);
+      } while (SIZ(v) == 0);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (v, v);
+
+      switch (i % 3) {
+      case 0:
+        mpf_div (got, u, v);
+        check_one ("separate", got, u, v);
+        break;
+      case 1:
+        prec = refmpf_set_overlap (got, u);
+        mpf_div (got, got, v);
+        check_one ("dst == u", got, u, v);
+        mpf_set_prec_raw (got, prec);
+        break;
+      case 2:
+        prec = refmpf_set_overlap (got, v);
+        mpf_div (got, u, got);
+        check_one ("dst == v", got, u, v);
+        mpf_set_prec_raw (got, prec);
+        break;
+      }
+    }
+
+  mpf_clear (got);
+  mpf_clear (u);
+  mpf_clear (v);
+}
+
+/* Exercise calls mpf(x,x,x) */
+void
+check_reuse_three (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  result_prec, input_prec, set_prec;
+  mpf_t  got;
+  int    i;
+
+  mpf_init (got);
+
+  for (i = 0; i < 8; i++)
+    {
+      result_prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      input_prec = min_prec + gmp_urandomm_ui (rands, 15L);
+
+      set_prec = MAX (result_prec, input_prec);
+      refmpf_set_prec_limbs (got, set_prec);
+
+      /* input, non-zero, possibly negative */
+      PREC(got) = input_prec;
+      do {
+        mpf_random2 (got, input_prec, (mp_exp_t) 20);
+      } while (SIZ(got) == 0);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (got, got);
+
+      PREC(got) = result_prec;
+
+      mpf_div (got, got, got);
+
+      /* expect exactly 1.0 always */
+      ASSERT_ALWAYS (mpf_cmp_ui (got, 1L) == 0);
+
+      PREC(got) = set_prec;
+    }
+
+  mpf_clear (got);
+}
+
+void
+check_various (void)
+{
+  mpf_t got, u, v;
+
+  mpf_init (got);
+  mpf_init (u);
+  mpf_init (v);
+
+  /* 100/4 == 25 */
+  mpf_set_prec (got, 20L);
+  mpf_set_ui (u, 100L);
+  mpf_set_ui (v, 4L);
+  mpf_div (got, u, v);
+  MPF_CHECK_FORMAT (got);
+  ASSERT_ALWAYS (mpf_cmp_ui (got, 25L) == 0);
+
+  /* 1/(2^n+1), a case where truncating the divisor would be wrong */
+  mpf_set_prec (got, 500L);
+  mpf_set_prec (v, 900L);
+  mpf_set_ui (v, 1L);
+  mpf_mul_2exp (v, v, 800L);
+  mpf_add_ui (v, v, 1L);
+  mpf_div (got, u, v);
+  check_one ("1/2^n+1, separate", got, u, v);
+
+  mpf_clear (got);
+  mpf_clear (u);
+  mpf_clear (v);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+  check_reuse_three ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-dm2exp.c b/tests/mpf/t-dm2exp.c
new file mode 100644
index 0000000..d17c9fa
--- /dev/null
+++ b/tests/mpf/t-dm2exp.c
@@ -0,0 +1,118 @@
+/* Test mpf_div, mpf_div_2exp, mpf_mul_2exp.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+int
+main (int argc, char **argv)
+{
+  int reps = 100000;
+  int i;
+  mpf_t u, v, w1, w2, w3;
+  mp_size_t bprec = 100;
+  mpf_t rerr, limit_rerr;
+  mp_size_t un;
+  mp_exp_t ue;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init (rerr);
+  mpf_init (limit_rerr);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w1);
+  mpf_init (w2);
+  mpf_init (w3);
+
+  for (i = 0; i < reps; i++)
+    {
+      unsigned long int res_prec;
+      unsigned long int pow2;
+
+      res_prec = urandom () % (bprec + 100);
+      mpf_set_prec (w1, res_prec);
+      mpf_set_prec (w2, res_prec);
+      mpf_set_prec (w3, res_prec);
+
+      mpf_set_ui (limit_rerr, 1);
+      mpf_div_2exp (limit_rerr, limit_rerr, res_prec);
+
+      pow2 = urandom () % 0x10000;
+      mpf_set_ui (v, 1);
+      mpf_mul_2exp (v, v, pow2);
+
+      un = urandom () % (2 * SIZE) - SIZE;
+      ue = urandom () % SIZE;
+      mpf_random2 (u, un, ue);
+
+      mpf_div_2exp (w1, u, pow2);
+      mpf_div (w2, u, v);
+      mpf_reldiff (rerr, w1, w2);
+      if (mpf_cmp (rerr, limit_rerr) > 0)
+	{
+	  printf ("ERROR in mpf_div or mpf_div_2exp after %d tests\n", i);
+	  printf ("   u = "); mpf_dump (u);
+	  printf ("   v = "); mpf_dump (v);
+	  printf ("  w1 = "); mpf_dump (w1);
+	  printf ("  w2 = "); mpf_dump (w2);
+	  abort ();
+	}
+      mpf_mul_2exp (w3, w1, pow2);
+      mpf_reldiff (rerr, u, w3);
+      if (mpf_cmp (rerr, limit_rerr) > 0)
+	{
+	  printf ("ERROR in mpf_mul_2exp after %d tests\n", i);
+	  printf ("   u = "); mpf_dump (u);
+	  printf ("   v = "); mpf_dump (v);
+	  printf ("  w1 = "); mpf_dump (w1);
+	  printf ("  w3 = "); mpf_dump (w3);
+	  abort ();
+	}
+    }
+
+  mpf_clear (rerr);
+  mpf_clear (limit_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w1);
+  mpf_clear (w2);
+  mpf_clear (w3);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-eq.c b/tests/mpf/t-eq.c
new file mode 100644
index 0000000..7b80b02
--- /dev/null
+++ b/tests/mpf/t-eq.c
@@ -0,0 +1,217 @@
+/* Test mpf_eq.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SZ (2 * sizeof(mp_limb_t))
+
+void insert_random_low_zero_limbs (mpf_t, gmp_randstate_ptr);
+void dump_abort (mpf_t, mpf_t, int, int, int, int, int, long);
+void hexdump (mpf_t);
+
+void
+check_data (void)
+{
+  static const struct
+  {
+    struct {
+      int        exp, size;
+      mp_limb_t  d[10];
+    } x, y;
+    mp_bitcnt_t bits;
+    int want;
+
+  } data[] = {
+    { { 0, 0, { 0 } },             { 0, 0, { 0 } },    0, 1 },
+
+    { { 0, 1, { 7 } },             { 0, 1, { 7 } },    0, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 7 } },   17, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 7 } }, 4711, 1 },
+
+    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    0, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    2, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    3, 0 },
+
+    { { 0, 0, { 0 } },             { 0, 1, { 1 } },    0, 0 },
+    { { 0, 1, { 1 } },             { 0,-1 ,{ 1 } },    0, 0 },
+    { { 1, 1, { 1 } },             { 0, 1, { 1 } },    0, 0 },
+
+    { { 0, 1, { 8 } },             { 0, 1, { 4 } },    0, 0 },
+
+    { { 0, 2, { 0, 3 } },          { 0, 1, { 3 } }, 1000, 1 },
+  };
+
+  mpf_t  x, y;
+  int got, got_swapped;
+  int i;
+  mp_trace_base = 16;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      PTR(x) = (mp_ptr) data[i].x.d;
+      SIZ(x) = data[i].x.size;
+      EXP(x) = data[i].x.exp;
+      PREC(x) = numberof (data[i].x.d);
+      MPF_CHECK_FORMAT (x);
+
+      PTR(y) = (mp_ptr) data[i].y.d;
+      SIZ(y) = data[i].y.size;
+      EXP(y) = data[i].y.exp;
+      PREC(y) = numberof (data[i].y.d);
+      MPF_CHECK_FORMAT (y);
+
+      got         = mpf_eq (x, y, data[i].bits);
+      got_swapped = mpf_eq (y, x, data[i].bits);
+
+      if (got != got_swapped || got != data[i].want)
+	{
+	  printf ("check_data() wrong result at data[%d]\n", i);
+	  mpf_trace ("x   ", x);
+	  mpf_trace ("y   ", y);
+	  printf ("got         %d\n", got);
+	  printf ("got_swapped %d\n", got_swapped);
+	  printf ("want        %d\n", data[i].want);
+	  abort ();
+        }
+    }
+}
+
+void
+check_random (long reps)
+{
+  unsigned long test;
+  gmp_randstate_ptr rands = RANDS;
+  mpf_t a, b, x;
+  mpz_t ds;
+  int hibits, lshift1, lshift2;
+  int xtra;
+
+#define HIBITS 10
+#define LSHIFT1 10
+#define LSHIFT2 10
+
+  mpf_set_default_prec ((1 << HIBITS) + (1 << LSHIFT1) + (1 << LSHIFT2));
+
+  mpz_init (ds);
+  mpf_inits (a, b, x, NULL);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_urandomb (ds, rands, HIBITS);
+      hibits = mpz_get_ui (ds) + 1;
+      mpz_urandomb (ds, rands, hibits);
+      mpz_setbit (ds, hibits  - 1);	/* make sure msb is set */
+      mpf_set_z (a, ds);
+      mpf_set_z (b, ds);
+
+      mpz_urandomb (ds, rands, LSHIFT1);
+      lshift1 = mpz_get_ui (ds);
+      mpf_mul_2exp (a, a, lshift1 + 1);
+      mpf_mul_2exp (b, b, lshift1 + 1);
+      mpf_add_ui (a, a, 1);	/* make a one-bit difference */
+
+      mpz_urandomb (ds, rands, LSHIFT2);
+      lshift2 = mpz_get_ui (ds);
+      mpf_mul_2exp (a, a, lshift2);
+      mpf_mul_2exp (b, b, lshift2);
+      mpz_urandomb (ds, rands, lshift2);
+      mpf_set_z (x, ds);
+      mpf_add (a, a, x);
+      mpf_add (b, b, x);
+
+      insert_random_low_zero_limbs (a, rands);
+      insert_random_low_zero_limbs (b, rands);
+
+      if (mpf_eq (a, b, lshift1 + hibits) == 0 ||
+	  mpf_eq (b, a, lshift1 + hibits) == 0)
+	{
+	  dump_abort (a, b, lshift1 + hibits, lshift1, lshift2, hibits, 1, test);
+	}
+      for (xtra = 1; xtra < 100; xtra++)
+	if (mpf_eq (a, b, lshift1 + hibits + xtra) != 0 ||
+	    mpf_eq (b, a, lshift1 + hibits + xtra) != 0)
+	  {
+	    dump_abort (a, b, lshift1 + hibits + xtra, lshift1, lshift2, hibits, 0, test);
+	  }
+    }
+
+  mpf_clears (a, b, x, NULL);
+  mpz_clear (ds);
+}
+
+void
+insert_random_low_zero_limbs (mpf_t x, gmp_randstate_ptr rands)
+{
+  mp_size_t max = PREC(x) - SIZ(x);
+  mp_size_t s;
+  mpz_t ds; mpz_init (ds);
+  mpz_urandomb (ds, rands, 32);
+  s = mpz_get_ui (ds) % (max + 1);
+  MPN_COPY_DECR (PTR(x) + s, PTR(x), SIZ(x));
+  MPN_ZERO (PTR(x), s);
+  SIZ(x) += s;
+  mpz_clear (ds);
+}
+
+void
+dump_abort (mpf_t a, mpf_t b, int cmp_prec, int lshift1, int lshift2, int hibits, int want, long test)
+{
+  printf ("ERROR in test %ld\n", test);
+  printf ("want %d got %d from mpf_eq\n", want, 1-want);
+  printf ("cmp_prec = %d\n", cmp_prec);
+  printf ("lshift1 = %d\n", lshift1);
+  printf ("lshift2 = %d\n", lshift2);
+  printf ("hibits = %d\n", hibits);
+  hexdump (a); puts ("");
+  hexdump (b); puts ("");
+  abort ();
+}
+
+void
+hexdump (mpf_t x)
+{
+  mp_size_t i;
+  for (i = ABSIZ(x) - 1; i >= 0; i--)
+    {
+      gmp_printf ("%0*MX", SZ, PTR(x)[i]);
+      if (i != 0)
+	printf (" ");
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  long reps = 10000;
+
+  if (argc == 2)
+    reps = strtol (argv[1], 0, 0);
+
+  tests_start ();
+
+  check_data ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-fits.c b/tests/mpf/t-fits.c
new file mode 100644
index 0000000..937e4e6
--- /dev/null
+++ b/tests/mpf/t-fits.c
@@ -0,0 +1,327 @@
+/* Test mpf_fits_*_p
+
+Copyright 2001, 2002, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Nothing sophisticated here, just exercise mpf_fits_*_p on a small amount
+   of data. */
+
+#define EXPECT_S(fun,name,answer)                                        \
+  got = fun (f);                                                         \
+  if (got != answer)                                                     \
+    {                                                                    \
+      printf ("%s (%s) got %d want %d\n", name, expr, got, answer);      \
+      printf (" f size %d exp %ld\n", SIZ(f), EXP(f));                   \
+      printf (" f dec "); mpf_out_str (stdout, 10, 0, f); printf ("\n"); \
+      printf (" f hex "); mpf_out_str (stdout, 16, 0, f); printf ("\n"); \
+      error = 1;                                                         \
+    }
+
+#define EXPECT(fun,answer)  EXPECT_S(fun,#fun,answer)
+
+int
+main (void)
+{
+  mpf_t       f, f0p5;
+  int         got;
+  const char  *expr;
+  int         error = 0;
+
+  tests_start ();
+  mpf_init2 (f, 200L);
+  mpf_init2 (f0p5, 200L);
+
+  /* 0.5 */
+  mpf_set_ui (f0p5, 1L);
+  mpf_div_2exp (f0p5, f0p5, 1L);
+
+  mpf_set_ui (f, 0L);
+  expr = "0";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_ui (f, 1L);
+  expr = "1";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, -1L);
+  expr = "-1";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+
+  mpf_set_ui (f, (unsigned long) USHRT_MAX);
+  expr = "USHRT_MAX";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+
+  mpf_set_ui (f, (unsigned long) USHRT_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "USHRT_MAX + 0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+
+  mpf_set_ui (f, (unsigned long) USHRT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "USHRT_MAX + 1";
+  EXPECT (mpf_fits_ushort_p, 0);
+
+
+  mpf_set_ui (f, (unsigned long) UINT_MAX);
+  expr = "UINT_MAX";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+
+  mpf_set_ui (f, (unsigned long) UINT_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "UINT_MAX + 0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+
+  mpf_set_ui (f, (unsigned long) UINT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "UINT_MAX + 1";
+  EXPECT (mpf_fits_uint_p, 0);
+
+
+  mpf_set_ui (f, ULONG_MAX);
+  expr = "ULONG_MAX";
+  EXPECT (mpf_fits_ulong_p, 1);
+
+  mpf_set_ui (f, ULONG_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "ULONG_MAX + 0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+
+  mpf_set_ui (f, ULONG_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "ULONG_MAX + 1";
+  EXPECT (mpf_fits_ulong_p, 0);
+
+
+  mpf_set_si (f, (long) SHRT_MAX);
+  expr = "SHRT_MAX";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MAX);
+  expr = "SHRT_MAX + 0.5";
+  mpf_add (f, f, f0p5);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "SHRT_MAX + 1";
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  mpf_set_si (f, (long) INT_MAX);
+  expr = "INT_MAX";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "INT_MAX + 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "INT_MAX + 1";
+  EXPECT (mpf_fits_sint_p, 0);
+
+
+  mpf_set_si (f, LONG_MAX);
+  expr = "LONG_MAX";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "LONG_MAX + 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "LONG_MAX + 1";
+  EXPECT (mpf_fits_slong_p, 0);
+
+
+  mpf_set_si (f, (long) SHRT_MIN);
+  expr = "SHRT_MIN";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MIN);
+  mpf_sub (f, f, f0p5);
+  expr = "SHRT_MIN - 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MIN);
+  mpf_sub_ui (f, f, 1L);
+  expr = "SHRT_MIN - 1";
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  mpf_set_si (f, (long) INT_MIN);
+  expr = "INT_MIN";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MIN);
+  mpf_sub (f, f, f0p5);
+  expr = "INT_MIN - 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MIN);
+  mpf_sub_ui (f, f, 1L);
+  expr = "INT_MIN - 1";
+  EXPECT (mpf_fits_sint_p, 0);
+
+
+  mpf_set_si (f, LONG_MIN);
+  expr = "LONG_MIN";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MIN);
+  mpf_sub (f, f, f0p5);
+  expr = "LONG_MIN - 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MIN);
+  mpf_sub_ui (f, f, 1L);
+  expr = "LONG_MIN - 1";
+  EXPECT (mpf_fits_slong_p, 0);
+
+
+  mpf_set_str_or_abort (f, "0.5", 10);
+  expr = "0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_str_or_abort (f, "-0.5", 10);
+  expr = "-0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_str_or_abort (f, "-1.5", 10);
+  expr = "-1.5";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+
+  mpf_set_str_or_abort (f, "1.000000000000000000000000000000000001", 16);
+  expr = "1.000000000000000000000000000000000001 base 16";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_str_or_abort (f, "1@1000", 16);
+  expr = "1@1000 base 16";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, BITS_PER_ULONG + 1);
+  mpf_sub_ui (f, f, 1L);
+  expr = "2^(BITS_PER_ULONG+1) - 1";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, BITS_PER_ULONG + 1);
+  mpf_ui_sub (f, 1L, f);
+  expr = "- (2^(BITS_PER_ULONG+1) - 1)";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, BITS_PER_ULONG + 5);
+  mpf_sub_ui (f, f, 1L);
+  expr = "2^(BITS_PER_ULONG+5) - 1";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  if (error)
+    abort ();
+
+  mpf_clear (f);
+  mpf_clear (f0p5);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-get_d.c b/tests/mpf/t-get_d.c
new file mode 100644
index 0000000..4e4c741
--- /dev/null
+++ b/tests/mpf/t-get_d.c
@@ -0,0 +1,106 @@
+/* Test mpf_get_d and mpf_set_d.
+
+Copyright 1996, 1999-2001, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if defined (__vax) || defined (__vax__)
+#define LOW_BOUND 1e-38
+#define HIGH_BOUND 8e37
+#endif
+
+#if defined (_CRAY) && ! defined (_CRAYIEEE)
+/* The range varies mysteriously between Cray version.  On an SV1,
+   the range seem to be 1e-600..1e603, but a cfp (non-ieee) T90
+   has a much smaller range of 1e-240..1e240.  */
+#define LOW_BOUND 1e-240
+#define HIGH_BOUND 1e240
+#endif
+
+#if ! defined (LOW_BOUND)
+#define LOW_BOUND 1e-300
+#define HIGH_BOUND 1e300
+#endif
+
+void
+test_denorms (int prc)
+{
+#ifdef _GMP_IEEE_FLOATS
+  double d1, d2;
+  mpf_t f;
+  int i;
+
+  mpf_set_default_prec (prc);
+
+  mpf_init (f);
+
+  d1 = 1.9;
+  for (i = 0; i < 820; i++)
+    {
+      mpf_set_d (f, d1);
+      d2 = mpf_get_d (f);
+      if (d1 != d2)
+        abort ();
+      d1 *= 0.4;
+    }
+
+  mpf_clear (f);
+#endif
+}
+
+int
+main (int argc, char **argv)
+{
+  double d, e, r;
+  mpf_t u, v;
+
+  tests_start ();
+  mpf_init (u);
+  mpf_init (v);
+
+  mpf_set_d (u, LOW_BOUND);
+  for (d = 2.0 * LOW_BOUND; d < HIGH_BOUND; d *= 1.01)
+    {
+      mpf_set_d (v, d);
+      if (mpf_cmp (u, v) >= 0)
+	abort ();
+      e = mpf_get_d (v);
+      r = e/d;
+      if (r < 0.99999999999999 || r > 1.00000000000001)
+	{
+	  fprintf (stderr, "should be one ulp from 1: %.16f\n", r);
+	  abort ();
+	}
+      mpf_set (u, v);
+    }
+
+  mpf_clear (u);
+  mpf_clear (v);
+
+  test_denorms (10);
+  test_denorms (32);
+  test_denorms (64);
+  test_denorms (100);
+  test_denorms (200);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-get_d_2exp.c b/tests/mpf/t-get_d_2exp.c
new file mode 100644
index 0000000..b716cf8
--- /dev/null
+++ b/tests/mpf/t-get_d_2exp.c
@@ -0,0 +1,136 @@
+/* Test mpf_get_d_2exp.
+
+Copyright 2002, 2003, 2017, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+static void
+check_data (void)
+{
+  mpf_t   f;
+  double  got, want;
+  long    got_exp;
+  long    exp;
+  struct {
+    int base;
+    int shift;
+  } data[] = {
+   {-1, 1}, {-3, 2}, {-5, 3}, {-7, 3}, { 1, 1}, { 3, 2}, { 5, 3}, { 7, 3}
+  };
+
+  mpf_init2 (f, 3);
+
+  got = mpf_get_d_2exp (&got_exp, f);
+  if (got != 0 || got_exp != 0)
+    {
+      printf    ("mpf_get_d_2exp wrong on zero\n");
+      mpf_trace ("   f    ", f);
+      d_trace   ("   got  ", got);
+      printf    ("   got exp  %ld\n", got_exp);
+      abort();
+    }
+
+  for (exp = -513; exp <= 513; exp++)
+    {
+      size_t i;
+      for (i = 0; i < numberof (data); i++)
+	{
+	  want = (double) data[i].base / (1 << data[i].shift);
+	  mpf_set_d (f, want);
+
+	  if (exp >= 0)
+	    mpf_mul_2exp (f, f, exp);
+	  else
+	    mpf_div_2exp (f, f, -exp);
+
+	  got = mpf_get_d_2exp (&got_exp, f);
+	  if (got != want || got_exp != exp)
+	    {
+	      printf    ("mpf_get_d_2exp wrong on 2**%ld\n", exp);
+	      mpf_trace ("   f    ", f);
+	      d_trace   ("   want ", want);
+	      d_trace   ("   got  ", got);
+	      printf    ("   want exp %ld\n", exp);
+	      printf    ("   got exp  %ld\n", got_exp);
+	      abort();
+	    }
+	}
+    }
+  mpf_clear (f);
+}
+
+/* Check that hardware rounding doesn't make mpf_get_d_2exp return a value
+   outside its defined range. */
+static void
+check_round (void)
+{
+  static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
+  mpf_t   f;
+  double  got;
+  long    got_exp;
+  int     i, rnd_mode, old_rnd_mode;
+
+  mpf_init2 (f, 1024L);
+  old_rnd_mode = tests_hardware_getround ();
+
+  for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
+    {
+      tests_hardware_setround (rnd_mode);
+
+      for (i = 0; i < numberof (data); i++)
+        {
+          mpf_set_ui (f, 1L);
+          mpf_mul_2exp (f, f, data[i]);
+          mpf_sub_ui (f, f, 1L);
+
+          got = mpf_get_d_2exp (&got_exp, f);
+          if (got < 0.5 || got >= 1.0)
+            {
+              printf    ("mpf_get_d_2exp bad on 2**%lu-1\n", data[i]);
+              printf    ("result out of range, expect 0.5 <= got < 1.0\n");
+              printf    ("   rnd_mode = %d\n", rnd_mode);
+              printf    ("   data[i]  = %lu\n", data[i]);
+              mpf_trace ("   f    ", f);
+              d_trace   ("   got  ", got);
+              printf    ("   got exp  %ld\n", got_exp);
+              abort();
+            }
+        }
+    }
+
+  mpf_clear (f);
+  tests_hardware_setround (old_rnd_mode);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_data ();
+  check_round ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-get_si.c b/tests/mpf/t-get_si.c
new file mode 100644
index 0000000..5510b04
--- /dev/null
+++ b/tests/mpf/t-get_si.c
@@ -0,0 +1,222 @@
+/* Exercise mpz_get_si.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    int         base;
+    const char  *f;
+    long        want;
+  } data[] = {
+    { 10, "0",      0L },
+    { 10, "1",      1L },
+    { 10, "-1",     -1L },
+    { 10, "2",      2L },
+    { 10, "-2",     -2L },
+    { 10, "12345",  12345L },
+    { 10, "-12345", -12345L },
+
+    /* fraction bits ignored */
+    { 10, "0.5",    0L },
+    { 10, "-0.5",   0L },
+    { 10, "1.1",    1L },
+    { 10, "-1.1",   -1L },
+    { 10, "1.9",    1L },
+    { 10, "-1.9",   -1L },
+    { 16, "1.000000000000000000000000000000000000000000000000001", 1L },
+    { 16, "-1.000000000000000000000000000000000000000000000000001", -1L },
+
+    /* low bits extracted (this is undocumented) */
+    { 16, "1000000000000000000000000000000000000000000000000001", 1L },
+    { 16, "-1000000000000000000000000000000000000000000000000001", -1L },
+  };
+
+  int    i;
+  mpf_t  f;
+  long   got;
+
+  mpf_init2 (f, 2000L);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (f, data[i].f, data[i].base);
+
+      got = mpf_get_si (f);
+      if (got != data[i].want)
+	{
+	  printf ("mpf_get_si wrong at data[%d]\n", i);
+	  printf ("   f     \"%s\"\n", data[i].f);
+	  printf ("     dec "); mpf_out_str (stdout, 10, 0, f); printf ("\n");
+	  printf ("     hex "); mpf_out_str (stdout, 16, 0, f); printf ("\n");
+	  printf ("     size %ld\n", (long) SIZ(f));
+	  printf ("     exp  %ld\n", (long) EXP(f));
+	  printf ("   got   %ld (0x%lX)\n", got, got);
+	  printf ("   want  %ld (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+  mpf_clear (f);
+}
+
+
+void
+check_max (void)
+{
+  mpf_t  f;
+  long   want;
+  long   got;
+
+  mpf_init2 (f, 200L);
+
+#define CHECK_MAX(name)                                         \
+  if (got != want)                                              \
+    {                                                           \
+      printf ("mpf_get_si wrong on %s\n", name);                \
+      printf ("   f    ");                                      \
+      mpf_out_str (stdout, 10, 0, f); printf (", hex ");        \
+      mpf_out_str (stdout, 16, 0, f); printf ("\n");            \
+      printf ("   got  %ld, hex %lX\n", got, got);              \
+      printf ("   want %ld, hex %lX\n", want, want);            \
+      abort();                                                  \
+    }
+
+  want = LONG_MAX;
+  mpf_set_si (f, want);
+  got = mpf_get_si (f);
+  CHECK_MAX ("LONG_MAX");
+
+  want = LONG_MIN;
+  mpf_set_si (f, want);
+  got = mpf_get_si (f);
+  CHECK_MAX ("LONG_MIN");
+
+  mpf_clear (f);
+}
+
+
+void
+check_limbdata (void)
+{
+#define M  GMP_NUMB_MAX
+
+  static const struct {
+    mp_exp_t       exp;
+    mp_size_t      size;
+    mp_limb_t      d[10];
+    unsigned long  want;
+
+  } data[] = {
+
+    /* in the comments here, a "_" indicates a digit (ie. limb) position not
+       included in the d data, and therefore zero */
+
+    { 0, 0, { 0 }, 0L },    /* 0 */
+
+    { 1,  1, { 1 }, 1L },   /* 1 */
+    { 1, -1, { 1 }, -1UL },  /* -1 */
+
+    { 0,  1, { 1 }, 0L },   /* .1 */
+    { 0, -1, { 1 }, 0L },   /* -.1 */
+
+    { -1,  1, { 1 }, 0L },  /* ._1 */
+    { -1, -1, { 1 }, 0L },  /* -._1 */
+
+    { -999,          1, { 1 }, 0L },   /* .___1 small */
+    { MP_EXP_T_MIN,  1, { 1 }, 0L },   /* .____1 very small */
+
+    { 999,          1, { 1 }, 0L },    /* 1____. big */
+    { MP_EXP_T_MAX, 1, { 1 }, 0L },    /* 1_____. very big */
+
+    { 1, 2, { 999, 2 }, 2L },                  /* 2.9 */
+    { 5, 8, { 7, 8, 9, 3, 0, 0, 0, 1 }, 3L },  /* 10003.987 */
+
+    { 2, 2, { M, M },    LONG_MAX }, /* FF. */
+    { 2, 2, { M, M, M }, LONG_MAX }, /* FF.F */
+    { 3, 3, { M, M, M }, LONG_MAX }, /* FFF. */
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    /* normal case, numb bigger than long */
+    { 2,  1, { 1 },    0L },      /* 1_. */
+    { 2,  2, { 0, 1 }, 0L },      /* 10. */
+    { 2,  2, { 999, 1 }, 999L },  /* 19. */
+    { 3,  2, { 999, 1 }, 0L },    /* 19_. */
+
+#else
+    /* nails case, numb smaller than long */
+    { 2,  1, { 1 }, 1L << GMP_NUMB_BITS },  /* 1_. */
+    { 3,  1, { 1 }, 0L },                   /* 1__. */
+
+    { 2,  2, { 99, 1 },    99L + (1L << GMP_NUMB_BITS) },  /* 19. */
+    { 3,  2, { 1, 99 },    1L << GMP_NUMB_BITS },          /* 91_. */
+    { 3,  3, { 0, 1, 99 }, 1L << GMP_NUMB_BITS },          /* 910. */
+
+#endif
+  };
+
+  mpf_t          f;
+  unsigned long  got;
+  int            i;
+  mp_limb_t      buf[20 + numberof(data[i].d)];
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_fill (buf, 10, CNST_LIMB(0xDEADBEEF));
+      refmpn_copy (buf+10, data[i].d, ABS(data[i].size));
+      refmpn_fill (buf+10+ABS(data[i].size), 10, CNST_LIMB(0xDEADBEEF));
+
+      PTR(f) = buf+10;
+      EXP(f) = data[i].exp;
+      SIZ(f) = data[i].size;
+      PREC(f) = numberof (data[i].d);
+      MPF_CHECK_FORMAT (f);
+
+      got = mpf_get_si (f);
+      if (got != data[i].want)
+	{
+	  printf    ("mpf_get_si wrong at limb data[%d]\n", i);
+	  mpf_trace ("  f", f);
+	  mpn_trace ("  d", data[i].d, data[i].size);
+	  printf    ("  size %ld\n", (long) data[i].size);
+	  printf    ("  exp %ld\n", (long) data[i].exp);
+	  printf    ("  got   %lu (0x%lX)\n", got, got);
+	  printf    ("  want  %lu (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_max ();
+  check_limbdata ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-get_ui.c b/tests/mpf/t-get_ui.c
new file mode 100644
index 0000000..6011b0f
--- /dev/null
+++ b/tests/mpf/t-get_ui.c
@@ -0,0 +1,127 @@
+/* Exercise mpf_get_ui.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_limbdata (void)
+{
+#define M  GMP_NUMB_MAX
+
+  static const struct {
+    mp_exp_t       exp;
+    mp_size_t      size;
+    mp_limb_t      d[10];
+    unsigned long  want;
+
+  } data[] = {
+
+    /* in the comments here, a "_" indicates a digit (ie. limb) position not
+       included in the d data, and therefore zero */
+
+    { 0, 0, { 0 }, 0L },    /* 0 */
+
+    { 1,  1, { 1 }, 1L },   /* 1 */
+    { 1, -1, { 1 }, 1L },   /* -1 */
+
+    { 0,  1, { 1 }, 0L },   /* .1 */
+    { 0, -1, { 1 }, 0L },   /* -.1 */
+
+    { -1,  1, { 1 }, 0L },  /* ._1 */
+    { -1, -1, { 1 }, 0L },  /* -._1 */
+
+    { -999,          1, { 1 }, 0L },   /* .___1 small */
+    { MP_EXP_T_MIN,  1, { 1 }, 0L },   /* .____1 very small */
+
+    { 999,          1, { 1 }, 0L },    /* 1____. big */
+    { MP_EXP_T_MAX, 1, { 1 }, 0L },    /* 1_____. very big */
+
+    { 1, 2, { 999, 2 }, 2L },                  /* 2.9 */
+    { 5, 8, { 7, 8, 9, 3, 0, 0, 0, 1 }, 3L },  /* 10003.987 */
+
+    { 2, 2, { M, M },    ULONG_MAX }, /* FF. */
+    { 2, 2, { M, M, M }, ULONG_MAX }, /* FF.F */
+    { 3, 3, { M, M, M }, ULONG_MAX }, /* FFF. */
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    /* normal case, numb bigger than long */
+    { 2,  1, { 1 },    0L },      /* 1_. */
+    { 2,  2, { 0, 1 }, 0L },      /* 10. */
+    { 2,  2, { 999, 1 }, 999L },  /* 19. */
+    { 3,  2, { 999, 1 }, 0L },    /* 19_. */
+
+#else
+    /* nails case, numb smaller than long */
+    { 2,  1, { 1 }, 1L << GMP_NUMB_BITS },  /* 1_. */
+    { 3,  1, { 1 }, 0L },                   /* 1__. */
+
+    { 2,  2, { 99, 1 },    99L + (1L << GMP_NUMB_BITS) },  /* 19. */
+    { 3,  2, { 1, 99 },    1L << GMP_NUMB_BITS },          /* 91_. */
+    { 3,  3, { 0, 1, 99 }, 1L << GMP_NUMB_BITS },          /* 910. */
+
+#endif
+  };
+
+  mpf_t          f;
+  unsigned long  got;
+  int            i;
+  mp_limb_t      buf[20 + numberof(data[i].d)];
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_fill (buf, 10, CNST_LIMB(0xDEADBEEF));
+      refmpn_copy (buf+10, data[i].d, ABS(data[i].size));
+      refmpn_fill (buf+10+ABS(data[i].size), 10, CNST_LIMB(0xDEADBEEF));
+
+      PTR(f) = buf+10;
+      EXP(f) = data[i].exp;
+      SIZ(f) = data[i].size;
+      PREC(f) = numberof (data[i].d);
+      MPF_CHECK_FORMAT (f);
+
+      got = mpf_get_ui (f);
+      if (got != data[i].want)
+	{
+	  printf    ("mpf_get_ui wrong at limb data[%d]\n", i);
+	  mpf_trace ("  f", f);
+	  mpn_trace ("  d", data[i].d, data[i].size);
+	  printf    ("  size %ld\n", (long) data[i].size);
+	  printf    ("  exp %ld\n", (long) data[i].exp);
+	  printf    ("  got   %lu (0x%lX)\n", got, got);
+	  printf    ("  want  %lu (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_limbdata ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-gsprec.c b/tests/mpf/t-gsprec.c
new file mode 100644
index 0000000..da07f3e
--- /dev/null
+++ b/tests/mpf/t-gsprec.c
@@ -0,0 +1,61 @@
+/* Test mpf_get_prec and mpf_set_prec.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_consistency (void)
+{
+  mpf_t  x;
+  unsigned long  i, a, b;
+
+  mpf_init (x);
+
+  for (i = 1; i < 2000; i++)
+    {
+      mpf_set_prec (x, i);
+      a = mpf_get_prec (x);
+      mpf_set_prec (x, a);
+      b = mpf_get_prec (x);
+      if (a != b)
+        {
+          printf ("mpf_get_prec / mpf_set_prec inconsistent\n");
+          printf ("   set %lu gives %lu, but then set %lu gives %lu\n",
+                  i, a,
+                  a, b);
+          abort ();
+        }
+    }
+
+  mpf_clear (x);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_consistency ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-inp_str.c b/tests/mpf/t-inp_str.c
new file mode 100644
index 0000000..75e0fce
--- /dev/null
+++ b/tests/mpf/t-inp_str.c
@@ -0,0 +1,191 @@
+/* Test mpf_inp_str.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define FILENAME  "/tmp/t-inp_str.tmp"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *inp;
+    int         base;
+    const char  *want;
+    int         want_nread;
+
+  } data[] = {
+
+    { "0",   10, "0", 1 },
+
+    { "abc", 10, "0", 0 },
+    { "ghi", 16, "0", 0 },
+
+    { "125",    10, "125",  3 },
+    { "125e1",  10, "1250", 5 },
+    { "12e+2",  10, "1200", 5 },
+    { "125e-1", 10, "12.5", 6 },
+
+    {  "ff", 16,  "255", 2 },
+    { "-ff", 16, "-255", 3 },
+    {  "FF", 16,  "255", 2 },
+    { "-FF", 16, "-255", 3 },
+
+    { "100",     16, "256",  3 },
+    { "100@1",   16, "4096", 5 },
+    { "100@10",  16, "4722366482869645213696", 6 },
+    { "100@10", -16, "281474976710656",        6 },
+    { "100@-1",  16, "16",   6 },
+    { "10000000000000000@-10",  16, "1", 21 },
+    { "10000000000@-10",       -16, "1", 15 },
+
+    { "z", 36, "35", 1 },
+    { "Z", 36, "35", 1 },
+    { "z@1", 36, "1260", 3 },
+    { "Z@1", 36, "1260", 3 },
+
+    {  "0",      0,   "0", 1 },
+  };
+
+  mpf_t  got, want;
+  long   ftell_nread;
+  int    i, pre, post, j, got_nread, want_nread;
+  FILE   *fp;
+
+  mpf_init (got);
+  mpf_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (pre = 0; pre <= 3; pre++)
+        {
+          for (post = 0; post <= 2; post++)
+            {
+              mpf_set_str_or_abort (want, data[i].want, 10);
+              MPF_CHECK_FORMAT (want);
+
+              /* create the file new each time to ensure its length is what
+                 we want */
+              fp = fopen (FILENAME, "w+");
+              ASSERT_ALWAYS (fp != NULL);
+              for (j = 0; j < pre; j++)
+                putc (' ', fp);
+              fputs (data[i].inp, fp);
+              for (j = 0; j < post; j++)
+                putc (' ', fp);
+              fflush (fp);
+              ASSERT_ALWAYS (! ferror(fp));
+
+              rewind (fp);
+              got_nread = mpf_inp_str (got, fp, data[i].base);
+
+              if (got_nread != 0)
+                {
+                  ftell_nread = ftell (fp);
+                  if (got_nread != ftell_nread)
+                    {
+                      printf ("mpf_inp_str nread wrong\n");
+                      printf ("  inp          \"%s\"\n", data[i].inp);
+                      printf ("  base         %d\n", data[i].base);
+                      printf ("  pre          %d\n", pre);
+                      printf ("  post         %d\n", post);
+                      printf ("  got_nread    %d\n", got_nread);
+                      printf ("  ftell_nread  %ld\n", ftell_nread);
+                      abort ();
+                    }
+                }
+
+              /* if data[i].inp is a whole string to read and there's no post
+                 whitespace then expect to have EOF */
+              if (post == 0 && data[i].want_nread == strlen(data[i].inp))
+                {
+                  int  c = getc(fp);
+                  if (c != EOF)
+                    {
+                      printf ("mpf_inp_str didn't read to EOF\n");
+                      printf ("  inp   \"%s\"\n", data[i].inp);
+                      printf ("  base  %d\n", data[i].base);
+                      printf ("  pre   %d\n", pre);
+                      printf ("  post  %d\n", post);
+                      printf ("  c     '%c' %#x\n", c, c);
+                      abort ();
+                    }
+                }
+
+              /* only expect "pre" included in the count when non-zero */
+              want_nread = data[i].want_nread;
+              if (want_nread != 0)
+                want_nread += pre;
+
+              if (got_nread != want_nread)
+                {
+                  printf ("mpf_inp_str nread wrong\n");
+                  printf ("  inp         \"%s\"\n", data[i].inp);
+                  printf ("  base        %d\n", data[i].base);
+                  printf ("  pre         %d\n", pre);
+                  printf ("  post        %d\n", post);
+                  printf ("  got_nread   %d\n", got_nread);
+                  printf ("  want_nread  %d\n", want_nread);
+                  abort ();
+                }
+
+              MPF_CHECK_FORMAT (got);
+
+              if (mpf_cmp (got, want) != 0)
+                {
+                  printf ("mpf_inp_str wrong result\n");
+                  printf ("  inp   \"%s\"\n", data[i].inp);
+                  printf ("  base  %d\n", data[i].base);
+                  mpf_trace ("  got ",  got);
+                  mpf_trace ("  want", want);
+                  abort ();
+                }
+
+              ASSERT_ALWAYS (fclose (fp) == 0);
+            }
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  unlink (FILENAME);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-int_p.c b/tests/mpf/t-int_p.c
new file mode 100644
index 0000000..3e536db
--- /dev/null
+++ b/tests/mpf/t-int_p.c
@@ -0,0 +1,90 @@
+/* Test mpf_integer_p.
+
+Copyright 2001, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+one (mpf_srcptr f, int want)
+{
+  int  got;
+  got = mpf_integer_p (f);
+  if (got != want)
+    {
+      printf ("mpf_integer_p got %d want %d\n", got, want);
+      mpf_trace (" f", f);
+      abort ();
+    }
+}
+
+void
+all (mpf_ptr f, int want)
+{
+  one (f, want);
+  mpf_neg (f, f);
+  one (f, want);
+}
+
+int
+main (void)
+{
+  mpf_t  f;
+
+  tests_start ();
+  mpf_init2 (f, 200L);
+
+  mpf_set_ui (f, 0L);
+  one (f, 1);
+
+  mpf_set_ui (f, 1L);
+  all (f, 1);
+
+  mpf_set_ui (f, 1L);
+  mpf_div_2exp (f, f, 1L);
+  all (f, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_div_2exp (f, f, 5000L);
+  all (f, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, 5000L);
+  all (f, 1);
+
+  mpf_set_str (f, "0.5", 10);
+  all (f, 0);
+
+  mpf_set_str (f, "2.5", 10);
+  all (f, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_div_ui (f, f, 3L);
+  all (f, 0);
+
+  mpf_set_ui (f, 7L);
+  mpf_div_ui (f, f, 3L);
+  all (f, 0);
+
+  mpf_clear (f);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-mul_ui.c b/tests/mpf/t-mul_ui.c
new file mode 100644
index 0000000..f362bb2
--- /dev/null
+++ b/tests/mpf/t-mul_ui.c
@@ -0,0 +1,164 @@
+/* Exercise mpf_mul_ui.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (const char *desc, mpf_ptr got, mpf_srcptr u, unsigned long v)
+{
+  mp_size_t  usize, usign;
+  mp_ptr     wp;
+  mpf_t      want;
+
+  MPF_CHECK_FORMAT (got);
+
+  /* this code not nailified yet */
+  ASSERT_ALWAYS (BITS_PER_ULONG <= GMP_NUMB_BITS);
+  usign = SIZ (u);
+  usize = ABS (usign);
+  wp = refmpn_malloc_limbs (usize + 1);
+  wp[usize] = mpn_mul_1 (wp, PTR(u), usize, (mp_limb_t) v);
+
+  PTR(want) = wp;
+  SIZ(want) = (usign >= 0 ? usize+1 : -(usize+1));
+  EXP(want) = EXP(u) + 1;
+  refmpf_normalize (want);
+
+  if (! refmpf_validate ("mpf_mul_ui", got, want))
+    {
+      mp_trace_base = -16;
+      printf    ("  %s\n", desc);
+      mpf_trace ("  u", u);
+      printf    ("  v %ld  0x%lX\n", v, v);
+      abort ();
+    }
+
+  free (wp);
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  mpf_t              got, u;
+  unsigned long      prec, v;
+  int                i;
+
+  /* The nails code in mpf_mul_ui currently isn't exact, so suppress these
+     tests for now.  */
+  if (BITS_PER_ULONG > GMP_NUMB_BITS)
+    return;
+
+  mpf_init (got);
+  mpf_init (u);
+
+  for (i = 0; i < 200; i++)
+    {
+      /* got precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* u precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (u, prec);
+
+      /* u, possibly negative */
+      mpf_random2 (u, PREC(u), (mp_exp_t) 20);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (u, u);
+
+      /* v, 0 to BITS_PER_ULONG bits (inclusive) */
+      prec = gmp_urandomm_ui (rands, BITS_PER_ULONG+1);
+      v = gmp_urandomb_ui (rands, prec);
+
+      if ((i % 2) == 0)
+        {
+          /* separate */
+          mpf_mul_ui (got, u, v);
+          check_one ("separate", got, u, v);
+        }
+      else
+        {
+          /* overlap */
+          prec = refmpf_set_overlap (got, u);
+          mpf_mul_ui (got, got, v);
+          check_one ("overlap src==dst", got, u, v);
+
+          mpf_set_prec_raw (got, prec);
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (u);
+}
+
+void
+check_various (void)
+{
+  mpf_t  u, got, want;
+  const char   *s;
+
+  mpf_init2 (u,    2*8*sizeof(long));
+  mpf_init2 (got,  2*8*sizeof(long));
+  mpf_init2 (want, 2*8*sizeof(long));
+
+  s = "0 * ULONG_MAX";
+  mpf_set_ui (u, 0L);
+  mpf_mul_ui (got, u, ULONG_MAX);
+  MPF_CHECK_FORMAT (got);
+  mpf_set_ui (want, 0L);
+  if (mpf_cmp (got, want) != 0)
+    {
+    error:
+      printf ("Wrong result from %s\n", s);
+      mpf_trace ("u   ", u);
+      mpf_trace ("got ", got);
+      mpf_trace ("want", want);
+      abort ();
+    }
+
+  s = "1 * ULONG_MAX";
+  mpf_set_ui (u, 1L);
+  mpf_mul_ui (got, u, ULONG_MAX);
+  MPF_CHECK_FORMAT (got);
+  mpf_set_ui (want, ULONG_MAX);
+  if (mpf_cmp (got, want) != 0)
+    goto error;
+
+  mpf_clear (u);
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-muldiv.c b/tests/mpf/t-muldiv.c
new file mode 100644
index 0000000..86dca57
--- /dev/null
+++ b/tests/mpf/t-muldiv.c
@@ -0,0 +1,158 @@
+/* Test mpf_mul, mpf_div, mpf_ui_div, and mpf_div_ui.
+
+Copyright 1996, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 10000;
+  int i;
+  mpf_t u, v, w, x;
+  mp_size_t bprec = SIZE * GMP_LIMB_BITS;
+  mpf_t rerr, limit_rerr;
+  unsigned long ulimb, vlimb;
+  int single_flag;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init (rerr);
+  mpf_init (limit_rerr);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w);
+  mpf_init (x);
+
+  for (i = 0; i < reps; i++)
+    {
+      mp_size_t res_prec;
+
+      res_prec = urandom () % bprec + 1;
+      mpf_set_prec (w, res_prec);
+      mpf_set_prec (x, res_prec);
+
+      mpf_set_ui (limit_rerr, 1);
+      mpf_div_2exp (limit_rerr, limit_rerr, res_prec - 1);
+
+      single_flag = 0;
+
+      if ((urandom () & 1) != 0)
+	{
+	  size = urandom () % (2 * SIZE) - SIZE;
+	  exp = urandom () % SIZE;
+	  mpf_random2 (u, size, exp);
+	}
+      else
+	{
+	  ulimb = urandom ();
+	  mpf_set_ui (u, ulimb);
+	  single_flag = 1;
+	}
+
+      if ((urandom () & 1) != 0)
+	{
+	  size = urandom () % (2 * SIZE) - SIZE;
+	  exp = urandom () % SIZE;
+	  mpf_random2 (v, size, exp);
+	}
+      else
+	{
+	  vlimb = urandom ();
+	  mpf_set_ui (v, vlimb);
+	  single_flag = 2;
+	}
+
+      if (mpf_sgn (v) == 0)
+	continue;
+
+      mpf_div (w, u, v);
+      mpf_mul (x, w, v);
+      mpf_reldiff (rerr, u, x);
+      if (mpf_cmp (rerr, limit_rerr) > 0)
+	{
+	  printf ("ERROR in mpf_mul or mpf_div after %d tests\n", i);
+	  printf ("   u = "); mpf_dump (u);
+	  printf ("   v = "); mpf_dump (v);
+	  printf ("   x = "); mpf_dump (x);
+	  printf ("   w = "); mpf_dump (w);
+	  abort ();
+	}
+
+      if (single_flag == 2)
+	{
+	  mpf_div_ui (x, u, vlimb);
+	  mpf_reldiff (rerr, w, x);
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR in mpf_div or mpf_div_ui after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+
+      if (single_flag == 1)
+	{
+	  mpf_ui_div (x, ulimb, v);
+	  mpf_reldiff (rerr, w, x);
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR in mpf_div or mpf_ui_div after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (rerr);
+  mpf_clear (limit_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w);
+  mpf_clear (x);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-pow_ui.c b/tests/mpf/t-pow_ui.c
new file mode 100644
index 0000000..f005301
--- /dev/null
+++ b/tests/mpf/t-pow_ui.c
@@ -0,0 +1,69 @@
+/* Test mpf_pow_ui
+
+Copyright 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  unsigned int b, e;
+  mpf_t b1, r, r2, limit;
+
+  mpf_inits (b1, r, r2, NULL);
+  mpf_init_set_ui (limit, 1);
+  mpf_mul_2exp (limit, limit, MAX (GMP_NUMB_BITS, 53));
+
+  /* This test just test integers with results that fit in a single
+     limb or 53 bits.  This avoids any rounding.  */
+
+  for (b = 0; b <= 400; b++)
+    {
+      mpf_set_ui (b1, b);
+      mpf_set_ui (r2, 1);
+      for (e = 0; e <= GMP_LIMB_BITS; e++)
+	{
+	  mpf_pow_ui (r, b1, e);
+
+	  if (mpf_cmp (r, r2))
+	    abort ();
+
+	  mpf_mul_ui (r2, r2, b);
+
+	  if (mpf_cmp (r2, limit) >= 0)
+	    break;
+	}
+    }
+
+  mpf_clears (b1, r, r2, limit, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-set.c b/tests/mpf/t-set.c
new file mode 100644
index 0000000..2510748
--- /dev/null
+++ b/tests/mpf/t-set.c
@@ -0,0 +1,112 @@
+/* Test mpf_set, mpf_init_set.
+
+Copyright 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_reuse (void)
+{
+  /* Try mpf_set(f,f) when f is bigger than prec.  In the past this had
+     resulted in an MPN_COPY with invalid operand overlap. */
+  mpf_t  f;
+  mp_size_t      limbs = 20;
+  unsigned long  bits = limbs * GMP_NUMB_BITS;
+  mpf_init2 (f, bits);
+  refmpf_fill (f, limbs, GMP_NUMB_MAX);
+  mpf_set_prec_raw (f, bits / 2);
+  mpf_set (f, f);
+  MPF_CHECK_FORMAT (f);
+  mpf_set_prec_raw (f, bits);
+  mpf_clear (f);
+}
+
+void
+check_random (long reps)
+{
+  unsigned long test;
+  gmp_randstate_ptr rands;
+  mpf_t a, b;
+  mpz_t z;
+  int precbits;
+
+#define PRECBITS 10
+
+  rands = RANDS;
+
+  mpz_init (z);
+  mpf_init2 (a, 1 << PRECBITS);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_urandomb (z, rands, PRECBITS + 1);
+      precbits = mpz_get_ui (z) + 1;
+      mpz_urandomb (z, rands, precbits);
+      mpz_setbit (z, precbits  - 1);	/* make sure msb is set */
+      mpf_set_z (a, z);
+      if (precbits & 1)
+	mpf_neg (a, a);
+      mpz_urandomb (z, rands, PRECBITS);
+      mpf_div_2exp (a, a, mpz_get_ui (z) + 1);
+      mpz_urandomb (z, rands, PRECBITS);
+      precbits -= mpz_get_ui (z);
+      if (precbits <= 0)
+	precbits = 1 - precbits;
+      mpf_set_default_prec (precbits);
+
+      mpf_init_set (b, a);
+      MPF_CHECK_FORMAT (b);
+      if (!mpf_eq (a, b, precbits))
+	{
+	  printf ("mpf_init_set wrong.\n");
+	  abort();
+	}
+
+      mpf_set_ui (b, 0);
+      mpf_set (b, a);
+      MPF_CHECK_FORMAT (b);
+      if (!mpf_eq (a, b, precbits))
+	{
+	  printf ("mpf_set wrong.\n");
+	  abort();
+	}
+
+      mpf_clear (b);
+    }
+
+  mpf_clear (a);
+  mpz_clear (z);
+}
+
+int
+main (int argc, char *argv[])
+{
+  long reps = 10000;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  check_reuse ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-set_q.c b/tests/mpf/t-set_q.c
new file mode 100644
index 0000000..86dec6e
--- /dev/null
+++ b/tests/mpf/t-set_q.c
@@ -0,0 +1,126 @@
+/* Test mpf_set_q.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpf_ptr got, mpq_srcptr q)
+{
+  mpf_t  n, d;
+
+  mpf_set_q (got, q);
+
+  PTR(n) = PTR(&q->_mp_num);
+  SIZ(n) = SIZ(&q->_mp_num);
+  EXP(n) = ABSIZ(&q->_mp_num);
+
+  PTR(d) = PTR(&q->_mp_den);
+  SIZ(d) = SIZ(&q->_mp_den);
+  EXP(d) = ABSIZ(&q->_mp_den);
+
+  if (! refmpf_validate_division ("mpf_set_q", got, n, d))
+    {
+      mp_trace_base = -16;
+      mpq_trace ("   q", q);
+      abort ();
+    }
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  prec;
+  mpf_t  got;
+  mpq_t  q;
+  int    i;
+
+  mpf_init (got);
+  mpq_init (q);
+
+  for (i = 0; i < 400; i++)
+    {
+      /* result precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 20L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* num */
+      prec = gmp_urandomm_ui (rands, 20L * GMP_NUMB_BITS);
+      mpz_rrandomb (mpq_numref(q), rands, prec);
+
+      /* possibly negative num */
+      if (gmp_urandomb_ui (rands, 1L))
+        mpz_neg (mpq_numref(q), mpq_numref(q));
+
+      /* den, non-zero */
+      do {
+        prec = gmp_urandomm_ui (rands, 20L * GMP_NUMB_BITS);
+        mpz_rrandomb (mpq_denref(q), rands, prec);
+      } while (mpz_sgn (mpq_denref(q)) <= 0);
+
+      check_one (got, q);
+    }
+
+  mpf_clear (got);
+  mpq_clear (q);
+}
+
+void
+check_various (void)
+{
+  mpf_t got;
+  mpq_t q;
+
+  mpf_init (got);
+  mpq_init (q);
+
+  /* 1/1 == 1 */
+  mpf_set_prec (got, 20L);
+  mpq_set_ui (q, 1L, 1L);
+  mpf_set_q (got, q);
+  MPF_CHECK_FORMAT (got);
+  ASSERT_ALWAYS (mpf_cmp_ui (got, 1L) == 0);
+
+  /* 1/(2^n+1), a case where truncating the divisor would be wrong */
+  mpf_set_prec (got, 500L);
+  mpq_set_ui (q, 1L, 1L);
+  mpz_mul_2exp (mpq_denref(q), mpq_denref(q), 800L);
+  mpz_add_ui (mpq_denref(q), mpq_denref(q), 1L);
+  check_one (got, q);
+
+  mpf_clear (got);
+  mpq_clear (q);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-set_si.c b/tests/mpf/t-set_si.c
new file mode 100644
index 0000000..5cd6c89
--- /dev/null
+++ b/tests/mpf/t-set_si.c
@@ -0,0 +1,90 @@
+/* Test mpf_set_si and mpf_init_set_si.
+
+Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  static const struct {
+    long       x;
+    mp_size_t  want_size;
+    mp_limb_t  want_data[2];
+  } data[] = {
+
+    {  0L,  0 },
+    {  1L,  1, { 1 } },
+    { -1L, -1, { 1 } },
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    { LONG_MAX,  1, { LONG_MAX, 0 } },
+    { -LONG_MAX,  -1, { LONG_MAX, 0 } },
+    { LONG_HIGHBIT,  -1, { ULONG_HIGHBIT, 0 } },
+#else
+    { LONG_MAX,  2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS } },
+    { -LONG_MAX,  -2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS }},
+    { LONG_HIGHBIT,  -2, { 0, ULONG_HIGHBIT >> GMP_NUMB_BITS } },
+#endif
+  };
+
+  mpf_t  x;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_init (x);
+      mpf_set_si (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+
+      mpf_init_set_si (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_init_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-set_ui.c b/tests/mpf/t-set_ui.c
new file mode 100644
index 0000000..828067c
--- /dev/null
+++ b/tests/mpf/t-set_ui.c
@@ -0,0 +1,89 @@
+/* Test mpf_set_ui and mpf_init_set_ui.
+
+Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  static const struct {
+    unsigned long  x;
+    mp_size_t      want_size;
+    mp_limb_t      want_data[2];
+  } data[] = {
+
+    {  0L,  0 },
+    {  1L,  1, { 1 } },
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    { ULONG_MAX,     1, { ULONG_MAX, 0 } },
+    { ULONG_HIGHBIT, 1, { ULONG_HIGHBIT, 0 } },
+#else
+    { ULONG_MAX,     2, { ULONG_MAX & GMP_NUMB_MASK,
+                          ULONG_MAX >> GMP_NUMB_BITS } },
+    { ULONG_HIGHBIT, 2, { 0,
+                          ULONG_HIGHBIT >> GMP_NUMB_BITS } },
+#endif
+  };
+
+  mpf_t  x;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_init (x);
+      mpf_set_ui (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_set_ui wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+
+      mpf_init_set_ui (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_init_set_ui wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-sqrt.c b/tests/mpf/t-sqrt.c
new file mode 100644
index 0000000..5e93aba
--- /dev/null
+++ b/tests/mpf/t-sqrt.c
@@ -0,0 +1,193 @@
+/* Test mpf_sqrt, mpf_mul.
+
+Copyright 1996, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+void
+check_rand1 (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 20000;
+  int i;
+  mpf_t x, y, y2;
+  mp_size_t bprec = 100;
+  mpf_t rerr, max_rerr, limit_rerr;
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (x);
+  mpf_init (y);
+  mpf_init (y2);
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (x, size, exp);
+
+      mpf_sqrt (y, x);
+      MPF_CHECK_FORMAT (y);
+      mpf_mul (y2, y, y);
+
+      mpf_reldiff (rerr, x, y2);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   y = "); mpf_dump (y);
+	      printf ("  y2 = "); mpf_dump (y2);
+	      printf ("   rerr       = "); mpf_dump (rerr);
+	      printf ("   limit_rerr = "); mpf_dump (limit_rerr);
+              printf ("in hex:\n");
+              mp_trace_base = 16;
+	      mpf_trace ("   x  ", x);
+	      mpf_trace ("   y  ", y);
+	      mpf_trace ("   y2 ", y2);
+	      mpf_trace ("   rerr      ", rerr);
+	      mpf_trace ("   limit_rerr", limit_rerr);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (x);
+  mpf_clear (y);
+  mpf_clear (y2);
+}
+
+void
+check_rand2 (void)
+{
+  unsigned long      max_prec = 20;
+  unsigned long      min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long      x_prec, r_prec;
+  mpf_t              x, r, s;
+  int                i;
+
+  mpf_init (x);
+  mpf_init (r);
+  mpf_init (s);
+  refmpf_set_prec_limbs (s, 2*max_prec+10);
+
+  for (i = 0; i < 500; i++)
+    {
+      /* input precision */
+      x_prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
+      refmpf_set_prec_limbs (x, x_prec);
+
+      /* result precision */
+      r_prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
+      refmpf_set_prec_limbs (r, r_prec);
+
+      mpf_random2 (x, x_prec, 1000);
+
+      mpf_sqrt (r, x);
+      MPF_CHECK_FORMAT (r);
+
+      /* Expect to prec limbs of result.
+         In the current implementation there's no stripping of low zero
+         limbs in mpf_sqrt, so size should be exactly prec.  */
+      if (SIZ(r) != r_prec)
+        {
+          printf ("mpf_sqrt wrong number of result limbs\n");
+          mpf_trace ("  x", x);
+          mpf_trace ("  r", r);
+          printf    ("  r_prec=%lu\n", r_prec);
+          printf    ("  SIZ(r)  %ld\n", (long) SIZ(r));
+          printf    ("  PREC(r) %ld\n", (long) PREC(r));
+          abort ();
+        }
+
+      /* Must have r^2 <= x, since r has been truncated. */
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp (s, x) <= 0))
+        {
+          printf    ("mpf_sqrt result too big\n");
+          mpf_trace ("  x", x);
+          printf    ("  r_prec=%lu\n", r_prec);
+          mpf_trace ("  r", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+
+      /* Must have (r+ulp)^2 > x, or else r is too small. */
+      refmpf_add_ulp (r);
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp (s, x) > 0))
+        {
+          printf    ("mpf_sqrt result too small\n");
+          mpf_trace ("  x", x);
+          printf    ("  r_prec=%lu\n", r_prec);
+          mpf_trace ("  r+ulp", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+    }
+
+  mpf_clear (x);
+  mpf_clear (r);
+  mpf_clear (s);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_rand1 (argc, argv);
+  check_rand2 ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-sqrt_ui.c b/tests/mpf/t-sqrt_ui.c
new file mode 100644
index 0000000..31c587f
--- /dev/null
+++ b/tests/mpf/t-sqrt_ui.c
@@ -0,0 +1,125 @@
+/* Test mpf_sqrt_ui.
+
+Copyright 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_rand (void)
+{
+  unsigned long      max_prec = 15;
+  unsigned long      min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long      x, prec;
+  mpf_t              r, s;
+  int                i;
+
+  mpf_init (r);
+  mpf_init (s);
+  refmpf_set_prec_limbs (s, 2*max_prec+10);
+
+  for (x = 0; x < 2; x++)
+    {
+      mpf_sqrt_ui (r, x);
+      MPF_CHECK_FORMAT (r);
+      if (mpf_cmp_ui (r, x) != 0)
+	{
+	  printf    ("mpf_sqrt_ui wrong for special case:\n");
+          printf    ("  x=%lu\n", x);
+          mpf_trace ("  r", r);
+	  abort ();
+	}
+    }
+
+  for (i = 0; i < 50; i++)
+    {
+      /* input, a random non-zero ulong, exponentially distributed */
+      do {
+        x = gmp_urandomb_ui (rands,
+                             gmp_urandomm_ui (rands, BITS_PER_ULONG) + 1);
+      } while (x <= 1);
+
+      /* result precision */
+      prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
+      refmpf_set_prec_limbs (r, prec);
+
+      mpf_sqrt_ui (r, x);
+      MPF_CHECK_FORMAT (r);
+
+      /* Expect to prec limbs of result.
+         In the current implementation there's no stripping of low zero
+         limbs in mpf_sqrt_ui, not even on perfect squares, so size should
+         be exactly prec.  */
+      if (SIZ(r) != prec)
+        {
+          printf ("mpf_sqrt_ui result not enough result limbs\n");
+          printf    ("  x=%lu\n", x);
+          printf    ("  want prec=%lu\n", prec);
+          mpf_trace ("  r", r);
+          printf    ("  r size %ld\n", (long) SIZ(r));
+          printf    ("  r prec %ld\n", (long) PREC(r));
+          abort ();
+        }
+
+      /* Must have r^2 <= x, since r has been truncated. */
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp_ui (s, x) <= 0))
+        {
+          printf    ("mpf_sqrt_ui result too big\n");
+          printf    ("  x=%lu\n", x);
+          printf    ("  want prec=%lu\n", prec);
+          mpf_trace ("  r", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+
+      /* Must have (r+ulp)^2 > x.
+         No overflow from refmpf_add_ulp since r is only prec limbs. */
+      refmpf_add_ulp (r);
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp_ui (s, x) > 0))
+        {
+          printf    ("mpf_sqrt_ui result too small\n");
+          printf    ("  x=%lu\n", x);
+          printf    ("  want prec=%lu\n", prec);
+          mpf_trace ("  r+ulp", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+    }
+
+  mpf_clear (r);
+  mpf_clear (s);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-sub.c b/tests/mpf/t-sub.c
new file mode 100644
index 0000000..3872264
--- /dev/null
+++ b/tests/mpf/t-sub.c
@@ -0,0 +1,287 @@
+/* Test mpf_sub.
+
+Copyright 1996, 2001, 2004, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+void
+check_rand (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 20000;
+  int i;
+  mpf_t u, v, w, wref;
+  mp_size_t bprec = 100;
+  mpf_t rerr, max_rerr, limit_rerr;
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w);
+  mpf_init (wref);
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (u, size, exp);
+
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (v, size, exp);
+
+      if ((urandom () & 1) != 0)
+	mpf_add_ui (u, v, 1);
+      else if ((urandom () & 1) != 0)
+	mpf_sub_ui (u, v, 1);
+
+      mpf_sub (w, u, v);
+      refmpf_sub (wref, u, v);
+
+      mpf_reldiff (rerr, w, wref);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("wref = "); mpf_dump (wref);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w);
+  mpf_clear (wref);
+}
+
+#define W GMP_NUMB_MAX
+
+void
+check_data (void)
+{
+  static const struct {
+    struct {
+      int        exp, size;
+      mp_limb_t  d[10];
+    } x, y, want;
+
+  } data[] = {
+    { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
+    { { 1, 1, { 9 } },                  { 1, 1, { 8 } },   { 1, 1, { 1 } } },
+    { { 1, 1, { 9 } },                 { 1, -1, { 6 } },   { 1, 1, { 15 } } },
+    { { 1, 2, { 8, 9 } },               { 1, 1, { 8 } },   { 1, 2, { 8, 1 } } },
+    { { 2, 2, { 8, 1 } },               { 1, 1, { 9 } },   { 1, 1, { W } } },
+    { { 2, 2, { 9, 8 } },               { 1, 1, { 9 } },   { 2, 1, { 8 } } },
+    { { 2, 1, { 1 } },                  { 1, 1, { 1 } },   { 1, 1, { W } } },
+    { { 2, 1, { 9 } },                  { 1, 1, { W } },   { 2, 2, { 1, 8 } } },
+
+    { { 1, 2, { W, 8 } },             { 1, 1, { 9 } },   { 0, -1, { 1 } } },
+    { { 1, 2, { W, 7 } },             { 1, 1, { 9 } },   { 1, -2, { 1, 1 } } },
+    { { 1, 2, { 1, 8 } },             { 1, 1, { 9 } },   { 0, -1, { W } } },
+    { { 1, 2, { 1, 7 } },             { 1, 1, { 9 } },   { 1, -2, { W, 1 } } },
+    { { 1, 2, { 0, 8 } },             { 1, 1, { 9 } },   { 1, -1, { 1 } } },
+    { { 2, 3, { 5, 8, 1 } },          { 1, 1, { 9 } },   { 1, 2, { 5, W } } },
+    { { 3, 1, { 1 } },                { 1, 1, { 1 } },   { 2, 2, { W, W } } },
+    { { 1, 6, { W, W, W, W, W, 8 } }, { 1, 1, { 9 } },   { -4, -1, { 1 } } },
+    { { 5, 5, { W-6, W, W, W, W } },  { 6, 1, { 1 } },   { 1, -1, { 7 } } },
+
+    /* f - f == 0, various sizes.
+       These exercise a past problem (gmp 4.1.3 and earlier) where the
+       result exponent was not zeroed on a zero result like this.  */
+    { { 0, 0 }, { 0, 0 }, { 0, 0 } },
+    { { 99, 3, { 0, 0, 1 } },       { 99, 1, { 1 } },             { 0, 0 } },
+    { { 99, 3, { 0, 123, 456 } },   { 99, 2, { 123, 456 } },      { 0, 0 } },
+    { { 99, 3, { 123, 456, 789 } }, { 99, 3, { 123, 456, 789 } }, { 0, 0 } },
+
+    /* High limbs cancel, leaving just the low limbs of the longer operand.
+       This exercises a past problem (gmp 4.1.3 and earlier) where high zero
+       limbs on the remainder were not stripped before truncating to the
+       destination, causing loss of precision.  */
+    { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
+    { { 123, 3, { 8, 0, 9 } },          { 123, 1, { 9 } }, { 121, 1, { 8 } } },
+    { { 123, 4, { 8, 0, 0, 9 } },       { 123, 1, { 9 } }, { 120, 1, { 8 } } },
+    { { 123, 5, { 8, 0, 0, 0, 9 } },    { 123, 1, { 9 } }, { 119, 1, { 8 } } },
+    { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 1, { 9 } }, { 118, 1, { 8 } } },
+    /* { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 6, { 9, 0, 0, 0, 0, 8 } }, { 122, 5, { W, W, W, W, W } } }, */
+
+  };
+
+  mpf_t  x, y, got, want;
+  int  i, swap, fail;
+
+  fail = 0;
+  mp_trace_base = 16;
+  mpf_init (got);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (swap = 0; swap <= 7; swap++)
+        {
+          PTR(x) = (mp_ptr) data[i].x.d;
+          SIZ(x) = data[i].x.size;
+          EXP(x) = data[i].x.exp;
+          PREC(x) = numberof (data[i].x.d);
+          MPF_CHECK_FORMAT (x);
+
+          PTR(y) = (mp_ptr) data[i].y.d;
+          SIZ(y) = data[i].y.size;
+          EXP(y) = data[i].y.exp;
+          PREC(y) = numberof (data[i].y.d);
+          MPF_CHECK_FORMAT (y);
+
+          PTR(want) = (mp_ptr) data[i].want.d;
+          SIZ(want) = data[i].want.size;
+          EXP(want) = data[i].want.exp;
+          PREC(want) = numberof (data[i].want.d);
+          MPF_CHECK_FORMAT (want);
+
+          if (swap & 4)
+            {
+              mpf_swap (want, y);
+            }
+
+	  if ((SIZ (x) ^ SIZ (y)) < 0)
+	    continue; /* It's an addition, not a subtraction (TO BE REMOVED) */
+
+          if (swap & 1)
+            {
+              mpf_swap (x, y);
+              SIZ(want) = - SIZ(want);
+            }
+
+          if (swap & 2)
+            {
+              SIZ(want) = - SIZ(want);
+              SIZ(x) = - SIZ(x);
+              SIZ(y) = - SIZ(y);
+            }
+
+          mpf_sub (got, x, y);
+/*           MPF_CHECK_FORMAT (got); */
+
+          if (! refmpf_validate ("mpf_sub", got, want))
+            {
+              printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
+              mpf_trace ("x   ", x);
+              mpf_trace ("y   ", y);
+              mpf_trace ("got ", got);
+              mpf_trace ("want", want);
+	      fail = 1;
+            }
+
+	  if (SIZ (x) == 1 || SIZ (x) == 0 )
+	    {
+	      if (SIZ (y)) EXP (y) -= EXP (x) - (mp_exp_t) SIZ (x);
+	      if (SIZ (want)) EXP (want) -= EXP (x) - (mp_exp_t) SIZ (x);
+	      EXP (x) = (mp_exp_t) SIZ (x);
+
+	      if (mpf_fits_uint_p (x))
+		{
+		  mpf_ui_sub (got, mpf_get_ui (x), y);
+
+		  if (! refmpf_validate ("mpf_ui_sub", got, want))
+		    {
+		      printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
+		      mpf_trace ("x   ", x);
+		      mpf_trace ("y   ", y);
+		      mpf_trace ("got ", got);
+		      mpf_trace ("want", want);
+		      fail = 1;
+		    }
+		}
+	    }
+
+	  if (SIZ (y) == 1 || SIZ (y) == 0)
+	    {
+	      if (SIZ (x)) EXP (x) -= EXP (y) - (mp_exp_t) SIZ (y);
+	      if (SIZ (want)) EXP (want) -= EXP (y) - (mp_exp_t) SIZ (y);
+	      EXP (y) = (mp_exp_t) SIZ (y);
+
+	      if (mpf_fits_uint_p (x))
+		{
+		  mpf_sub_ui (got, x, mpf_get_ui (y));
+
+		  if (! refmpf_validate ("mpf_sub_ui", got, want))
+		    {
+		      printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
+		      mpf_trace ("x   ", x);
+		      mpf_trace ("y   ", y);
+		      mpf_trace ("got ", got);
+		      mpf_trace ("want", want);
+		      fail = 1;
+		    }
+		}
+	    }
+
+        }
+    }
+
+  mpf_clear (got);
+  if (fail)
+    abort ();
+}
+
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_data ();
+  check_rand (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-trunc.c b/tests/mpf/t-trunc.c
new file mode 100644
index 0000000..6543a1e
--- /dev/null
+++ b/tests/mpf/t-trunc.c
@@ -0,0 +1,270 @@
+/* Test mpf_trunc, mpf_ceil, mpf_floor.
+
+Copyright 2001, 2002, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_print (mpf_srcptr src, mpf_srcptr got, mpf_srcptr want)
+{
+  mp_trace_base = 16;
+  mpf_trace ("src ", src);
+  mpf_trace ("got ", got);
+  mpf_trace ("want", want);
+
+  printf ("got  size=%d exp=%ld\n", SIZ(got), EXP(got));
+  mpn_trace ("     limbs=", PTR(got), (mp_size_t) ABSIZ(got));
+
+  printf ("want size=%d exp=%ld\n", SIZ(want), EXP(want));
+  mpn_trace ("     limbs=", PTR(want), (mp_size_t) ABSIZ(want));
+}
+
+void
+check_one (mpf_srcptr src, mpf_srcptr trunc, mpf_srcptr ceil, mpf_srcptr floor)
+{
+  mpf_t  got;
+
+  mpf_init2 (got, mpf_get_prec (trunc));
+  ASSERT_ALWAYS (PREC(got) == PREC(trunc));
+  ASSERT_ALWAYS (PREC(got) == PREC(ceil));
+  ASSERT_ALWAYS (PREC(got) == PREC(floor));
+
+#define CHECK_SEP(name, fun, want)              \
+  mpf_set_ui (got, 54321L); /* initial junk */  \
+  fun (got, src);                               \
+  MPF_CHECK_FORMAT (got);                       \
+  if (mpf_cmp (got, want) != 0)                 \
+    {                                           \
+	printf ("%s wrong\n", name);            \
+	check_print (src, got, want);           \
+	abort ();                               \
+    }
+
+  CHECK_SEP ("mpf_trunc", mpf_trunc, trunc);
+  CHECK_SEP ("mpf_ceil",  mpf_ceil,  ceil);
+  CHECK_SEP ("mpf_floor", mpf_floor, floor);
+
+#define CHECK_INPLACE(name, fun, want)  \
+  mpf_set (got, src);                   \
+  fun (got, got);                       \
+  MPF_CHECK_FORMAT (got);               \
+  if (mpf_cmp (got, want) != 0)         \
+    {                                   \
+	printf ("%s wrong\n", name);    \
+	check_print (src, got, want);   \
+	abort ();                       \
+    }
+
+  CHECK_INPLACE ("mpf_trunc", mpf_trunc, trunc);
+
+  /* Can't do these unconditionally in case truncation by mpf_set strips
+     some low non-zero limbs which would have rounded the result.  */
+  if (mpf_size (src) <= PREC(trunc)+1)
+    {
+      CHECK_INPLACE ("mpf_ceil",  mpf_ceil,  ceil);
+      CHECK_INPLACE ("mpf_floor", mpf_floor, floor);
+    }
+
+  mpf_clear (got);
+}
+
+void
+check_all (mpf_ptr src, mpf_ptr trunc, mpf_ptr ceil, mpf_ptr floor)
+{
+  /* some of these values are generated with direct field assignments */
+  MPF_CHECK_FORMAT (src);
+  MPF_CHECK_FORMAT (trunc);
+  MPF_CHECK_FORMAT (ceil);
+  MPF_CHECK_FORMAT (floor);
+
+  check_one (src, trunc, ceil, floor);
+
+  mpf_neg (src,   src);
+  mpf_neg (trunc, trunc);
+  mpf_neg (ceil,  ceil);
+  mpf_neg (floor, floor);
+  check_one (src, trunc, floor, ceil);
+}
+
+void
+check_various (void)
+{
+  mpf_t  src, trunc, ceil, floor;
+  int    n, i;
+
+  mpf_init2 (src, 512L);
+  mpf_init2 (trunc, 256L);
+  mpf_init2 (ceil,  256L);
+  mpf_init2 (floor, 256L);
+
+  /* 0 */
+  mpf_set_ui (src, 0L);
+  mpf_set_ui (trunc, 0L);
+  mpf_set_ui (ceil, 0L);
+  mpf_set_ui (floor, 0L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 1 */
+  mpf_set_ui (src, 1L);
+  mpf_set_ui (trunc, 1L);
+  mpf_set_ui (ceil, 1L);
+  mpf_set_ui (floor, 1L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 2^1024 */
+  mpf_set_ui (src, 1L);
+  mpf_mul_2exp (src,   src,   1024L);
+  mpf_set (trunc, src);
+  mpf_set (ceil,  src);
+  mpf_set (floor, src);
+  check_all (src, trunc, ceil, floor);
+
+  /* 1/2^1024, fraction only */
+  mpf_set_ui (src, 1L);
+  mpf_div_2exp (src,  src, 1024L);
+  mpf_set_si (trunc, 0L);
+  mpf_set_si (ceil, 1L);
+  mpf_set_si (floor, 0L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 1/2 */
+  mpf_set_ui (src, 1L);
+  mpf_div_2exp (src,  src, 1L);
+  mpf_set_si (trunc, 0L);
+  mpf_set_si (ceil, 1L);
+  mpf_set_si (floor, 0L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 123+1/2^64 */
+  mpf_set_ui (src, 1L);
+  mpf_div_2exp (src,  src, 64L);
+  mpf_add_ui (src,  src, 123L);
+  mpf_set_si (trunc, 123L);
+  mpf_set_si (ceil, 124L);
+  mpf_set_si (floor, 123L);
+  check_all (src, trunc, ceil, floor);
+
+  /* integer of full prec+1 limbs, unchanged */
+  n = PREC(trunc)+1;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+100;
+  mpf_set (trunc, src);
+  mpf_set (ceil, src);
+  mpf_set (floor, src);
+  check_all (src, trunc, ceil, floor);
+
+  /* full prec+1 limbs, 1 trimmed for integer */
+  n = PREC(trunc)+1;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n-1;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+200;
+  EXP(trunc) = n-1;
+  SIZ(trunc) = n-1;
+  for (i = 0; i < SIZ(trunc); i++)
+    PTR(trunc)[i] = i+201;
+  mpf_set (floor, trunc);
+  mpf_add_ui (ceil, trunc, 1L);
+  check_all (src, trunc, ceil, floor);
+
+  /* prec+3 limbs, 2 trimmed for size */
+  n = PREC(trunc)+3;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+300;
+  EXP(trunc) = n;
+  SIZ(trunc) = n-2;
+  for (i = 0; i < SIZ(trunc); i++)
+    PTR(trunc)[i] = i+302;
+  mpf_set (floor, trunc);
+  mpf_set (ceil, trunc);
+  PTR(ceil)[0]++;
+  check_all (src, trunc, ceil, floor);
+
+  /* prec+4 limbs, 2 trimmed for size, 1 trimmed for integer */
+  n = PREC(trunc)+4;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n-1;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+400;
+  EXP(trunc) = n-1;
+  SIZ(trunc) = n-3;
+  for (i = 0; i < SIZ(trunc); i++)
+    PTR(trunc)[i] = i+403;
+  mpf_set (floor, trunc);
+  mpf_set (ceil, trunc);
+  PTR(ceil)[0]++;
+  check_all (src, trunc, ceil, floor);
+
+  /* F.F, carry out of ceil */
+  EXP(src) = 1;
+  SIZ(src) = 2;
+  PTR(src)[0] = GMP_NUMB_MAX;
+  PTR(src)[1] = GMP_NUMB_MAX;
+  EXP(trunc) = 1;
+  SIZ(trunc) = 1;
+  PTR(trunc)[0] = GMP_NUMB_MAX;
+  mpf_set (floor, trunc);
+  EXP(ceil) = 2;
+  SIZ(ceil) = 1;
+  PTR(ceil)[0] = 1;
+  check_all (src, trunc, ceil, floor);
+
+  /* FF.F, carry out of ceil */
+  EXP(src) = 2;
+  SIZ(src) = 3;
+  PTR(src)[0] = GMP_NUMB_MAX;
+  PTR(src)[1] = GMP_NUMB_MAX;
+  PTR(src)[2] = GMP_NUMB_MAX;
+  EXP(trunc) = 2;
+  SIZ(trunc) = 2;
+  PTR(trunc)[0] = GMP_NUMB_MAX;
+  PTR(trunc)[1] = GMP_NUMB_MAX;
+  mpf_set (floor, trunc);
+  EXP(ceil) = 3;
+  SIZ(ceil) = 1;
+  PTR(ceil)[0] = 1;
+  check_all (src, trunc, ceil, floor);
+
+  mpf_clear (src);
+  mpf_clear (trunc);
+  mpf_clear (ceil);
+  mpf_clear (floor);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpf/t-ui_div.c b/tests/mpf/t-ui_div.c
new file mode 100644
index 0000000..4b86215
--- /dev/null
+++ b/tests/mpf/t-ui_div.c
@@ -0,0 +1,151 @@
+/* Test mpf_ui_div.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (const char *desc, mpf_ptr got, unsigned long u, mpf_srcptr v)
+{
+  mpf_t      uf;
+  mp_limb_t  ulimbs[2];
+  mp_size_t  usize;
+
+  ulimbs[0] = u & GMP_NUMB_MASK;
+  usize = (u != 0);
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  u >>= GMP_NUMB_BITS;
+  ulimbs[1] = u;
+  usize += (u != 0);
+#endif
+  PTR(uf) = ulimbs;
+  SIZ(uf) = usize;
+  EXP(uf) = usize;
+
+  if (! refmpf_validate_division ("mpf_ui_div", got, uf, v))
+    {
+      mp_trace_base = -16;
+      printf    ("  u 0x%lX  (%lu)\n", u, u);
+      mpf_trace ("  v", v);
+      printf    ("  %s\n", desc);
+      abort ();
+    }
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  prec, u;
+  mpf_t  got, v;
+  int    i;
+
+  mpf_init (got);
+  mpf_init (v);
+
+  for (i = 0; i < 200; i++)
+    {
+      /* got precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* u */
+      prec = gmp_urandomm_ui (rands, BITS_PER_ULONG+1);
+      u = gmp_urandomb_ui (rands, prec);
+
+      /* v precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (v, prec);
+
+      /* v, non-zero */
+      do {
+        mpf_random2 (v, PREC(v), (mp_exp_t) 20);
+      } while (SIZ(v) == 0);
+
+      /* v possibly negative */
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (v, v);
+
+      if ((i % 2) == 0)
+        {
+          /* src != dst */
+          mpf_ui_div (got, u, v);
+          check_one ("separate", got, u, v);
+        }
+      else
+        {
+          /* src == dst */
+          prec = refmpf_set_overlap (got, v);
+          mpf_ui_div (got, u, got);
+          check_one ("overlap src==dst", got, u, v);
+
+          mpf_set_prec_raw (got, prec);
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (v);
+}
+
+void
+check_various (void)
+{
+  mpf_t got, v;
+
+  mpf_init (got);
+  mpf_init (v);
+
+  /* 100/4 == 25 */
+  mpf_set_prec (got, 20L);
+  mpf_set_ui (v, 4L);
+  mpf_ui_div (got, 100L, v);
+  MPF_CHECK_FORMAT (got);
+  ASSERT_ALWAYS (mpf_cmp_ui (got, 25L) == 0);
+
+  {
+    /* 1/(2^n+1), a case where truncating the divisor would be wrong */
+    unsigned long  u = 1L;
+    mpf_set_prec (got, 500L);
+    mpf_set_prec (v, 900L);
+    mpf_set_ui (v, 1L);
+    mpf_mul_2exp (v, v, 800L);
+    mpf_add_ui (v, v, 1L);
+    mpf_ui_div (got, u, v);
+    check_one ("1/2^n+1, separate", got, u, v);
+  }
+
+  mpf_clear (got);
+  mpf_clear (v);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/logic.c b/tests/mpn/logic.c
new file mode 100644
index 0000000..2b1c9a9
--- /dev/null
+++ b/tests/mpn/logic.c
@@ -0,0 +1,133 @@
+/* Test mpn_and, mpn_ior, mpn_xor, mpn_andn, mpn_iorn, mpn_xnor, mpn_nand, and
+   mpn_nior.
+
+Copyright 2011-2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Fake native prevalence of the tested operations, so that we actually test
+   the compiled functions, i.e., the ones which users will reach.  The inlined
+   variants will be tested through tests/mpz/logic.c.  */
+#define HAVE_NATIVE_mpn_com    1
+#define HAVE_NATIVE_mpn_and_n  1
+#define HAVE_NATIVE_mpn_andn_n 1
+#define HAVE_NATIVE_mpn_nand_n 1
+#define HAVE_NATIVE_mpn_ior_n  1
+#define HAVE_NATIVE_mpn_iorn_n 1
+#define HAVE_NATIVE_mpn_nior_n 1
+#define HAVE_NATIVE_mpn_xor_n  1
+#define HAVE_NATIVE_mpn_xnor_n 1
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mp_srcptr refp, mp_srcptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n, const char *funcname)
+{
+  if (mpn_cmp (refp, rp, n))
+    {
+      printf ("ERROR in mpn_%s\n", funcname);
+      printf ("a: "); mpn_dump (ap, n);
+      printf ("b: "); mpn_dump (bp, n);
+      printf ("r:   "); mpn_dump (rp, n);
+      printf ("ref: "); mpn_dump (refp, n);
+      abort();
+    }
+}
+
+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;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  mpz_inits (a, b, NULL);
+
+  rands = RANDS;		/* FIXME: not used */
+
+  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);
+
+  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);
+	  ap = PTR(a);
+	  bp = PTR(b);
+	  n = SIZ(a);
+
+	  refmpn_and_n (refp, ap, bp, n);
+	  mpn_and_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "and_n");
+
+	  refmpn_ior_n (refp, ap, bp, n);
+	  mpn_ior_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "ior_n");
+
+	  refmpn_xor_n (refp, ap, bp, n);
+	  mpn_xor_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "xor_n");
+
+	  refmpn_andn_n (refp, ap, bp, n);
+	  mpn_andn_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "andn_n");
+
+	  refmpn_iorn_n (refp, ap, bp, n);
+	  mpn_iorn_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "iorn_n");
+
+	  refmpn_nand_n (refp, ap, bp, n);
+	  mpn_nand_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "nand_n");
+
+	  refmpn_nior_n (refp, ap, bp, n);
+	  mpn_nior_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "nior_n");
+
+	  refmpn_xnor_n (refp, ap, bp, n);
+	  mpn_xnor_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "xnor_n");
+
+	  refmpn_com (refp, ap, n);
+	  mpn_com (rp, ap, n);
+	  check_one (refp, rp, ap, bp, n, "com");
+	}
+    }
+
+  TMP_FREE;
+  mpz_clears (a, b, NULL);
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-addaddmul.c b/tests/mpn/t-addaddmul.c
new file mode 100644
index 0000000..8d3b0da
--- /dev/null
+++ b/tests/mpn/t-addaddmul.c
@@ -0,0 +1,98 @@
+/* Test mpn_addaddmul_1msb0.
+
+Copyright 2021 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if !HAVE_NATIVE_mpn_addaddmul_1msb0
+int main(int argc, char **argv) {
+  return 77;  /* Test driver "SKIP" */
+}
+#else
+
+static void
+one_test (int i, mp_srcptr a, mp_srcptr b, mp_size_t n, mp_limb_t u, mp_limb_t v)
+{
+  mp_ptr r = refmpn_malloc_limbs (n + 1);
+  mp_ptr ref = refmpn_malloc_limbs (n + 1);
+
+  u &= ~GMP_NUMB_HIGHBIT;
+  v &= ~GMP_NUMB_HIGHBIT;
+  ref[n] = mpn_mul_1 (ref, a, n, u);
+  ref[n] += mpn_addmul_1 (ref, b, n, v);
+  r[n] = mpn_addaddmul_1msb0 (r, a, b, n, u, v);
+
+  if (mpn_cmp (r, ref, n+1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "Bad result from addaddmul_1msb0\n");
+      gmp_fprintf (stderr, "op1=%Nx\n", a, n);
+      gmp_fprintf (stderr, "op2=%Nx\n", b, n);
+      gmp_fprintf (stderr, "u = %Mx, v = %Mx\n", u, v);
+      gmp_fprintf (stderr, "res=%Nx\n", r, n + 1);
+      gmp_fprintf (stderr, "ref=%Nx\n", ref, n + 1);
+
+      abort();
+    }
+}
+
+int main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  int i;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_inits (bs, op1, op2, NULL);
+
+  for (i = 0; i < 10000; i++)
+    {
+      unsigned long size_range;
+      mp_size_t bit_size;
+      mp_size_t limb_size;
+      mp_limb_t u, v;
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+      mpz_urandomb (bs, rands, size_range);
+
+      bit_size = mpz_get_ui (bs) + 10;
+      mpz_rrandomb (op1, rands, bit_size);
+      mpz_rrandomb (op2, rands, bit_size);
+
+      mpz_rrandomb (bs, rands, GMP_NUMB_BITS - 1);
+      u = mpz_getlimbn (bs, 0);
+
+      mpz_rrandomb (bs, rands, GMP_NUMB_BITS - 1);
+      v = mpz_getlimbn (bs, 0);
+
+      limb_size = mpz_size (op1);
+      one_test (i, mpz_limbs_read (op1), mpz_limbs_read(op2), limb_size, u, v);
+    }
+  mpz_clears (bs, op1, op2, NULL);
+  return 0;
+}
+#endif
diff --git a/tests/mpn/t-aors_1.c b/tests/mpn/t-aors_1.c
new file mode 100644
index 0000000..c894922
--- /dev/null
+++ b/tests/mpn/t-aors_1.c
@@ -0,0 +1,310 @@
+/* Test mpn_add_1 and mpn_sub_1.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define M      GMP_NUMB_MAX
+#define ASIZE  10
+#define MAGIC  0x1234
+
+#define SETUP()                         \
+  do {                                  \
+    refmpn_random (got, data[i].size);  \
+    got[data[i].size] = MAGIC;          \
+  } while (0)
+
+#define SETUP_INPLACE()                                 \
+  do {                                                  \
+    refmpn_copyi (got, data[i].src, data[i].size);      \
+    got[data[i].size] = MAGIC;                          \
+  } while (0)
+
+#define VERIFY(name)                            \
+  do {                                          \
+    verify (name, i, data[i].src, data[i].n,    \
+            got_c, data[i].want_c,              \
+            got, data[i].want, data[i].size);   \
+  } while (0)
+
+typedef mp_limb_t (*mpn_aors_1_t) (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mpn_aors_1_t fudge (mpn_aors_1_t);
+
+
+void
+verify (const char *name, int i,
+        mp_srcptr src, mp_limb_t n,
+        mp_limb_t got_c, mp_limb_t want_c,
+        mp_srcptr got, mp_srcptr want, mp_size_t size)
+{
+  if (got[size] != MAGIC)
+    {
+      printf ("Overwrite at %s i=%d\n", name, i);
+      abort ();
+    }
+
+  if (got_c != want_c || ! refmpn_equal_anynail (got, want, size))
+    {
+      printf ("Wrong at %s i=%d size=%ld\n", name, i, size);
+      mpn_trace ("   src", src,  size);
+      mpn_trace ("     n", &n,   (mp_size_t) 1);
+      mpn_trace ("   got", got,  size);
+      mpn_trace ("  want", want, size);
+      mpn_trace (" got c", &got_c,  (mp_size_t) 1);
+      mpn_trace ("want c", &want_c, (mp_size_t) 1);
+      abort ();
+    }
+}
+
+
+void
+check_add_1 (void)
+{
+  static const struct {
+    mp_size_t        size;
+    mp_limb_t        n;
+    const mp_limb_t  src[ASIZE];
+    mp_limb_t        want_c;
+    const mp_limb_t  want[ASIZE];
+  } data[] = {
+    { 1, 0, { 0 },  0, { 0 } },
+    { 1, 0, { 1 },  0, { 1 } },
+    { 1, 1, { 0 },  0, { 1 } },
+    { 1, 0, { M },  0, { M } },
+    { 1, M, { 0 },  0, { M } },
+    { 1, 1, { 123 }, 0, { 124 } },
+
+    { 1, 1, { M },  1, { 0 } },
+    { 1, M, { 1 },  1, { 0 } },
+    { 1, M, { M },  1, { M-1 } },
+
+    { 2, 0, { 0, 0 },  0, { 0, 0 } },
+    { 2, 0, { 1, 0 },  0, { 1, 0 } },
+    { 2, 1, { 0, 0 },  0, { 1, 0 } },
+    { 2, 0, { M, 0 },  0, { M, 0 } },
+    { 2, M, { 0, 0 },  0, { M, 0 } },
+    { 2, 1, { M, 0 },  0, { 0, 1 } },
+    { 2, M, { 1, 0 },  0, { 0, 1 } },
+    { 2, M, { M, 0 },  0, { M-1, 1 } },
+    { 2, M, { M, 0 },  0, { M-1, 1 } },
+
+    { 2, 1, { M, M },  1, { 0, 0 } },
+    { 2, M, { 1, M },  1, { 0, 0 } },
+    { 2, M, { M, M },  1, { M-1, 0 } },
+    { 2, M, { M, M },  1, { M-1, 0 } },
+
+    { 3, 1, { M, M, M },  1, { 0, 0, 0 } },
+    { 3, M, { 1, M, M },  1, { 0, 0, 0 } },
+    { 3, M, { M, M, M },  1, { M-1, 0, 0 } },
+    { 3, M, { M, M, M },  1, { M-1, 0, 0 } },
+
+    { 4, 1, { M, M, M, M },  1, { 0, 0, 0, 0 } },
+    { 4, M, { 1, M, M, M },  1, { 0, 0, 0, 0 } },
+    { 4, M, { M, M, M, M },  1, { M-1, 0, 0, 0 } },
+    { 4, M, { M, M, M, M },  1, { M-1, 0, 0, 0 } },
+
+    { 4, M, { M, 0,   M, M },  0, { M-1, 1, M, M } },
+    { 4, M, { M, M-1, M, M },  0, { M-1, M, M, M } },
+
+    { 4, M, { M, M, 0,   M },  0, { M-1, 0, 1, M } },
+    { 4, M, { M, M, M-1, M },  0, { M-1, 0, M, M } },
+  };
+
+  mp_limb_t  got[ASIZE];
+  mp_limb_t  got_c;
+  /* mpn_sec_add_a_itch(n) <= n */
+  mp_limb_t  scratch[ASIZE];
+  int        i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      SETUP ();
+      got_c = mpn_add_1 (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_add_1 (got, got, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (in-place)");
+
+      SETUP ();
+      scratch [mpn_sec_add_1_itch(data[i].size)] = MAGIC;
+      got_c = mpn_sec_add_1 (got, data[i].src, data[i].size, data[i].n, scratch);
+      got_c ^= scratch [mpn_sec_add_1_itch(data[i].size)] ^ MAGIC;
+      VERIFY ("check_sec_add_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_sec_add_1 (got, got, data[i].size, data[i].n, scratch);
+      VERIFY ("check_sec_add_1 (in-place)");
+
+      if (data[i].n == 1)
+        {
+          SETUP ();
+          got_c = mpn_add_1 (got, data[i].src, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_add_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_add_1 (got, got, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_add_1 (in-place, const 1)");
+
+          SETUP ();
+          got_c = mpn_sec_add_1 (got, data[i].src, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_add_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_sec_add_1 (got, got, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_add_1 (in-place, const 1)");
+        }
+
+      /* Same again on functions, not inlines. */
+      SETUP ();
+      got_c = (*fudge(mpn_add_1)) (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (function, separate)");
+
+      SETUP_INPLACE ();
+      got_c = (*fudge(mpn_add_1)) (got, got, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (function, in-place)");
+    }
+}
+
+void
+check_sub_1 (void)
+{
+  static const struct {
+    mp_size_t        size;
+    mp_limb_t        n;
+    const mp_limb_t  src[ASIZE];
+    mp_limb_t        want_c;
+    const mp_limb_t  want[ASIZE];
+  } data[] = {
+    { 1, 0, { 0 },  0, { 0 } },
+    { 1, 0, { 1 },  0, { 1 } },
+    { 1, 1, { 1 },  0, { 0 } },
+    { 1, 0, { M },  0, { M } },
+    { 1, 1, { M },  0, { M-1 } },
+    { 1, 1, { 123 }, 0, { 122 } },
+
+    { 1, 1, { 0 },  1, { M } },
+    { 1, M, { 0 },  1, { 1 } },
+
+    { 2, 0, { 0, 0 },  0, { 0, 0 } },
+    { 2, 0, { 1, 0 },  0, { 1, 0 } },
+    { 2, 1, { 1, 0 },  0, { 0, 0 } },
+    { 2, 0, { M, 0 },  0, { M, 0 } },
+    { 2, 1, { M, 0 },  0, { M-1, 0 } },
+    { 2, 1, { 123, 0 }, 0, { 122, 0 } },
+
+    { 2, 1, { 0, 0 },  1, { M, M } },
+    { 2, M, { 0, 0 },  1, { 1, M } },
+
+    { 3, 0, { 0,   0, 0 },  0, { 0,   0, 0 } },
+    { 3, 0, { 123, 0, 0 },  0, { 123, 0, 0 } },
+
+    { 3, 1, { 0, 0, 0 },  1, { M, M, M } },
+    { 3, M, { 0, 0, 0 },  1, { 1, M, M } },
+
+    { 4, 1, { 0, 0, 0, 0 },  1, { M, M, M, M } },
+    { 4, M, { 0, 0, 0, 0 },  1, { 1, M, M, M } },
+
+    { 4, 1, { 0, 0, 1,   42 },  0, { M, M, 0,   42 } },
+    { 4, M, { 0, 0, 123, 24 },  0, { 1, M, 122, 24 } },
+  };
+
+  mp_limb_t  got[ASIZE];
+  mp_limb_t  got_c;
+  /* mpn_sec_sub_1_itch(n) <= n */
+  mp_limb_t  scratch[ASIZE];
+  int        i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      SETUP ();
+      got_c = mpn_sub_1 (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_sub_1 (got, got, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (in-place)");
+
+      SETUP ();
+      scratch [mpn_sec_sub_1_itch(data[i].size)] = MAGIC;
+      got_c = mpn_sec_sub_1 (got, data[i].src, data[i].size, data[i].n, scratch);
+      got_c ^= scratch [mpn_sec_sub_1_itch(data[i].size)] ^ MAGIC;
+      VERIFY ("check_sec_sub_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_sec_sub_1 (got, got, data[i].size, data[i].n, scratch);
+      VERIFY ("check_sec_sub_1 (in-place)");
+
+      if (data[i].n == 1)
+        {
+          SETUP ();
+          got_c = mpn_sub_1 (got, data[i].src, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_sub_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_sub_1 (got, got, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_sub_1 (in-place, const 1)");
+
+          SETUP ();
+          got_c = mpn_sec_sub_1 (got, data[i].src, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_sub_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_sec_sub_1 (got, got, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_sub_1 (in-place, const 1)");
+        }
+
+      /* Same again on functions, not inlines. */
+      SETUP ();
+      got_c = (*fudge(mpn_sub_1)) (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (function, separate)");
+
+      SETUP_INPLACE ();
+      got_c = (*fudge(mpn_sub_1)) (got, got, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (function, in-place)");
+    }
+}
+
+/* Try to prevent the optimizer inlining. */
+mpn_aors_1_t
+fudge (mpn_aors_1_t f)
+{
+  return f;
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_add_1 ();
+  check_sub_1 ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-asmtype.c b/tests/mpn/t-asmtype.c
new file mode 100644
index 0000000..c6577d1
--- /dev/null
+++ b/tests/mpn/t-asmtype.c
@@ -0,0 +1,63 @@
+/* Test .type directives on assembler functions.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+/* This apparently trivial test is designed to detect missing .type and
+   .size directives in asm code, per the problem described under
+   GMP_ASM_TYPE in acinclude.m4.
+
+   A failure can be provoked in a shared or shared+static build by making
+   TYPE and SIZE in config.m4 empty, either by editing it or by configuring
+   with
+
+       ./configure gmp_cv_asm_type= gmp_cv_asm_size=
+
+   mpn_add_n is used for the test because normally it's implemented in
+   assembler on a CPU that has any asm code.
+
+   Enhancement: As noted with GMP_ASM_TYPE, if .type is wrong but .size is
+   right then everything works, but uses code copied down to the mainline
+   data area.  Maybe we could detect that if we built a test library with an
+   object that had .size deliberately disabled.  */
+
+int
+main (void)
+{
+  static const mp_limb_t x[3]    = { 1, 2, 3 };
+  static const mp_limb_t y[3]    = { 4, 5, 6 };
+  static const mp_limb_t want[3] = { 5, 7, 9 };
+  mp_limb_t  got[3];
+
+  mpn_add_n (got, x, y, (mp_size_t) 3);
+
+  if (refmpn_cmp (got, want, (mp_size_t) 3) != 0)
+    {
+      printf ("Wrong result from mpn_add_n\n");
+      abort ();
+    }
+
+  exit (0);
+}
diff --git a/tests/mpn/t-bdiv.c b/tests/mpn/t-bdiv.c
new file mode 100644
index 0000000..60f58da
--- /dev/null
+++ b/tests/mpn/t-bdiv.c
@@ -0,0 +1,354 @@
+/* Copyright 2006, 2007, 2009, 2010, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+
+static void
+dumpy (mp_srcptr p, mp_size_t n)
+{
+  mp_size_t i;
+  if (n > 20)
+    {
+      for (i = n - 1; i >= n - 4; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (" ");
+	}
+      printf ("... ");
+      for (i = 3; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  else
+    {
+      for (i = n - 1; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  puts ("");
+}
+
+static unsigned long test;
+
+void
+check_one (mp_ptr qp, mp_srcptr rp, mp_limb_t rh,
+	   mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, const char *fname)
+{
+  mp_size_t qn;
+  mp_ptr tp;
+  mp_limb_t cy = 4711;		/* silence warnings */
+  TMP_DECL;
+
+  qn = nn - dn;
+
+  if (qn == 0)
+    return;
+
+  TMP_MARK;
+
+  tp = TMP_ALLOC_LIMBS (nn + 1);
+
+  if (dn >= qn)
+    mpn_mul (tp, dp, dn, qp, qn);
+  else
+    mpn_mul (tp, qp, qn, dp, dn);
+
+  cy = mpn_add_n (tp, tp, np, nn);
+
+  if (! mpn_zero_p (tp, qn)
+      || (rp != NULL && (cy != rh || mpn_cmp (tp + qn, rp, dn) != 0)))
+    {
+      printf ("\r*******************************************************************************\n");
+      printf ("%s inconsistent in test %lu\n", fname, test);
+      printf ("N=   "); dumpy (np, nn);
+      printf ("D=   "); dumpy (dp, dn);
+      printf ("Q=   "); dumpy (qp, qn);
+      if (rp != NULL)
+	{
+	  printf ("R=   "); dumpy (rp, dn);
+	  printf ("Rb=  %d, Cy=%d\n", (int) cy, (int) rh);
+	}
+      printf ("T=   "); dumpy (tp, nn);
+      printf ("nn = %ld, dn = %ld, qn = %ld", nn, dn, qn);
+      printf ("\n*******************************************************************************\n");
+      abort ();
+    }
+
+  TMP_FREE;
+}
+
+
+/* These are *bit* sizes. */
+#define SIZE_LOG 16
+#define MAX_DN (1L << SIZE_LOG)
+#define MAX_NN (1L << (SIZE_LOG + 1))
+
+#define COUNT 500
+
+mp_limb_t
+random_word (gmp_randstate_ptr rs)
+{
+  mpz_t x;
+  mp_limb_t r;
+  TMP_DECL;
+  TMP_MARK;
+
+  MPZ_TMP_INIT (x, 2);
+  mpz_urandomb (x, rs, 32);
+  r = mpz_get_ui (x);
+  TMP_FREE;
+  return r;
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  unsigned long maxnbits, maxdbits, nbits, dbits;
+  mpz_t n, d, tz;
+  mp_size_t maxnn, maxdn, nn, dn, clearn, i;
+  mp_ptr np, dp, qp, rp;
+  mp_limb_t rh;
+  mp_limb_t t;
+  mp_limb_t dinv;
+  int count = COUNT;
+  mp_ptr scratch;
+  mp_limb_t ran;
+  mp_size_t alloc, itch;
+  mp_limb_t rran0, rran1, qran0, qran1;
+  TMP_DECL;
+
+  TESTS_REPS (count, argv, argc);
+
+  maxdbits = MAX_DN;
+  maxnbits = MAX_NN;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (n);
+  mpz_init (d);
+  mpz_init (tz);
+
+  maxnn = maxnbits / GMP_NUMB_BITS + 1;
+  maxdn = maxdbits / GMP_NUMB_BITS + 1;
+
+  TMP_MARK;
+
+  qp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+  rp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+
+  alloc = 1;
+  scratch = __GMP_ALLOCATE_FUNC_LIMBS (alloc);
+
+  for (test = 0; test < count;)
+    {
+      nbits = random_word (rands) % (maxnbits - GMP_NUMB_BITS) + 2 * GMP_NUMB_BITS;
+      if (maxdbits > nbits)
+	dbits = random_word (rands) % nbits + 1;
+      else
+	dbits = random_word (rands) % maxdbits + 1;
+
+#if RAND_UNIFORM
+#define RANDFUNC mpz_urandomb
+#else
+#define RANDFUNC mpz_rrandomb
+#endif
+
+      do
+	{
+	  RANDFUNC (n, rands, nbits);
+	  do
+	    {
+	      RANDFUNC (d, rands, dbits);
+	    }
+	  while (mpz_sgn (d) == 0);
+
+	  np = PTR (n);
+	  dp = PTR (d);
+	  nn = SIZ (n);
+	  dn = SIZ (d);
+	}
+      while (nn < dn);
+
+      dp[0] |= 1;
+
+      mpz_urandomb (tz, rands, 32);
+      t = mpz_get_ui (tz);
+
+      if (t % 17 == 0)
+	dp[0] = GMP_NUMB_MAX;
+
+      switch ((int) t % 16)
+	{
+	case 0:
+	  clearn = random_word (rands) % nn;
+	  for (i = 0; i <= clearn; i++)
+	    np[i] = 0;
+	  break;
+	case 1:
+	  mpn_sub_1 (np + nn - dn, dp, dn, random_word (rands));
+	  break;
+	case 2:
+	  mpn_add_1 (np + nn - dn, dp, dn, random_word (rands));
+	  break;
+	}
+
+      test++;
+
+      binvert_limb (dinv, dp[0]);
+
+      rran0 = random_word (rands);
+      rran1 = random_word (rands);
+      qran0 = random_word (rands);
+      qran1 = random_word (rands);
+
+      qp[-1] = qran0;
+      qp[nn - dn + 1] = qran1;
+      rp[-1] = rran0;
+
+      ran = random_word (rands);
+
+      if ((double) (nn - dn) * dn < 1e5)
+	{
+	  if (nn > dn)
+	    {
+	      /* Test mpn_sbpi1_bdiv_qr */
+	      MPN_ZERO (qp, nn - dn);
+	      MPN_ZERO (rp, dn);
+	      MPN_COPY (rp, np, nn);
+	      rh = mpn_sbpi1_bdiv_qr (qp, rp, nn, dp, dn, -dinv);
+	      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	      ASSERT_ALWAYS (rp[-1] == rran0);
+	      check_one (qp, rp + nn - dn, rh, np, nn, dp, dn, "mpn_sbpi1_bdiv_qr");
+
+	      /* Test mpn_sbpi1_bdiv_q */
+	      MPN_COPY (rp, np, nn);
+	      MPN_ZERO (qp, nn - dn);
+	      mpn_sbpi1_bdiv_q (qp, rp, nn - dn, dp, MIN(dn,nn-dn), -dinv);
+	      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	      ASSERT_ALWAYS (rp[-1] == rran0);
+	      check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_sbpi1_bdiv_q");
+
+	      /* Test mpn_sbpi1_bdiv_r; we use mpn_sbpi1_bdiv_q's quotient. */
+	      MPN_COPY (rp, np, nn);
+	      mpn_sbpi1_bdiv_r (rp, nn, dp, dn, -dinv);
+	      ASSERT_ALWAYS (rp[-1] == rran0);
+	      check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_sbpi1_bdiv_r");
+	    }
+	}
+
+      if (dn >= 4 && nn - dn >= 2)
+	{
+	  /* Test mpn_dcpi1_bdiv_qr */
+	  MPN_COPY (rp, np, nn);
+	  MPN_ZERO (qp, nn - dn);
+	  rh = mpn_dcpi1_bdiv_qr (qp, rp, nn, dp, dn, -dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, rp + nn - dn, rh, np, nn, dp, dn, "mpn_dcpi1_bdiv_qr");
+	}
+
+      if (dn >= 4 && nn - dn >= 2)
+	{
+	  /* Test mpn_dcpi1_bdiv_q */
+	  MPN_COPY (rp, np, nn);
+	  MPN_ZERO (qp, nn - dn);
+	  mpn_dcpi1_bdiv_q (qp, rp, nn - dn, dp, MIN(dn,nn-dn), -dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_dcpi1_bdiv_q");
+	}
+
+      if (nn > dn)
+	{
+	  /* Test mpn_bdiv_qr */
+	  itch = mpn_bdiv_qr_itch (nn, dn);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_ZERO (qp, nn - dn);
+	  MPN_ZERO (rp, dn);
+	  rp[dn] = rran1;
+	  rh = mpn_bdiv_qr (qp, rp, np, nn, dp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);  ASSERT_ALWAYS (rp[dn] == rran1);
+
+	  check_one (qp, rp, rh, np, nn, dp, dn, "mpn_bdiv_qr");
+	}
+
+      if (nn - dn < 2 || dn < 2)
+	continue;
+
+      /* Test mpn_mu_bdiv_qr */
+      itch = mpn_mu_bdiv_qr_itch (nn, dn);
+      if (itch + 1 > alloc)
+	{
+	  scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	  alloc = itch + 1;
+	}
+      scratch[itch] = ran;
+      MPN_ZERO (qp, nn - dn);
+      MPN_ZERO (rp, dn);
+      rp[dn] = rran1;
+      rh = mpn_mu_bdiv_qr (qp, rp, np, nn, dp, dn, scratch);
+      ASSERT_ALWAYS (ran == scratch[itch]);
+      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+      ASSERT_ALWAYS (rp[-1] == rran0);  ASSERT_ALWAYS (rp[dn] == rran1);
+      check_one (qp, rp, rh, np, nn, dp, dn, "mpn_mu_bdiv_qr");
+
+      /* Test mpn_mu_bdiv_q */
+      itch = mpn_mu_bdiv_q_itch (nn, dn);
+      if (itch + 1 > alloc)
+	{
+	  scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	  alloc = itch + 1;
+	}
+      scratch[itch] = ran;
+      MPN_ZERO (qp, nn - dn + 1);
+      mpn_mu_bdiv_q (qp, np, nn - dn, dp, dn, scratch);
+      ASSERT_ALWAYS (ran == scratch[itch]);
+      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+      check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_mu_bdiv_q");
+    }
+
+  __GMP_FREE_FUNC_LIMBS (scratch, alloc);
+
+  TMP_FREE;
+
+  mpz_clear (n);
+  mpz_clear (d);
+  mpz_clear (tz);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-broot.c b/tests/mpn/t-broot.c
new file mode 100644
index 0000000..bd8e80f
--- /dev/null
+++ b/tests/mpn/t-broot.c
@@ -0,0 +1,108 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#define MAX_LIMBS 150
+#define COUNT 500
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+
+  mp_ptr ap, rp, pp, scratch;
+  int count = COUNT;
+  unsigned i;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  rp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  pp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  scratch = TMP_ALLOC_LIMBS (3*MAX_LIMBS); /* For mpn_powlo */
+
+  for (i = 0; i < count; i++)
+    {
+      mp_size_t n;
+      mp_limb_t k;
+      int c;
+
+      n = 1 + gmp_urandomm_ui (rands, MAX_LIMBS);
+
+      if (i & 1)
+	mpn_random2 (ap, n);
+      else
+	mpn_random (ap, n);
+
+      ap[0] |= 1;
+
+      if (i < 100)
+	k = 3 + 2*i;
+      else
+	{
+	  mpn_random (&k, 1);
+	  if (k < 3)
+	    k = 3;
+	  else
+	    k |= 1;
+	}
+      mpn_broot (rp, ap, n, k);
+      mpn_powlo (pp, rp, &k, 1, n, scratch);
+
+      MPN_CMP (c, ap, pp, n);
+      if (c != 0)
+	{
+	  gmp_fprintf (stderr,
+		       "mpn_broot returned bad result: %u limbs\n",
+		       (unsigned) n);
+	  gmp_fprintf (stderr, "k   = %Mx\n", k);
+	  gmp_fprintf (stderr, "a   = %Nx\n", ap, n);
+	  gmp_fprintf (stderr, "r   = %Nx\n", rp, n);
+	  gmp_fprintf (stderr, "r^k = %Nx\n", pp, n);
+	  abort ();
+	}
+    }
+
+  mpn_broot (rp, ap, MAX_LIMBS, 1);
+  if (mpn_cmp (ap, rp, MAX_LIMBS) != 0)
+    {
+      gmp_fprintf (stderr,
+		   "mpn_broot returned bad result: %u limbs\n",
+		   (unsigned) MAX_LIMBS);
+      gmp_fprintf (stderr, "k   = %Mx\n", 1);
+      gmp_fprintf (stderr, "a   = %Nx\n", ap, MAX_LIMBS);
+      gmp_fprintf (stderr, "r   = %Nx\n", rp, MAX_LIMBS);
+      abort ();
+    }
+
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-brootinv.c b/tests/mpn/t-brootinv.c
new file mode 100644
index 0000000..f5a9950
--- /dev/null
+++ b/tests/mpn/t-brootinv.c
@@ -0,0 +1,96 @@
+/* Copyright 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#define MAX_LIMBS 150
+#define COUNT 500
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+
+  mp_ptr ap, rp, pp, app, scratch;
+  int count = COUNT;
+  unsigned i;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  rp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  pp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  app = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  scratch = TMP_ALLOC_LIMBS (5*MAX_LIMBS);
+
+  for (i = 0; i < count; i++)
+    {
+      mp_size_t n;
+      mp_limb_t k;
+
+      n = 1 + gmp_urandomm_ui (rands, MAX_LIMBS);
+
+      if (i & 1)
+	mpn_random2 (ap, n);
+      else
+	mpn_random (ap, n);
+
+      ap[0] |= 1;
+
+      if (i < 100)
+	k = 3 + 2*i;
+      else
+	{
+	  mpn_random (&k, 1);
+	  if (k < 3)
+	    k = 3;
+	  else
+	    k |= 1;
+	}
+      mpn_brootinv (rp, ap, n, k, scratch);
+      mpn_powlo (pp, rp, &k, 1, n, scratch);
+      mpn_mullo_n (app, ap, pp, n);
+
+      if (app[0] != 1 || !(n == 1 || mpn_zero_p (app+1, n-1)))
+	{
+	  gmp_fprintf (stderr,
+		       "mpn_brootinv returned bad result: %u limbs\n",
+		       (unsigned) n);
+	  gmp_fprintf (stderr, "k     = %Mx\n", k);
+	  gmp_fprintf (stderr, "a     = %Nx\n", ap, n);
+	  gmp_fprintf (stderr, "r     = %Nx\n", rp, n);
+	  gmp_fprintf (stderr, "r^n   = %Nx\n", pp, n);
+	  gmp_fprintf (stderr, "a r^n = %Nx\n", app, n);
+	  abort ();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-div.c b/tests/mpn/t-div.c
new file mode 100644
index 0000000..110385f
--- /dev/null
+++ b/tests/mpn/t-div.c
@@ -0,0 +1,497 @@
+/* Copyright 2006, 2007, 2009, 2010, 2013-2015, 2018 Free Software
+   Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+
+static void
+dumpy (mp_srcptr p, mp_size_t n)
+{
+  mp_size_t i;
+  if (n > 20)
+    {
+      for (i = n - 1; i >= n - 4; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (" ");
+	}
+      printf ("... ");
+      for (i = 3; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  else
+    {
+      for (i = n - 1; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  puts ("");
+}
+
+static signed long test;
+
+static void
+check_one (mp_ptr qp, mp_srcptr rp,
+	   mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn,
+	   const char *fname, mp_limb_t q_allowed_err)
+{
+  mp_size_t qn = nn - dn + 1;
+  mp_ptr tp;
+  const char *msg;
+  const char *tvalue;
+  mp_limb_t i;
+  TMP_DECL;
+  TMP_MARK;
+
+  tp = TMP_ALLOC_LIMBS (nn + 1);
+  if (dn >= qn)
+    refmpn_mul (tp, dp, dn, qp, qn);
+  else
+    refmpn_mul (tp, qp, qn, dp, dn);
+
+  for (i = 0; i < q_allowed_err && (tp[nn] > 0 || mpn_cmp (tp, np, nn) > 0); i++)
+    ASSERT_NOCARRY (refmpn_sub (tp, tp, nn+1, dp, dn));
+
+  if (tp[nn] > 0 || mpn_cmp (tp, np, nn) > 0)
+    {
+      msg = "q too large";
+      tvalue = "Q*D";
+    error:
+      printf ("\r*******************************************************************************\n");
+      printf ("%s failed test %ld: %s\n", fname, test, msg);
+      printf ("N=    "); dumpy (np, nn);
+      printf ("D=    "); dumpy (dp, dn);
+      printf ("Q=    "); dumpy (qp, qn);
+      if (rp)
+	{ printf ("R=    "); dumpy (rp, dn); }
+      printf ("%5s=", tvalue); dumpy (tp, nn+1);
+      printf ("nn = %ld, dn = %ld, qn = %ld\n", nn, dn, qn);
+      abort ();
+    }
+
+  ASSERT_NOCARRY (refmpn_sub_n (tp, np, tp, nn));
+  tvalue = "N-Q*D";
+  if (!(nn == dn || mpn_zero_p (tp + dn, nn - dn)) || mpn_cmp (tp, dp, dn) >= 0)
+    {
+      msg = "q too small";
+      goto error;
+    }
+
+  if (rp && mpn_cmp (rp, tp, dn) != 0)
+    {
+      msg = "r incorrect";
+      goto error;
+    }
+
+  TMP_FREE;
+}
+
+
+/* These are *bit* sizes. */
+#ifndef SIZE_LOG
+#define SIZE_LOG 17
+#endif
+#define MAX_DN (1L << SIZE_LOG)
+#define MAX_NN (1L << (SIZE_LOG + 1))
+
+#define COUNT 200
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  unsigned long maxnbits, maxdbits, nbits, dbits;
+  mpz_t n, d, q, r, tz, junk;
+  mp_size_t maxnn, maxdn, nn, dn, clearn, i;
+  mp_ptr np, dup, dnp, qp, rp, junkp;
+  mp_limb_t t;
+  gmp_pi1_t dinv;
+  long count = COUNT;
+  mp_ptr scratch;
+  mp_limb_t ran;
+  mp_size_t alloc, itch;
+  mp_limb_t rran0, rran1, qran0, qran1;
+  TMP_DECL;
+
+  TESTS_REPS (count, argv, argc);
+
+  maxdbits = MAX_DN;
+  maxnbits = MAX_NN;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (n);
+  mpz_init (d);
+  mpz_init (q);
+  mpz_init (r);
+  mpz_init (tz);
+  mpz_init (junk);
+
+  maxnn = maxnbits / GMP_NUMB_BITS + 1;
+  maxdn = maxdbits / GMP_NUMB_BITS + 1;
+
+  TMP_MARK;
+
+  qp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+  rp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+  dnp = TMP_ALLOC_LIMBS (maxdn);
+
+  alloc = 1;
+  scratch = __GMP_ALLOCATE_FUNC_LIMBS (alloc);
+
+  for (test = -300; test < count; test++)
+    {
+      nbits = urandom () % (maxnbits - GMP_NUMB_BITS) + 2 * GMP_NUMB_BITS;
+
+      if (test < 0)
+	dbits = (test + 300) % (nbits - 1) + 1;
+      else
+	dbits = urandom () % (nbits - 1) % maxdbits + 1;
+
+#if RAND_UNIFORM
+#define RANDFUNC mpz_urandomb
+#else
+#define RANDFUNC mpz_rrandomb
+#endif
+
+      do
+	RANDFUNC (d, rands, dbits);
+      while (mpz_sgn (d) == 0);
+      dn = SIZ (d);
+      dup = PTR (d);
+      MPN_COPY (dnp, dup, dn);
+      dnp[dn - 1] |= GMP_NUMB_HIGHBIT;
+
+      if (test % 2 == 0)
+	{
+	  RANDFUNC (n, rands, nbits);
+	  nn = SIZ (n);
+	  ASSERT_ALWAYS (nn >= dn);
+	}
+      else
+	{
+	  do
+	    {
+	      RANDFUNC (q, rands, urandom () % (nbits - dbits + 1));
+	      RANDFUNC (r, rands, urandom () % mpz_sizeinbase (d, 2));
+	      mpz_mul (n, q, d);
+	      mpz_add (n, n, r);
+	      nn = SIZ (n);
+	    }
+	  while (nn > maxnn || nn < dn);
+	}
+
+      ASSERT_ALWAYS (nn <= maxnn);
+      ASSERT_ALWAYS (dn <= maxdn);
+
+      mpz_urandomb (junk, rands, nbits);
+      junkp = PTR (junk);
+
+      np = PTR (n);
+
+      mpz_urandomb (tz, rands, 32);
+      t = mpz_get_ui (tz);
+
+      if (t % 17 == 0)
+	{
+	  dnp[dn - 1] = GMP_NUMB_MAX;
+	  dup[dn - 1] = GMP_NUMB_MAX;
+	}
+
+      switch ((int) t % 16)
+	{
+	case 0:
+	  clearn = urandom () % nn;
+	  for (i = clearn; i < nn; i++)
+	    np[i] = 0;
+	  break;
+	case 1:
+	  mpn_sub_1 (np + nn - dn, dnp, dn, urandom ());
+	  break;
+	case 2:
+	  mpn_add_1 (np + nn - dn, dnp, dn, urandom ());
+	  break;
+	}
+
+      if (dn >= 2)
+	invert_pi1 (dinv, dnp[dn - 1], dnp[dn - 2]);
+
+      rran0 = urandom ();
+      rran1 = urandom ();
+      qran0 = urandom ();
+      qran1 = urandom ();
+
+      qp[-1] = qran0;
+      qp[nn - dn + 1] = qran1;
+      rp[-1] = rran0;
+
+      ran = urandom ();
+
+      if ((double) (nn - dn) * dn < 1e5)
+	{
+	  /* Test mpn_sbpi1_div_qr */
+	  if (dn > 2)
+	    {
+	      MPN_COPY (rp, np, nn);
+	      if (nn > dn)
+		MPN_COPY (qp, junkp, nn - dn);
+	      qp[nn - dn] = mpn_sbpi1_div_qr (qp, rp, nn, dnp, dn, dinv.inv32);
+	      check_one (qp, rp, np, nn, dnp, dn, "mpn_sbpi1_div_qr", 0);
+	    }
+
+	  /* Test mpn_sbpi1_divappr_q */
+	  if (dn > 2)
+	    {
+	      MPN_COPY (rp, np, nn);
+	      if (nn > dn)
+		MPN_COPY (qp, junkp, nn - dn);
+	      qp[nn - dn] = mpn_sbpi1_divappr_q (qp, rp, nn, dnp, dn, dinv.inv32);
+	      check_one (qp, NULL, np, nn, dnp, dn, "mpn_sbpi1_divappr_q", 1);
+	    }
+
+	  /* Test mpn_sbpi1_div_q */
+	  if (dn > 2)
+	    {
+	      MPN_COPY (rp, np, nn);
+	      if (nn > dn)
+		MPN_COPY (qp, junkp, nn - dn);
+	      qp[nn - dn] = mpn_sbpi1_div_q (qp, rp, nn, dnp, dn, dinv.inv32);
+	      check_one (qp, NULL, np, nn, dnp, dn, "mpn_sbpi1_div_q", 0);
+	    }
+
+	  /* Test mpn_sec_div_qr */
+	  itch = mpn_sec_div_qr_itch (nn, dn);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (rp, np, nn);
+	  if (nn >= dn)
+	    MPN_COPY (qp, junkp, nn - dn + 1);
+	  qp[nn - dn] = mpn_sec_div_qr (qp, rp, nn, dup, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  check_one (qp, rp, np, nn, dup, dn, "mpn_sec_div_qr (unnorm)", 0);
+
+	  /* Test mpn_sec_div_r */
+	  itch = mpn_sec_div_r_itch (nn, dn);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (rp, np, nn);
+	  mpn_sec_div_r (rp, nn, dup, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  /* Note: Since check_one cannot cope with remainder-only functions, we
+	     pass qp[] from the previous function, mpn_sec_div_qr.  */
+	  check_one (qp, rp, np, nn, dup, dn, "mpn_sec_div_r (unnorm)", 0);
+
+	  /* Normalised case, mpn_sec_div_qr */
+	  itch = mpn_sec_div_qr_itch (nn, dn);
+	  scratch[itch] = ran;
+
+	  MPN_COPY (rp, np, nn);
+	  if (nn >= dn)
+	    MPN_COPY (qp, junkp, nn - dn + 1);
+	  qp[nn - dn] = mpn_sec_div_qr (qp, rp, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_sec_div_qr (norm)", 0);
+
+	  /* Normalised case, mpn_sec_div_r */
+	  itch = mpn_sec_div_r_itch (nn, dn);
+	  scratch[itch] = ran;
+	  MPN_COPY (rp, np, nn);
+	  mpn_sec_div_r (rp, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  /* Note: Since check_one cannot cope with remainder-only functions, we
+	     pass qp[] from the previous function, mpn_sec_div_qr.  */
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_sec_div_r (norm)", 0);
+	}
+
+      /* Test mpn_dcpi1_div_qr */
+      if (dn >= 6 && nn - dn >= 3)
+	{
+	  MPN_COPY (rp, np, nn);
+	  if (nn > dn)
+	    MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_dcpi1_div_qr (qp, rp, nn, dnp, dn, &dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_dcpi1_div_qr", 0);
+	}
+
+      /* Test mpn_dcpi1_divappr_q */
+      if (dn >= 6 && nn - dn >= 3)
+	{
+	  MPN_COPY (rp, np, nn);
+	  if (nn > dn)
+	    MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_dcpi1_divappr_q (qp, rp, nn, dnp, dn, &dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_dcpi1_divappr_q", 1);
+	}
+
+      /* Test mpn_dcpi1_div_q */
+      if (dn >= 6 && nn - dn >= 3)
+	{
+	  MPN_COPY (rp, np, nn);
+	  if (nn > dn)
+	    MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_dcpi1_div_q (qp, rp, nn, dnp, dn, &dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_dcpi1_div_q", 0);
+	}
+
+     /* Test mpn_mu_div_qr */
+      if (nn - dn > 2 && dn >= 2)
+	{
+	  itch = mpn_mu_div_qr_itch (nn, dn, 0);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn);
+	  MPN_ZERO (rp, dn);
+	  rp[dn] = rran1;
+	  qp[nn - dn] = mpn_mu_div_qr (qp, rp, np, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);  ASSERT_ALWAYS (rp[dn] == rran1);
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_mu_div_qr", 0);
+	}
+
+      /* Test mpn_mu_divappr_q */
+      if (nn - dn > 2 && dn >= 2)
+	{
+	  itch = mpn_mu_divappr_q_itch (nn, dn, 0);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_mu_divappr_q (qp, np, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_mu_divappr_q", 4);
+	}
+
+      /* Test mpn_mu_div_q */
+      if (nn - dn > 2 && dn >= 2)
+	{
+	  itch = mpn_mu_div_q_itch (nn, dn, 0);
+	  if (itch + 1> alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_mu_div_q (qp, np, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_mu_div_q", 0);
+	}
+
+      if (1)
+	{
+	  itch = nn + 1;
+	  if (itch + 1> alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn + 1);
+	  mpn_div_q (qp, np, nn, dup, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  check_one (qp, NULL, np, nn, dup, dn, "mpn_div_q", 0);
+	}
+
+      if (dn >= 2 && nn >= 2)
+	{
+	  mp_limb_t qh;
+
+	  /* mpn_divrem_2 */
+	  MPN_COPY (rp, np, nn);
+	  qp[nn - 2] = qp[nn-1] = qran1;
+
+	  qh = mpn_divrem_2 (qp, 0, rp, nn, dnp + dn - 2);
+	  ASSERT_ALWAYS (qp[nn - 2] == qran1);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - 1] == qran1);
+	  qp[nn - 2] = qh;
+	  check_one (qp, rp, np, nn, dnp + dn - 2, 2, "mpn_divrem_2", 0);
+
+	  /* Missing: divrem_2 with fraction limbs. */
+
+	  /* mpn_div_qr_2 */
+	  qp[nn - 2] = qran1;
+
+	  qh = mpn_div_qr_2 (qp, rp, np, nn, dup + dn - 2);
+	  ASSERT_ALWAYS (qp[nn - 2] == qran1);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - 1] == qran1);
+	  qp[nn - 2] = qh;
+	  check_one (qp, rp, np, nn, dup + dn - 2, 2, "mpn_div_qr_2", 0);
+	}
+      if (dn >= 1 && nn >= 1)
+	{
+	  /* mpn_div_qr_1 */
+	  mp_limb_t qh;
+	  qp[nn-1] = qran1;
+	  rp[0] = mpn_div_qr_1 (qp, &qh, np, nn, dnp[dn - 1]);
+	  ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - 1] == qran1);
+	  qp[nn - 1] = qh;
+	  check_one (qp, rp, np, nn,  dnp + dn - 1, 1, "mpn_div_qr_1", 0);
+	}
+    }
+
+  __GMP_FREE_FUNC_LIMBS (scratch, alloc);
+
+  TMP_FREE;
+
+  mpz_clear (n);
+  mpz_clear (d);
+  mpz_clear (q);
+  mpz_clear (r);
+  mpz_clear (tz);
+  mpz_clear (junk);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-divrem_1.c b/tests/mpn/t-divrem_1.c
new file mode 100644
index 0000000..991b7da
--- /dev/null
+++ b/tests/mpn/t-divrem_1.c
@@ -0,0 +1,123 @@
+/* Test mpn_divrem_1 and mpn_preinv_divrem_1.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    mp_limb_t  n[1];
+    mp_size_t  nsize;
+    mp_limb_t  d;
+    mp_size_t  qxn;
+    mp_limb_t  want_q[5];
+    mp_limb_t  want_r;
+  } data[] = {
+    { { 0 }, 1, 1, 0,
+      { 0 }, 0},
+
+    { { 5 }, 1, 2, 0,
+      { 2 }, 1},
+
+    /* Exercises the q update in the nl == constant 0 case of
+       udiv_qrnnd_preinv3. Test case copied from t-fat.c. */
+    { { 287 }, 1, 7, 1,
+      { 0, 41 }, 0 },
+
+#if GMP_NUMB_BITS == 32
+    { { 0x3C }, 1, 0xF2, 1,
+      { 0x3F789854, 0 }, 0x98 },
+#endif
+
+#if GMP_NUMB_BITS == 64
+    { { 0x3C }, 1, 0xF2, 1,
+      { CNST_LIMB(0x3F789854A0CB1B81), 0 }, 0x0E },
+
+    /* This case exposed some wrong code generated by SGI cc on mips64 irix
+       6.5 with -n32 -O2, in the fractional loop for normalized divisor
+       using udiv_qrnnd_preinv.  A test "x>al" in one of the sub_ddmmss
+       expansions came out wrong, leading to an incorrect quotient.  */
+    { { CNST_LIMB(0x3C00000000000000) }, 1, CNST_LIMB(0xF200000000000000), 1,
+      { CNST_LIMB(0x3F789854A0CB1B81), 0 }, CNST_LIMB(0x0E00000000000000) },
+#endif
+  };
+
+  mp_limb_t  dinv, got_r, got_q[numberof(data[0].want_q)];
+  mp_size_t  qsize;
+  int        i, shift;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      qsize = data[i].nsize + data[i].qxn;
+      ASSERT_ALWAYS (qsize <= numberof (got_q));
+
+      got_r = mpn_divrem_1 (got_q, data[i].qxn, data[i].n, data[i].nsize,
+                            data[i].d);
+      if (got_r != data[i].want_r
+          || refmpn_cmp (got_q, data[i].want_q, qsize) != 0)
+        {
+          printf        ("mpn_divrem_1 wrong at data[%d]\n", i);
+        bad:
+          mpn_trace     ("  n", data[i].n, data[i].nsize);
+          printf        ("  nsize=%ld\n", (long) data[i].nsize);
+          mp_limb_trace ("  d", data[i].d);
+          printf        ("  qxn=%ld\n", (long) data[i].qxn);
+          mpn_trace     ("  want q", data[i].want_q, qsize);
+          mpn_trace     ("  got  q", got_q, qsize);
+          mp_limb_trace ("  want r", data[i].want_r);
+          mp_limb_trace ("  got  r", got_r);
+          abort ();
+        }
+
+      /* test if available */
+#if USE_PREINV_DIVREM_1 || HAVE_NATIVE_mpn_preinv_divrem_1
+      shift = refmpn_count_leading_zeros (data[i].d);
+      dinv = refmpn_invert_limb (data[i].d << shift);
+      got_r = mpn_preinv_divrem_1 (got_q, data[i].qxn,
+                                   data[i].n, data[i].nsize,
+                                   data[i].d, dinv, shift);
+      if (got_r != data[i].want_r
+          || refmpn_cmp (got_q, data[i].want_q, qsize) != 0)
+        {
+          printf        ("mpn_preinv divrem_1 wrong at data[%d]\n", i);
+          printf        ("  shift=%d\n", shift);
+          mp_limb_trace ("  dinv", dinv);
+          goto bad;
+        }
+#endif
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-fat.c b/tests/mpn/t-fat.c
new file mode 100644
index 0000000..4e71017
--- /dev/null
+++ b/tests/mpn/t-fat.c
@@ -0,0 +1,310 @@
+/* Test fat binary setups.
+
+Copyright 2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+/* In this program we're aiming to pick up certain subtle problems that
+   might creep into a fat binary.
+
+   1. We want to ensure the application entry point routines like
+      __gmpn_add_n dispatch to the correct field of __gmpn_cpuvec.
+
+      Note that these routines are not exercised as a side effect of other
+      tests (eg. the mpz routines).  Internally the fields of __gmpn_cpuvec
+      are used directly, so we need to write test code explicitly calling
+      the mpn functions, like an application will have.
+
+   2. We want to ensure the initial __gmpn_cpuvec data has the initializer
+      function pointers in the correct fields, and that those initializer
+      functions dispatch to their correct corresponding field once
+      initialization has been done.
+
+      Only one of the initializer routines executes in a normal program,
+      since that routine sets all the pointers to actual mpn functions.  We
+      forcibly reset __gmpn_cpuvec so we can run each.
+
+   In both cases for the above, the data put through the functions is
+   nothing special, just enough to verify that for instance an add_n is
+   really doing an add_n and has not for instance mistakenly gone to sub_n
+   or something.
+
+   The loop around each test will exercise the initializer routine on the
+   first iteration, and the dispatcher routine on the second.
+
+   If the dispatcher and/or initializer routines are generated mechanically
+   via macros (eg. mpn/x86/fat/fat_entry.asm) then there shouldn't be too
+   much risk of them going wrong, provided the structure layout is correctly
+   expressed.  But if they're in C then it's good to guard against typos in
+   what is rather repetitive code.  The initializer data for __gmpn_cpuvec
+   in fat.c is always done by hand and is likewise a bit repetitive.  */
+
+
+/* dummies when not a fat binary */
+#if ! WANT_FAT_BINARY
+struct cpuvec_t {
+  int  dummy;
+};
+struct cpuvec_t __gmpn_cpuvec;
+#define ITERATE_FAT_THRESHOLDS()  do { } while (0)
+#endif
+
+/* saved from program startup */
+struct cpuvec_t  initial_cpuvec;
+
+void
+check_functions (void)
+{
+  mp_limb_t  wp[2], xp[2], yp[2], r;
+  int  i;
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      yp[0] = 456;
+      mpn_add_n (wp, xp, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 579);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      wp[0] = 456;
+      r = mpn_addmul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(2));
+      ASSERT_ALWAYS (wp[0] == 702);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+#if HAVE_NATIVE_mpn_copyd
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      xp[1] = 456;
+      mpn_copyd (xp+1, xp, (mp_size_t) 1);
+      ASSERT_ALWAYS (xp[1] == 123);
+    }
+#endif
+
+#if HAVE_NATIVE_mpn_copyi
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      xp[1] = 456;
+      mpn_copyi (xp, xp+1, (mp_size_t) 1);
+      ASSERT_ALWAYS (xp[0] == 456);
+    }
+#endif
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 1605;
+      mpn_divexact_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(5));
+      ASSERT_ALWAYS (wp[0] == 321);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 1296;
+      r = mpn_divexact_by3c (wp, xp, (mp_size_t) 1, CNST_LIMB(0));
+      ASSERT_ALWAYS (wp[0] == 432);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 287;
+      r = mpn_divrem_1 (wp, (mp_size_t) 1, xp, (mp_size_t) 1, CNST_LIMB(7));
+      ASSERT_ALWAYS (wp[1] == 41);
+      ASSERT_ALWAYS (wp[0] == 0);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 12;
+      r = mpn_gcd_1 (xp, (mp_size_t) 1, CNST_LIMB(9));
+      ASSERT_ALWAYS (r == 3);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 0x1001;
+      mpn_lshift (wp, xp, (mp_size_t) 1, 1);
+      ASSERT_ALWAYS (wp[0] == 0x2002);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 14;
+      r = mpn_mod_1 (xp, (mp_size_t) 1, CNST_LIMB(4));
+      ASSERT_ALWAYS (r == 2);
+    }
+
+#if (GMP_NUMB_BITS % 4) == 0
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      int  bits = (GMP_NUMB_BITS / 4) * 3;
+      mp_limb_t  mod = (CNST_LIMB(1) << bits) - 1;
+      mp_limb_t  want = GMP_NUMB_MAX % mod;
+      xp[0] = GMP_NUMB_MAX;
+      r = mpn_mod_34lsub1 (xp, (mp_size_t) 1);
+      ASSERT_ALWAYS (r % mod == want);
+    }
+#endif
+
+  /*   DECL_modexact_1c_odd ((*modexact_1c_odd)); */
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 14;
+      r = mpn_mul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(4));
+      ASSERT_ALWAYS (wp[0] == 56);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 5;
+      yp[0] = 7;
+      mpn_mul_basecase (wp, xp, (mp_size_t) 1, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 35);
+      ASSERT_ALWAYS (wp[1] == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 5;
+      yp[0] = 7;
+      mpn_mullo_basecase (wp, xp, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 35);
+    }
+
+#if HAVE_NATIVE_mpn_preinv_divrem_1 && GMP_NAIL_BITS == 0
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 0x101;
+      r = mpn_preinv_divrem_1 (wp, (mp_size_t) 1, xp, (mp_size_t) 1,
+                               GMP_LIMB_HIGHBIT,
+                               refmpn_invert_limb (GMP_LIMB_HIGHBIT), 0);
+      ASSERT_ALWAYS (wp[0] == 0x202);
+      ASSERT_ALWAYS (wp[1] == 0);
+      ASSERT_ALWAYS (r == 0);
+    }
+#endif
+
+#if GMP_NAIL_BITS == 0
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = GMP_LIMB_HIGHBIT+123;
+      r = mpn_preinv_mod_1 (xp, (mp_size_t) 1, GMP_LIMB_HIGHBIT,
+                            refmpn_invert_limb (GMP_LIMB_HIGHBIT));
+      ASSERT_ALWAYS (r == 123);
+    }
+#endif
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 0x8008;
+      mpn_rshift (wp, xp, (mp_size_t) 1, 1);
+      ASSERT_ALWAYS (wp[0] == 0x4004);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 5;
+      mpn_sqr_basecase (wp, xp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 25);
+      ASSERT_ALWAYS (wp[1] == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 999;
+      yp[0] = 666;
+      mpn_sub_n (wp, xp, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 333);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      wp[0] = 456;
+      r = mpn_submul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(2));
+      ASSERT_ALWAYS (wp[0] == 210);
+      ASSERT_ALWAYS (r == 0);
+    }
+}
+
+/* Expect the first use of each fat threshold to invoke the necessary
+   initialization.  */
+void
+check_thresholds (void)
+{
+#define ITERATE(name,field)                                             \
+  do {                                                                  \
+    __gmpn_cpuvec_initialized = 0;					\
+    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));   \
+    ASSERT_ALWAYS (name != 0);                                          \
+    ASSERT_ALWAYS (name == __gmpn_cpuvec.field);                        \
+    ASSERT_ALWAYS (__gmpn_cpuvec_initialized);                          \
+  } while (0)
+
+  ITERATE_FAT_THRESHOLDS ();
+}
+
+
+int
+main (void)
+{
+  memcpy (&initial_cpuvec, &__gmpn_cpuvec, sizeof (__gmpn_cpuvec));
+
+  tests_start ();
+
+  check_functions ();
+  check_thresholds ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-fib2m.c b/tests/mpn/t-fib2m.c
new file mode 100644
index 0000000..5ad3942
--- /dev/null
+++ b/tests/mpn/t-fib2m.c
@@ -0,0 +1,344 @@
+/* Test mpn_fib2m.
+
+Copyright 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define MAX_K_BITS 16
+#define MAX_K (1L << MAX_K_BITS)
+#define MIN_K 1
+
+#define MAX_MN 20
+#define MAX_KN 30
+
+#define COUNT 200
+
+static int
+test_fib2_fib2m (int count, gmp_randstate_ptr rands)
+{
+  int test;
+  mp_ptr fk, fks1, fkm, fks1m, mp, qp;
+  mp_size_t mn, fn, size, max_mn;
+  TMP_DECL;
+
+  size = MPN_FIB2_SIZE (MAX_K);
+  max_mn = size / 4 + 10;
+  ASSERT (max_mn < size);
+
+  TMP_MARK;
+  fk	 = TMP_ALLOC_LIMBS (size);
+  fks1	 = TMP_ALLOC_LIMBS (size);
+  qp	 = TMP_ALLOC_LIMBS (size);
+  mp	 = TMP_ALLOC_LIMBS (max_mn);
+  fkm	 = 1 + TMP_ALLOC_LIMBS (max_mn * 2 + 1 + 2);
+  fks1m	 = 1 + TMP_ALLOC_LIMBS (max_mn * 2 + 1 + 2);
+
+  for (test = 1; test <= count; ++test)
+    {
+      mp_limb_t fk_before, fk_after, fk1_before, fk1_after;
+      int signflip;
+      unsigned long k;
+
+      k = MIN_K +
+	gmp_urandomm_ui (rands, test < MAX_K_BITS ?
+			 MAX_K >> test : (MAX_K - MIN_K));
+
+      fn = mpn_fib2_ui (fk, fks1, k);
+      do {
+	mn = gmp_urandomm_ui (rands, MAX_K) % (fn / 4 + 10);
+      } while (mn == 0);
+      ASSERT (mn <= max_mn);
+      mpn_random2 (mp, mn);
+      ASSERT (mp [mn - 1] != 0);
+
+      if (fn >= mn)
+	{
+	  mpn_tdiv_qr (qp, fk, 0, fk, fn, mp, mn);
+	  mpn_tdiv_qr (qp, fks1, 0, fks1, fn, mp, mn);
+	}
+      else
+	{
+	  MPN_ZERO (fk + fn, mn - fn);
+	  MPN_ZERO (fks1 + fn, mn - fn);
+	}
+
+      mpn_random2 (fkm - 1, 2*mn+1+2);
+      fk_before = fkm [-1];
+      fk_after = fkm [2 * mn + 1];
+
+      mpn_random2 (fks1m - 1, 2*mn+1+2);
+      fk1_before = fks1m [-1];
+      fk1_after = fks1m [2 * mn + 1];
+
+      qp [0] = k;
+      signflip = mpn_fib2m (fkm, fks1m, qp, 1, mp, mn);
+      if (fkm [-1] != fk_before || fkm [2 * mn + 1] != fk_after
+	  || fks1m [-1] != fk1_before || fks1m [2 * mn + 1] != fk1_after)
+	{
+	  printf ("REDZONE violation in test %d, k = %lu, mn = %u\n",
+		  test, k, (unsigned) mn);
+	  if (fkm[-1] != fk_before)
+	    {
+	      printf ("before fkm:"); mpn_dump (fkm - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk_before, 1);
+	    }
+	  if (fkm[2 * mn + 1] != fk_after)
+	    {
+	      printf ("after fkm:"); mpn_dump (fkm + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk_after, 1);
+	    }
+	  if (fks1m[-1] != fk1_before)
+	    {
+	      printf ("before fks1m:"); mpn_dump (fks1m - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1_before, 1);
+	    }
+	  if (fks1m[2 * mn + 1] != fk1_after)
+	    {
+	      printf ("after fks1m:"); mpn_dump (fks1m + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1_after, 1);
+	    }
+	  abort();
+	}
+
+      if (mpn_cmp (fkm, fk, mn) != 0)
+	{
+	  if (mpn_sub_n (fk, mp, fk, mn) || mpn_cmp (fkm, fk, mn) != 0)
+	    {
+	      printf ("ERROR(k) in test %d, k = %lu, mn = %u\n",
+		      test, k, (unsigned) mn);
+	      mpn_dump (fk, mn);
+	      mpn_dump (fkm, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (mpn_cmp (fks1m, fks1, mn) != 0)
+	{
+	  if (mpn_sub_n (fks1, mp, fks1, mn) || mpn_cmp (fks1m, fks1, mn) != 0)
+	    {
+	      printf ("ERROR(k-1) in test %d, k = %lu, mn = %u\n",
+		      test, k, (unsigned) mn);
+	      mpn_dump (fks1, mn);
+	      mpn_dump (fks1m, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (signflip != 0 && ! mpn_zero_p (fks1m, mn) && ! mpn_zero_p (fkm, mn))
+	{
+	  if ((mp [0] & 1) == 0) /* Should we test only odd modulus-es? */
+	    {
+	      if (! mpn_lshift (fks1m, fks1m, mn, 1) &&
+		  mpn_cmp (mp, fks1m, mn) == 0)
+		continue;
+	      if (! mpn_lshift (fkm, fkm, mn, 1) &&
+		  mpn_cmp (mp, fkm, mn) == 0)
+		continue;
+	    }
+	  printf ("ERROR(sign) in test %d, k = %lu, mn = %u\n",
+		  test, k, (unsigned) mn);
+	  abort();
+	}
+    }
+  TMP_FREE;
+  return 0;
+}
+
+static int
+test_fib2m_2exp (int count, gmp_randstate_ptr rands)
+{
+  int test;
+  mp_ptr fka, fks1a, fkb, fks1b, mp, kp;
+  TMP_DECL;
+
+  TMP_MARK;
+  kp	 = TMP_ALLOC_LIMBS (MAX_KN);
+  mp	 = TMP_ALLOC_LIMBS (MAX_MN);
+  fka	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+  fks1a	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+  fkb	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+  fks1b	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+
+  for (test = 1; test <= count; ++test)
+    {
+      mp_limb_t fka_before, fka_after, fk1a_before, fk1a_after;
+      mp_limb_t fkb_before, fkb_after, fk1b_before, fk1b_after;
+      mp_size_t mn, kn;
+      int signflip;
+      mp_bitcnt_t exp2;
+
+      mn = gmp_urandomm_ui (rands, MAX_MN - 1) + 1;
+      mpn_random2 (mp, mn);
+
+      exp2 = MIN_K + 1 + gmp_urandomm_ui (rands, MAX_KN * GMP_NUMB_BITS - MIN_K - 1);
+
+      kn = BITS_TO_LIMBS (exp2);
+      MPN_ZERO (kp, kn - 1);
+      kp [kn - 1] = CNST_LIMB (1) << ((exp2 - 1) % GMP_NUMB_BITS);
+
+      mpn_random2 (fka - 1, 2*mn+1+2);
+      fka_before = fka [-1];
+      fka_after = fka [2 * mn + 1];
+
+      mpn_random2 (fks1a - 1, 2*mn+1+2);
+      fk1a_before = fks1a [-1];
+      fk1a_after = fks1a [2 * mn + 1];
+
+      signflip = mpn_fib2m (fka, fks1a, kp, kn, mp, mn);
+      if (fka [-1] != fka_before || fka [2 * mn + 1] != fka_after
+	  || fks1a [-1] != fk1a_before || fks1a [2 * mn + 1] != fk1a_after)
+	{
+	  printf ("REDZONE(a) violation in test %d, exp2 = %lu\n", test, exp2);
+	  if (fka[-1] != fka_before)
+	    {
+	      printf ("before fka:"); mpn_dump (fka - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fka_before, 1);
+	    }
+	  if (fka[2 * mn + 1] != fka_after)
+	    {
+	      printf ("after fka:"); mpn_dump (fka + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fka_after, 1);
+	    }
+	  if (fks1a[-1] != fk1a_before)
+	    {
+	      printf ("before fks1a:"); mpn_dump (fks1a - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1a_before, 1);
+	    }
+	  if (fks1a[2 * mn + 1] != fk1a_after)
+	    {
+	      printf ("after fks1a:"); mpn_dump (fks1a + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1a_after, 1);
+	    }
+	  abort();
+	}
+
+      if (signflip && ! mpn_zero_p (fks1a, mn))
+	mpn_sub_n (fks1a, mp, fks1a, mn);
+      if (mpn_sub_n (fka, fka, fks1a, mn))
+	ASSERT_CARRY (mpn_add_n (fka, fka, mp, mn));
+
+      mpn_sub_1 (kp, kp, kn, 1);
+      ASSERT (exp2 % GMP_NUMB_BITS == 1 || kp [kn - 1] != 0);
+      kn -= kp [kn - 1] == 0;
+
+      mpn_random2 (fkb - 1, 2*mn+1+2);
+      fkb_before = fkb [-1];
+      fkb_after = fkb [2 * mn + 1];
+
+      mpn_random2 (fks1b - 1, 2*mn+1+2);
+      fk1b_before = fks1b [-1];
+      fk1b_after = fks1b [2 * mn + 1];
+
+      signflip = mpn_fib2m (fkb, fks1b, kp, kn, mp, mn);
+      if (fkb [-1] != fkb_before || fkb [2 * mn + 1] != fkb_after
+	  || fks1b [-1] != fk1b_before || fks1b [2 * mn + 1] != fk1b_after)
+	{
+	  printf ("REDZONE(b) violation in test %d, exp2 = %lu\n", test, exp2);
+	  if (fkb[-1] != fkb_before)
+	    {
+	      printf ("before fkb:"); mpn_dump (fkb - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fkb_before, 1);
+	    }
+	  if (fkb[2 * mn + 1] != fkb_after)
+	    {
+	      printf ("after fkb:"); mpn_dump (fkb + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fkb_after, 1);
+	    }
+	  if (fks1b[-1] != fk1b_before)
+	    {
+	      printf ("before fks1b:"); mpn_dump (fks1b - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1b_before, 1);
+	    }
+	  if (fks1b[2 * mn + 1] != fk1b_after)
+	    {
+	      printf ("after fks1b:"); mpn_dump (fks1b + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1b_after, 1);
+	    }
+	  abort();
+	}
+
+      if (mpn_cmp (fks1a, fkb, mn) != 0)
+	{
+	  if (mpn_sub_n (fkb, mp, fkb, mn) || mpn_cmp (fks1a, fkb, mn) != 0)
+	    {
+	      printf ("ERROR(k) in test %d, exp2 = %lu\n", test, exp2);
+	      mpn_dump (fks1a, mn);
+	      mpn_dump (fkb, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (mpn_cmp (fka, fks1b, mn) != 0)
+	{
+	  if (mpn_sub_n (fks1b, mp, fks1b, mn) || mpn_cmp (fka, fks1b, mn) != 0)
+	    {
+	      printf ("ERROR(k-1) in test %d, exp2 = %lu\n", test, exp2);
+	      mpn_dump (fka, mn);
+	      mpn_dump (fks1b, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (signflip != 0 && ! mpn_zero_p (fks1b, mn) && ! mpn_zero_p (fkb, mn))
+	{
+	  if ((mp [0] & 1) == 0) /* Should we test only odd modulus-es? */
+	    {
+	      if (! mpn_lshift (fks1b, fks1b, mn, 1) &&
+		  mpn_cmp (mp, fks1b, mn) == 0)
+		continue;
+	      if (! mpn_lshift (fkb, fkb, mn, 1) &&
+		  mpn_cmp (mp, fkb, mn) == 0)
+		continue;
+	    }
+	  printf ("ERROR(sign) in test %d, exp2 = %lu\n",
+		  test, exp2);
+	  abort();
+	}
+    }
+  TMP_FREE;
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int count = COUNT;
+  gmp_randstate_ptr rands;
+
+  tests_start ();
+  TESTS_REPS (count, argv, argc);
+  rands = RANDS;
+
+  test_fib2_fib2m (count / 2, rands);
+  test_fib2m_2exp (count / 2, rands);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-gcd_11.c b/tests/mpn/t-gcd_11.c
new file mode 100644
index 0000000..2b4de2f
--- /dev/null
+++ b/tests/mpn/t-gcd_11.c
@@ -0,0 +1,86 @@
+/* Test mpn_gcd_11.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef COUNT
+#define COUNT 500000
+#endif
+
+static void
+one_test (mp_limb_t a, mp_limb_t b, mp_limb_t ref)
+{
+  mp_limb_t r = mpn_gcd_11 (a, b);
+  if (r != ref)
+    {
+      gmp_fprintf (stderr,
+		   "gcd_11 (0x%Mx, 0x%Mx) failed, got: 0x%Mx, ref: 0x%Mx\n",
+		   a, b, r, ref);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  for (test = 0; test < count; test++)
+    {
+      mp_limb_t al, bl;
+      mp_bitcnt_t asize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      mp_bitcnt_t bsize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      if (test & 1)
+	{
+	  mpz_urandomb (a, rands, asize);
+	  mpz_urandomb (b, rands, bsize);
+	}
+      else
+	{
+	  mpz_rrandomb (a, rands, asize);
+	  mpz_rrandomb (b, rands, bsize);
+	}
+
+      mpz_setbit (a, 0);
+      mpz_setbit (b, 0);
+      al = mpz_getlimbn (a, 0);
+      bl = mpz_getlimbn (b, 0);
+      one_test (al, bl, refmpn_gcd_11 (al, bl));
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-gcd_22.c b/tests/mpn/t-gcd_22.c
new file mode 100644
index 0000000..314bf18
--- /dev/null
+++ b/tests/mpn/t-gcd_22.c
@@ -0,0 +1,87 @@
+/* Test mpn_gcd_22.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef COUNT
+#define COUNT 150000
+#endif
+
+static void
+one_test (mpz_srcptr a, mpz_srcptr b, mpz_srcptr ref)
+{
+  mp_double_limb_t r = mpn_gcd_22 (mpz_getlimbn (a, 1), mpz_getlimbn (a, 0),
+				   mpz_getlimbn (b, 1), mpz_getlimbn (b, 0));
+  if (r.d0 != mpz_getlimbn (ref, 0) || r.d1 != mpz_getlimbn (ref, 1))
+    {
+      gmp_fprintf (stderr,
+		   "gcd_22 (0x%Zx, 0x%Zx) failed, got: g1 = 0x%Mx g0 = %Mx, ref: 0x%Zx\n",
+                   a, b, r.d1, r.d0, ref);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b, ref;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (ref);
+  for (test = 0; test < count; test++)
+    {
+      mp_bitcnt_t asize = 1 + gmp_urandomm_ui(rands, 2*GMP_NUMB_BITS);
+      mp_bitcnt_t bsize = 1 + gmp_urandomm_ui(rands, 2*GMP_NUMB_BITS);
+      if (test & 1)
+	{
+	  mpz_urandomb (a, rands, asize);
+	  mpz_urandomb (b, rands, bsize);
+	}
+      else
+	{
+	  mpz_rrandomb (a, rands, asize);
+	  mpz_rrandomb (b, rands, bsize);
+	}
+
+      mpz_setbit (a, 0);
+      mpz_setbit (b, 0);
+      refmpz_gcd (ref, a, b);
+      one_test (a, b, ref);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (ref);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-gcdext_1.c b/tests/mpn/t-gcdext_1.c
new file mode 100644
index 0000000..1e73a11
--- /dev/null
+++ b/tests/mpn/t-gcdext_1.c
@@ -0,0 +1,134 @@
+/* Test mpn_gcdext_1.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef COUNT
+#define COUNT 250000
+#endif
+
+static void
+set_signed_limb (mpz_t r, mp_limb_signed_t x)
+{
+  mpz_t t;
+  mp_limb_t abs_x = ABS_CAST(mp_limb_t, x);
+  mpz_set (r, mpz_roinit_n (t, &abs_x, 1));
+  if (x < 0)
+    mpz_neg (r, r);
+}
+
+static void
+one_test (mp_limb_t a, mp_limb_t b)
+{
+  mp_limb_signed_t s, t;
+  mp_limb_t g;
+
+  g = mpn_gcdext_1 (&s, &t, a, b);
+
+  if (g > 0)
+    {
+      mpz_t d, sz, tz, tmp;
+
+      mpz_init (d);
+      mpz_init (sz);
+      mpz_init (tz);
+
+      set_signed_limb (sz, s);
+      set_signed_limb (tz, t);
+
+      mpz_mul (d, mpz_roinit_n (tmp, &a, 1), sz);
+      mpz_addmul (d, mpz_roinit_n (tmp, &b, 1), tz);
+
+      if (mpz_cmp (d, mpz_roinit_n (tmp, &g, 1)) == 0
+	  && a % g == 0 && b % g == 0)
+	{
+	  mp_limb_t a_div_g = a / g;
+	  mp_limb_t b_div_g = b / g;
+	  mp_limb_t abs_s = ABS_CAST(mp_limb_t, s);
+	  mp_limb_t abs_t = ABS_CAST(mp_limb_t, t);
+	  mpz_mul_ui (sz, sz, 2);
+	  mpz_mul_ui (tz, tz, 2);
+	  if ((abs_s == 1 || mpz_cmpabs (sz, mpz_roinit_n (tmp, &b_div_g, 1)) < 0)
+	       && (abs_t == 1 || mpz_cmpabs (tz, mpz_roinit_n (tmp, &a_div_g, 1)) < 0))
+	    {
+	      mpz_clear (d);
+	      mpz_clear (sz);
+	      mpz_clear (tz);
+
+	      return;
+	    }
+	}
+    }
+  gmp_fprintf (stderr,
+	       "gcdext_1 (0x%Mx, 0x%Mx) failed, got: g = 0x%Mx, s = %s0x%Mx, t = %s0x%Mx\n",
+	       a, b, g,
+	       s < 0 ? "-" : "", ABS_CAST(mp_limb_t, s),
+	       t < 0 ? "-" : "", ABS_CAST(mp_limb_t, t));
+  abort();
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  for (test = 0; test < count; test++)
+    {
+      mp_limb_t al, bl;
+      mp_bitcnt_t asize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      mp_bitcnt_t bsize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      if (test & 1)
+	{
+	  mpz_urandomb (a, rands, asize);
+	  mpz_urandomb (b, rands, bsize);
+	}
+      else
+	{
+	  mpz_rrandomb (a, rands, asize);
+	  mpz_rrandomb (b, rands, bsize);
+	}
+
+      al = mpz_getlimbn (a, 0);
+      bl = mpz_getlimbn (b, 0);
+      al += (al == 0);
+      bl += (bl == 0);
+
+      one_test (al, bl);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-get_d.c b/tests/mpn/t-get_d.c
new file mode 100644
index 0000000..ab0e2ec
--- /dev/null
+++ b/tests/mpn/t-get_d.c
@@ -0,0 +1,497 @@
+/* Test mpn_get_d.
+
+Copyright 2002-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#ifndef _GMP_IEEE_FLOATS
+#define _GMP_IEEE_FLOATS 0
+#endif
+
+
+/* Exercise various 2^n values, with various exponents and positive and
+   negative.  */
+void
+check_onebit (void)
+{
+  static const int bit_table[] = {
+    0, 1, 2, 3,
+    GMP_NUMB_BITS - 2, GMP_NUMB_BITS - 1,
+    GMP_NUMB_BITS,
+    GMP_NUMB_BITS + 1, GMP_NUMB_BITS + 2,
+    2 * GMP_NUMB_BITS - 2, 2 * GMP_NUMB_BITS - 1,
+    2 * GMP_NUMB_BITS,
+    2 * GMP_NUMB_BITS + 1, 2 * GMP_NUMB_BITS + 2,
+    3 * GMP_NUMB_BITS - 2, 3 * GMP_NUMB_BITS - 1,
+    3 * GMP_NUMB_BITS,
+    3 * GMP_NUMB_BITS + 1, 3 * GMP_NUMB_BITS + 2,
+    4 * GMP_NUMB_BITS - 2, 4 * GMP_NUMB_BITS - 1,
+    4 * GMP_NUMB_BITS,
+    4 * GMP_NUMB_BITS + 1, 4 * GMP_NUMB_BITS + 2,
+    5 * GMP_NUMB_BITS - 2, 5 * GMP_NUMB_BITS - 1,
+    5 * GMP_NUMB_BITS,
+    5 * GMP_NUMB_BITS + 1, 5 * GMP_NUMB_BITS + 2,
+    6 * GMP_NUMB_BITS - 2, 6 * GMP_NUMB_BITS - 1,
+    6 * GMP_NUMB_BITS,
+    6 * GMP_NUMB_BITS + 1, 6 * GMP_NUMB_BITS + 2,
+  };
+  static const int exp_table[] = {
+    0, -100, -10, -1, 1, 10, 100,
+  };
+
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+  int     limit = 127;  /* vax fp numbers have limited range */
+#else
+  int     limit = 511;
+#endif
+
+  int        bit_i, exp_i, i;
+  double     got, want;
+  mp_size_t  nsize, sign;
+  long       bit, exp, want_bit;
+  mp_limb_t  np[20];
+
+  for (bit_i = 0; bit_i < numberof (bit_table); bit_i++)
+    {
+      bit = bit_table[bit_i];
+
+      nsize = BITS_TO_LIMBS (bit+1);
+      refmpn_zero (np, nsize);
+      np[bit/GMP_NUMB_BITS] = CNST_LIMB(1) << (bit % GMP_NUMB_BITS);
+
+      for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
+        {
+          exp = exp_table[exp_i];
+
+          want_bit = bit + exp;
+          if (want_bit >= limit || want_bit <= -limit)
+            continue;
+
+          want = 1.0;
+          for (i = 0; i < want_bit; i++)
+            want *= 2.0;
+          for (i = 0; i > want_bit; i--)
+            want *= 0.5;
+
+          for (sign = 0; sign >= -1; sign--, want = -want)
+            {
+              got = mpn_get_d (np, nsize, sign, exp);
+              if (got != want)
+                {
+                  printf    ("mpn_get_d wrong on 2^n\n");
+                  printf    ("   bit      %ld\n", bit);
+                  printf    ("   exp      %ld\n", exp);
+                  printf    ("   want_bit %ld\n", want_bit);
+                  printf    ("   sign     %ld\n", (long) sign);
+                  mpn_trace ("   n        ", np, nsize);
+                  printf    ("   nsize    %ld\n", (long) nsize);
+                  d_trace   ("   want     ", want);
+                  d_trace   ("   got      ", got);
+                  abort();
+                }
+            }
+        }
+    }
+}
+
+
+/* Exercise values 2^n+1, while such a value fits the mantissa of a double. */
+void
+check_twobit (void)
+{
+  int        i, mant_bits;
+  double     got, want;
+  mp_size_t  nsize, sign;
+  mp_ptr     np;
+
+  mant_bits = tests_dbl_mant_bits ();
+  if (mant_bits == 0)
+    return;
+
+  np = refmpn_malloc_limbs (BITS_TO_LIMBS (mant_bits));
+  want = 3.0;
+  for (i = 1; i < mant_bits; i++)
+    {
+      nsize = BITS_TO_LIMBS (i+1);
+      refmpn_zero (np, nsize);
+      np[i/GMP_NUMB_BITS] = CNST_LIMB(1) << (i % GMP_NUMB_BITS);
+      np[0] |= 1;
+
+      for (sign = 0; sign >= -1; sign--)
+        {
+          got = mpn_get_d (np, nsize, sign, 0);
+          if (got != want)
+            {
+              printf    ("mpn_get_d wrong on 2^%d + 1\n", i);
+              printf    ("   sign     %ld\n", (long) sign);
+              mpn_trace ("   n        ", np, nsize);
+              printf    ("   nsize    %ld\n", (long) nsize);
+              d_trace   ("   want     ", want);
+              d_trace   ("   got      ", got);
+              abort();
+            }
+          want = -want;
+        }
+
+      want = 2.0 * want - 1.0;
+    }
+
+  free (np);
+}
+
+
+/* Expect large negative exponents to underflow to 0.0.
+   Some systems might have hardware traps for such an underflow (though
+   usually it's not the default), so watch out for SIGFPE. */
+void
+check_underflow (void)
+{
+  static const long exp_table[] = {
+    -999999L, LONG_MIN,
+  };
+  static const mp_limb_t  np[1] = { 1 };
+
+  static long exp;
+  mp_size_t  nsize, sign;
+  double     got;
+  int        exp_i;
+
+  nsize = numberof (np);
+
+  if (tests_setjmp_sigfpe() == 0)
+    {
+      for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
+        {
+          exp = exp_table[exp_i];
+
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (np, nsize, sign, exp);
+              if (got != 0.0)
+                {
+                  printf  ("mpn_get_d wrong, didn't get 0.0 on underflow\n");
+                  printf  ("  nsize    %ld\n", (long) nsize);
+                  printf  ("  exp      %ld\n", exp);
+                  printf  ("  sign     %ld\n", (long) sign);
+                  d_trace ("  got      ", got);
+                  abort ();
+                }
+            }
+        }
+    }
+  else
+    {
+      printf ("Warning, underflow to zero tests skipped due to SIGFPE (exp=%ld)\n", exp);
+    }
+  tests_sigfpe_done ();
+}
+
+
+/* Expect large values to result in +/-inf, on IEEE systems. */
+void
+check_inf (void)
+{
+  static const long exp_table[] = {
+    999999L, LONG_MAX,
+  };
+  static const mp_limb_t  np[4] = { 1, 1, 1, 1 };
+  long       exp;
+  mp_size_t  nsize, sign, got_sign;
+  double     got;
+  int        exp_i;
+
+  if (! _GMP_IEEE_FLOATS)
+    return;
+
+  for (nsize = 1; nsize <= numberof (np); nsize++)
+    {
+      for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
+        {
+          exp = exp_table[exp_i];
+
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (np, nsize, sign, exp);
+              got_sign = (got >= 0 ? 0 : -1);
+              if (! tests_isinf (got))
+                {
+                  printf  ("mpn_get_d wrong, didn't get infinity\n");
+                bad:
+                  printf  ("  nsize    %ld\n", (long) nsize);
+                  printf  ("  exp      %ld\n", exp);
+                  printf  ("  sign     %ld\n", (long) sign);
+                  d_trace ("  got      ", got);
+                  printf  ("  got sign %ld\n", (long) got_sign);
+                  abort ();
+                }
+              if (got_sign != sign)
+                {
+                  printf  ("mpn_get_d wrong sign on infinity\n");
+                  goto bad;
+                }
+            }
+        }
+    }
+}
+
+/* Check values 2^n approaching and into IEEE denorm range.
+   Some systems might not support denorms, or might have traps setup, so
+   watch out for SIGFPE.  */
+void
+check_ieee_denorm (void)
+{
+  static long exp;
+  mp_limb_t  n = 1;
+  long       i;
+  mp_size_t  sign;
+  double     want, got;
+
+  if (! _GMP_IEEE_FLOATS)
+    return;
+
+  if (tests_setjmp_sigfpe() == 0)
+    {
+      exp = -1020;
+      want = 1.0;
+      for (i = 0; i > exp; i--)
+        want *= 0.5;
+
+      for ( ; exp > -1500 && want != 0.0; exp--)
+        {
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
+              if (got != want)
+                {
+                  printf  ("mpn_get_d wrong on denorm\n");
+                  printf  ("  n=1\n");
+                  printf  ("  exp   %ld\n", exp);
+                  printf  ("  sign  %ld\n", (long) sign);
+                  d_trace ("  got   ", got);
+                  d_trace ("  want  ", want);
+                  abort ();
+                }
+              want = -want;
+            }
+          want *= 0.5;
+          FORCE_DOUBLE (want);
+        }
+    }
+  else
+    {
+      printf ("Warning, IEEE denorm tests skipped due to SIGFPE (exp=%ld)\n", exp);
+    }
+  tests_sigfpe_done ();
+}
+
+
+/* Check values 2^n approaching exponent overflow.
+   Some systems might trap on overflow, so watch out for SIGFPE.  */
+void
+check_ieee_overflow (void)
+{
+  static long exp;
+  mp_limb_t  n = 1;
+  long       i;
+  mp_size_t  sign;
+  double     want, got;
+
+  if (! _GMP_IEEE_FLOATS)
+    return;
+
+  if (tests_setjmp_sigfpe() == 0)
+    {
+      exp = 1010;
+      want = 1.0;
+      for (i = 0; i < exp; i++)
+        want *= 2.0;
+
+      for ( ; exp < 1050; exp++)
+        {
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
+              if (got != want)
+                {
+                  printf  ("mpn_get_d wrong on overflow\n");
+                  printf  ("  n=1\n");
+                  printf  ("  exp   %ld\n", exp);
+                  printf  ("  sign  %ld\n", (long) sign);
+                  d_trace ("  got   ", got);
+                  d_trace ("  want  ", want);
+                  abort ();
+                }
+              want = -want;
+            }
+          want *= 2.0;
+          FORCE_DOUBLE (want);
+        }
+    }
+  else
+    {
+      printf ("Warning, IEEE overflow tests skipped due to SIGFPE (exp=%ld)\n", exp);
+    }
+  tests_sigfpe_done ();
+}
+
+
+/* ARM gcc 2.95.4 was seen generating bad code for ulong->double
+   conversions, resulting in for instance 0x81c25113 incorrectly converted.
+   This test exercises that value, to see mpn_get_d has avoided the
+   problem.  */
+void
+check_0x81c25113 (void)
+{
+#if GMP_NUMB_BITS >= 32
+  double     want = 2176995603.0;
+  double     got;
+  mp_limb_t  np[4];
+  mp_size_t  nsize;
+  long       exp;
+
+  if (tests_dbl_mant_bits() < 32)
+    return;
+
+  for (nsize = 1; nsize <= numberof (np); nsize++)
+    {
+      refmpn_zero (np, nsize-1);
+      np[nsize-1] = CNST_LIMB(0x81c25113);
+      exp = - (nsize-1) * GMP_NUMB_BITS;
+      got = mpn_get_d (np, nsize, (mp_size_t) 0, exp);
+      if (got != want)
+        {
+          printf  ("mpn_get_d wrong on 2176995603 (0x81c25113)\n");
+          printf  ("  nsize  %ld\n", (long) nsize);
+          printf  ("  exp    %ld\n", exp);
+          d_trace ("  got    ", got);
+          d_trace ("  want   ", want);
+          abort ();
+        }
+    }
+#endif
+}
+
+
+void
+check_rand (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  int            rep, i;
+  unsigned long  mant_bits;
+  long           exp, exp_min, exp_max;
+  double         got, want, d;
+  mp_size_t      nalloc, nsize, sign;
+  mp_limb_t      nhigh_mask;
+  mp_ptr         np;
+
+  mant_bits = tests_dbl_mant_bits ();
+  if (mant_bits == 0)
+    return;
+
+  /* Allow for vax D format with exponent 127 to -128 only.
+     FIXME: Do something to probe for a valid exponent range.  */
+  exp_min = -100 - mant_bits;
+  exp_max =  100 - mant_bits;
+
+  /* space for mant_bits */
+  nalloc = BITS_TO_LIMBS (mant_bits);
+  np = refmpn_malloc_limbs (nalloc);
+  nhigh_mask = MP_LIMB_T_MAX
+    >> (GMP_NAIL_BITS + nalloc * GMP_NUMB_BITS - mant_bits);
+
+  for (rep = 0; rep < 200; rep++)
+    {
+      /* random exp_min to exp_max, inclusive */
+      exp = exp_min + (long) gmp_urandomm_ui (rands, exp_max - exp_min + 1);
+
+      /* mant_bits worth of random at np */
+      if (rep & 1)
+        mpn_random (np, nalloc);
+      else
+        mpn_random2 (np, nalloc);
+      nsize = nalloc;
+      np[nsize-1] &= nhigh_mask;
+      MPN_NORMALIZE (np, nsize);
+      if (nsize == 0)
+        continue;
+
+      sign = (mp_size_t) gmp_urandomb_ui (rands, 1L) - 1;
+
+      /* want = {np,nsize}, converting one bit at a time */
+      want = 0.0;
+      for (i = 0, d = 1.0; i < mant_bits; i++, d *= 2.0)
+        if (np[i/GMP_NUMB_BITS] & (CNST_LIMB(1) << (i%GMP_NUMB_BITS)))
+          want += d;
+      if (sign < 0)
+        want = -want;
+
+      /* want = want * 2^exp */
+      for (i = 0; i < exp; i++)
+        want *= 2.0;
+      for (i = 0; i > exp; i--)
+        want *= 0.5;
+
+      got = mpn_get_d (np, nsize, sign, exp);
+
+      if (got != want)
+        {
+          printf    ("mpn_get_d wrong on random data\n");
+          printf    ("   sign     %ld\n", (long) sign);
+          mpn_trace ("   n        ", np, nsize);
+          printf    ("   nsize    %ld\n", (long) nsize);
+          printf    ("   exp      %ld\n", exp);
+          d_trace   ("   want     ", want);
+          d_trace   ("   got      ", got);
+          abort();
+        }
+    }
+
+  free (np);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_onebit ();
+  check_twobit ();
+  check_inf ();
+  check_underflow ();
+  check_ieee_denorm ();
+  check_ieee_overflow ();
+  check_0x81c25113 ();
+#if ! (defined (__vax) || defined (__vax__))
+  check_rand ();
+#endif
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-hgcd.c b/tests/mpn/t-hgcd.c
new file mode 100644
index 0000000..07f83e9
--- /dev/null
+++ b/tests/mpn/t-hgcd.c
@@ -0,0 +1,406 @@
+/* Test mpn_hgcd.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static mp_size_t one_test (mpz_t, mpz_t, int);
+static void debug_mp (mpz_t, int);
+
+#define MIN_OPERAND_SIZE 2
+
+/* Fixed values, for regression testing of mpn_hgcd. */
+struct value { int res; const char *a; const char *b; };
+static const struct value hgcd_values[] = {
+#if GMP_NUMB_BITS == 32
+  { 5,
+    "0x1bddff867272a9296ac493c251d7f46f09a5591fe",
+    "0xb55930a2a68a916450a7de006031068c5ddb0e5c" },
+  { 4,
+    "0x2f0ece5b1ee9c15e132a01d55768dc13",
+    "0x1c6f4fd9873cdb24466e6d03e1cc66e7" },
+  { 3, "0x7FFFFC003FFFFFFFFFC5", "0x3FFFFE001FFFFFFFFFE3"},
+#endif
+  { -1, NULL, NULL }
+};
+
+struct hgcd_ref
+{
+  mpz_t m[2][2];
+};
+
+static void hgcd_ref_init (struct hgcd_ref *);
+static void hgcd_ref_clear (struct hgcd_ref *);
+static int hgcd_ref (struct hgcd_ref *, mpz_t, mpz_t);
+static int hgcd_ref_equal (const struct hgcd_matrix *, const struct hgcd_ref *);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, temp1, temp2;
+  int i, j, chain_len;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (temp1);
+  mpz_init (temp2);
+
+  for (i = 0; hgcd_values[i].res >= 0; i++)
+    {
+      mp_size_t res;
+
+      mpz_set_str (op1, hgcd_values[i].a, 0);
+      mpz_set_str (op2, hgcd_values[i].b, 0);
+
+      res = one_test (op1, op2, -1-i);
+      if (res != hgcd_values[i].res)
+	{
+	  fprintf (stderr, "ERROR in test %d\n", -1-i);
+	  fprintf (stderr, "Bad return code from hgcd\n");
+	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+	  fprintf (stderr, "expected: %d\n", hgcd_values[i].res);
+	  fprintf (stderr, "hgcd:     %d\n", (int) res);
+	  abort ();
+	}
+    }
+
+  for (i = 0; i < 15; i++)
+    {
+      /* Generate plain operands with unknown gcd.  These types of operands
+	 have proven to trigger certain bugs in development versions of the
+	 gcd code. */
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+
+      /* Generate a division chain backwards, allowing otherwise
+	 unlikely huge quotients.  */
+
+      mpz_set_ui (op1, 0);
+      mpz_urandomb (bs, rands, 32);
+      mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs));
+      mpz_add_ui (op2, op2, 1);
+
+#if 0
+      chain_len = 1000000;
+#else
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
+#endif
+
+      for (j = 0; j < chain_len; j++)
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op2, temp2);
+	  mpz_add (op1, op1, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
+	    break;
+
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op1, temp2);
+	  mpz_add (op2, op2, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
+	    break;
+	}
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (temp1);
+  mpz_clear (temp2);
+
+  tests_end ();
+  exit (0);
+}
+
+static void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
+
+static int
+mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize);
+
+static mp_size_t
+one_test (mpz_t a, mpz_t b, int i)
+{
+  struct hgcd_matrix hgcd;
+  struct hgcd_ref ref;
+
+  mpz_t ref_r0;
+  mpz_t ref_r1;
+  mpz_t hgcd_r0;
+  mpz_t hgcd_r1;
+
+  mp_size_t res[2];
+  mp_size_t asize;
+  mp_size_t bsize;
+
+  mp_size_t hgcd_init_scratch;
+  mp_size_t hgcd_scratch;
+
+  mp_ptr hgcd_init_tp;
+  mp_ptr hgcd_tp;
+
+  asize = a->_mp_size;
+  bsize = b->_mp_size;
+
+  ASSERT (asize >= bsize);
+
+  hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
+  hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch);
+  mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
+
+  hgcd_scratch = mpn_hgcd_itch (asize);
+  hgcd_tp = refmpn_malloc_limbs (hgcd_scratch);
+
+#if 0
+  fprintf (stderr,
+	   "one_test: i = %d asize = %d, bsize = %d\n",
+	   i, a->_mp_size, b->_mp_size);
+
+  gmp_fprintf (stderr,
+	       "one_test: i = %d\n"
+	       "  a = %Zx\n"
+	       "  b = %Zx\n",
+	       i, a, b);
+#endif
+  hgcd_ref_init (&ref);
+
+  mpz_init_set (ref_r0, a);
+  mpz_init_set (ref_r1, b);
+  res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
+
+  mpz_init_set (hgcd_r0, a);
+  mpz_init_set (hgcd_r1, b);
+  if (bsize < asize)
+    {
+      _mpz_realloc (hgcd_r1, asize);
+      MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
+    }
+  res[1] = mpn_hgcd (hgcd_r0->_mp_d,
+		     hgcd_r1->_mp_d,
+		     asize,
+		     &hgcd, hgcd_tp);
+
+  if (res[0] != res[1])
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "Different return value from hgcd and hgcd_ref\n");
+      fprintf (stderr, "op1=");                 debug_mp (a, -16);
+      fprintf (stderr, "op2=");                 debug_mp (b, -16);
+      fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
+      fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]);
+      abort ();
+    }
+  if (res[0] > 0)
+    {
+      if (!hgcd_ref_equal (&hgcd, &ref)
+	  || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1])
+	  || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1]))
+	{
+	  fprintf (stderr, "ERROR in test %d\n", i);
+	  fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n");
+	  fprintf (stderr, "op1=");                 debug_mp (a, -16);
+	  fprintf (stderr, "op2=");                 debug_mp (b, -16);
+	  abort ();
+	}
+    }
+
+  refmpn_free_limbs (hgcd_init_tp);
+  refmpn_free_limbs (hgcd_tp);
+  hgcd_ref_clear (&ref);
+  mpz_clear (ref_r0);
+  mpz_clear (ref_r1);
+  mpz_clear (hgcd_r0);
+  mpz_clear (hgcd_r1);
+
+  return res[0];
+}
+
+static void
+hgcd_ref_init (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_init (hgcd->m[i][j]);
+    }
+}
+
+static void
+hgcd_ref_clear (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_clear (hgcd->m[i][j]);
+    }
+}
+
+
+static int
+sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
+{
+  mpz_fdiv_qr (q, r, a, b);
+  if (mpz_size (r) <= s)
+    {
+      mpz_add (r, r, b);
+      mpz_sub_ui (q, q, 1);
+    }
+
+  return (mpz_sgn (q) > 0);
+}
+
+static int
+hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
+{
+  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
+  mp_size_t s = n/2 + 1;
+  mp_size_t asize;
+  mp_size_t bsize;
+  mpz_t q;
+  int res;
+
+  if (mpz_size (a) <= s || mpz_size (b) <= s)
+    return 0;
+
+  res = mpz_cmp (a, b);
+  if (res < 0)
+    {
+      mpz_sub (b, b, a);
+      if (mpz_size (b) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
+      mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else if (res > 0)
+    {
+      mpz_sub (a, a, b);
+      if (mpz_size (a) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
+      mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else
+    return 0;
+
+  mpz_init (q);
+
+  for (;;)
+    {
+      ASSERT (mpz_size (a) > s);
+      ASSERT (mpz_size (b) > s);
+
+      if (mpz_cmp (a, b) > 0)
+	{
+	  if (!sdiv_qr (q, a, s, a, b))
+	    break;
+	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
+	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
+	}
+      else
+	{
+	  if (!sdiv_qr (q, b, s, b, a))
+	    break;
+	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
+	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
+	}
+    }
+
+  mpz_clear (q);
+
+  asize = mpz_size (a);
+  bsize = mpz_size (b);
+  return MAX (asize, bsize);
+}
+
+static int
+mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize)
+{
+  mp_srcptr ap = a->_mp_d;
+  mp_size_t asize = a->_mp_size;
+
+  MPN_NORMALIZE (bp, bsize);
+  return asize == bsize && mpn_cmp (ap, bp, asize) == 0;
+}
+
+static int
+hgcd_ref_equal (const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref)
+{
+  unsigned i;
+
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+
+      for (j = 0; j<2; j++)
+	if (!mpz_mpn_equal (ref->m[i][j], hgcd->p[i][j], hgcd->n))
+	  return 0;
+    }
+
+  return 1;
+}
diff --git a/tests/mpn/t-hgcd_appr.c b/tests/mpn/t-hgcd_appr.c
new file mode 100644
index 0000000..f9e2ea8
--- /dev/null
+++ b/tests/mpn/t-hgcd_appr.c
@@ -0,0 +1,563 @@
+/* Test mpn_hgcd_appr.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004, 2011 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static mp_size_t one_test (mpz_t, mpz_t, int);
+static void debug_mp (mpz_t, int);
+
+#define MIN_OPERAND_SIZE 2
+
+struct hgcd_ref
+{
+  mpz_t m[2][2];
+};
+
+static void hgcd_ref_init (struct hgcd_ref *hgcd);
+static void hgcd_ref_clear (struct hgcd_ref *hgcd);
+static int hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b);
+static int hgcd_ref_equal (const struct hgcd_ref *, const struct hgcd_ref *);
+static int hgcd_appr_valid_p (mpz_t, mpz_t, mp_size_t, struct hgcd_ref *,
+			      mpz_t, mpz_t, mp_size_t, struct hgcd_matrix *);
+
+static int verbose_flag = 0;
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, temp1, temp2;
+  int i, j, chain_len;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  if (argc > 1)
+    {
+      if (strcmp (argv[1], "-v") == 0)
+	verbose_flag = 1;
+      else
+	{
+	  fprintf (stderr, "Invalid argument.\n");
+	  return 1;
+	}
+    }
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (temp1);
+  mpz_init (temp2);
+
+  for (i = 0; i < 15; i++)
+    {
+      /* Generate plain operands with unknown gcd.  These types of operands
+	 have proven to trigger certain bugs in development versions of the
+	 gcd code. */
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_urandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_urandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+
+      /* Generate a division chain backwards, allowing otherwise
+	 unlikely huge quotients.  */
+
+      mpz_set_ui (op1, 0);
+      mpz_urandomb (bs, rands, 32);
+      mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs));
+      mpz_add_ui (op2, op2, 1);
+
+#if 0
+      chain_len = 1000000;
+#else
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
+#endif
+
+      for (j = 0; j < chain_len; j++)
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op2, temp2);
+	  mpz_add (op1, op1, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
+	    break;
+
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op1, temp2);
+	  mpz_add (op2, op2, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
+	    break;
+	}
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (temp1);
+  mpz_clear (temp2);
+
+  tests_end ();
+  exit (0);
+}
+
+static void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
+
+static mp_size_t
+one_test (mpz_t a, mpz_t b, int i)
+{
+  struct hgcd_matrix hgcd;
+  struct hgcd_ref ref;
+
+  mpz_t ref_r0;
+  mpz_t ref_r1;
+  mpz_t hgcd_r0;
+  mpz_t hgcd_r1;
+
+  int res[2];
+  mp_size_t asize;
+  mp_size_t bsize;
+
+  mp_size_t hgcd_init_scratch;
+  mp_size_t hgcd_scratch;
+
+  mp_ptr hgcd_init_tp;
+  mp_ptr hgcd_tp;
+  mp_limb_t marker[4];
+
+  asize = a->_mp_size;
+  bsize = b->_mp_size;
+
+  ASSERT (asize >= bsize);
+
+  hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
+  hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch + 2) + 1;
+  mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
+
+  hgcd_scratch = mpn_hgcd_appr_itch (asize);
+  hgcd_tp = refmpn_malloc_limbs (hgcd_scratch + 2) + 1;
+
+  mpn_random (marker, 4);
+
+  hgcd_init_tp[-1] = marker[0];
+  hgcd_init_tp[hgcd_init_scratch] = marker[1];
+  hgcd_tp[-1] = marker[2];
+  hgcd_tp[hgcd_scratch] = marker[3];
+
+#if 0
+  fprintf (stderr,
+	   "one_test: i = %d asize = %d, bsize = %d\n",
+	   i, a->_mp_size, b->_mp_size);
+
+  gmp_fprintf (stderr,
+	       "one_test: i = %d\n"
+	       "  a = %Zx\n"
+	       "  b = %Zx\n",
+	       i, a, b);
+#endif
+  hgcd_ref_init (&ref);
+
+  mpz_init_set (ref_r0, a);
+  mpz_init_set (ref_r1, b);
+  res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
+
+  mpz_init_set (hgcd_r0, a);
+  mpz_init_set (hgcd_r1, b);
+  if (bsize < asize)
+    {
+      _mpz_realloc (hgcd_r1, asize);
+      MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
+    }
+  res[1] = mpn_hgcd_appr (hgcd_r0->_mp_d,
+			  hgcd_r1->_mp_d,
+			  asize,
+			  &hgcd, hgcd_tp);
+
+  if (hgcd_init_tp[-1] != marker[0]
+      || hgcd_init_tp[hgcd_init_scratch] != marker[1]
+      || hgcd_tp[-1] != marker[2]
+      || hgcd_tp[hgcd_scratch] != marker[3])
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "scratch space overwritten!\n");
+
+      if (hgcd_init_tp[-1] != marker[0])
+	gmp_fprintf (stderr,
+		     "before init_tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_init_tp[-1], marker[0]);
+      if (hgcd_init_tp[hgcd_init_scratch] != marker[1])
+	gmp_fprintf (stderr,
+		     "after init_tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_init_tp[hgcd_init_scratch], marker[1]);
+      if (hgcd_tp[-1] != marker[2])
+	gmp_fprintf (stderr,
+		     "before tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_tp[-1], marker[2]);
+      if (hgcd_tp[hgcd_scratch] != marker[3])
+	gmp_fprintf (stderr,
+		     "after tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_tp[hgcd_scratch], marker[3]);
+
+      abort ();
+    }
+
+  if (!hgcd_appr_valid_p (a, b, res[0], &ref, ref_r0, ref_r1,
+			  res[1], &hgcd))
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "Invalid results for hgcd and hgcd_ref\n");
+      fprintf (stderr, "op1=");                 debug_mp (a, -16);
+      fprintf (stderr, "op2=");                 debug_mp (b, -16);
+      fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
+      fprintf (stderr, "mpn_hgcd_appr: %ld\n", (long) res[1]);
+      abort ();
+    }
+
+  refmpn_free_limbs (hgcd_init_tp - 1);
+  refmpn_free_limbs (hgcd_tp - 1);
+  hgcd_ref_clear (&ref);
+  mpz_clear (ref_r0);
+  mpz_clear (ref_r1);
+  mpz_clear (hgcd_r0);
+  mpz_clear (hgcd_r1);
+
+  return res[0];
+}
+
+static void
+hgcd_ref_init (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_init (hgcd->m[i][j]);
+    }
+}
+
+static void
+hgcd_ref_clear (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_clear (hgcd->m[i][j]);
+    }
+}
+
+static int
+sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
+{
+  mpz_fdiv_qr (q, r, a, b);
+  if (mpz_size (r) <= s)
+    {
+      mpz_add (r, r, b);
+      mpz_sub_ui (q, q, 1);
+    }
+
+  return (mpz_sgn (q) > 0);
+}
+
+static int
+hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
+{
+  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
+  mp_size_t s = n/2 + 1;
+  mpz_t q;
+  int res;
+
+  if (mpz_size (a) <= s || mpz_size (b) <= s)
+    return 0;
+
+  res = mpz_cmp (a, b);
+  if (res < 0)
+    {
+      mpz_sub (b, b, a);
+      if (mpz_size (b) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
+      mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else if (res > 0)
+    {
+      mpz_sub (a, a, b);
+      if (mpz_size (a) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
+      mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else
+    return 0;
+
+  mpz_init (q);
+
+  for (;;)
+    {
+      ASSERT (mpz_size (a) > s);
+      ASSERT (mpz_size (b) > s);
+
+      if (mpz_cmp (a, b) > 0)
+	{
+	  if (!sdiv_qr (q, a, s, a, b))
+	    break;
+	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
+	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
+	}
+      else
+	{
+	  if (!sdiv_qr (q, b, s, b, a))
+	    break;
+	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
+	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
+	}
+    }
+
+  mpz_clear (q);
+
+  return 1;
+}
+
+static int
+hgcd_ref_equal (const struct hgcd_ref *A, const struct hgcd_ref *B)
+{
+  unsigned i;
+
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+
+      for (j = 0; j<2; j++)
+	if (mpz_cmp (A->m[i][j], B->m[i][j]) != 0)
+	  return 0;
+    }
+
+  return 1;
+}
+
+static int
+hgcd_appr_valid_p (mpz_t a, mpz_t b, mp_size_t res0,
+		   struct hgcd_ref *ref, mpz_t ref_r0, mpz_t ref_r1,
+		   mp_size_t res1, struct hgcd_matrix *hgcd)
+{
+  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
+  mp_size_t s = n/2 + 1;
+
+  mp_bitcnt_t dbits, abits, margin;
+  mpz_t appr_r0, appr_r1, t, q;
+  struct hgcd_ref appr;
+
+  if (!res0)
+    {
+      if (!res1)
+	return 1;
+
+      fprintf (stderr, "mpn_hgcd_appr returned 1 when no reduction possible.\n");
+      return 0;
+    }
+
+  /* NOTE: No *_clear calls on error return, since we're going to
+     abort anyway. */
+  mpz_init (t);
+  mpz_init (q);
+  hgcd_ref_init (&appr);
+  mpz_init (appr_r0);
+  mpz_init (appr_r1);
+
+  if (mpz_size (ref_r0) <= s)
+    {
+      fprintf (stderr, "ref_r0 too small!!!: "); debug_mp (ref_r0, 16);
+      return 0;
+    }
+  if (mpz_size (ref_r1) <= s)
+    {
+      fprintf (stderr, "ref_r1 too small!!!: "); debug_mp (ref_r1, 16);
+      return 0;
+    }
+
+  mpz_sub (t, ref_r0, ref_r1);
+  dbits = mpz_sizeinbase (t, 2);
+  if (dbits > s*GMP_NUMB_BITS)
+    {
+      fprintf (stderr, "ref |r0 - r1| too large!!!: "); debug_mp (t, 16);
+      return 0;
+    }
+
+  if (!res1)
+    {
+      mpz_set (appr_r0, a);
+      mpz_set (appr_r1, b);
+    }
+  else
+    {
+      unsigned i;
+
+      for (i = 0; i<2; i++)
+	{
+	  unsigned j;
+
+	  for (j = 0; j<2; j++)
+	    {
+	      mp_size_t mn = hgcd->n;
+	      MPN_NORMALIZE (hgcd->p[i][j], mn);
+	      mpz_realloc (appr.m[i][j], mn);
+	      MPN_COPY (PTR (appr.m[i][j]), hgcd->p[i][j], mn);
+	      SIZ (appr.m[i][j]) = mn;
+	    }
+	}
+      mpz_mul (appr_r0, appr.m[1][1], a);
+      mpz_mul (t, appr.m[0][1], b);
+      mpz_sub (appr_r0, appr_r0, t);
+      if (mpz_sgn (appr_r0) <= 0
+	  || mpz_size (appr_r0) <= s)
+	{
+	  fprintf (stderr, "appr_r0 too small: "); debug_mp (appr_r0, 16);
+	  return 0;
+	}
+
+      mpz_mul (appr_r1, appr.m[1][0], a);
+      mpz_mul (t, appr.m[0][0], b);
+      mpz_sub (appr_r1, t, appr_r1);
+      if (mpz_sgn (appr_r1) <= 0
+	  || mpz_size (appr_r1) <= s)
+	{
+	  fprintf (stderr, "appr_r1 too small: "); debug_mp (appr_r1, 16);
+	  return 0;
+	}
+    }
+
+  mpz_sub (t, appr_r0, appr_r1);
+  abits = mpz_sizeinbase (t, 2);
+  if (abits < dbits)
+    {
+      fprintf (stderr, "|r0 - r1| too small: "); debug_mp (t, 16);
+      return 0;
+    }
+
+  /* We lose one bit each time we discard the least significant limbs.
+     For the lehmer code, that can happen at most s * (GMP_NUMB_BITS)
+     / (GMP_NUMB_BITS - 1) times. For the dc code, we lose an entire
+     limb (or more?) for each level of recursion. */
+
+  margin = (n/2+1) * GMP_NUMB_BITS / (GMP_NUMB_BITS - 1);
+  {
+    mp_size_t rn;
+    for (rn = n; ABOVE_THRESHOLD (rn, HGCD_APPR_THRESHOLD); rn = (rn + 1)/2)
+      margin += GMP_NUMB_BITS;
+  }
+
+  if (verbose_flag && abits > dbits)
+    fprintf (stderr, "n = %u: sbits = %u: ref #(r0-r1): %u, appr #(r0-r1): %u excess: %d, margin: %u\n",
+	     (unsigned) n, (unsigned) s*GMP_NUMB_BITS,
+	     (unsigned) dbits, (unsigned) abits,
+	     (int) (abits - s * GMP_NUMB_BITS), (unsigned) margin);
+
+  if (abits > s*GMP_NUMB_BITS + margin)
+    {
+      fprintf (stderr, "appr |r0 - r1| much larger than minimal (by %u bits, margin = %u bits)\n",
+	       (unsigned) (abits - s*GMP_NUMB_BITS), (unsigned) margin);
+      return 0;
+    }
+
+  while (mpz_cmp (appr_r0, ref_r0) > 0 || mpz_cmp (appr_r1, ref_r1) > 0)
+    {
+      ASSERT (mpz_size (appr_r0) > s);
+      ASSERT (mpz_size (appr_r1) > s);
+
+      if (mpz_cmp (appr_r0, appr_r1) > 0)
+	{
+	  if (!sdiv_qr (q, appr_r0, s, appr_r0, appr_r1))
+	    break;
+	  mpz_addmul (appr.m[0][1], q, appr.m[0][0]);
+	  mpz_addmul (appr.m[1][1], q, appr.m[1][0]);
+	}
+      else
+	{
+	  if (!sdiv_qr (q, appr_r1, s, appr_r1, appr_r0))
+	    break;
+	  mpz_addmul (appr.m[0][0], q, appr.m[0][1]);
+	  mpz_addmul (appr.m[1][0], q, appr.m[1][1]);
+	}
+    }
+
+  if (mpz_cmp (appr_r0, ref_r0) != 0
+      || mpz_cmp (appr_r1, ref_r1) != 0
+      || !hgcd_ref_equal (ref, &appr))
+    {
+      fprintf (stderr, "appr_r0: "); debug_mp (appr_r0, 16);
+      fprintf (stderr, "ref_r0: "); debug_mp (ref_r0, 16);
+
+      fprintf (stderr, "appr_r1: "); debug_mp (appr_r1, 16);
+      fprintf (stderr, "ref_r1: "); debug_mp (ref_r1, 16);
+
+      return 0;
+    }
+  mpz_clear (t);
+  mpz_clear (q);
+  hgcd_ref_clear (&appr);
+  mpz_clear (appr_r0);
+  mpz_clear (appr_r1);
+
+  return 1;
+}
diff --git a/tests/mpn/t-instrument.c b/tests/mpn/t-instrument.c
new file mode 100644
index 0000000..694e171
--- /dev/null
+++ b/tests/mpn/t-instrument.c
@@ -0,0 +1,415 @@
+/* Test assembler support for --enable-profiling=instrument.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+#if WANT_PROFILING_INSTRUMENT
+
+/* This program exercises each mpn routine that might be implemented in
+   assembler.  It ensures the __cyg_profile_func_enter and exit calls have
+   come out right, and that in the x86 code "ret_internal" is correctly used
+   for PIC setups.  */
+
+
+/* Changes to enter_seen done by __cyg_profile_func_enter are essentially
+   unknown to the optimizer, so must use volatile.  */
+volatile int  enter_seen;
+
+/* Dummy used to stop various calls going dead. */
+unsigned long  notdead;
+
+const char     *name = "<none>";
+int  old_ncall;
+
+struct {
+  void  *this_fn;
+  void  *call_site;
+} call[100];
+int  ncall;
+
+
+void __cyg_profile_func_enter (void *, void *)
+  __attribute__ ((no_instrument_function));
+
+void
+__cyg_profile_func_enter (void *this_fn, void *call_site)
+{
+#if 0
+  printf ("%24s %p %p\n", name, this_fn, call_site);
+#endif
+  ASSERT_ALWAYS (ncall >= 0);
+  ASSERT_ALWAYS (ncall <= numberof (call));
+
+  if (ncall >= numberof (call))
+    {
+      printf ("__cyg_profile_func_enter: oops, call stack full, from %s\n", name);
+      abort ();
+    }
+
+  enter_seen = 1;
+  call[ncall].this_fn = this_fn;
+  call[ncall].call_site = call_site;
+  ncall++;
+}
+
+void __cyg_profile_func_exit (void *, void *)
+  __attribute__ ((no_instrument_function));
+
+void
+__cyg_profile_func_exit  (void *this_fn, void *call_site)
+{
+  ASSERT_ALWAYS (ncall >= 0);
+  ASSERT_ALWAYS (ncall <= numberof (call));
+
+  if (ncall == 0)
+    {
+      printf ("__cyg_profile_func_exit: call stack empty, from %s\n", name);
+      abort ();
+    }
+
+  ncall--;
+  if (this_fn != call[ncall].this_fn || call_site != call[ncall].call_site)
+    {
+      printf ("__cyg_profile_func_exit: unbalanced this_fn/call_site from %s\n", name);
+      printf ("  this_fn got  %p\n", this_fn);
+      printf ("          want %p\n", call[ncall].this_fn);
+      printf ("  call_site got  %p\n", call_site);
+      printf ("            want %p\n", call[ncall].call_site);
+      abort ();
+    }
+}
+
+
+void
+pre (const char *str)
+{
+  name = str;
+  enter_seen = 0;
+  old_ncall = ncall;
+}
+
+void
+post (void)
+{
+  if (! enter_seen)
+    {
+      printf ("did not reach __cyg_profile_func_enter from %s\n", name);
+      abort ();
+    }
+
+  if (ncall != old_ncall)
+    {
+      printf ("unbalance enter/exit calls from %s\n", name);
+      printf ("  ncall     %d\n", ncall);
+      printf ("  old_ncall %d\n", old_ncall);
+      abort ();
+    }
+}
+
+void
+check (void)
+{
+  mp_limb_t  wp[100], xp[100], yp[100];
+  mp_size_t  size = 100;
+
+  refmpn_zero (xp, size);
+  refmpn_zero (yp, size);
+  refmpn_zero (wp, size);
+
+  pre ("mpn_add_n");
+  mpn_add_n (wp, xp, yp, size);
+  post ();
+
+#if HAVE_NATIVE_mpn_add_nc
+  pre ("mpn_add_nc");
+  mpn_add_nc (wp, xp, yp, size, CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_n
+  pre ("mpn_addlsh1_n");
+  mpn_addlsh1_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_and_n
+  pre ("mpn_and_n");
+  mpn_and_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_andn_n
+  pre ("mpn_andn_n");
+  mpn_andn_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_addmul_1");
+  mpn_addmul_1 (wp, xp, size, yp[0]);
+  post ();
+
+#if HAVE_NATIVE_mpn_addmul_1c
+  pre ("mpn_addmul_1c");
+  mpn_addmul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_com
+  pre ("mpn_com");
+  mpn_com (wp, xp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_copyd
+  pre ("mpn_copyd");
+  mpn_copyd (wp, xp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_copyi
+  pre ("mpn_copyi");
+  mpn_copyi (wp, xp, size);
+  post ();
+#endif
+
+  pre ("mpn_divexact_1");
+  mpn_divexact_1 (wp, xp, size, CNST_LIMB(123));
+  post ();
+
+  pre ("mpn_divexact_by3c");
+  mpn_divexact_by3c (wp, xp, size, CNST_LIMB(0));
+  post ();
+
+  pre ("mpn_divrem_1");
+  mpn_divrem_1 (wp, (mp_size_t) 0, xp, size, CNST_LIMB(123));
+  post ();
+
+#if HAVE_NATIVE_mpn_divrem_1c
+  pre ("mpn_divrem_1c");
+  mpn_divrem_1c (wp, (mp_size_t) 0, xp, size, CNST_LIMB(123), CNST_LIMB(122));
+  post ();
+#endif
+
+  pre ("mpn_gcd_1");
+  xp[0] |= 1;
+  notdead += (unsigned long) mpn_gcd_1 (xp, size, CNST_LIMB(123));
+  post ();
+
+  pre ("mpn_hamdist");
+  notdead += mpn_hamdist (xp, yp, size);
+  post ();
+
+#if HAVE_NATIVE_mpn_ior_n
+  pre ("mpn_ior_n");
+  mpn_ior_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_iorn_n
+  pre ("mpn_iorn_n");
+  mpn_iorn_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_lshift");
+  mpn_lshift (wp, xp, size, 1);
+  post ();
+
+  pre ("mpn_mod_1");
+  notdead += mpn_mod_1 (xp, size, CNST_LIMB(123));
+  post ();
+
+#if HAVE_NATIVE_mpn_mod_1c
+  pre ("mpn_mod_1c");
+  notdead += mpn_mod_1c (xp, size, CNST_LIMB(123), CNST_LIMB(122));
+  post ();
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+  pre ("mpn_mod_34lsub1");
+  notdead += mpn_mod_34lsub1 (xp, size);
+  post ();
+#endif
+
+  pre ("mpn_modexact_1_odd");
+  notdead += mpn_modexact_1_odd (xp, size, CNST_LIMB(123));
+  post ();
+
+  pre ("mpn_modexact_1c_odd");
+  notdead += mpn_modexact_1c_odd (xp, size, CNST_LIMB(123), CNST_LIMB(456));
+  post ();
+
+  pre ("mpn_mul_1");
+  mpn_mul_1 (wp, xp, size, yp[0]);
+  post ();
+
+#if HAVE_NATIVE_mpn_mul_1c
+  pre ("mpn_mul_1c");
+  mpn_mul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_mul_2
+  pre ("mpn_mul_2");
+  mpn_mul_2 (wp, xp, size-1, yp);
+  post ();
+#endif
+
+  pre ("mpn_mul_basecase");
+  mpn_mul_basecase (wp, xp, (mp_size_t) 3, yp, (mp_size_t) 3);
+  post ();
+
+#if HAVE_NATIVE_mpn_nand_n
+  pre ("mpn_nand_n");
+  mpn_nand_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_nior_n
+  pre ("mpn_nior_n");
+  mpn_nior_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_popcount");
+  notdead += mpn_popcount (xp, size);
+  post ();
+
+  pre ("mpn_preinv_mod_1");
+  notdead += mpn_preinv_mod_1 (xp, size, GMP_NUMB_MAX,
+                               refmpn_invert_limb (GMP_NUMB_MAX));
+  post ();
+
+#if USE_PREINV_DIVREM_1 || HAVE_NATIVE_mpn_preinv_divrem_1
+  pre ("mpn_preinv_divrem_1");
+  mpn_preinv_divrem_1 (wp, (mp_size_t) 0, xp, size, GMP_NUMB_MAX,
+                       refmpn_invert_limb (GMP_NUMB_MAX), 0);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_rsh1add_n
+  pre ("mpn_rsh1add_n");
+  mpn_rsh1add_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  pre ("mpn_rsh1sub_n");
+  mpn_rsh1sub_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_rshift");
+  mpn_rshift (wp, xp, size, 1);
+  post ();
+
+  pre ("mpn_sqr_basecase");
+  mpn_sqr_basecase (wp, xp, (mp_size_t) 3);
+  post ();
+
+  pre ("mpn_submul_1");
+  mpn_submul_1 (wp, xp, size, yp[0]);
+  post ();
+
+#if HAVE_NATIVE_mpn_submul_1c
+  pre ("mpn_submul_1c");
+  mpn_submul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
+  post ();
+#endif
+
+  pre ("mpn_sub_n");
+  mpn_sub_n (wp, xp, yp, size);
+  post ();
+
+#if HAVE_NATIVE_mpn_sub_nc
+  pre ("mpn_sub_nc");
+  mpn_sub_nc (wp, xp, yp, size, CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh1_n
+  pre ("mpn_sublsh1_n");
+  mpn_sublsh1_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_udiv_qrnnd
+  pre ("mpn_udiv_qrnnd");
+  mpn_udiv_qrnnd (&wp[0], CNST_LIMB(122), xp[0], CNST_LIMB(123));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_udiv_qrnnd_r
+  pre ("mpn_udiv_qrnnd_r");
+  mpn_udiv_qrnnd (CNST_LIMB(122), xp[0], CNST_LIMB(123), &wp[0]);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_umul_ppmm
+  pre ("mpn_umul_ppmm");
+  mpn_umul_ppmm (&wp[0], xp[0], yp[0]);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_umul_ppmm_r
+  pre ("mpn_umul_ppmm_r");
+  mpn_umul_ppmm_r (&wp[0], xp[0], yp[0]);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_xor_n
+  pre ("mpn_xor_n");
+  mpn_xor_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_xnor_n
+  pre ("mpn_xnor_n");
+  mpn_xnor_n (wp, xp, yp, size);
+  post ();
+#endif
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check ();
+
+  tests_end ();
+  exit (0);
+}
+
+
+#else /* ! WANT_PROFILING_INSTRUMENT */
+
+int
+main (void)
+{
+  exit (0);
+}
+
+#endif
diff --git a/tests/mpn/t-invert.c b/tests/mpn/t-invert.c
new file mode 100644
index 0000000..1493467
--- /dev/null
+++ b/tests/mpn/t-invert.c
@@ -0,0 +1,151 @@
+/* Test for mpn_invert function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 12
+#endif
+
+#ifndef COUNT
+#define COUNT 1000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N 1
+
+
+static int
+invert_valid (mp_srcptr ip, mp_srcptr dp, mp_size_t n)
+{
+  mp_ptr tp;
+  int cy;
+  TMP_DECL;
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (2*n);
+
+  refmpn_mul (tp, ip, n, dp, n);
+  cy  = refmpn_add_n (tp + n, tp + n, dp, n); /* This must not give a carry. */
+  cy -= refmpn_add (tp, tp, 2*n, dp, n); /* This must give a carry. */
+  TMP_FREE;
+
+  return (cy == -1);
+}
+
+/*
+  Check the result of the mpn_invert function in the library.
+*/
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ip, dp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  dp = TMP_ALLOC_LIMBS (MAX_N);
+  ip = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_invert_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t n;
+      mp_size_t itch;
+      mp_limb_t i_before, i_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+
+      mpn_random2 (dp, n);
+
+      mpn_random2 (ip-1, n + 2);
+      i_before = ip[-1];
+      i_after = ip[n];
+
+      itch = mpn_invert_itch (n);
+      ASSERT_ALWAYS (itch <= mpn_invert_itch (MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      dp[n-1] |= GMP_NUMB_HIGHBIT;
+      mpn_invert (ip, dp, n, scratch);
+      if (ip[-1] != i_before || ip[n] != i_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || ! invert_valid(ip, dp, n))
+	{
+	  printf ("ERROR in test %d, n = %d\n",
+		  test, (int) n);
+	  if (ip[-1] != i_before)
+	    {
+	      printf ("before ip:"); mpn_dump (ip -1, 1);
+	      printf ("keep:   "); mpn_dump (&i_before, 1);
+	    }
+	  if (ip[n] != i_after)
+	    {
+	      printf ("after ip:"); mpn_dump (ip + n, 1);
+	      printf ("keep:   "); mpn_dump (&i_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (dp, n);
+	  mpn_dump (ip, n);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-iord_u.c b/tests/mpn/t-iord_u.c
new file mode 100644
index 0000000..2b27713
--- /dev/null
+++ b/tests/mpn/t-iord_u.c
@@ -0,0 +1,220 @@
+/* Test MPN_INCR_U and MPN_DECR_U.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* The i386 MPN_INCR_U and MPN_DECR_U have special cases for "n" being a
+   compile-time constant 1, so that's exercised explicitly.  */
+
+
+#define M     GMP_NUMB_MAX
+#define SIZE  ((mp_size_t) 10)
+
+
+void
+check_one (const char *name, int i,
+           mp_srcptr src, mp_limb_t n,
+           mp_srcptr got, mp_srcptr want, mp_size_t size)
+{
+  if (! refmpn_equal_anynail (got, want, size))
+    {
+      printf ("Wrong at %s i=%d\n", name, i);
+      mpn_trace ("  src", src,  size);
+      mpn_trace ("    n", &n,   (mp_size_t) 1);
+      mpn_trace ("  got", got,  size);
+      mpn_trace (" want", want, size);
+      abort ();
+    }
+}
+
+
+void
+check_incr_data (void)
+{
+  static const struct {
+    mp_limb_t        n;
+    const mp_limb_t  src[SIZE];
+    const mp_limb_t  want[SIZE];
+  } data[] = {
+    { 1, { 0 },   { 1 } },
+    { 1, { 123 }, { 124 } },
+    { 2, { 0 },   { 2 } },
+    { 2, { 123 }, { 125 } },
+    { M, { 0 },   { M } },
+
+    { 1, { M, 0 },   { 0,   1 } },
+    { 1, { M, 123 }, { 0,   124 } },
+    { 2, { M, 0 },   { 1,   1 } },
+    { 2, { M, 123 }, { 1,   124 } },
+    { M, { M, 0 },   { M-1, 1 } },
+    { M, { M, 123 }, { M-1, 124 } },
+
+    { 1, { M, M, 0 },   { 0,   0, 1 } },
+    { 1, { M, M, 123 }, { 0,   0, 124 } },
+    { 2, { M, M, 0 },   { 1,   0, 1 } },
+    { 2, { M, M, 123 }, { 1,   0, 124 } },
+    { M, { M, M, 0 },   { M-1, 0, 1 } },
+    { M, { M, M, 123 }, { M-1, 0, 124 } },
+
+    { 1, { M, M, M, 0 },   { 0,   0, 0, 1 } },
+    { 1, { M, M, M, 123 }, { 0,   0, 0, 124 } },
+    { 2, { M, M, M, 0 },   { 1,   0, 0, 1 } },
+    { 2, { M, M, M, 123 }, { 1,   0, 0, 124 } },
+    { M, { M, M, M, 0 },   { M-1, 0, 0, 1 } },
+    { M, { M, M, M, 123 }, { M-1, 0, 0, 124 } },
+
+    { 1, { M, M, M, M, 0 },   { 0,   0, 0, 0, 1 } },
+    { 1, { M, M, M, M, 123 }, { 0,   0, 0, 0, 124 } },
+    { 2, { M, M, M, M, 0 },   { 1,   0, 0, 0, 1 } },
+    { 2, { M, M, M, M, 123 }, { 1,   0, 0, 0, 124 } },
+    { M, { M, M, M, M, 0 },   { M-1, 0, 0, 0, 1 } },
+    { M, { M, M, M, M, 123 }, { M-1, 0, 0, 0, 124
+#if defined (__hpux) && ! defined (__GNUC__)
+    /* Some versions (at least HP92453-01 B.11.11.23709.GP) of the
+       HP C compilers fail to zero-fill aggregates as the ISO C standard
+       requires (cf 6.5.7 Initialization).  Compensate here:  */
+				, 0, 0, 0, 0, 0
+#endif
+    } }
+  };
+
+  mp_limb_t  got[SIZE];
+  int   i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_copyi (got, data[i].src, SIZE);
+      MPN_INCR_U (got, SIZE, data[i].n);
+      check_one ("check_incr (general)", i,
+                 data[i].src, data[i].n,
+                 got, data[i].want, SIZE);
+
+      if (data[i].n == 1)
+        {
+          refmpn_copyi (got, data[i].src, SIZE);
+          MPN_INCR_U (got, SIZE, CNST_LIMB(1));
+          check_one ("check_incr (const 1)", i,
+                     data[i].src, data[i].n,
+                     got, data[i].want, SIZE);
+        }
+    }
+}
+
+void
+check_decr_data (void)
+{
+  static const struct {
+    mp_limb_t        n;
+    const mp_limb_t  src[SIZE];
+    const mp_limb_t  want[SIZE];
+  } data[] = {
+    { 1,   { 1 },   { 0   } },
+    { 1,   { 123 }, { 122 } },
+    { 1,   { M },   { M-1 } },
+    { 2,   { 2 },   { 0   } },
+    { 2,   { 123 }, { 121 } },
+    { M,   { M },   { 0   } },
+    { M-1, { M },   { 1   } },
+
+    { 1,   { 0,   1   }, { M,   0   } },
+    { 1,   { 0,   123 }, { M,   122 } },
+    { 1,   { 0,   M   }, { M,   M-1 } },
+    { 2,   { 0,   123 }, { M-1, 122 } },
+    { 2,   { 1,   123 }, { M,   122 } },
+    { M,   { 0,   123 }, { 1,   122 } },
+    { M,   { M-1, M   }, { M,   M-1 } },
+
+    { 1,   { 0,   0, 1   }, { M,   M, 0   } },
+    { 1,   { 0,   0, 123 }, { M,   M, 122 } },
+    { 1,   { 0,   0, M   }, { M,   M, M-1 } },
+    { 2,   { 0,   0, 123 }, { M-1, M, 122 } },
+    { 2,   { 1,   0, 123 }, { M,   M, 122 } },
+    { M,   { 0,   0, 123 }, { 1,   M, 122 } },
+    { M,   { M-1, 0, M   }, { M,   M, M-1 } },
+
+    { 1,   { 0,   0, 0, 1   }, { M,   M, M, 0   } },
+    { 1,   { 0,   0, 0, 123 }, { M,   M, M, 122 } },
+    { 1,   { 0,   0, 0, M   }, { M,   M, M, M-1 } },
+    { 2,   { 0,   0, 0, 123 }, { M-1, M, M, 122 } },
+    { 2,   { 1,   0, 0, 123 }, { M,   M, M, 122 } },
+    { M,   { 0,   0, 0, 123 }, { 1,   M, M, 122 } },
+    { M,   { M-1, 0, 0, M   }, { M,   M, M, M-1 } },
+
+    { 1,   { 0,   0, 0, 0, 1   }, { M,   M, M, M, 0   } },
+    { 1,   { 0,   0, 0, 0, 123 }, { M,   M, M, M, 122 } },
+    { 1,   { 0,   0, 0, 0, M   }, { M,   M, M, M, M-1 } },
+    { 2,   { 0,   0, 0, 0, 123 }, { M-1, M, M, M, 122 } },
+    { 2,   { 1,   0, 0, 0, 123 }, { M,   M, M, M, 122 } },
+    { M,   { 0,   0, 0, 0, 123 }, { 1,   M, M, M, 122 } },
+    { M,   { M-1, 0, 0, 0, M   }, { M,   M, M, M, M-1 } },
+
+    { 1,   { 0,   0, 0, 0, 0, 1   }, { M,   M, M, M, M, 0   } },
+    { 1,   { 0,   0, 0, 0, 0, 123 }, { M,   M, M, M, M, 122 } },
+    { 1,   { 0,   0, 0, 0, 0, M   }, { M,   M, M, M, M, M-1 } },
+    { 2,   { 0,   0, 0, 0, 0, 123 }, { M-1, M, M, M, M, 122 } },
+    { 2,   { 1,   0, 0, 0, 0, 123 }, { M,   M, M, M, M, 122 } },
+    { M,   { 0,   0, 0, 0, 0, 123 }, { 1,   M, M, M, M, 122 } },
+    { M,   { M-1, 0, 0, 0, 0, M   }, { M,   M, M, M, M, M-1
+#if defined (__hpux) && ! defined (__GNUC__)
+    /* For explanation of this garbage, see previous function.  */
+				       , 0, 0, 0, 0
+#endif
+    } }
+  };
+
+  mp_limb_t  got[SIZE];
+  int   i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_copyi (got, data[i].src, SIZE);
+      MPN_DECR_U (got, SIZE, data[i].n);
+      check_one ("check_decr_data", i,
+                 data[i].src, data[i].n,
+                 got, data[i].want, SIZE);
+
+      if (data[i].n == 1)
+        {
+          refmpn_copyi (got, data[i].src, SIZE);
+          MPN_DECR_U (got, SIZE, CNST_LIMB(1));
+          check_one ("check_decr (const 1)", i,
+                     data[i].src, data[i].n,
+                     got, data[i].want, SIZE);
+        }
+    }
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_incr_data ();
+  check_decr_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-matrix22.c b/tests/mpn/t-matrix22.c
new file mode 100644
index 0000000..1fa1e3f
--- /dev/null
+++ b/tests/mpn/t-matrix22.c
@@ -0,0 +1,206 @@
+/* Tests matrix22_mul.
+
+Copyright 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+struct matrix {
+  mp_size_t alloc;
+  mp_size_t n;
+  mp_ptr e00, e01, e10, e11;
+};
+
+static void
+matrix_init (struct matrix *M, mp_size_t n)
+{
+  mp_ptr p = refmpn_malloc_limbs (4*(n+1));
+  M->e00 = p; p += n+1;
+  M->e01 = p; p += n+1;
+  M->e10 = p; p += n+1;
+  M->e11 = p;
+  M->alloc = n + 1;
+  M->n = 0;
+}
+
+static void
+matrix_clear (struct matrix *M)
+{
+  refmpn_free_limbs (M->e00);
+}
+
+static void
+matrix_copy (struct matrix *R, const struct matrix *M)
+{
+  R->n = M->n;
+  MPN_COPY (R->e00, M->e00, M->n);
+  MPN_COPY (R->e01, M->e01, M->n);
+  MPN_COPY (R->e10, M->e10, M->n);
+  MPN_COPY (R->e11, M->e11, M->n);
+}
+
+/* Used with same size, so no need for normalization. */
+static int
+matrix_equal_p (const struct matrix *A, const struct matrix *B)
+{
+  return (A->n == B->n
+	  && mpn_cmp (A->e00, B->e00, A->n) == 0
+	  && mpn_cmp (A->e01, B->e01, A->n) == 0
+	  && mpn_cmp (A->e10, B->e10, A->n) == 0
+	  && mpn_cmp (A->e11, B->e11, A->n) == 0);
+}
+
+static void
+matrix_random(struct matrix *M, mp_size_t n, gmp_randstate_ptr rands)
+{
+  M->n = n;
+  mpn_random (M->e00, n);
+  mpn_random (M->e01, n);
+  mpn_random (M->e10, n);
+  mpn_random (M->e11, n);
+}
+
+#define MUL(rp, ap, an, bp, bn) do { \
+    if (an > bn)		     \
+      mpn_mul (rp, ap, an, bp, bn);  \
+    else			     \
+      mpn_mul (rp, bp, bn, ap, an);  \
+  } while(0)
+
+static void
+ref_matrix22_mul (struct matrix *R,
+		  const struct matrix *A,
+		  const struct matrix *B, mp_ptr tp)
+{
+  mp_size_t an, bn, n;
+  mp_ptr r00, r01, r10, r11, a00, a01, a10, a11, b00, b01, b10, b11;
+
+  if (A->n >= B->n)
+    {
+      r00 = R->e00; a00 = A->e00; b00 = B->e00;
+      r01 = R->e01; a01 = A->e01; b01 = B->e01;
+      r10 = R->e10; a10 = A->e10; b10 = B->e10;
+      r11 = R->e11; a11 = A->e11; b11 = B->e11;
+      an = A->n, bn = B->n;
+    }
+  else
+    {
+      /* Transpose */
+      r00 = R->e00; a00 = B->e00; b00 = A->e00;
+      r01 = R->e10; a01 = B->e10; b01 = A->e10;
+      r10 = R->e01; a10 = B->e01; b10 = A->e01;
+      r11 = R->e11; a11 = B->e11; b11 = A->e11;
+      an = B->n, bn = A->n;
+    }
+  n = an + bn;
+  R->n = n + 1;
+
+  mpn_mul (r00, a00, an, b00, bn);
+  mpn_mul (tp, a01, an, b10, bn);
+  r00[n] = mpn_add_n (r00, r00, tp, n);
+
+  mpn_mul (r01, a00, an, b01, bn);
+  mpn_mul (tp, a01, an, b11, bn);
+  r01[n] = mpn_add_n (r01, r01, tp, n);
+
+  mpn_mul (r10, a10, an, b00, bn);
+  mpn_mul (tp, a11, an, b10, bn);
+  r10[n] = mpn_add_n (r10, r10, tp, n);
+
+  mpn_mul (r11, a10, an, b01, bn);
+  mpn_mul (tp, a11, an, b11, bn);
+  r11[n] = mpn_add_n (r11, r11, tp, n);
+}
+
+static void
+one_test (const struct matrix *A, const struct matrix *B, int i)
+{
+  struct matrix R;
+  struct matrix P;
+  mp_ptr tp;
+
+  matrix_init (&R, A->n + B->n + 1);
+  matrix_init (&P, A->n + B->n + 1);
+
+  tp = refmpn_malloc_limbs (mpn_matrix22_mul_itch (A->n, B->n));
+
+  ref_matrix22_mul (&R, A, B, tp);
+  matrix_copy (&P, A);
+  mpn_matrix22_mul (P.e00, P.e01, P.e10, P.e11, A->n,
+		    B->e00, B->e01, B->e10, B->e11, B->n, tp);
+  P.n = A->n + B->n + 1;
+  if (!matrix_equal_p (&R, &P))
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      gmp_fprintf (stderr, "A = (%Nx, %Nx\n      %Nx, %Nx)\n"
+		   "B = (%Nx, %Nx\n      %Nx, %Nx)\n"
+		   "R = (%Nx, %Nx (expected)\n      %Nx, %Nx)\n"
+		   "P = (%Nx, %Nx (incorrect)\n      %Nx, %Nx)\n",
+		   A->e00, A->n, A->e01, A->n, A->e10, A->n, A->e11, A->n,
+		   B->e00, B->n, B->e01, B->n, B->e10, B->n, B->e11, B->n,
+		   R.e00, R.n, R.e01, R.n, R.e10, R.n, R.e11, R.n,
+		   P.e00, P.n, P.e01, P.n, P.e10, P.n, P.e11, P.n);
+      abort();
+    }
+  refmpn_free_limbs (tp);
+  matrix_clear (&R);
+  matrix_clear (&P);
+}
+
+#define MAX_SIZE (2+2*MATRIX22_STRASSEN_THRESHOLD)
+
+int
+main (int argc, char **argv)
+{
+  struct matrix A;
+  struct matrix B;
+
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  int i;
+
+  tests_start ();
+  rands = RANDS;
+
+  matrix_init (&A, MAX_SIZE);
+  matrix_init (&B, MAX_SIZE);
+  mpz_init (bs);
+
+  for (i = 0; i < 1000; i++)
+    {
+      mp_size_t an, bn;
+      mpz_urandomb (bs, rands, 32);
+      an = 1 + mpz_get_ui (bs) % MAX_SIZE;
+      mpz_urandomb (bs, rands, 32);
+      bn = 1 + mpz_get_ui (bs) % MAX_SIZE;
+
+      matrix_random (&A, an, rands);
+      matrix_random (&B, bn, rands);
+
+      one_test (&A, &B, i);
+    }
+  mpz_clear (bs);
+  matrix_clear (&A);
+  matrix_clear (&B);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-minvert.c b/tests/mpn/t-minvert.c
new file mode 100644
index 0000000..ca5690f
--- /dev/null
+++ b/tests/mpn/t-minvert.c
@@ -0,0 +1,167 @@
+/* Copyright 2013-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>		/* for strtol */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#define MAX_SIZE 50
+
+#define COUNT 200
+
+static void
+mpz_to_mpn (mp_ptr ap, mp_size_t an, const mpz_t b)
+{
+  mp_size_t bn = mpz_size (b);
+  ASSERT_ALWAYS (bn <= an);
+  MPN_COPY_INCR (ap, mpz_limbs_read (b), bn);
+  MPN_ZERO (ap + bn, an - bn);
+}
+
+int
+mpz_eq_mpn (mp_ptr ap, mp_size_t an, const mpz_t b)
+{
+  mp_size_t bn = mpz_size (b);
+
+  return (bn >= 0 && bn <= an
+	  && mpn_cmp (ap, mpz_limbs_read (b), bn) == 0
+	  && (an == bn || mpn_zero_p (ap + bn, an - bn)));
+}
+
+static mp_bitcnt_t
+bit_size (mp_srcptr xp, mp_size_t n)
+{
+  MPN_NORMALIZE (xp, n);
+  return n > 0 ? mpn_sizeinbase (xp, n, 2) : 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  long count = COUNT;
+  mp_ptr mp;
+  mp_ptr ap;
+  mp_ptr tp;
+  mp_ptr scratch;
+  mpz_t m, a, r, g;
+  int test;
+  mp_limb_t ran;
+  mp_size_t itch;
+  TMP_DECL;
+
+  tests_start ();
+  rands = RANDS;
+
+
+  TMP_MARK;
+  mpz_init (m);
+  mpz_init (a);
+  mpz_init (r);
+  mpz_init (g);
+
+  TESTS_REPS (count, argv, argc);
+
+  mp = TMP_ALLOC_LIMBS (MAX_SIZE);
+  ap = TMP_ALLOC_LIMBS (MAX_SIZE);
+  tp = TMP_ALLOC_LIMBS (MAX_SIZE);
+  scratch = TMP_ALLOC_LIMBS (mpn_sec_invert_itch (MAX_SIZE) + 1);
+
+  for (test = 0; test < count; test++)
+    {
+      mp_bitcnt_t bits;
+      int rres, tres;
+      mp_size_t n;
+
+      bits = urandom () % (GMP_NUMB_BITS * MAX_SIZE) + 1;
+
+      if (test & 1)
+	mpz_rrandomb (m, rands, bits);
+      else
+	mpz_urandomb (m, rands, bits);
+      if (test & 2)
+	mpz_rrandomb (a, rands, bits);
+      else
+	mpz_urandomb (a, rands, bits);
+
+      mpz_setbit (m, 0);
+      if (test & 4)
+	{
+	  /* Ensure it really is invertible */
+	  if (mpz_sgn (a) == 0)
+	    mpz_set_ui (a, 1);
+	  else
+	    for (;;)
+	      {
+		mpz_gcd (g, a, m);
+		if (mpz_cmp_ui (g, 1) == 0)
+		  break;
+		mpz_remove (a, a, g);
+	      }
+	}
+
+      rres = mpz_invert (r, a, m);
+      if ( (test & 4) && !rres)
+	{
+	  gmp_fprintf (stderr, "test %d: Not invertible!\n"
+		       "m = %Zd\n"
+		       "a = %Zd\n", test, m, a);
+	  abort ();
+	}
+      ASSERT_ALWAYS (! (test & 4) || rres);
+
+      n = (bits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
+      ASSERT_ALWAYS (n <= MAX_SIZE);
+      itch = mpn_sec_invert_itch (n);
+      scratch[itch] = ran = urandom ();
+
+      mpz_to_mpn (ap, n, a);
+      mpz_to_mpn (mp, n, m);
+      tres = mpn_sec_invert (tp, ap, mp, n,
+			     bit_size (ap, n) + bit_size (mp, n),
+			     scratch);
+
+      if (rres != tres || (rres == 1 && !mpz_eq_mpn (tp, n, r)) || ran != scratch[itch])
+	{
+	  gmp_fprintf (stderr, "Test %d failed.\n"
+		       "m = %Zd\n"
+		       "a = %Zd\n", test, m, a);
+	  fprintf (stderr, "ref ret: %d\n"
+		  "got ret: %d\n", rres, tres);
+	  if (rres)
+	    gmp_fprintf (stderr, "ref: %Zd\n", r);
+	  if (tres)
+	    gmp_fprintf (stderr, "got: %Nd\n", tp, n);
+	  if (ran != scratch[itch])
+	    fprintf (stderr, "scratch[itch] changed.\n");
+	  abort ();
+	}
+    }
+
+  TMP_FREE;
+
+  mpz_clear (m);
+  mpz_clear (a);
+  mpz_clear (r);
+  mpz_clear (g);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-mod_1.c b/tests/mpn/t-mod_1.c
new file mode 100644
index 0000000..5b9570d
--- /dev/null
+++ b/tests/mpn/t-mod_1.c
@@ -0,0 +1,127 @@
+/* Test mpn_mod_1 variants.
+
+Copyright 2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static void
+check_one (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_limb_t r_ref = refmpn_mod_1 (ap, n, b);
+  mp_limb_t r;
+
+  if (n >= 2)
+    {
+      mp_limb_t pre[4];
+      mpn_mod_1_1p_cps (pre, b);
+      r = mpn_mod_1_1p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1_1p failed\n");
+	  goto fail;
+	}
+    }
+  if ((b & GMP_NUMB_HIGHBIT) == 0)
+    {
+      mp_limb_t pre[5];
+      mpn_mod_1s_2p_cps (pre, b);
+      r = mpn_mod_1s_2p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1s_2p failed\n");
+	  goto fail;
+	}
+    }
+  if (b <= GMP_NUMB_MASK / 3)
+    {
+      mp_limb_t pre[6];
+      mpn_mod_1s_3p_cps (pre, b);
+      r = mpn_mod_1s_3p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1s_3p failed\n");
+	  goto fail;
+	}
+    }
+  if (b <= GMP_NUMB_MASK / 4)
+    {
+      mp_limb_t pre[7];
+      mpn_mod_1s_4p_cps (pre, b);
+      r = mpn_mod_1s_4p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1s_4p failed\n");
+	  goto fail;
+	}
+    }
+  r = mpn_mod_1 (ap, n, b);
+  if (r != r_ref)
+    {
+      printf ("mpn_mod_1 failed\n");
+    fail:
+      printf ("an = %d, a: ", (int) n); mpn_dump (ap, n);
+      printf ("b           : "); mpn_dump (&b, 1);
+      printf ("r (expected): "); mpn_dump (&r_ref, 1);
+      printf ("r (bad)     : "); mpn_dump (&r, 1);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  int i;
+  unsigned a_bits;
+  unsigned b_bits;
+  mpz_t a;
+  mpz_t b;
+
+  tests_start ();
+  rands = RANDS;
+  mpz_init (a);
+  mpz_init (b);
+
+  for (i = 0; i < 300; i++)
+    {
+      mp_size_t asize;
+      a_bits = 1 + gmp_urandomm_ui (rands, 1000);
+      b_bits = 1 + gmp_urandomm_ui (rands, GMP_NUMB_BITS);
+
+      mpz_rrandomb (a, rands, a_bits);
+      mpz_rrandomb (b, rands, b_bits);
+
+      asize = SIZ(a);
+      if (!asize)
+	asize = 1;
+      if (mpz_sgn (b) == 0)
+	mpz_set_ui (b, 1);
+
+      check_one (PTR(a), asize, PTR(b)[0]);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-mp_bases.c b/tests/mpn/t-mp_bases.c
new file mode 100644
index 0000000..deb7f5c
--- /dev/null
+++ b/tests/mpn/t-mp_bases.c
@@ -0,0 +1,104 @@
+/* Check mp_bases values.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+int
+main (int argc, char *argv[])
+{
+  mp_limb_t  want_bb, want_bb_inv;
+  int        base, want_chars_per_limb;
+
+  want_chars_per_limb = refmpn_chars_per_limb (10);
+  if (MP_BASES_CHARS_PER_LIMB_10 != want_chars_per_limb)
+    {
+      printf ("MP_BASES_CHARS_PER_LIMB_10 wrong\n");
+      abort ();
+    }
+
+  want_bb = refmpn_big_base (10);
+  if (MP_BASES_BIG_BASE_10 != want_bb)
+    {
+      printf ("MP_BASES_BIG_BASE_10 wrong\n");
+      abort ();
+    }
+
+  want_bb_inv = refmpn_invert_limb
+    (want_bb << refmpn_count_leading_zeros (want_bb));
+  if (MP_BASES_BIG_BASE_INVERTED_10 != want_bb_inv)
+    {
+      printf ("MP_BASES_BIG_BASE_INVERTED_10 wrong\n");
+      abort ();
+    }
+
+  if (MP_BASES_NORMALIZATION_STEPS_10
+      != refmpn_count_leading_zeros (MP_BASES_BIG_BASE_10))
+    {
+      printf ("MP_BASES_NORMALIZATION_STEPS_10 wrong\n");
+      abort ();
+    }
+
+  for (base = 2; base < numberof (mp_bases); base++)
+    {
+      want_chars_per_limb = refmpn_chars_per_limb (base);
+      if (mp_bases[base].chars_per_limb != want_chars_per_limb)
+        {
+          printf ("mp_bases[%d].chars_per_limb wrong\n", base);
+          printf ("  got  %d\n", mp_bases[base].chars_per_limb);
+          printf ("  want %d\n", want_chars_per_limb);
+          abort ();
+        }
+
+      if (POW2_P (base))
+        {
+          want_bb = refmpn_count_trailing_zeros ((mp_limb_t) base);
+          if (mp_bases[base].big_base != want_bb)
+            {
+              printf ("mp_bases[%d].big_base (log2 of base) wrong\n", base);
+              abort ();
+            }
+        }
+      else
+        {
+          want_bb = refmpn_big_base (base);
+          if (mp_bases[base].big_base != want_bb)
+            {
+              printf ("mp_bases[%d].big_base wrong\n", base);
+              abort ();
+            }
+
+#if USE_PREINV_DIVREM_1
+          want_bb_inv = refmpn_invert_limb
+            (want_bb << refmpn_count_leading_zeros (want_bb));
+          if (mp_bases[base].big_base_inverted != want_bb_inv)
+            {
+              printf ("mp_bases[%d].big_base_inverted wrong\n", base);
+              abort ();
+            }
+#endif
+        }
+    }
+
+  exit (0);
+}
diff --git a/tests/mpn/t-mul.c b/tests/mpn/t-mul.c
new file mode 100644
index 0000000..40f6de7
--- /dev/null
+++ b/tests/mpn/t-mul.c
@@ -0,0 +1,97 @@
+/* Test mpn_mul function for all sizes up to a selected limit.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static unsigned
+isqrt (unsigned t)
+{
+  unsigned s, b;
+
+  for (b = 0, s = t;  b++, s >>= 1; )
+    ;
+
+  s = 1 << (b >> 1);
+  if (b & 1)
+    s += s >> 1;
+
+  do
+    {
+      b = t / s;
+      s = (s + b) >> 1;
+    }
+  while (b < s);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, rp, refp;
+  mp_size_t max_n, an, bn, rn;
+  int reps;
+  TMP_DECL;
+  TMP_MARK;
+
+  reps = 1;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  /* Re-interpret reps argument as a size argument.  */
+  max_n = isqrt (reps * 25000);
+
+  ap = TMP_ALLOC_LIMBS (max_n + 1);
+  bp = TMP_ALLOC_LIMBS (max_n + 1);
+  rp = TMP_ALLOC_LIMBS (2 * max_n);
+  refp = TMP_ALLOC_LIMBS (2 * max_n);
+
+  for (an = 1; an <= max_n; an += 1)
+    {
+      for (bn = 1; bn <= an; bn += 1)
+	{
+	  mpn_random2 (ap, an + 1);
+	  mpn_random2 (bp, bn + 1);
+
+	  refmpn_mul (refp, ap, an, bp, bn);
+	  mpn_mul (rp, ap, an, bp, bn);
+
+	  rn = an + bn;
+	  if (mpn_cmp (refp, rp, rn))
+	    {
+	      printf ("ERROR, an = %d, bn = %d, rn = %d\n",
+		      (int) an, (int) bn, (int) rn);
+	      printf ("a: "); mpn_dump (ap, an);
+	      printf ("b: "); mpn_dump (bp, bn);
+	      printf ("r:   "); mpn_dump (rp, rn);
+	      printf ("ref: "); mpn_dump (refp, rn);
+	      abort();
+	    }
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-mullo.c b/tests/mpn/t-mullo.c
new file mode 100644
index 0000000..75a0f01
--- /dev/null
+++ b/tests/mpn/t-mullo.c
@@ -0,0 +1,132 @@
+/* Test for mullo function.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 10
+#endif
+
+#ifndef COUNT
+#define COUNT 10000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N (1)
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+#define mpn_mullo_itch(n) (0)
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  bp = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 2);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_mullo_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+
+      mpn_random2 (ap, n);
+      mpn_random2 (bp, n);
+      mpn_random2 (pp-1, n + 2);
+      p_before = pp[-1];
+      p_after = pp[n];
+
+      itch = mpn_mullo_itch (n);
+      ASSERT_ALWAYS (itch <= mpn_mullo_itch (MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_mullo_n (pp, ap, bp, n);
+      mpn_mul_n (refp, ap, bp, n);
+      if (pp[-1] != p_before || pp[n] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, n) != 0)
+	{
+	  printf ("ERROR in test %d, n = %d",
+		  test, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[n] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + n, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, n);
+	  mpn_dump (bp, n);
+	  mpn_dump (pp, n);
+	  mpn_dump (refp, n);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-mulmid.c b/tests/mpn/t-mulmid.c
new file mode 100644
index 0000000..9491b0e
--- /dev/null
+++ b/tests/mpn/t-mulmid.c
@@ -0,0 +1,92 @@
+/* Test for mulmid function.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 9
+#endif
+
+#ifndef COUNT
+#define COUNT 5000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, rp, refp;
+  gmp_randstate_ptr rands;
+  int test;
+  TMP_DECL;
+  TMP_MARK;
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  bp = TMP_ALLOC_LIMBS (MAX_N);
+  rp = TMP_ALLOC_LIMBS (MAX_N + 2);
+  refp = TMP_ALLOC_LIMBS (MAX_N + 2);
+
+  for (test = 0; test < COUNT; test++)
+    {
+      mp_size_t an, bn, rn;
+      unsigned size_log;
+
+      size_log = 1 + gmp_urandomm_ui (rands, SIZE_LOG);
+      an = 1 + gmp_urandomm_ui(rands, 1L << size_log);
+
+      size_log = 1 + gmp_urandomm_ui (rands, SIZE_LOG);
+      bn = 1 + gmp_urandomm_ui(rands, 1L << size_log);
+
+      /* Make sure an >= bn */
+      if (an < bn)
+	MP_SIZE_T_SWAP (an, bn);
+
+      mpn_random2 (ap, an);
+      mpn_random2 (bp, bn);
+
+      refmpn_mulmid (refp, ap, an, bp, bn);
+      mpn_mulmid (rp, ap, an, bp, bn);
+
+      rn = an + 3 - bn;
+      if (mpn_cmp (refp, rp, rn))
+	{
+	  printf ("ERROR in test %d, an = %d, bn = %d, rn = %d\n",
+		  test, (int) an, (int) bn, (int) rn);
+	  printf("a: "); mpn_dump (ap, an);
+	  printf("b: "); mpn_dump (bp, bn);
+	  printf("r:   "); mpn_dump (rp, rn);
+	  printf("ref: "); mpn_dump (refp, rn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-mulmod_bknp1.c b/tests/mpn/t-mulmod_bknp1.c
new file mode 100644
index 0000000..93da1eb
--- /dev/null
+++ b/tests/mpn/t-mulmod_bknp1.c
@@ -0,0 +1,202 @@
+/* Test for mulmod_bknp1 function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009, 2020-2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if MOD_BKNP1_USE11
+#define USE11 11,
+#else
+#define USE11
+#endif
+
+
+#if GMP_NUMB_BITS % 32 == 0
+#define MAX_K 17
+#define SUPPORTED_K {3, 5, 7, 13, USE11 MAX_K}
+#else
+#if GMP_NUMB_BITS % 16 == 0
+#define MAX_K 13
+#define SUPPORTED_K {3, 5, 7, USE11 MAX_K}
+#else
+#if GMP_NUMB_BITS % 8 == 0
+#define MAX_K 7
+#define SUPPORTED_K {3, USE11 MAX_K}
+#else
+#define SUPPORTED_K {USE11} /* Supported ? */
+#endif /* GMP_NUMB_BITS % 8 == 0 */
+#endif /* GMP_NUMB_BITS % 16 == 0 */
+#endif /* GMP_NUMB_BITS % 32 == 0 */
+
+#if MOD_BKNP1_ONLY3
+#undef SUPPORTED_K
+#undef MAX_K
+#define MAX_K 3
+#define SUPPORTED_K {3}
+#endif
+
+/* Sizes are up to MAX_K * 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 7
+#endif
+
+#ifndef COUNT
+#define COUNT 5000
+#endif
+
+#define MAX_N (MAX_K << SIZE_LOG)
+#define MIN_N 1
+
+/*
+  Reference function for multiplication modulo B^{k*rn}+1.
+*/
+
+static void
+ref_mulmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t rn)
+{
+  mp_limb_t cy;
+
+  mpn_mul_n (rp, ap, bp, rn + 1);
+  cy = rp[2 * rn];
+  MPN_INCR_U (rp, 2 * rn + 1, rp[2 * rn]);
+  cy = rp[2 * rn] - cy + mpn_sub_n (rp, rp, rp + rn, rn);
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, cy);
+}
+
+/*
+  Compare the result of the mpn_mulmod_bnp1 function in the library
+  with the reference function above.
+*/
+unsigned supported_k[] = SUPPORTED_K;
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_N + 1);
+  bp = TMP_ALLOC_LIMBS (MAX_N + 1);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 2 + 2);
+  pp = 1 + TMP_ALLOC_LIMBS (MAX_N + 3);
+  scratch
+    = 1 + TMP_ALLOC_LIMBS (mpn_mulmod_bknp1_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      unsigned k;
+      mp_size_t rn, n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate rn in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      k = supported_k[test % numberof (supported_k)];
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+      rn = k * n;
+      if ((GMP_NUMB_MAX % k != 0) && (rn % 3 == 0))
+	n = rn / (k = 3);
+
+      if (test == 0)
+	{
+	  mpn_random2 (ap, n);
+	  mpn_add_1 (ap + n, ap, n, 1); /* {ap,an} = -1 mod B+1 */
+	  MPN_ZERO (ap + 2 * n, rn - 2 * n + 1);
+	}
+      else
+	mpn_random2 (ap, rn + 1);
+      mpn_random2 (bp, rn + 1);
+
+      bp [rn] &= 1;
+      ap [rn] &= 1;
+
+      mpn_random2 (pp-1, rn + 3);
+      p_before = pp[-1];
+      p_after = pp[rn + 1];
+
+      itch = mpn_mulmod_bknp1_itch (rn);
+      ASSERT_ALWAYS (itch <= mpn_mulmod_bknp1_itch (MAX_N));
+      mpn_random2 (scratch - 1, itch + 2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_mulmod_bknp1 ( pp, ap, bp, n, k, scratch);
+      ref_mulmod_bnp1 (refp, ap, bp, rn);
+      if (pp[-1] != p_before || pp[rn + 1] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn + 1) != 0)
+	{
+	  printf ("ERROR in test %d, rn = %d, n = %d, k = %d\n",
+		  test, (int) rn, (int) n, (int) k);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp - 1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn + 1] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch - 1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, rn + 1);
+	  mpn_dump (bp, rn + 1);
+	  mpn_dump (pp, rn + 1);
+	  mpn_dump (refp, rn + 1);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-mulmod_bnm1.c b/tests/mpn/t-mulmod_bnm1.c
new file mode 100644
index 0000000..08f59bb
--- /dev/null
+++ b/tests/mpn/t-mulmod_bnm1.c
@@ -0,0 +1,210 @@
+
+/* Test for mulmod_bnm1 function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 11
+#endif
+
+#ifndef COUNT
+#define COUNT 5000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N 1
+
+/*
+  Reference function for multiplication modulo B^rn-1.
+
+  The result is expected to be ZERO if and only if one of the operand
+  already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+  B^rn-1. This should not be a problem if mulmod_bnm1 is used to
+  combine results and obtain a natural number when one knows in
+  advance that the final value is less than (B^rn-1).
+*/
+
+static void
+ref_mulmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < an && an <= rn);
+  ASSERT (0 < bn && bn <= rn);
+
+  if (an >= bn)
+    refmpn_mul (rp, ap, an, bp, bn);
+  else
+    refmpn_mul (rp, bp, bn, ap, an);
+  an += bn;
+  if (an > rn) {
+    cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
+    /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+     * be no overflow when adding in the carry. */
+    MPN_INCR_U (rp, rn, cy);
+  }
+}
+
+/*
+  Compare the result of the mpn_mulmod_bnm1 function in the library
+  with the reference function above.
+*/
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ASSERT_ALWAYS (mpn_mulmod_bnm1_next_size (MAX_N) == MAX_N);
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  bp = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 4);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t an,bn,rn,n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+      n = mpn_mulmod_bnm1_next_size (n);
+
+      if ( (test & 1) || n == 1) {
+	/* Half of the tests are done with the main scenario in mind:
+	   both an and bn >= rn/2 */
+	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
+	bn = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
+      } else {
+	/* Second half of the tests are done using mulmod to compute a
+	   full product with n/2 < an+bn <= n. */
+	an = 1 + gmp_urandomm_ui (rands, n - 1);
+	if (an >= n/2)
+	  bn = 1 + gmp_urandomm_ui (rands, n - an);
+	else
+	  bn = n/2 + 1 - an + gmp_urandomm_ui (rands, (n+1)/2);
+      }
+
+      /* Make sure an >= bn */
+      if (an < bn)
+	MP_SIZE_T_SWAP (an, bn);
+
+      mpn_random2 (ap, an);
+      mpn_random2 (bp, bn);
+
+      /* Sometime trigger the borderline conditions
+	 A = -1,0,+1 or B = -1,0,+1 or A*B == -1,0,1 Mod(B^{n/2}+1).
+	 This only makes sense if there is at least a split, i.e. n is even. */
+      if ((test & 0x1f) == 1 && (n & 1) == 0) {
+	mp_size_t x;
+	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
+	MPN_ZERO (ap + an - (n >> 1) , n - an);
+	MPN_COPY (bp, bp + (n >> 1), bn - (n >> 1));
+	MPN_ZERO (bp + bn - (n >> 1) , n - bn);
+	x = 0;
+	/* x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an); */
+	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
+	/* x = (n >> 1) - x % (n >> 1); */
+	bp[x] += gmp_urandomm_ui (rands, 3) - 1;
+	/* We don't propagate carry, this means that the desired condition
+	   is not triggered all the times. A few times are enough anyway. */
+      }
+      rn = MIN(n, an + bn);
+      mpn_random2 (pp-1, rn + 2);
+      p_before = pp[-1];
+      p_after = pp[rn];
+
+      itch = mpn_mulmod_bnm1_itch (n, an, bn);
+      ASSERT_ALWAYS (itch <= mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_mulmod_bnm1 (  pp, n, ap, an, bp, bn, scratch);
+      ref_mulmod_bnm1 (refp, n, ap, an, bp, bn);
+      if (pp[-1] != p_before || pp[rn] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn) != 0)
+	{
+	  printf ("ERROR in test %d, an = %d, bn = %d, n = %d\n",
+		  test, (int) an, (int) bn, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (bp, bn);
+	  mpn_dump (pp, rn);
+	  mpn_dump (refp, rn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-perfsqr.c b/tests/mpn/t-perfsqr.c
new file mode 100644
index 0000000..b65ee8b
--- /dev/null
+++ b/tests/mpn/t-perfsqr.c
@@ -0,0 +1,116 @@
+/* Test mpn_perfect_square_p data.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#include "mpn/perfsqr.h"
+
+
+#define PERFSQR_MOD_MASK   ((CNST_LIMB(1) << PERFSQR_MOD_BITS) - 1)
+
+void
+check_mod_2 (mp_limb_t d, mp_limb_t inv, mp_limb_t got_hi, mp_limb_t got_lo)
+{
+  int        want[2*GMP_LIMB_BITS], got;
+  unsigned   r, idx;
+  mp_limb_t  q;
+
+  ASSERT_ALWAYS (d <= numberof (want));
+  ASSERT_ALWAYS (((inv * d) & PERFSQR_MOD_MASK) == 1);
+  ASSERT_ALWAYS (MP_LIMB_T_MAX / d >= PERFSQR_MOD_MASK);
+
+  /* the squares mod d */
+  for (r = 0; r < d; r++)
+    want[r] = 0;
+  for (r = 0; r < d; r++)
+    want[(r*r)%d] = 1;
+
+  /* for each remainder mod d, expect the table data to correctly identify
+     it as a residue or non-residue */
+  for (r = 0; r < d; r++)
+    {
+      /* as per PERFSQR_MOD_IDX */
+      q = ((r) * (inv)) & PERFSQR_MOD_MASK;
+      idx = (q * (d)) >> PERFSQR_MOD_BITS;
+
+      if (idx >= GMP_LIMB_BITS)
+        got = (got_hi >> (idx - GMP_LIMB_BITS)) & 1;
+      else
+        got = (got_lo >> idx) & 1;
+
+      if (got != want[r])
+        {
+          printf ("Wrong generated data\n");
+          printf ("  d=%u\n", (unsigned) d);
+          printf ("  r=%u\n", r);
+          printf ("  idx=%u\n", idx);
+          printf ("  got  %d\n", got);
+          printf ("  want %d\n", want[r]);
+          abort ();
+        }
+    }
+}
+
+/* Check the generated data in perfsqr.h. */
+void
+check_mod (void)
+{
+#define PERFSQR_MOD_34(r, up, usize)       { r = 0; } /* so r isn't unused */
+#define PERFSQR_MOD_PP(r, up, usize)       { r = 0; }
+#define PERFSQR_MOD_1(r, d, inv, mask)     check_mod_2 (d, inv, CNST_LIMB(0), mask)
+#define PERFSQR_MOD_2(r, d, inv, mhi, mlo) check_mod_2 (d, inv, mhi, mlo)
+
+  PERFSQR_MOD_TEST (dummy, dummy);
+}
+
+/* Check PERFSQR_PP, if in use. */
+void
+check_pp (void)
+{
+#ifdef PERFSQR_PP
+  ASSERT_ALWAYS_LIMB (PERFSQR_PP);
+  ASSERT_ALWAYS_LIMB (PERFSQR_PP_NORM);
+  ASSERT_ALWAYS_LIMB (PERFSQR_PP_INVERTED);
+
+  /* preinv stuff only for nails==0 */
+  if (GMP_NAIL_BITS == 0)
+    {
+      ASSERT_ALWAYS (PERFSQR_PP_NORM
+                     == PERFSQR_PP << refmpn_count_leading_zeros (PERFSQR_PP));
+      ASSERT_ALWAYS (PERFSQR_PP_INVERTED
+                     == refmpn_invert_limb (PERFSQR_PP_NORM));
+    }
+#endif
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_mod ();
+  check_pp ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-scan.c b/tests/mpn/t-scan.c
new file mode 100644
index 0000000..ec25b95
--- /dev/null
+++ b/tests/mpn/t-scan.c
@@ -0,0 +1,144 @@
+/* Test mpn_scan0 and mpn_scan1.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+#define SIZE  ((mp_size_t) 3)
+mp_limb_t  x[SIZE+1];
+
+void
+check (void)
+{
+  unsigned long  i, got, want;
+
+  x[SIZE] = 1;
+  for (i = 0; i < SIZE*GMP_NUMB_BITS; i++)
+    {
+      got = refmpn_scan1 (x, i);
+      want = mpn_scan1 (x, i);
+      if (got != want)
+        {
+          printf ("mpn_scan1\n");
+          printf ("  i     %lu\n", i);
+          printf ("  got   %lu\n", got);
+          printf ("  want  %lu\n", want);
+          mpn_trace ("  x    ", x, SIZE);
+          abort ();
+        }
+    }
+
+  x[SIZE] = 0;
+  for (i = 0; i < SIZE*GMP_NUMB_BITS; i++)
+    {
+      got = refmpn_scan0 (x, i);
+      want = mpn_scan0 (x, i);
+      if (got != want)
+        {
+          printf ("mpn_scan0\n");
+          printf ("  i     %lu\n", i);
+          printf ("  got   %lu\n", got);
+          printf ("  want  %lu\n", want);
+          mpn_trace ("  x    ", x, SIZE);
+          abort ();
+        }
+    }
+}
+
+void
+check_twobits (void)
+{
+#define TWOBITS(a, b) \
+  ((CNST_LIMB(1) << (a)) | (CNST_LIMB(1) << (b)))
+
+  refmpn_zero (x, SIZE);
+  x[0] = TWOBITS (1, 0);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[0] = TWOBITS (GMP_NUMB_BITS-1, 1);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[0] = CNST_LIMB(1);
+  x[1] = CNST_LIMB(1);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[0] = CNST_LIMB(1) << (GMP_NUMB_BITS-1);
+  x[1] = CNST_LIMB(1);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[1] = TWOBITS (1, 0);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[1] = CNST_LIMB(1);
+  x[2] = CNST_LIMB(1);
+  check ();
+}
+
+/* This is unused, it takes too long, especially on 64-bit systems. */
+void
+check_twobits_exhaustive (void)
+{
+  unsigned long  i, j;
+
+  for (i = 0; i < GMP_NUMB_BITS * SIZE; i++)
+    {
+      for (j = 0; j < GMP_NUMB_BITS * SIZE; j++)
+        {
+          refmpn_zero (x, SIZE);
+          refmpn_setbit (x, i);
+          refmpn_setbit (x, j);
+          check ();
+        }
+    }
+}
+
+void
+check_rand (void)
+{
+  int  i;
+
+  for (i = 0; i < 100; i++)
+    {
+      refmpn_random2 (x, SIZE);
+      check ();
+    }
+}
+
+int
+main (void)
+{
+  mp_trace_base = -16;
+  tests_start ();
+
+  check_twobits ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpn/t-sizeinbase.c b/tests/mpn/t-sizeinbase.c
new file mode 100644
index 0000000..f34714a
--- /dev/null
+++ b/tests/mpn/t-sizeinbase.c
@@ -0,0 +1,98 @@
+/* Test for sizeinbase function.
+
+Copyright 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Exponents up to 2^SIZE_LOG */
+#ifndef SIZE_LOG
+#define SIZE_LOG 13
+#endif
+
+#ifndef COUNT
+#define COUNT 30
+#endif
+
+#define MAX_N (1<<SIZE_LOG)
+
+int
+main (int argc, char **argv)
+{
+  mp_limb_t a;
+  mp_ptr pp, scratch;
+  mp_limb_t max_b;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  TMP_MARK;
+  rands = RANDS;
+
+  pp = TMP_ALLOC_LIMBS (MAX_N);
+  scratch = TMP_ALLOC_LIMBS (MAX_N);
+  max_b = numberof (mp_bases);
+
+  ASSERT_ALWAYS (max_b > 62);
+  ASSERT_ALWAYS (max_b < GMP_NUMB_MAX);
+
+  for (a = 2; a < max_b; ++a)
+    for (test = 0; test < count; ++test)
+      {
+	mp_size_t pn;
+	mp_limb_t exp;
+	mp_bitcnt_t res;
+
+	exp = gmp_urandomm_ui (rands, MAX_N);
+
+	pn = mpn_pow_1 (pp, &a, 1, exp, scratch);
+
+	res = mpn_sizeinbase (pp, pn, a) - 1;
+
+	if ((res < exp) || (res > exp + 1))
+	  {
+	    printf ("ERROR in test %d, base = %d, exp = %d, res = %d\n",
+		    test, (int) a, (int) exp, (int) res);
+	    abort();
+	  }
+
+	mpn_sub_1 (pp, pp, pn, CNST_LIMB(1));
+	pn -= pp[pn-1] == 0;
+
+	res = mpn_sizeinbase (pp, pn, a);
+
+	if ((res < exp) || (res - 1 > exp))
+	  {
+	    printf ("ERROR in -1 test %d, base = %d, exp = %d, res = %d\n",
+		    test, (int) a, (int) exp, (int) res);
+	    abort();
+	  }
+      }
+
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-sqrlo.c b/tests/mpn/t-sqrlo.c
new file mode 100644
index 0000000..e9ab1e0
--- /dev/null
+++ b/tests/mpn/t-sqrlo.c
@@ -0,0 +1,129 @@
+/* Test for sqrlo function.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 10
+#endif
+
+#ifndef COUNT
+#define COUNT 10000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N (1)
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+#define mpn_sqrlo_itch(n) (0)
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 2);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_sqrlo_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+
+      mpn_random2 (ap, n);
+      mpn_random2 (pp-1, n + 2);
+      p_before = pp[-1];
+      p_after = pp[n];
+
+      itch = mpn_sqrlo_itch (n);
+      ASSERT_ALWAYS (itch <= mpn_sqrlo_itch (MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_sqrlo (pp, ap, n);
+      mpn_sqr (refp, ap, n);
+      if (pp[-1] != p_before || pp[n] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, n) != 0)
+	{
+	  printf ("ERROR in test %d, n = %d",
+		  test, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[n] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + n, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, n);
+	  mpn_dump (pp, n);
+	  mpn_dump (refp, n);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-sqrmod_bknp1.c b/tests/mpn/t-sqrmod_bknp1.c
new file mode 100644
index 0000000..1620925
--- /dev/null
+++ b/tests/mpn/t-sqrmod_bknp1.c
@@ -0,0 +1,251 @@
+/* Test for mulmod_bknp1 function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009, 2020-2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#if MOD_BKNP1_USE11
+#define USE11 11,
+#else
+#define USE11
+#endif
+
+#if GMP_NUMB_BITS % 32 == 0
+#define MAX_K 17
+#define SUPPORTED_K {3, 5, 7, 13, USE11 MAX_K}
+#else
+#if GMP_NUMB_BITS % 16 == 0
+#define MAX_K 13
+#define SUPPORTED_K {3, 5, 7, USE11 MAX_K}
+#else
+#if GMP_NUMB_BITS % 8 == 0
+#define MAX_K 7
+#define SUPPORTED_K {3, USE11 MAX_K}
+#else
+#define SUPPORTED_K {USE11} /* Supported ? */
+#endif /* GMP_NUMB_BITS % 8 == 0 */
+#endif /* GMP_NUMB_BITS % 16 == 0 */
+#endif /* GMP_NUMB_BITS % 32 == 0 */
+
+#if MOD_BKNP1_ONLY3
+#undef SUPPORTED_K
+#undef MAX_K
+#define MAX_K 3
+#define SUPPORTED_K {3}
+#endif
+
+/* Sizes are up to MAX_K * 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 7
+#endif
+
+#ifndef COUNT
+#define COUNT 5000
+#endif
+
+#define MAX_N (MAX_K << SIZE_LOG)
+#define MIN_N 1
+
+/*
+  Reference function for multiplication modulo B^{k*rn}+1.
+*/
+
+static void
+ref_sqrmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_size_t rn)
+{
+  mp_limb_t cy;
+
+  mpn_sqr (rp, ap, rn + 1);
+  cy = rp[2 * rn];
+  MPN_INCR_U (rp, 2 * rn + 1, rp[2 * rn]);
+  cy = rp[2 * rn] - cy + mpn_sub_n (rp, rp, rp + rn, rn);
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn + 1, cy);
+}
+
+/*
+  Compare the result of the mpn_mulmod_bnp1 function in the library
+  with the reference function above.
+*/
+unsigned supported_k[] = SUPPORTED_K;
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_N + 1);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 2 + 2);
+  pp = 1 + TMP_ALLOC_LIMBS (MAX_N + 3);
+  scratch
+    = 1 + TMP_ALLOC_LIMBS (mpn_mulmod_bknp1_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      unsigned k;
+      mp_size_t rn, n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate rn in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      k = supported_k[test % numberof (supported_k)];
+      if (test < numberof (supported_k))
+	{
+	  n = 1;
+	  rn = k;
+	  ap [rn] = 0;
+	  mp_limb_t x = GMP_NUMB_MAX / k + 1;
+	  ap [0] = x;
+	  for (int i = 1; i < k; i += 2)
+	    {
+	      ap [i] = - x;
+	      ap [i + 1] = x - 1;
+	    }
+	}
+      else
+	{
+	  n = MIN_N
+	    + gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+	  rn = k * n;
+	  if ((GMP_NUMB_MAX % k != 0) && (rn % 3 == 0))
+	    n = rn / (k = 3);
+
+	  mpn_random2 (ap, rn + 1);
+
+	  ap [rn] &= 1;
+	}
+
+      mpn_random2 (pp-1, rn + 3);
+      p_before = pp[-1];
+      p_after = pp[rn + 1];
+
+      itch = mpn_sqrmod_bknp1_itch (rn);
+      ASSERT_ALWAYS (itch <= mpn_mulmod_bknp1_itch (MAX_N));
+      mpn_random2 (scratch - 1, itch + 2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_sqrmod_bknp1 (  pp, ap, n, k, scratch);
+      ref_sqrmod_bnp1 (refp, ap, rn);
+      if (pp[-1] != p_before || pp[rn + 1] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn + 1) != 0)
+	{
+	  printf ("ERROR in test %d(sqr), rn = %d, n = %d, k = %d\n",
+		  test, (int) rn, (int) n, (int) k);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp - 1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn + 1] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch - 1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, rn + 1);
+	  mpn_dump (pp, rn + 1);
+	  mpn_dump (refp, rn + 1);
+
+	  abort();
+	}
+
+      mpn_random2 (pp-1, rn + 3);
+      p_before = pp[-1];
+      p_after = pp[rn + 1];
+
+      itch = mpn_mulmod_bknp1_itch (rn);
+      ASSERT_ALWAYS (itch <= mpn_mulmod_bknp1_itch (MAX_N));
+      mpn_random2 (scratch - 1, itch + 2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_mulmod_bknp1 (  pp, ap, ap, n, k, scratch);
+      if (pp[-1] != p_before || pp[rn + 1] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn + 1) != 0)
+	{
+	  printf ("ERROR in test %d(mul), rn = %d, n = %d, k = %d\n",
+		  test, (int) rn, (int) n, (int) k);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp - 1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn + 1] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch - 1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, rn + 1);
+	  mpn_dump (pp, rn + 1);
+	  mpn_dump (refp, rn + 1);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-sqrmod_bnm1.c b/tests/mpn/t-sqrmod_bnm1.c
new file mode 100644
index 0000000..27e5f38
--- /dev/null
+++ b/tests/mpn/t-sqrmod_bnm1.c
@@ -0,0 +1,182 @@
+/* Test for sqrmod_bnm1 function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 12
+#endif
+
+#ifndef COUNT
+#define COUNT 3000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N 1
+
+/*
+  Reference function for squaring modulo B^rn-1.
+
+  The result is expected to be ZERO if and only if one of the operand
+  already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+  B^rn-1. This should not be a problem if sqrmod_bnm1 is used to
+  combine results and obtain a natural number when one knows in
+  advance that the final value is less than (B^rn-1).
+*/
+
+static void
+ref_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < an && an <= rn);
+
+  refmpn_mul (rp, ap, an, ap, an);
+  an *= 2;
+  if (an > rn) {
+    cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
+    /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+     * be no overflow when adding in the carry. */
+    MPN_INCR_U (rp, rn, cy);
+  }
+}
+
+/*
+  Compare the result of the mpn_sqrmod_bnm1 function in the library
+  with the reference function above.
+*/
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ASSERT_ALWAYS (mpn_sqrmod_bnm1_next_size (MAX_N) == MAX_N);
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 4);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (MAX_N, MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t an,rn,n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+      n = mpn_sqrmod_bnm1_next_size (n);
+
+      if (n == 1)
+	an = 1;
+      else
+	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
+
+      mpn_random2 (ap, an);
+
+      /* Sometime trigger the borderline conditions
+	 A = -1,0,+1 Mod(B^{n/2}+1).
+	 This only makes sense if there is at least a split, i.e. n is even. */
+      if ((test & 0x1f) == 1 && (n & 1) == 0) {
+	mp_size_t x;
+	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
+	MPN_ZERO (ap + an - (n >> 1) , n - an);
+	x = 0;
+	/* x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an); */
+	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
+      }
+      rn = MIN(n, 2*an);
+      mpn_random2 (pp-1, rn + 2);
+      p_before = pp[-1];
+      p_after = pp[rn];
+
+      itch = mpn_sqrmod_bnm1_itch (n, an);
+      ASSERT_ALWAYS (itch <= mpn_sqrmod_bnm1_itch (MAX_N, MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_sqrmod_bnm1 (  pp, n, ap, an, scratch);
+      ref_sqrmod_bnm1 (refp, n, ap, an);
+      if (pp[-1] != p_before || pp[rn] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn) != 0)
+	{
+	  printf ("ERROR in test %d, an = %d, n = %d\n",
+		  test, (int) an, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (pp, rn);
+	  mpn_dump (refp, rn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/t-toom2-sqr.c b/tests/mpn/t-toom2-sqr.c
new file mode 100644
index 0000000..1b42850
--- /dev/null
+++ b/tests/mpn/t-toom2-sqr.c
@@ -0,0 +1,86 @@
+#define mpn_toomN_sqr mpn_toom2_sqr
+#define mpn_toomN_sqr_itch mpn_toom2_sqr_itch
+#define MIN_AN MPN_TOOM2_SQR_MINSIZE
+#define MAX_AN SQR_TOOM3_THRESHOLD
+
+#define MORE_SQR_TESTS explore_unlikely_branch
+#include "toom-sqr-shared.h"
+
+void
+explore_unlikely_branch (gmp_randstate_ptr rands)
+{
+  mp_ptr ap, refp, pp, scratch;
+  mp_size_t an;
+  mp_bitcnt_t bit;
+  TMP_DECL;
+  TMP_MARK;
+
+  ap = TMP_ALLOC_LIMBS (MAX_AN);
+  refp = TMP_ALLOC_LIMBS (MAX_AN * 2);
+  pp = 1 + TMP_ALLOC_LIMBS (MAX_AN * 2 + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_toomN_sqr_itch (MAX_AN) + 2);
+
+  for (an = MIN_AN + (MIN_AN & 1); an < MAX_AN; an+=2)
+    {
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      bit = an / 2 * GMP_NUMB_BITS
+	+ gmp_urandomm_ui (rands, an / 2 * GMP_NUMB_BITS - 1);
+
+      mpn_zero (ap, an);
+      mpn_zero (pp, an * 2);
+      pp [an - 1] |= GMP_NUMB_HIGHBIT;
+      pp [bit / GMP_NUMB_BITS] |= CNST_LIMB (1) << (bit % GMP_NUMB_BITS);
+      mpn_sqrtrem (ap, NULL, pp, an);
+      /* We need {ap, an} such that {ap + an/2, an/2} is zero and
+	 the result {pp, 2*an} is such that the sum
+	 {pp, an/2} + {pp + an/2, an/2} gives a carry. */
+      mpn_random2 (pp-1, an * 2 + 2);
+      p_before = pp[-1];
+      p_after = pp[an * 2];
+
+      itch = mpn_toomN_sqr_itch (an);
+      ASSERT_ALWAYS (itch <= mpn_toomN_sqr_itch (MAX_AN));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_toomN_sqr (pp, ap, an, scratch);
+      refmpn_mul (refp, ap, an, ap, an);
+      if (pp[-1] != p_before || pp[an * 2] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, an * 2) != 0)
+	{
+	  printf ("ERROR with bit %lu, an = %d\n",
+		  (unsigned long) bit, (int) an);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[an * 2] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + an * 2, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (pp, an * 2);
+	  mpn_dump (refp, an * 2);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+}
diff --git a/tests/mpn/t-toom22.c b/tests/mpn/t-toom22.c
new file mode 100644
index 0000000..c9beed9
--- /dev/null
+++ b/tests/mpn/t-toom22.c
@@ -0,0 +1,10 @@
+#define mpn_toomMN_mul mpn_toom22_mul
+#define mpn_toomMN_mul_itch mpn_toom22_mul_itch
+#define MIN_AN MIN(MPN_TOOM22_MUL_MINSIZE,4)
+
+#define MIN_BN(an)				\
+  ((an) >= 2*MUL_TOOM22_THRESHOLD		\
+   ? (an) + 2 - MUL_TOOM22_THRESHOLD		\
+   : ((an)+1)/2 + 1 + (an & 1))
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom3-sqr.c b/tests/mpn/t-toom3-sqr.c
new file mode 100644
index 0000000..ccc3b99
--- /dev/null
+++ b/tests/mpn/t-toom3-sqr.c
@@ -0,0 +1,6 @@
+#define mpn_toomN_sqr mpn_toom3_sqr
+#define mpn_toomN_sqr_itch mpn_toom3_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MPN_TOOM3_SQR_MINSIZE)
+#define MAX_AN SQR_TOOM4_THRESHOLD
+
+#include "toom-sqr-shared.h"
diff --git a/tests/mpn/t-toom32.c b/tests/mpn/t-toom32.c
new file mode 100644
index 0000000..e42745d
--- /dev/null
+++ b/tests/mpn/t-toom32.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom32_mul
+#define mpn_toomMN_mul_itch mpn_toom32_mul_itch
+
+#define MIN_AN 6
+#define MIN_BN(an) (((an) + 8) / (size_t) 3)
+#define MAX_BN(an) ((an) - 2)
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom33.c b/tests/mpn/t-toom33.c
new file mode 100644
index 0000000..7de82b2
--- /dev/null
+++ b/tests/mpn/t-toom33.c
@@ -0,0 +1,11 @@
+#define mpn_toomMN_mul mpn_toom33_mul
+#define mpn_toomMN_mul_itch mpn_toom33_mul_itch
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom22_mul with invalid input size. */
+#define MIN_AN MUL_TOOM33_THRESHOLD
+#define MIN_BN(an) (1 + 2*(((an)+2)/(size_t) 3))
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom4-sqr.c b/tests/mpn/t-toom4-sqr.c
new file mode 100644
index 0000000..ca14ab1
--- /dev/null
+++ b/tests/mpn/t-toom4-sqr.c
@@ -0,0 +1,6 @@
+#define mpn_toomN_sqr mpn_toom4_sqr
+#define mpn_toomN_sqr_itch mpn_toom4_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MAX(SQR_TOOM4_THRESHOLD,MPN_TOOM4_SQR_MINSIZE))
+#define MAX_AN SQR_TOOM6_THRESHOLD
+
+#include "toom-sqr-shared.h"
diff --git a/tests/mpn/t-toom42.c b/tests/mpn/t-toom42.c
new file mode 100644
index 0000000..09a4a0c
--- /dev/null
+++ b/tests/mpn/t-toom42.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom42_mul
+#define mpn_toomMN_mul_itch mpn_toom42_mul_itch
+
+#define MIN_AN 10
+#define MIN_BN(an) (((an) + 7) >> 2)
+#define MAX_BN(an) ((2*(an)-5) / (size_t) 3)
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom43.c b/tests/mpn/t-toom43.c
new file mode 100644
index 0000000..224a45b
--- /dev/null
+++ b/tests/mpn/t-toom43.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom43_mul
+#define mpn_toomMN_mul_itch mpn_toom43_mul_itch
+
+#define MIN_AN 25
+#define MIN_BN(an) (1 + 2*(((an)+3) >> 2))
+#define MAX_BN(an) ((an)-3)
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom44.c b/tests/mpn/t-toom44.c
new file mode 100644
index 0000000..6c627e3
--- /dev/null
+++ b/tests/mpn/t-toom44.c
@@ -0,0 +1,11 @@
+#define mpn_toomMN_mul mpn_toom44_mul
+#define mpn_toomMN_mul_itch mpn_toom44_mul_itch
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom22_mul or toom33_mul with invalid input size. */
+#define MIN_AN MUL_TOOM44_THRESHOLD
+#define MIN_BN(an) (1 + 3*(((an)+3)>>2))
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom52.c b/tests/mpn/t-toom52.c
new file mode 100644
index 0000000..d3fb134
--- /dev/null
+++ b/tests/mpn/t-toom52.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom52_mul
+#define mpn_toomMN_mul_itch mpn_toom52_mul_itch
+
+#define MIN_AN 32
+#define MIN_BN(an) (((an) + 9) / (size_t) 5)
+#define MAX_BN(an) (((an) - 3) >> 1)
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom53.c b/tests/mpn/t-toom53.c
new file mode 100644
index 0000000..ddbf177
--- /dev/null
+++ b/tests/mpn/t-toom53.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom53_mul
+#define mpn_toomMN_mul_itch mpn_toom53_mul_itch
+
+#define MIN_AN 17
+#define MIN_BN(an) (1 + 2*(((an) + 4) / (size_t) 5))
+#define MAX_BN(an) ((3*(an) - 11) >> 2)
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom54.c b/tests/mpn/t-toom54.c
new file mode 100644
index 0000000..52a2bee
--- /dev/null
+++ b/tests/mpn/t-toom54.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom54_mul
+#define mpn_toomMN_mul_itch mpn_toom54_mul_itch
+
+#define MIN_AN 31
+#define MIN_BN(an) ((3*(an) + 32) / (size_t) 5)		/* 3/5 */
+#define MAX_BN(an) ((an) - 6)	                        /* 1/1 */
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom6-sqr.c b/tests/mpn/t-toom6-sqr.c
new file mode 100644
index 0000000..67d7a63
--- /dev/null
+++ b/tests/mpn/t-toom6-sqr.c
@@ -0,0 +1,8 @@
+#define mpn_toomN_sqr mpn_toom6_sqr
+#define mpn_toomN_sqr_itch mpn_toom6_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MAX(SQR_TOOM4_THRESHOLD,MAX(SQR_TOOM6_THRESHOLD,MPN_TOOM6_SQR_MINSIZE)))
+#define MAX_AN SQR_TOOM8_THRESHOLD
+
+#define COUNT 250
+
+#include "toom-sqr-shared.h"
diff --git a/tests/mpn/t-toom62.c b/tests/mpn/t-toom62.c
new file mode 100644
index 0000000..1cb2aab
--- /dev/null
+++ b/tests/mpn/t-toom62.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom62_mul
+#define mpn_toomMN_mul_itch mpn_toom62_mul_itch
+
+#define MIN_AN 31
+#define MIN_BN(an) (((an) + 11) / (size_t) 6)
+#define MAX_BN(an) ((2*(an) - 7) / (size_t) 5)
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom63.c b/tests/mpn/t-toom63.c
new file mode 100644
index 0000000..d79165d
--- /dev/null
+++ b/tests/mpn/t-toom63.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom63_mul
+#define mpn_toomMN_mul_itch mpn_toom63_mul_itch
+
+#define MIN_AN 49
+#define MIN_BN(an) (2*(((an) + 23) / (size_t) 6))	/* 2/6 */
+#define MAX_BN(an) ((3*(an) - 23)  / (size_t) 5)	/* 3/5 */
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom6h.c b/tests/mpn/t-toom6h.c
new file mode 100644
index 0000000..5cca9fc
--- /dev/null
+++ b/tests/mpn/t-toom6h.c
@@ -0,0 +1,13 @@
+#define mpn_toomMN_mul mpn_toom6h_mul
+#define mpn_toomMN_mul_itch mpn_toom6h_mul_itch
+
+#define SIZE_LOG 11
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom22_mul, toom33_mul, or toom44_mul with invalid input size. */
+#define MIN_AN MUL_TOOM6H_MIN
+#define MIN_BN(an) (MAX ((an*3)>>3, 46))
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/tests/mpn/t-toom8-sqr.c b/tests/mpn/t-toom8-sqr.c
new file mode 100644
index 0000000..0eee605
--- /dev/null
+++ b/tests/mpn/t-toom8-sqr.c
@@ -0,0 +1,8 @@
+#define mpn_toomN_sqr mpn_toom8_sqr
+#define mpn_toomN_sqr_itch mpn_toom8_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MAX(SQR_TOOM4_THRESHOLD,MAX(SQR_TOOM6_THRESHOLD,MAX(SQR_TOOM8_THRESHOLD,MPN_TOOM8_SQR_MINSIZE))))
+#define MAX_AN SQR_FFT_THRESHOLD
+
+#define COUNT 250
+
+#include "toom-sqr-shared.h"
diff --git a/tests/mpn/t-toom8h.c b/tests/mpn/t-toom8h.c
new file mode 100644
index 0000000..b21344e
--- /dev/null
+++ b/tests/mpn/t-toom8h.c
@@ -0,0 +1,19 @@
+#define mpn_toomMN_mul mpn_toom8h_mul
+#define mpn_toomMN_mul_itch mpn_toom8h_mul_itch
+
+#define SIZE_LOG 11
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom{22,33,44,6h}_mul with invalid input size. */
+#define MIN_AN MUL_TOOM8H_MIN
+
+#define MIN_BN(an)			 \
+(MAX(GMP_NUMB_BITS <=  9*3 ? (an*7)/ 9 : \
+     GMP_NUMB_BITS <= 10*3 ? (an*6)/10 : \
+     GMP_NUMB_BITS <= 11*3 ? (an*5)/11 : \
+     GMP_NUMB_BITS <= 12*3 ? (an*4)/12 : \
+     (an*4)/13, 86) )
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/tests/mpn/toom-shared.h b/tests/mpn/toom-shared.h
new file mode 100644
index 0000000..8188b00
--- /dev/null
+++ b/tests/mpn/toom-shared.h
@@ -0,0 +1,148 @@
+/* Test for various Toom functions.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Main file is expected to define mpn_toomMN_mul,
+ * mpn_toomMN_mul_itch, MIN_AN, MIN_BN(an), MAX_BN(an) and then
+ * include this file. */
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 10
+#endif
+
+#ifndef COUNT
+#define COUNT 2000
+#endif
+
+#define MAX_AN (1L << SIZE_LOG)
+
+#ifndef MAX_BN
+#define MAX_BN(an) (an)
+#endif
+
+/* For general toomMN_mul, we need
+ *
+ * MIN_BN(an) = N + floor(((N-1)*an + M - N)/M)
+ *
+ * MAX_BN(an) = floor(N*(an-1)/(M-1)) - N + 1
+ */
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_AN);
+  bp = TMP_ALLOC_LIMBS (MAX_BN(MAX_AN));
+  refp = TMP_ALLOC_LIMBS (MAX_AN + MAX_BN(MAX_AN));
+  pp = 1+TMP_ALLOC_LIMBS (MAX_AN + MAX_BN(MAX_AN)+2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_toomMN_mul_itch (MAX_AN, MAX_BN(MAX_AN))
+			 + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t an, bn;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_AN; size_min++)
+	;
+
+      /* We generate an in the MIN_AN <= an <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      an = MIN_AN
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_AN);
+      bn = MIN_BN(an)
+	+ gmp_urandomm_ui (rands, MAX_BN(an) + 1 - MIN_BN(an));
+
+      mpn_random2 (ap, an);
+      mpn_random2 (bp, bn);
+      mpn_random2 (pp-1, an + bn + 2);
+      p_before = pp[-1];
+      p_after = pp[an + bn];
+
+      itch = mpn_toomMN_mul_itch (an, bn);
+      ASSERT_ALWAYS (itch <= mpn_toomMN_mul_itch (MAX_AN, MAX_BN(MAX_AN)));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_toomMN_mul (pp, ap, an, bp, bn, scratch);
+      refmpn_mul (refp, ap, an, bp, bn);
+      if (pp[-1] != p_before || pp[an + bn] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, an + bn) != 0)
+	{
+	  printf ("ERROR in test %d, an = %d, bn = %d\n",
+		  test, (int) an, (int) bn);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[an + bn] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + an + bn, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (bp, bn);
+	  mpn_dump (pp, an + bn);
+	  mpn_dump (refp, an + bn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpn/toom-sqr-shared.h b/tests/mpn/toom-sqr-shared.h
new file mode 100644
index 0000000..8bab8e1
--- /dev/null
+++ b/tests/mpn/toom-sqr-shared.h
@@ -0,0 +1,125 @@
+/* Test for various Toom squaring functions.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Main file is expected to define mpn_toomN_mul, mpn_toomN_sqr_itch,
+ * MIN_AN, MAX_AN and then include this file. */
+
+#ifndef COUNT
+#define COUNT 2000
+#endif
+
+#ifdef MORE_SQR_TESTS
+void MORE_SQR_TESTS (gmp_randstate_ptr);
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+
+  if (MAX_AN > MIN_AN) {
+    rands = RANDS;
+
+    ap = TMP_ALLOC_LIMBS (MAX_AN);
+    refp = TMP_ALLOC_LIMBS (MAX_AN * 2);
+    pp = 1 + TMP_ALLOC_LIMBS (MAX_AN * 2 + 2);
+    scratch
+      = 1+TMP_ALLOC_LIMBS (mpn_toomN_sqr_itch (MAX_AN) + 2);
+
+    for (test = 0; test < count; test++)
+      {
+	mp_size_t an;
+	mp_size_t itch;
+	mp_limb_t p_before, p_after, s_before, s_after;
+
+	an = MIN_AN
+	  + gmp_urandomm_ui (rands, MAX_AN - MIN_AN);
+
+	mpn_random2 (ap, an);
+	mpn_random2 (pp-1, an * 2 + 2);
+	p_before = pp[-1];
+	p_after = pp[an * 2];
+
+	itch = mpn_toomN_sqr_itch (an);
+	ASSERT_ALWAYS (itch <= mpn_toomN_sqr_itch (MAX_AN));
+	mpn_random2 (scratch-1, itch+2);
+	s_before = scratch[-1];
+	s_after = scratch[itch];
+
+	mpn_toomN_sqr (pp, ap, an, scratch);
+	refmpn_mul (refp, ap, an, ap, an);
+	if (pp[-1] != p_before || pp[an * 2] != p_after
+	    || scratch[-1] != s_before || scratch[itch] != s_after
+	    || mpn_cmp (refp, pp, an * 2) != 0)
+	  {
+	    printf ("ERROR in test %d, an = %d\n",
+		    test, (int) an);
+	    if (pp[-1] != p_before)
+	      {
+		printf ("before pp:"); mpn_dump (pp -1, 1);
+		printf ("keep:   "); mpn_dump (&p_before, 1);
+	      }
+	    if (pp[an * 2] != p_after)
+	      {
+		printf ("after pp:"); mpn_dump (pp + an * 2, 1);
+		printf ("keep:   "); mpn_dump (&p_after, 1);
+	      }
+	    if (scratch[-1] != s_before)
+	      {
+		printf ("before scratch:"); mpn_dump (scratch-1, 1);
+		printf ("keep:   "); mpn_dump (&s_before, 1);
+	      }
+	    if (scratch[itch] != s_after)
+	      {
+		printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+		printf ("keep:   "); mpn_dump (&s_after, 1);
+	      }
+	    mpn_dump (ap, an);
+	    mpn_dump (pp, an * 2);
+	    mpn_dump (refp, an * 2);
+
+	    abort();
+	  }
+      }
+    TMP_FREE;
+
+#ifdef MORE_SQR_TESTS
+  MORE_SQR_TESTS (rands);
+#endif
+  }
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpq/io.c b/tests/mpq/io.c
new file mode 100644
index 0000000..9516d49
--- /dev/null
+++ b/tests/mpq/io.c
@@ -0,0 +1,136 @@
+/* Test conversion and I/O using mpq_out_str and mpq_inp_str.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define FILENAME  "/tmp/io.tmp"
+
+void
+debug_mp (mpq_t x, int base)
+{
+  mpq_out_str (stdout, base, x); fputc ('\n', stdout);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpq_t  op1, op2;
+  mp_size_t size;
+  int i;
+  int reps = 10000;
+  FILE *fp;
+  int base;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  size_t nread;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpq_init (op1);
+  mpq_init (op2);
+
+  fp = fopen (FILENAME, "w+");
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs) + 2;
+      mpz_errandomb (mpq_numref(op1), rands, size);
+      mpz_errandomb_nonzero (mpq_denref(op1), rands, size);
+      mpq_canonicalize (op1);
+
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpq_neg (op1, op1);
+
+      mpz_urandomb (bs, rands, 16);
+      bsi = mpz_get_ui (bs);
+      base = bsi % 36 + 1;
+      if (base == 1)
+	base = 0;
+
+      rewind (fp);
+      if (mpq_out_str (fp, base, op1) == 0
+	  || putc (' ', fp) == EOF
+	  || fflush (fp) != 0)
+	{
+	  printf ("mpq_out_str write error\n");
+	  abort ();
+	}
+
+      rewind (fp);
+      nread = mpq_inp_str (op2, fp, base);
+      if (nread == 0)
+	{
+	  if (ferror (fp))
+	    printf ("mpq_inp_str stream read error\n");
+	  else
+	    printf ("mpq_inp_str data conversion error\n");
+	  abort ();
+	}
+
+      if (nread != ftell(fp))
+	{
+	  printf ("mpq_inp_str nread doesn't match ftell\n");
+	  printf ("  nread  %lu\n", (unsigned long) nread);
+	  printf ("  ftell  %ld\n", ftell(fp));
+	  abort ();
+	}
+
+      if (mpq_cmp (op1, op2))
+	{
+	  printf ("ERROR\n");
+	  printf ("op1  = "); debug_mp (op1, -16);
+	  printf ("op2  = "); debug_mp (op2, -16);
+	  printf ("base = %d\n", base);
+	  abort ();
+	}
+    }
+
+  fclose (fp);
+
+  unlink (FILENAME);
+
+  mpz_clear (bs);
+  mpq_clear (op1);
+  mpq_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/reuse.c b/tests/mpq/reuse.c
new file mode 100644
index 0000000..b724ffc
--- /dev/null
+++ b/tests/mpq/reuse.c
@@ -0,0 +1,245 @@
+/* Test that routines allow reusing a source variable as destination.
+
+Copyright 1996, 2000-2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMP_LIBGMP_DLL
+
+/* FIXME: When linking to a DLL libgmp, mpq_add etc can't be used as
+   initializers for global variables because they're effectively global
+   variables (function pointers) themselves.  Perhaps calling a test
+   function successively with mpq_add etc would be better.  */
+
+int
+main (void)
+{
+  printf ("Test suppressed for windows DLL\n");
+  exit (0);
+}
+
+
+#else /* ! DLL_EXPORT */
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+void dump_abort (const char *, mpq_t, mpq_t);
+
+typedef void (*dss_func) (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+dss_func dss_funcs[] =
+{
+  mpq_div, mpq_add, mpq_mul, mpq_sub,
+};
+
+const char *dss_func_names[] =
+{
+  "mpq_div", "mpq_add", "mpq_mul", "mpq_sub",
+};
+
+typedef void (*ds_func) (mpq_ptr, mpq_srcptr);
+
+ds_func ds_funcs[] =
+{
+  mpq_abs, mpq_neg,
+};
+
+const char *ds_func_names[] =
+{
+  "mpq_abs", "mpq_neg",
+};
+
+typedef void (*dsi_func) (mpq_ptr, mpq_srcptr, unsigned long int);
+
+dsi_func dsi_funcs[] =
+{
+  mpq_mul_2exp, mpq_div_2exp
+};
+
+const char *dsi_func_names[] =
+{
+  "mpq_mul_2exp", "mpq_div_2exp"
+};
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  int pass, reps = 100;
+  mpq_t in1, in2, out1;
+  unsigned long int randbits, in2i;
+  mpq_t res1, res2;
+  gmp_randstate_ptr  rands;
+
+  tests_start ();
+
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpq_init (in1);
+  mpq_init (in2);
+  mpq_init (out1);
+  mpq_init (res1);
+  mpq_init (res2);
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+      randbits = urandom ();
+
+      if (randbits & 1)
+	{
+	  mpq_clear (in1);
+	  mpq_init (in1);
+	}
+      randbits >>= 1;
+      mpz_errandomb (mpq_numref(in1), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(in1), rands, 512L);
+      if (randbits & 1)
+	mpz_neg (mpq_numref(in1),mpq_numref(in1));
+      randbits >>= 1;
+      mpq_canonicalize (in1);
+
+      if (randbits & 1)
+	{
+	  mpq_clear (in2);
+	  mpq_init (in2);
+	}
+      randbits >>= 1;
+      mpz_errandomb (mpq_numref(in2), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(in2), rands, 512L);
+      if (randbits & 1)
+	mpz_neg (mpq_numref(in2),mpq_numref(in2));
+      randbits >>= 1;
+      mpq_canonicalize (in2);
+
+      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
+	{
+	  /* Don't divide by 0.  */
+	  if (i == 0 && mpq_cmp_ui (in2, 0, 1) == 0)
+	    continue;
+
+	  if (randbits & 1)
+	    {
+	      mpq_clear (res1);
+	      mpq_init (res1);
+	    }
+	  randbits >>= 1;
+
+	  (dss_funcs[i]) (res1, in1, in2);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  mpq_set (out1, in1);
+	  (dss_funcs[i]) (out1, out1, in2);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dss_func_names[i], res1, out1);
+
+	  mpq_set (out1, in2);
+	  (dss_funcs[i]) (out1, in1, out1);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dss_func_names[i], res1, out1);
+
+	  mpq_set (out1, in2);
+	  (dss_funcs[i]) (res1, out1, in2);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  (dss_funcs[i]) (res2, in2, in2);
+	  MPQ_CHECK_FORMAT(res2);
+
+	  (dss_funcs[i]) (out1, out1, out1);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, res2) != 0)
+	    dump_abort (dss_func_names[i], res1, res2);
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dss_func_names[i], res1, out1);
+	}
+
+      for (i = 0; i < sizeof (ds_funcs) / sizeof (ds_func); i++)
+	{
+	  if (randbits & 1)
+	    {
+	      mpq_clear (res1);
+	      mpq_init (res1);
+	    }
+	  randbits >>= 1;
+	  (ds_funcs[i]) (res1, in1);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  mpq_set (out1, in1);
+	  (ds_funcs[i]) (out1, out1);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (ds_func_names[i], res1, out1);
+	}
+
+      in2i = urandom () % 65536;
+      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
+	{
+	  if (randbits & 1)
+	    {
+	      mpq_clear (res1);
+	      mpq_init (res1);
+	    }
+	  randbits >>= 1;
+
+	  (dsi_funcs[i]) (res1, in1, in2i);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  mpq_set (out1, in1);
+	  (dsi_funcs[i]) (out1, out1, in2i);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dsi_func_names[i], res1, out1);
+	}
+
+    }
+
+  mpq_clear (in1);
+  mpq_clear (in2);
+  mpq_clear (out1);
+  mpq_clear (res1);
+  mpq_clear (res2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *name, mpq_t res1, mpq_t res2)
+{
+  printf ("failure in %s:\n", name);
+  mpq_trace ("  res1  ", res1);
+  mpq_trace ("  res2  ", res2);
+  abort ();
+}
+
+#endif /* ! DLL_EXPORT */
diff --git a/tests/mpq/t-aors.c b/tests/mpq/t-aors.c
new file mode 100644
index 0000000..8ee9f93
--- /dev/null
+++ b/tests/mpq/t-aors.c
@@ -0,0 +1,182 @@
+/* Test mpq_add and mpq_sub.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_all (mpq_ptr x, mpq_ptr y, mpq_ptr want_add, mpq_ptr want_sub)
+{
+  mpq_t  got;
+  int    neg_x, neg_y, swap;
+
+  mpq_init (got);
+
+  MPQ_CHECK_FORMAT (want_add);
+  MPQ_CHECK_FORMAT (want_sub);
+  MPQ_CHECK_FORMAT (x);
+  MPQ_CHECK_FORMAT (y);
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      for (neg_x = 0; neg_x <= 1; neg_x++)
+        {
+          for (neg_y = 0; neg_y <= 1; neg_y++)
+            {
+              mpq_add (got, x, y);
+              MPQ_CHECK_FORMAT (got);
+              if (! mpq_equal (got, want_add))
+                {
+                  printf ("mpq_add wrong\n");
+                  mpq_trace ("  x   ", x);
+                  mpq_trace ("  y   ", y);
+                  mpq_trace ("  got ", got);
+                  mpq_trace ("  want", want_add);
+                  abort ();
+                }
+
+              mpq_sub (got, x, y);
+              MPQ_CHECK_FORMAT (got);
+              if (! mpq_equal (got, want_sub))
+                {
+                  printf ("mpq_sub wrong\n");
+                  mpq_trace ("  x   ", x);
+                  mpq_trace ("  y   ", y);
+                  mpq_trace ("  got ", got);
+                  mpq_trace ("  want", want_sub);
+                  abort ();
+                }
+
+
+              mpq_neg (y, y);
+              mpq_swap (want_add, want_sub);
+            }
+
+          mpq_neg (x, x);
+          mpq_swap (want_add, want_sub);
+          mpq_neg (want_add, want_add);
+          mpq_neg (want_sub, want_sub);
+        }
+
+      mpq_swap (x, y);
+      mpq_neg (want_sub, want_sub);
+    }
+
+  mpq_clear (got);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *x;
+    const char  *y;
+    const char  *want_add;
+    const char  *want_sub;
+
+  } data[] = {
+
+    { "0", "0", "0", "0" },
+    { "1", "0", "1", "1" },
+    { "1", "1", "2", "0" },
+
+    { "1/2", "1/2", "1", "0" },
+    { "5/6", "14/15", "53/30", "-1/10" },
+  };
+
+  mpq_t  x, y, want_add, want_sub;
+  int i;
+
+  mpq_init (x);
+  mpq_init (y);
+  mpq_init (want_add);
+  mpq_init (want_sub);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (x, data[i].x, 0);
+      mpq_set_str_or_abort (y, data[i].y, 0);
+      mpq_set_str_or_abort (want_add, data[i].want_add, 0);
+      mpq_set_str_or_abort (want_sub, data[i].want_sub, 0);
+
+      check_all (x, y, want_add, want_sub);
+    }
+
+  mpq_clear (x);
+  mpq_clear (y);
+  mpq_clear (want_add);
+  mpq_clear (want_sub);
+}
+
+
+void
+check_rand (void)
+{
+  mpq_t  x, y, want_add, want_sub;
+  int i;
+  gmp_randstate_ptr  rands = RANDS;
+
+  mpq_init (x);
+  mpq_init (y);
+  mpq_init (want_add);
+  mpq_init (want_sub);
+
+  for (i = 0; i < 500; i++)
+    {
+      mpz_errandomb (mpq_numref(x), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(x), rands, 512L);
+      mpq_canonicalize (x);
+
+      mpz_errandomb (mpq_numref(y), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(y), rands, 512L);
+      mpq_canonicalize (y);
+
+      refmpq_add (want_add, x, y);
+      refmpq_sub (want_sub, x, y);
+
+      check_all (x, y, want_add, want_sub);
+    }
+
+  mpq_clear (x);
+  mpq_clear (y);
+  mpq_clear (want_add);
+  mpq_clear (want_sub);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_rand ();
+
+  tests_end ();
+
+  exit (0);
+}
diff --git a/tests/mpq/t-cmp.c b/tests/mpq/t-cmp.c
new file mode 100644
index 0000000..187db7f
--- /dev/null
+++ b/tests/mpq/t-cmp.c
@@ -0,0 +1,101 @@
+/* Test mpq_cmp.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
+
+int
+ref_mpq_cmp (mpq_t a, mpq_t b)
+{
+  mpz_t ai, bi;
+  int cc;
+
+  mpz_init (ai);
+  mpz_init (bi);
+
+  mpz_mul (ai, NUM (a), DEN (b));
+  mpz_mul (bi, NUM (b), DEN (a));
+  cc = mpz_cmp (ai, bi);
+  mpz_clear (ai);
+  mpz_clear (bi);
+  return cc;
+}
+
+#ifndef SIZE
+#define SIZE 8	/* increasing this lowers the probability of finding an error */
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a, b;
+  mp_size_t size;
+  int reps = 10000;
+  int i;
+  int cc, ccref;
+
+  tests_start ();
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpq_init (a);
+  mpq_init (b);
+
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (a), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (DEN (a), size);
+	}
+      while (mpz_cmp_ui (DEN (a), 0) == 0);
+
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (b), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (DEN (b), size);
+	}
+      while (mpz_cmp_ui (DEN (b), 0) == 0);
+
+      mpq_canonicalize (a);
+      mpq_canonicalize (b);
+
+      ccref = ref_mpq_cmp (a, b);
+      cc = mpq_cmp (a, b);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+    }
+
+  mpq_clear (a);
+  mpq_clear (b);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-cmp_si.c b/tests/mpq/t-cmp_si.c
new file mode 100644
index 0000000..5ffa247
--- /dev/null
+++ b/tests/mpq/t-cmp_si.c
@@ -0,0 +1,117 @@
+/* Test mpq_cmp_si.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define SGN(x)   ((x)<0 ? -1 : (x) != 0)
+
+void
+check_data (void)
+{
+  static const struct {
+    const char     *q;
+    long           n;
+    unsigned long  d;
+    int            want;
+  } data[] = {
+    { "0", 0, 1, 0 },
+    { "0", 0, 123, 0 },
+    { "0", 0, ULONG_MAX, 0 },
+    { "1", 0, 1, 1 },
+    { "1", 0, 123, 1 },
+    { "1", 0, ULONG_MAX, 1 },
+    { "-1", 0, 1, -1 },
+    { "-1", 0, 123, -1 },
+    { "-1", 0, ULONG_MAX, -1 },
+
+    { "123", 123, 1, 0 },
+    { "124", 123, 1, 1 },
+    { "122", 123, 1, -1 },
+
+    { "-123", 123, 1, -1 },
+    { "-124", 123, 1, -1 },
+    { "-122", 123, 1, -1 },
+
+    { "123", -123, 1, 1 },
+    { "124", -123, 1, 1 },
+    { "122", -123, 1, 1 },
+
+    { "-123", -123, 1, 0 },
+    { "-124", -123, 1, -1 },
+    { "-122", -123, 1, 1 },
+
+    { "5/7", 3,4, -1 },
+    { "5/7", -3,4, 1 },
+    { "-5/7", 3,4, -1 },
+    { "-5/7", -3,4, 1 },
+  };
+
+  mpq_t  q;
+  int    i, got;
+
+  mpq_init (q);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (q, data[i].q, 0);
+      MPQ_CHECK_FORMAT (q);
+
+      got = mpq_cmp_si (q, data[i].n, data[i].d);
+      if (SGN(got) != data[i].want)
+        {
+          printf ("mpq_cmp_si wrong\n");
+        error:
+          mpq_trace ("  q", q);
+          printf ("  n=%ld\n", data[i].n);
+          printf ("  d=%lu\n", data[i].d);
+          printf ("  got=%d\n", got);
+          printf ("  want=%d\n", data[i].want);
+          abort ();
+        }
+
+      if (data[i].n == 0)
+        {
+          got = mpq_cmp_si (q, 0L, data[i].d);
+          if (SGN(got) != data[i].want)
+            {
+              printf ("mpq_cmp_si wrong\n");
+              goto error;
+            }
+        }
+    }
+
+  mpq_clear (q);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-cmp_ui.c b/tests/mpq/t-cmp_ui.c
new file mode 100644
index 0000000..51bb2cb
--- /dev/null
+++ b/tests/mpq/t-cmp_ui.c
@@ -0,0 +1,116 @@
+/* Test mpq_cmp_ui.
+
+Copyright 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
+
+int
+ref_mpq_cmp_ui (mpq_t a, unsigned long int bn, unsigned long int bd)
+{
+  mpz_t ai, bi;
+  int cc;
+
+  mpz_init (ai);
+  mpz_init (bi);
+
+  mpz_mul_ui (ai, NUM (a), bd);
+  mpz_mul_ui (bi, DEN (a), bn);
+  cc = mpz_cmp (ai, bi);
+  mpz_clear (ai);
+  mpz_clear (bi);
+  return cc;
+}
+
+#ifndef SIZE
+#define SIZE 8	/* increasing this lowers the probability of finding an error */
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a, b;
+  mp_size_t size;
+  int reps = 10000;
+  int i;
+  int cc, ccref;
+  unsigned long int bn, bd;
+
+  tests_start ();
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpq_init (a);
+  mpq_init (b);
+
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (a), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (DEN (a), size);
+	}
+      while (mpz_cmp_ui (DEN (a), 0) == 0);
+
+      mpz_random2 (NUM (b), (mp_size_t) 1);
+      mpz_mod_ui (NUM (b), NUM (b), ~(unsigned long int) 0);
+      mpz_add_ui (NUM (b), NUM (b), 1);
+
+      mpz_random2 (DEN (b), (mp_size_t) 1);
+      mpz_mod_ui (DEN (b), DEN (b), ~(unsigned long int) 0);
+      mpz_add_ui (DEN (b), DEN (b), 1);
+
+      mpq_canonicalize (a);
+      mpq_canonicalize (b);
+
+      ccref = ref_mpq_cmp_ui (a, 1, 1);
+      cc = mpq_cmp_ui (a, 1, 1);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+
+      ccref = ref_mpq_cmp_ui (a, 0, 1);
+      cc = mpq_cmp_ui (a, 0, 1);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+
+      bn = mpz_get_ui (NUM (b));
+      bd = mpz_get_ui (DEN (b));
+
+      ccref = ref_mpq_cmp_ui (a, bn, bd);
+      cc = mpq_cmp_ui (a, bn, bd);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+    }
+
+  mpq_clear (a);
+  mpq_clear (b);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-cmp_z.c b/tests/mpq/t-cmp_z.c
new file mode 100644
index 0000000..3e66a3c
--- /dev/null
+++ b/tests/mpq/t-cmp_z.c
@@ -0,0 +1,146 @@
+/* Test mpq_cmp_z.
+
+Copyright 1996, 2001, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
+
+int
+ref_mpq_cmp_z (mpq_t a, mpz_t b)
+{
+  mpz_t bi;
+  int cc;
+
+  mpz_init (bi);
+
+  mpz_mul (bi, b, DEN (a));
+  cc = mpz_cmp (NUM (a), bi);
+  mpz_clear (bi);
+  return cc;
+}
+
+#ifndef SIZE
+#define SIZE 8	/* increasing this lowers the probability of finding an error */
+#endif
+
+#ifndef MAXN
+#define MAXN 5	/* increasing this impatcs on total timing */
+#endif
+
+void
+sizes_test (int m)
+{
+  mpq_t a;
+  mpz_t b;
+  int i, j, k, s;
+  int cc, ccref;
+
+  mpq_init (a);
+  mpz_init (b);
+
+  for (i = 0; i <= MAXN ; ++i)
+    {
+      mpz_setbit (DEN (a), i*m); /* \sum_0^i 2^(i*m) */
+      for (j = 0; j <= MAXN; ++j)
+	{
+	  mpz_set_ui (NUM (a), 0);
+	  mpz_setbit (NUM (a), j*m); /* 2^(j*m) */
+	  for (k = 0; k <= MAXN; ++k)
+	    {
+	      mpz_set_ui (b, 0);
+	      mpz_setbit (b, k*m); /* 2^(k*m) */
+	      if (i == 0) /* Denominator is 1, compare the two exponents */
+		ccref = (j>k)-(j<k);
+	      else
+		ccref = j-i > k ? 1 : -1;
+	      for (s = 1; s >= -1; s -= 2)
+		{
+		  cc = mpq_cmp_z (a, b);
+
+		  if (ccref != SGN (cc))
+		    {
+		      fprintf (stderr, "i=%i, j=%i, k=%i, m=%i, s=%i\n; ccref= %i, cc= %i\n", i, j, k, m, s, ccref, cc);
+		      abort ();
+		    }
+
+		  mpq_neg (a, a);
+		  mpz_neg (b, b);
+		  ccref = - ccref;
+		}
+	    }
+	}
+    }
+
+  mpq_clear (a);
+  mpz_clear (b);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a;
+  mpz_t b;
+  mp_size_t size;
+  int reps = 10000;
+  int i;
+  int cc, ccref;
+
+  tests_start ();
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpq_init (a);
+  mpz_init (b);
+
+  for (i = 0; i < reps; i++)
+    {
+      if (i % 8192 == 0)
+	sizes_test (urandom () % (i + 1) + 1);
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (a), size);
+      do
+	{
+	  size = urandom () % (SIZE/2);
+	  mpz_random2 (DEN (a), size);
+	}
+      while (mpz_cmp_ui (DEN (a), 0) == 0);
+
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (b, size);
+
+      mpq_canonicalize (a);
+
+      ccref = ref_mpq_cmp_z (a, b);
+      cc = mpq_cmp_z (a, b);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+    }
+
+  mpq_clear (a);
+  mpz_clear (b);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-equal.c b/tests/mpq/t-equal.c
new file mode 100644
index 0000000..671c530
--- /dev/null
+++ b/tests/mpq/t-equal.c
@@ -0,0 +1,146 @@
+/* Test mpq_equal.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpq_srcptr x, mpq_srcptr y, int want)
+{
+  int  got;
+
+  MPQ_CHECK_FORMAT (x);
+  MPQ_CHECK_FORMAT (y);
+
+  got = mpq_equal (x, y);
+  if ((got != 0) != (want != 0))
+    {
+      printf ("mpq_equal got %d want %d\n", got, want);
+      mpq_trace ("x", x);
+      mpq_trace ("y", y);
+      abort ();
+    }
+}
+
+
+void
+check_all (mpq_ptr x, mpq_ptr y, int want)
+{
+  check_one (x, y, want);
+  check_one (y, x, want);
+
+  mpq_neg (x, x);
+  mpq_neg (y, y);
+
+  check_one (x, y, want);
+  check_one (y, x, want);
+}
+
+
+#define SET4Z(z, size,l3,l2,l1,l0) \
+  SIZ(z) = size; PTR(z)[3] = l3; PTR(z)[2] = l2; PTR(z)[1] = l1; PTR(z)[0] = l0
+
+#define SET4(q, nsize,n3,n2,n1,n0, dsize,d3,d2,d1,d0)   \
+  SET4Z (mpq_numref(q), nsize,n3,n2,n1,n0);             \
+  SET4Z (mpq_denref(q), dsize,d3,d2,d1,d0)
+
+
+/* Exercise various combinations of same and slightly different values. */
+
+void
+check_various (void)
+{
+  mpq_t  x, y;
+
+  mpq_init (x);
+  mpq_init (y);
+
+  mpz_realloc (mpq_numref(x), (mp_size_t) 20);
+  mpz_realloc (mpq_denref(x), (mp_size_t) 20);
+  mpz_realloc (mpq_numref(y), (mp_size_t) 20);
+  mpz_realloc (mpq_denref(y), (mp_size_t) 20);
+
+  /* 0 == 0 */
+  SET4 (x, 0,13,12,11,10, 1,23,22,21,1);
+  SET4 (y, 0,33,32,31,30, 1,43,42,41,1);
+  check_all (x, y, 1);
+
+  /* 83/99 == 83/99 */
+  SET4 (x, 1,13,12,11,83, 1,23,22,21,99);
+  SET4 (y, 1,33,32,31,83, 1,43,42,41,99);
+  check_all (x, y, 1);
+
+  /* 1:2:3:4/5:6:7 == 1:2:3:4/5:6:7 */
+  SET4 (x, 4,1,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 1);
+
+  /* various individual changes making != */
+  SET4 (x, 4,1,2,3,667, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,666,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,666,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+#if GMP_NUMB_BITS != 62
+  SET4 (x, 4,667,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+#endif
+  SET4 (x, 4,1,2,3,4, 3,88,5,6,667);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,3,4, 3,88,5,667,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,3,4, 3,88,666,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, -4,1,2,3,4, 3,88,5,6,7);
+  SET4 (y,  4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 1,1,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 2,99,5,6,7);
+  check_all (x, y, 0);
+
+  mpq_clear (x);
+  mpq_clear (y);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-get_d.c b/tests/mpq/t-get_d.c
new file mode 100644
index 0000000..98d6a5f
--- /dev/null
+++ b/tests/mpq/t-get_d.c
@@ -0,0 +1,294 @@
+/* Test mpq_get_d and mpq_set_d
+
+Copyright 1991, 1993, 1994, 1996, 2000-2003, 2012, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 8
+#endif
+
+/* VAX D floats only have an 8 bit signed exponent, so anything 2^128 or
+   bigger will overflow, that being 4 limbs. */
+#if defined (__vax) || defined (__vax__) && SIZE > 4
+#undef SIZE
+#define SIZE 4
+#define EPSIZE 3
+#else
+#define EPSIZE SIZE
+#endif
+
+void dump (mpq_t);
+
+void
+check_monotonic (int argc, char **argv)
+{
+  mpq_t a;
+  mp_size_t size;
+  int reps = 100;
+  int i, j;
+  double last_d, new_d;
+  mpq_t qlast_d, qnew_d;
+  mpq_t eps;
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  /* The idea here is to test the monotonousness of mpq_get_d by adding
+     numbers to the numerator and denominator.  */
+
+  mpq_init (a);
+  mpq_init (eps);
+  mpq_init (qlast_d);
+  mpq_init (qnew_d);
+
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (mpq_numref (a), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (mpq_denref (a), size);
+	}
+      while (mpz_cmp_ui (mpq_denref (a), 0) == 0);
+
+      mpq_canonicalize (a);
+
+      last_d = mpq_get_d (a);
+      mpq_set_d (qlast_d, last_d);
+      for (j = 0; j < 10; j++)
+	{
+	  size = urandom () % EPSIZE + 1;
+	  mpz_random2 (mpq_numref (eps), size);
+	  size = urandom () % EPSIZE + 1;
+	  mpz_random2 (mpq_denref (eps), size);
+	  mpq_canonicalize (eps);
+
+	  mpq_add (a, a, eps);
+	  mpq_canonicalize (a);
+	  new_d = mpq_get_d (a);
+	  if (last_d > new_d)
+	    {
+	      printf ("\nERROR (test %d/%d): bad mpq_get_d results\n", i, j);
+	      printf ("last: %.16g\n", last_d);
+	      printf (" new: %.16g\n", new_d); dump (a);
+	      abort ();
+	    }
+	  mpq_set_d (qnew_d, new_d);
+	  MPQ_CHECK_FORMAT (qnew_d);
+	  if (mpq_cmp (qlast_d, qnew_d) > 0)
+	    {
+	      printf ("ERROR (test %d/%d): bad mpq_set_d results\n", i, j);
+	      printf ("last: %.16g\n", last_d); dump (qlast_d);
+	      printf (" new: %.16g\n", new_d); dump (qnew_d);
+	      abort ();
+	    }
+	  last_d = new_d;
+	  mpq_set (qlast_d, qnew_d);
+	}
+    }
+
+  mpq_clear (a);
+  mpq_clear (eps);
+  mpq_clear (qlast_d);
+  mpq_clear (qnew_d);
+}
+
+double
+my_ldexp (double d, int e)
+{
+  for (;;)
+    {
+      if (e > 0)
+	{
+	  if (e >= 16)
+	    {
+	      d *= 65536.0;
+	      e -= 16;
+	    }
+	  else
+	    {
+	      d *= 2.0;
+	      e -= 1;
+	    }
+	}
+      else if (e < 0)
+	{
+
+	  if (e <= -16)
+	    {
+	      d /= 65536.0;
+	      e += 16;
+	    }
+	  else
+	    {
+	      d /= 2.0;
+	      e += 1;
+	    }
+	}
+      else
+	return d;
+    }
+}
+
+#define MAXEXP 500
+
+#if defined (__vax) || defined (__vax__)
+#undef MAXEXP
+#define MAXEXP 30
+#endif
+
+void
+check_random (int argc, char **argv)
+{
+  gmp_randstate_ptr rands = RANDS;
+
+  double d;
+  mpq_t q;
+  mpz_t a, t;
+  int exp;
+
+  int test, reps = 100000;
+
+  if (argc == 2)
+     reps = 100 * atoi (argv[1]);
+
+  mpq_init (q);
+  mpz_init (a);
+  mpz_init (t);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_rrandomb (a, rands, 53);
+      mpz_urandomb (t, rands, 32);
+      exp = mpz_get_ui (t) % (2*MAXEXP) - MAXEXP;
+
+      d = my_ldexp (mpz_get_d (a), exp);
+      mpq_set_d (q, d);
+      /* Check that n/d = a * 2^exp, or
+	 d*a 2^{exp} = n */
+      mpz_mul (t, a, mpq_denref (q));
+      if (exp > 0)
+	mpz_mul_2exp (t, t, exp);
+      else
+	{
+	  if (!mpz_divisible_2exp_p (t, -exp))
+	    goto fail;
+	  mpz_div_2exp (t, t, -exp);
+	}
+      if (mpz_cmp (t, mpq_numref (q)) != 0)
+	{
+	fail:
+	  printf ("ERROR (check_random test %d): bad mpq_set_d results\n", test);
+	  printf ("%.16g\n", d);
+	  gmp_printf ("%Qd\n", q);
+	  abort ();
+	}
+    }
+  mpq_clear (q);
+  mpz_clear (t);
+  mpz_clear (a);
+}
+
+void
+dump (mpq_t x)
+{
+  mpz_out_str (stdout, 10, mpq_numref (x));
+  printf ("/");
+  mpz_out_str (stdout, 10, mpq_denref (x));
+  printf ("\n");
+}
+
+/* Check various values 2^n and 1/2^n. */
+void
+check_onebit (void)
+{
+  static const long data[] = {
+    -3*GMP_NUMB_BITS-1, -3*GMP_NUMB_BITS, -3*GMP_NUMB_BITS+1,
+    -2*GMP_NUMB_BITS-1, -2*GMP_NUMB_BITS, -2*GMP_NUMB_BITS+1,
+    -GMP_NUMB_BITS-1, -GMP_NUMB_BITS, -GMP_NUMB_BITS+1,
+    -5, -2, -1, 0, 1, 2, 5,
+    GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
+    2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
+    3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
+  };
+
+  int     i, neg;
+  long    exp, l;
+  mpq_t   q;
+  double  got, want;
+
+  mpq_init (q);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      exp = data[i];
+
+      mpq_set_ui (q, 1L, 1L);
+      if (exp >= 0)
+	mpq_mul_2exp (q, q, exp);
+      else
+	mpq_div_2exp (q, q, -exp);
+
+      want = 1.0;
+      for (l = 0; l < exp; l++)
+	want *= 2.0;
+      for (l = 0; l > exp; l--)
+	want /= 2.0;
+
+      for (neg = 0; neg <= 1; neg++)
+	{
+	  if (neg)
+	    {
+	      mpq_neg (q, q);
+	      want = -want;
+	    }
+
+	  got = mpq_get_d (q);
+
+	  if (got != want)
+	    {
+	      printf    ("mpq_get_d wrong on %s2**%ld\n", neg ? "-" : "", exp);
+	      mpq_trace ("   q    ", q);
+	      d_trace   ("   want ", want);
+	      d_trace   ("   got  ", got);
+	      abort();
+	    }
+	}
+    }
+  mpq_clear (q);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_onebit ();
+  check_monotonic (argc, argv);
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-get_str.c b/tests/mpq/t-get_str.c
new file mode 100644
index 0000000..e586521
--- /dev/null
+++ b/tests/mpq/t-get_str.c
@@ -0,0 +1,142 @@
+/* Test mpq_get_str.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpq_srcptr q, int base, const char *want)
+{
+  char    *str, *ret;
+  size_t  str_alloc;
+
+  MPQ_CHECK_FORMAT (q);
+  mp_trace_base = base;
+
+  str_alloc =
+    mpz_sizeinbase (mpq_numref(q), ABS(base)) +
+    mpz_sizeinbase (mpq_denref(q), ABS(base)) + 3;
+
+  str = mpq_get_str (NULL, base, q);
+  if (strlen(str)+1 > str_alloc)
+    {
+      printf ("mpq_get_str size bigger than should be (passing NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  size %lu \"%s\"\n", (unsigned long)  strlen(str)+1, str);
+      printf ("  want size %lu\n", (unsigned long) str_alloc);
+      abort ();
+    }
+  if (strcmp (str, want) != 0)
+    {
+      printf ("mpq_get_str wrong (passing NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  \"%s\"\n", str);
+      printf ("  want \"%s\"\n", want);
+      mpq_trace ("  q", q);
+      abort ();
+    }
+  (*__gmp_free_func) (str, strlen (str) + 1);
+
+  str = (char *) (*__gmp_allocate_func) (str_alloc);
+
+  ret = mpq_get_str (str, base, q);
+  if (str != ret)
+    {
+      printf ("mpq_get_str wrong return value (passing non-NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  %p\n", (void *) ret);
+      printf ("  want %p\n", (void *) str);
+      abort ();
+    }
+  if (strcmp (str, want) != 0)
+    {
+      printf ("mpq_get_str wrong (passing non-NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  \"%s\"\n", str);
+      printf ("  want \"%s\"\n", want);
+      abort ();
+    }
+  (*__gmp_free_func) (str, str_alloc);
+}
+
+
+void
+check_all (mpq_srcptr q, int base, const char *want)
+{
+  char  *s;
+
+  check_one (q, base, want);
+
+  s = __gmp_allocate_strdup (want);
+  strtoupper (s);
+  check_one (q, -base, s);
+  (*__gmp_free_func) (s, strlen(s)+1);
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    int         base;
+    const char  *num;
+    const char  *den;
+    const char  *want;
+  } data[] = {
+    { 10, "0", "1", "0" },
+    { 10, "1", "1", "1" },
+
+    { 16, "ffffffff", "1", "ffffffff" },
+    { 16, "ffffffffffffffff", "1", "ffffffffffffffff" },
+
+    { 16, "1", "ffffffff", "1/ffffffff" },
+    { 16, "1", "ffffffffffffffff", "1/ffffffffffffffff" },
+    { 16, "1", "10000000000000003", "1/10000000000000003" },
+
+    { 10, "12345678901234567890", "9876543210987654323",
+      "12345678901234567890/9876543210987654323" },
+  };
+
+  mpq_t  q;
+  int    i;
+
+  mpq_init (q);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (mpq_numref(q), data[i].num, data[i].base);
+      mpz_set_str_or_abort (mpq_denref(q), data[i].den, data[i].base);
+      check_all (q, data[i].base, data[i].want);
+    }
+  mpq_clear (q);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-inp_str.c b/tests/mpq/t-inp_str.c
new file mode 100644
index 0000000..5964054
--- /dev/null
+++ b/tests/mpq/t-inp_str.c
@@ -0,0 +1,171 @@
+/* Test mpq_inp_str.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>   /* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define FILENAME  "/tmp/t-inp_str.tmp"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *inp;
+    int         base;
+    const char  *want;
+    int         want_nread;
+
+  } data[] = {
+
+    { "0",   10, "0", 1 },
+    { "0/1", 10, "0", 3 },
+
+    { "0/",   10, "0", 0 },
+    { "/123", 10, "0", 0 },
+    { "blah", 10, "0", 0 },
+    { "123/blah", 10, "0", 0 },
+    { "5 /8", 10, "5", 1 },
+    { "5/ 8", 10, "0", 0 },
+
+    {  "ff", 16,  "255", 2 },
+    { "-ff", 16, "-255", 3 },
+    {  "FF", 16,  "255", 2 },
+    { "-FF", 16, "-255", 3 },
+
+    { "z", 36, "35", 1 },
+    { "Z", 36, "35", 1 },
+
+    {  "0x0",    0,   "0", 3 },
+    {  "0x10",   0,  "16", 4 },
+    { "-0x0",    0,   "0", 4 },
+    { "-0x10",   0, "-16", 5 },
+    { "-0x10/5", 0, "-16/5", 7 },
+
+    {  "00",   0,  "0", 2 },
+    {  "010",  0,  "8", 3 },
+    { "-00",   0,  "0", 3 },
+    { "-010",  0, "-8", 4 },
+  };
+
+  mpq_t  got, want;
+  long   ftell_nread;
+  int    i, post, j, got_nread;
+  FILE   *fp;
+
+  mpq_init (got);
+  mpq_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (post = 0; post <= 2; post++)
+	{
+	  mpq_set_str_or_abort (want, data[i].want, 0);
+	  MPQ_CHECK_FORMAT (want);
+
+	  fp = fopen (FILENAME, "w+");
+	  ASSERT_ALWAYS (fp != NULL);
+	  fputs (data[i].inp, fp);
+	  for (j = 0; j < post; j++)
+	    putc (' ', fp);
+	  fflush (fp);
+	  ASSERT_ALWAYS (! ferror(fp));
+
+	  rewind (fp);
+	  got_nread = mpq_inp_str (got, fp, data[i].base);
+
+	  if (got_nread != 0)
+	    {
+	      ftell_nread = ftell (fp);
+	      if (got_nread != ftell_nread)
+		{
+		  printf ("mpq_inp_str nread wrong\n");
+		  printf ("  inp          \"%s\"\n", data[i].inp);
+		  printf ("  base         %d\n", data[i].base);
+		  printf ("  got_nread    %d\n", got_nread);
+		  printf ("  ftell_nread  %ld\n", ftell_nread);
+		  abort ();
+		}
+	    }
+
+	  if (post == 0 && data[i].want_nread == strlen(data[i].inp))
+	    {
+	      int  c = getc(fp);
+	      if (c != EOF)
+		{
+		  printf ("mpq_inp_str didn't read to EOF\n");
+		  printf ("  inp         \"%s\"\n", data[i].inp);
+		  printf ("  base        %d\n", data[i].base);
+		  printf ("  c '%c' %#x\n", c, c);
+		  abort ();
+		}
+	    }
+
+	  if (got_nread != data[i].want_nread)
+	    {
+	      printf ("mpq_inp_str nread wrong\n");
+	      printf ("  inp         \"%s\"\n", data[i].inp);
+	      printf ("  base        %d\n", data[i].base);
+	      printf ("  got_nread   %d\n", got_nread);
+	      printf ("  want_nread  %d\n", data[i].want_nread);
+	      abort ();
+	    }
+
+	  MPQ_CHECK_FORMAT (got);
+
+	  if (! mpq_equal (got, want))
+	    {
+	      printf ("mpq_inp_str wrong result\n");
+	      printf ("  inp   \"%s\"\n", data[i].inp);
+	      printf ("  base  %d\n", data[i].base);
+	      mpq_trace ("  got ",  got);
+	      mpq_trace ("  want", want);
+	      abort ();
+	    }
+
+	  ASSERT_ALWAYS (fclose (fp) == 0);
+	}
+    }
+
+  mpq_clear (got);
+  mpq_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  unlink (FILENAME);
+  tests_end ();
+
+  exit (0);
+}
diff --git a/tests/mpq/t-inv.c b/tests/mpq/t-inv.c
new file mode 100644
index 0000000..87ba8d4
--- /dev/null
+++ b/tests/mpq/t-inv.c
@@ -0,0 +1,60 @@
+/* Test mpq_inv (and set/get_num/den).
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a, b;
+  mpz_t m, n;
+  const char* s = "-420000000000000000000000";
+
+  tests_start ();
+
+  mpq_inits (a, b, (mpq_ptr)0);
+  mpz_inits (m, n, (mpz_ptr)0);
+
+  mpz_set_ui (m, 13);
+  mpq_set_den (a, m);
+  mpz_set_str (m, s, 0);
+  mpq_set_num (a, m);
+  MPQ_CHECK_FORMAT (a);
+  mpq_inv (b, a);
+  MPQ_CHECK_FORMAT (b);
+  mpq_get_num (n, b);
+  ASSERT_ALWAYS (mpz_cmp_si (n, -13) == 0);
+  mpq_neg (b, b);
+  mpq_inv (a, b);
+  MPQ_CHECK_FORMAT (a);
+  mpq_inv (b, b);
+  MPQ_CHECK_FORMAT (b);
+  mpq_get_den (n, b);
+  ASSERT_ALWAYS (mpz_cmp_ui (n, 13) == 0);
+  mpq_get_num (n, a);
+  mpz_add (n, n, m);
+  ASSERT_ALWAYS (mpz_sgn (n) == 0);
+
+  mpq_clears (a, b, (mpq_ptr)0);
+  mpz_clears (m, n, (mpz_ptr)0);
+
+  tests_end ();
+  return 0;
+}
diff --git a/tests/mpq/t-md_2exp.c b/tests/mpq/t-md_2exp.c
new file mode 100644
index 0000000..2bffce9
--- /dev/null
+++ b/tests/mpq/t-md_2exp.c
@@ -0,0 +1,244 @@
+/* Test mpq_mul_2exp and mpq_div_2exp.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+struct pair_t {
+  const char     *num;
+  const char     *den;
+};
+
+void
+check_random ()
+{
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long arg_size, size_range;
+  mpq_t q, r;
+  int i;
+  mp_bitcnt_t shift;
+  int reps = 10000;
+
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpq_init (q);
+  mpq_init (r);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 11 + 2; /* 0..4096 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      arg_size = mpz_get_ui (bs);
+      mpz_rrandomb (mpq_numref (q), rands, arg_size);
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  arg_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mpq_denref (q), rands, arg_size);
+	}
+      while (mpz_sgn (mpq_denref (q)) == 0);
+
+      /* We now have a random rational in q, albeit an unnormalised one.  The
+	 lack of normalisation should not matter here, so let's save the time a
+	 gcd would require.  */
+
+      mpz_urandomb (bs, rands, 32);
+      shift = mpz_get_ui (bs) % 4096;
+
+      mpq_mul_2exp (r, q, shift);
+
+      if (mpq_cmp (r, q) < 0)
+	{
+	  printf ("mpq_mul_2exp wrong on random\n");
+	  abort ();
+	}
+
+      mpq_div_2exp (r, r, shift);
+
+      if (mpq_cmp (r, q) != 0)
+	{
+	  printf ("mpq_mul_2exp or mpq_div_2exp wrong on random\n");
+	  abort ();
+	}
+    }
+  mpq_clear (q);
+  mpq_clear (r);
+  mpz_clear (bs);
+}
+
+int
+main (int argc, char **argv)
+{
+  static const struct {
+    struct pair_t  left;
+    unsigned long  n;
+    struct pair_t  right;
+
+  } data[] = {
+    { {"0","1"}, 0, {"0","1"} },
+    { {"0","1"}, 1, {"0","1"} },
+    { {"0","1"}, 2, {"0","1"} },
+
+    { {"1","1"}, 0, {"1","1"} },
+    { {"1","1"}, 1, {"2","1"} },
+    { {"1","1"}, 2, {"4","1"} },
+    { {"1","1"}, 3, {"8","1"} },
+
+    { {"1","1"}, 31, {"0x80000000","1"} },
+    { {"1","1"}, 32, {"0x100000000","1"} },
+    { {"1","1"}, 33, {"0x200000000","1"} },
+    { {"1","1"}, 63, {"0x8000000000000000","1"} },
+    { {"1","1"}, 64, {"0x10000000000000000","1"} },
+    { {"1","1"}, 65, {"0x20000000000000000","1"} },
+    { {"1","1"}, 95, {"0x800000000000000000000000","1"} },
+    { {"1","1"}, 96, {"0x1000000000000000000000000","1"} },
+    { {"1","1"}, 97, {"0x2000000000000000000000000","1"} },
+    { {"1","1"}, 127, {"0x80000000000000000000000000000000","1"} },
+    { {"1","1"}, 128, {"0x100000000000000000000000000000000","1"} },
+    { {"1","1"}, 129, {"0x200000000000000000000000000000000","1"} },
+
+    { {"1","2"}, 31, {"0x40000000","1"} },
+    { {"1","2"}, 32, {"0x80000000","1"} },
+    { {"1","2"}, 33, {"0x100000000","1"} },
+    { {"1","2"}, 63, {"0x4000000000000000","1"} },
+    { {"1","2"}, 64, {"0x8000000000000000","1"} },
+    { {"1","2"}, 65, {"0x10000000000000000","1"} },
+    { {"1","2"}, 95, {"0x400000000000000000000000","1"} },
+    { {"1","2"}, 96, {"0x800000000000000000000000","1"} },
+    { {"1","2"}, 97, {"0x1000000000000000000000000","1"} },
+    { {"1","2"}, 127, {"0x40000000000000000000000000000000","1"} },
+    { {"1","2"}, 128, {"0x80000000000000000000000000000000","1"} },
+    { {"1","2"}, 129, {"0x100000000000000000000000000000000","1"} },
+
+    { {"1","0x80000000"}, 30, {"1","2"} },
+    { {"1","0x80000000"}, 31, {"1","1"} },
+    { {"1","0x80000000"}, 32, {"2","1"} },
+    { {"1","0x80000000"}, 33, {"4","1"} },
+    { {"1","0x80000000"}, 62, {"0x80000000","1"} },
+    { {"1","0x80000000"}, 63, {"0x100000000","1"} },
+    { {"1","0x80000000"}, 64, {"0x200000000","1"} },
+    { {"1","0x80000000"}, 94, {"0x8000000000000000","1"} },
+    { {"1","0x80000000"}, 95, {"0x10000000000000000","1"} },
+    { {"1","0x80000000"}, 96, {"0x20000000000000000","1"} },
+    { {"1","0x80000000"}, 126, {"0x800000000000000000000000","1"} },
+    { {"1","0x80000000"}, 127, {"0x1000000000000000000000000","1"} },
+    { {"1","0x80000000"}, 128, {"0x2000000000000000000000000","1"} },
+
+    { {"1","0x100000000"}, 1, {"1","0x80000000"} },
+    { {"1","0x100000000"}, 2, {"1","0x40000000"} },
+    { {"1","0x100000000"}, 3, {"1","0x20000000"} },
+
+    { {"1","0x10000000000000000"}, 1, {"1","0x8000000000000000"} },
+    { {"1","0x10000000000000000"}, 2, {"1","0x4000000000000000"} },
+    { {"1","0x10000000000000000"}, 3, {"1","0x2000000000000000"} },
+  };
+
+  void (*fun) (mpq_ptr, mpq_srcptr, unsigned long);
+  const struct pair_t  *p_start, *p_want;
+  const char  *name;
+  mpq_t    sep, got, want;
+  mpq_ptr  q;
+  int      i, muldiv, sign, overlap;
+
+  tests_start ();
+
+  mpq_init (sep);
+  mpq_init (got);
+  mpq_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (muldiv = 0; muldiv < 2; muldiv++)
+        {
+          if (muldiv == 0)
+            {
+              fun = mpq_mul_2exp;
+              name = "mpq_mul_2exp";
+              p_start = &data[i].left;
+              p_want = &data[i].right;
+            }
+          else
+            {
+              fun = mpq_div_2exp;
+              name = "mpq_div_2exp";
+              p_start = &data[i].right;
+              p_want = &data[i].left;
+            }
+
+          for (sign = 0; sign <= 1; sign++)
+            {
+              mpz_set_str_or_abort (mpq_numref(want), p_want->num, 0);
+              mpz_set_str_or_abort (mpq_denref(want), p_want->den, 0);
+              if (sign)
+                mpq_neg (want, want);
+
+              for (overlap = 0; overlap <= 1; overlap++)
+                {
+                  q = overlap ? got : sep;
+
+                  /* initial garbage in "got" */
+                  mpq_set_ui (got, 123L, 456L);
+
+                  mpz_set_str_or_abort (mpq_numref(q), p_start->num, 0);
+                  mpz_set_str_or_abort (mpq_denref(q), p_start->den, 0);
+                  if (sign)
+                    mpq_neg (q, q);
+
+                  (*fun) (got, q, data[i].n);
+                  MPQ_CHECK_FORMAT (got);
+
+                  if (! mpq_equal (got, want))
+                    {
+                      printf ("%s wrong at data[%d], sign %d, overlap %d\n",
+                              name, i, sign, overlap);
+                      printf ("   num \"%s\"\n", p_start->num);
+                      printf ("   den \"%s\"\n", p_start->den);
+                      printf ("   n   %lu\n", data[i].n);
+
+                      printf ("   got  ");
+                      mpq_out_str (stdout, 16, got);
+                      printf (" (hex)\n");
+
+                      printf ("   want ");
+                      mpq_out_str (stdout, 16, want);
+                      printf (" (hex)\n");
+
+                      abort ();
+                    }
+                }
+            }
+        }
+    }
+
+  check_random ();
+
+  mpq_clear (sep);
+  mpq_clear (got);
+  mpq_clear (want);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpq/t-set_f.c b/tests/mpq/t-set_f.c
new file mode 100644
index 0000000..e92e3aa
--- /dev/null
+++ b/tests/mpq/t-set_f.c
@@ -0,0 +1,169 @@
+/* Test mpq_set_f.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+#if GMP_NAIL_BITS == 0
+  static const struct {
+    int         f_base;
+    const char  *f;
+    int         z_base;
+    const char  *want_num;
+    const char  *want_den;
+
+  } data[] = {
+
+    { -2, "0",    16, "0", "1" },
+    { -2, "1",    16, "1", "1" },
+    { -2, "1@1",  16, "2", "1" },
+    { -2, "1@2",  16, "4", "1" },
+    { -2, "1@3",  16, "8", "1" },
+
+    { -2, "1@30", 16,  "40000000", "1" },
+    { -2, "1@31", 16,  "80000000", "1" },
+    { -2, "1@32", 16, "100000000", "1" },
+    { -2, "1@33", 16, "200000000", "1" },
+    { -2, "1@34", 16, "400000000", "1" },
+
+    { -2, "1@62", 16,  "4000000000000000", "1" },
+    { -2, "1@63", 16,  "8000000000000000", "1" },
+    { -2, "1@64", 16, "10000000000000000", "1" },
+    { -2, "1@65", 16, "20000000000000000", "1" },
+    { -2, "1@66", 16, "40000000000000000", "1" },
+
+    { -2, "1@126", 16,  "40000000000000000000000000000000", "1" },
+    { -2, "1@127", 16,  "80000000000000000000000000000000", "1" },
+    { -2, "1@128", 16, "100000000000000000000000000000000", "1" },
+    { -2, "1@129", 16, "200000000000000000000000000000000", "1" },
+    { -2, "1@130", 16, "400000000000000000000000000000000", "1" },
+
+    { -2, "1@-1",  16, "1", "2" },
+    { -2, "1@-2",  16, "1", "4" },
+    { -2, "1@-3",  16, "1", "8" },
+
+    { -2, "1@-30", 16, "1",  "40000000" },
+    { -2, "1@-31", 16, "1",  "80000000" },
+    { -2, "1@-32", 16, "1", "100000000" },
+    { -2, "1@-33", 16, "1", "200000000" },
+    { -2, "1@-34", 16, "1", "400000000" },
+
+    { -2, "1@-62", 16, "1",  "4000000000000000" },
+    { -2, "1@-63", 16, "1",  "8000000000000000" },
+    { -2, "1@-64", 16, "1", "10000000000000000" },
+    { -2, "1@-65", 16, "1", "20000000000000000" },
+    { -2, "1@-66", 16, "1", "40000000000000000" },
+
+    { -2, "1@-126", 16, "1",  "40000000000000000000000000000000" },
+    { -2, "1@-127", 16, "1",  "80000000000000000000000000000000" },
+    { -2, "1@-128", 16, "1", "100000000000000000000000000000000" },
+    { -2, "1@-129", 16, "1", "200000000000000000000000000000000" },
+    { -2, "1@-130", 16, "1", "400000000000000000000000000000000" },
+
+    { -2, "1@-30", 16, "1",  "40000000" },
+    { -2, "1@-31", 16, "1",  "80000000" },
+    { -2, "1@-32", 16, "1", "100000000" },
+    { -2, "1@-33", 16, "1", "200000000" },
+    { -2, "1@-34", 16, "1", "400000000" },
+
+    { -2, "11@-62", 16, "3",  "4000000000000000" },
+    { -2, "11@-63", 16, "3",  "8000000000000000" },
+    { -2, "11@-64", 16, "3", "10000000000000000" },
+    { -2, "11@-65", 16, "3", "20000000000000000" },
+    { -2, "11@-66", 16, "3", "40000000000000000" },
+
+    { 16, "80000000.00000001", 16, "8000000000000001", "100000000" },
+    { 16, "80000000.00000008", 16, "1000000000000001",  "20000000" },
+    { 16, "80000000.8",        16, "100000001", "2" },
+
+  };
+
+  mpf_t  f;
+  mpq_t  got;
+  mpz_t  want_num, want_den;
+  int    i, neg;
+
+  tests_start ();
+
+  mpf_init2 (f, 1024L);
+  mpq_init (got);
+  mpz_init (want_num);
+  mpz_init (want_den);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (neg = 0; neg <= 1; neg++)
+        {
+          mpf_set_str_or_abort (f, data[i].f, data[i].f_base);
+          mpz_set_str_or_abort (want_num, data[i].want_num, data[i].z_base);
+          mpz_set_str_or_abort (want_den, data[i].want_den, data[i].z_base);
+
+          if (neg)
+            {
+              mpf_neg (f, f);
+              mpz_neg (want_num, want_num);
+            }
+
+          mpq_set_f (got, f);
+          MPQ_CHECK_FORMAT (got);
+
+          if (mpz_cmp (mpq_numref(got), want_num) != 0
+              || mpz_cmp (mpq_denref(got), want_den) != 0)
+            {
+              printf ("wrong at data[%d]\n", i);
+              printf ("   f_base %d, z_base %d\n",
+                      data[i].f_base, data[i].z_base);
+
+              printf ("   f \"%s\" hex ", data[i].f);
+              mpf_out_str (stdout, 16, 0, f);
+              printf ("\n");
+
+              printf ("   want num 0x");
+              mpz_out_str (stdout, 16, want_num);
+              printf ("\n");
+              printf ("   want den 0x");
+              mpz_out_str (stdout, 16, want_den);
+              printf ("\n");
+
+              printf ("   got num 0x");
+              mpz_out_str (stdout, 16, mpq_numref(got));
+              printf ("\n");
+              printf ("   got den 0x");
+              mpz_out_str (stdout, 16, mpq_denref(got));
+              printf ("\n");
+
+              abort ();
+            }
+        }
+    }
+
+  mpf_clear (f);
+  mpq_clear (got);
+  mpz_clear (want_num);
+  mpz_clear (want_den);
+
+  tests_end ();
+#endif
+  exit (0);
+}
diff --git a/tests/mpq/t-set_str.c b/tests/mpq/t-set_str.c
new file mode 100644
index 0000000..1f5ca8b
--- /dev/null
+++ b/tests/mpq/t-set_str.c
@@ -0,0 +1,102 @@
+/* Test mpq_set_str.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpq_srcptr want, int base, const char *str)
+{
+  mpq_t   got;
+
+  MPQ_CHECK_FORMAT (want);
+  mp_trace_base = base;
+
+  mpq_init (got);
+
+  if (mpq_set_str (got, str, base) != 0)
+    {
+      printf ("mpq_set_str unexpectedly failed\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      abort ();
+    }
+  MPQ_CHECK_FORMAT (got);
+
+  if (! mpq_equal (got, want))
+    {
+      printf ("mpq_set_str wrong\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      mpq_trace ("got ", got);
+      mpq_trace ("want", want);
+      abort ();
+    }
+
+  mpq_clear (got);
+}
+
+void
+check_samples (void)
+{
+  mpq_t  q;
+
+  mpq_init (q);
+
+  mpq_set_ui (q, 0L, 1L);
+  check_one (q, 10, "0");
+  check_one (q, 10, "0/1");
+  check_one (q, 10, "0  / 1");
+  check_one (q, 0, "0x0/ 1");
+  check_one (q, 0, "0x0/ 0x1");
+  check_one (q, 0, "0 / 0x1");
+
+  check_one (q, 10, "-0");
+  check_one (q, 10, "-0/1");
+  check_one (q, 10, "-0  / 1");
+  check_one (q, 0, "-0x0/ 1");
+  check_one (q, 0, "-0x0/ 0x1");
+  check_one (q, 0, "-0 / 0x1");
+
+  mpq_set_ui (q, 255L, 256L);
+  check_one (q, 10, "255/256");
+  check_one (q, 0,  "0xFF/0x100");
+  check_one (q, 16, "FF/100");
+
+  mpq_neg (q, q);
+  check_one (q, 10, "-255/256");
+  check_one (q, 0,  "-0xFF/0x100");
+  check_one (q, 16, "-FF/100");
+
+  mpq_clear (q);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_samples ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/convert.c b/tests/mpz/convert.c
new file mode 100644
index 0000000..c449c66
--- /dev/null
+++ b/tests/mpz/convert.c
@@ -0,0 +1,186 @@
+/* Test conversion using mpz_get_str and mpz_set_str.
+
+Copyright 1993, 1994, 1996, 1999-2002, 2006, 2007, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strlen */
+#include <ctype.h> /* for tolower */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+static int str_casecmp (const char *, const char *);
+
+void
+string_urandomb (char *bp, size_t len, int base, gmp_randstate_ptr rands)
+{
+  mpz_t bs;
+  unsigned long bsi;
+  int d, l;
+  const char *collseq = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+  mpz_init (bs);
+
+  mpz_urandomb (bs, rands, 32);
+  bsi = mpz_get_ui (bs);
+  d = bsi % base;
+  while (len != 0)
+    {
+      l = (bsi >> 16) % 20;
+      l = MIN (l, len);
+
+      memset (bp, collseq[d], l);
+
+      len -= l;
+      bp += l;
+
+      mpz_urandomb (bs, rands, 32);
+      bsi = mpz_get_ui (bs);
+      d = bsi & 0xfff;
+      if (d >= base)
+	d = 0;
+    }
+
+  bp[0] = '\0';
+  mpz_clear (bs);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  mp_size_t size;
+  int i;
+  int reps = 2000;
+  char *str, *buf, *bp;
+  int base;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  size_t len;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (op1);
+  mpz_init (op2);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* 1. Generate random mpz_t and convert to a string and back to mpz_t
+	 again.  */
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2;	/* 2..18 */
+      mpz_urandomb (bs, rands, size_range);	/* 3..262144 bits */
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, size);
+
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+
+      mpz_urandomb (bs, rands, 32);
+      bsi = mpz_get_ui (bs);
+      base = bsi % 62 + 1;
+      if (base == 1)
+	base = 0;
+
+      str = mpz_get_str ((char *) 0, base, op1);
+      mpz_set_str_or_abort (op2, str, base);
+
+      if (mpz_cmp (op1, op2))
+	{
+	  fprintf (stderr, "ERROR, op1 and op2 different in test %d\n", i);
+	  fprintf (stderr, "str  = %s\n", str);
+	  fprintf (stderr, "base = %d\n", base);
+	  fprintf (stderr, "op1  = "); debug_mp (op1, -16);
+	  fprintf (stderr, "op2  = "); debug_mp (op2, -16);
+	  abort ();
+	}
+
+      (*__gmp_free_func) (str, strlen (str) + 1);
+
+      /* 2. Generate random string and convert to mpz_t and back to a string
+	 again.  */
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 1;	/* 1..16 */
+      mpz_urandomb (bs, rands, size_range);	/* 1..65536 digits */
+      len = mpz_get_ui (bs) + 1;
+      buf = (char *) (*__gmp_allocate_func) (len + 1);
+      if (base == 0)
+	base = 10;
+      string_urandomb (buf, len, base, rands);
+
+      mpz_set_str_or_abort (op1, buf, base);
+      str = mpz_get_str ((char *) 0, base, op1);
+
+      /* Skip over leading zeros, but don't leave the string at zero length. */
+      for (bp = buf; bp[0] == '0' && bp[1] != '\0'; bp++)
+	;
+
+      if (str_casecmp (str, bp) != 0)
+	{
+	  fprintf (stderr, "ERROR, str and buf different in test %d\n", i);
+	  fprintf (stderr, "str  = %s\n", str);
+	  fprintf (stderr, "buf  = %s\n", buf);
+	  fprintf (stderr, "base = %d\n", base);
+	  fprintf (stderr, "op1  = "); debug_mp (op1, -16);
+	  abort ();
+	}
+
+      (*__gmp_free_func) (buf, len + 1);
+      (*__gmp_free_func) (str, strlen (str) + 1);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
+
+/* This is similar to POSIX strcasecmp except that we don't do the comparison
+   with unsigned char.  We avoid strcasecmp for C standard conformance.  */
+static int
+str_casecmp (const char *s1, const char *s2)
+{
+  size_t i;
+  for (i = 0;; i++)
+    {
+      int c1 = s1[i];
+      int c2 = s2[i];
+      if (c1 == 0 || tolower (c1) != tolower (c2))
+	return c1 - c2;
+    }
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/dive.c b/tests/mpz/dive.c
new file mode 100644
index 0000000..99e8caf
--- /dev/null
+++ b/tests/mpz/dive.c
@@ -0,0 +1,100 @@
+/* Test mpz_mul, mpz_divexact.
+
+Copyright 1996, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  mpz_t prod, quot;
+  mp_size_t size;
+  int i;
+  int reps = 5000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mp_trace_base = -16;
+
+  mpz_init (bs);
+
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (prod);
+  mpz_init (quot);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2; /* 0..2047 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, size);
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  size = mpz_get_ui (bs);
+	  mpz_rrandomb (op2, rands, size);
+	}
+      while (mpz_sgn (op2) == 0);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 2) != 0)
+	mpz_neg (op2, op2);
+
+      mpz_mul (prod, op1, op2);
+
+      mpz_divexact (quot, prod, op2);
+      MPZ_CHECK_FORMAT (quot);
+
+      if (mpz_cmp (quot, op1) != 0)
+        {
+          printf ("Wrong results:\n");
+          mpz_trace ("  got     ", quot);
+          mpz_trace ("  want    ", op1);
+          mpz_trace ("  dividend", prod);
+          mpz_trace ("  divisor ", op2);
+          abort ();
+        }
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (prod);
+  mpz_clear (quot);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/dive_ui.c b/tests/mpz/dive_ui.c
new file mode 100644
index 0000000..8f74bce
--- /dev/null
+++ b/tests/mpz/dive_ui.c
@@ -0,0 +1,86 @@
+/* Test mpz_divexact_ui.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr rands = RANDS;
+  int    reps = 500000;
+  mpz_t  a, q, got;
+  int    i, qneg;
+  unsigned long  d;
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (a);
+  mpz_init (q);
+  mpz_init (got);
+
+  for (i = 0; i < reps; i++)
+    {
+      do
+	d = (unsigned long) urandom();
+      while (d == 0);
+      mpz_erandomb (q, rands, 512);
+      mpz_mul_ui (a, q, d);
+
+      for (qneg = 0; qneg <= 1; qneg++)
+        {
+          mpz_divexact_ui (got, a, d);
+          MPZ_CHECK_FORMAT (got);
+          if (mpz_cmp (got, q) != 0)
+            {
+              printf    ("mpz_divexact_ui wrong\n");
+              mpz_trace ("    a", a);
+              printf    ("    d=%lu\n", d);
+              mpz_trace ("    q", q);
+              mpz_trace ("  got", got);
+              abort ();
+            }
+
+          mpz_neg (q, q);
+          mpz_neg (a, a);
+        }
+
+    }
+
+  mpz_clear (a);
+  mpz_clear (q);
+  mpz_clear (got);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/io.c b/tests/mpz/io.c
new file mode 100644
index 0000000..6862994
--- /dev/null
+++ b/tests/mpz/io.c
@@ -0,0 +1,151 @@
+/* Test conversion and I/O using mpz_out_str and mpz_inp_str.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2012, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define FILENAME  "/tmp/io.tmp"
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stdout, base, x); fputc ('\n', stdout);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t  op1, op2;
+  mp_size_t size;
+  int i;
+  int reps = 10000;
+  FILE *fp;
+  int base, base_out;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  size_t nread;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (op1);
+  mpz_init (op2);
+
+  fp = fopen (FILENAME, "w+");
+
+  if (mpz_out_str (fp, 63, op1) != 0)
+    {
+      printf ("mpz_out_str did not return 0 (error) with base > 62\n");
+      abort ();
+    }
+
+  if (mpz_out_str (fp, -37, op1) != 0)
+    {
+      printf ("mpz_out_str did not return 0 (error) with base < -37\n");
+      abort ();
+    }
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, size);
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+
+      mpz_urandomb (bs, rands, 16);
+      bsi = mpz_get_ui (bs);
+      base = bsi % 62 + 1;
+      if (base == 1)
+	base = 0;
+
+      if (i % 2 == 0 && base <= 36)
+	base_out = -base;
+      else
+	base_out = base;
+
+      rewind (fp);
+      if (mpz_out_str (fp, base_out, op1) == 0
+	  || putc (' ', fp) == EOF
+	  || fflush (fp) != 0)
+	{
+	  printf ("mpz_out_str write error\n");
+	  abort ();
+	}
+
+      rewind (fp);
+      nread = mpz_inp_str (op2, fp, base);
+      if (nread == 0)
+	{
+	  if (ferror (fp))
+	    printf ("mpz_inp_str stream read error\n");
+	  else
+	    printf ("mpz_inp_str data conversion error\n");
+	  abort ();
+	}
+
+      if (nread != ftell(fp))
+	{
+	  printf ("mpz_inp_str nread doesn't match ftell\n");
+	  printf ("  nread  %lu\n", (unsigned long) nread);
+	  printf ("  ftell  %ld\n", ftell(fp));
+	  abort ();
+	}
+
+      if (mpz_cmp (op1, op2))
+	{
+	  printf ("ERROR\n");
+	  printf ("op1  = "); debug_mp (op1, -16);
+	  printf ("op2  = "); debug_mp (op2, -16);
+	  printf ("base = %d\n", base);
+	  abort ();
+	}
+    }
+
+  fclose (fp);
+
+  unlink (FILENAME);
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/logic.c b/tests/mpz/logic.c
new file mode 100644
index 0000000..f3b38b1
--- /dev/null
+++ b/tests/mpz/logic.c
@@ -0,0 +1,194 @@
+/* Test mpz_com, mpz_and, mpz_ior, and mpz_xor.
+
+Copyright 1993, 1994, 1996, 1997, 2001, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (void);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t x, y, r1, r2;
+  mpz_t t1, t2, t3;
+  mp_size_t xsize, ysize;
+  int i;
+  int reps = 100000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (x);
+  mpz_init (y);
+  mpz_init (r1);
+  mpz_init (r2);
+  mpz_init (t1);
+  mpz_init (t2);
+  mpz_init (t3);
+
+  mpz_set_si (x, -1);
+  mpz_set_ui (y, 0);
+  for (i = 0; i < 300; i++)
+    {
+      mpz_mul_2exp (x, x, 1);
+
+      mpz_and (r1, x, x);
+      MPZ_CHECK_FORMAT (r1);
+      if (mpz_cmp (r1, x) != 0)
+	dump_abort ();
+
+      mpz_ior (r2, x, x);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r2, x) != 0)
+	dump_abort ();
+
+      mpz_xor (t1, x, x);
+      MPZ_CHECK_FORMAT (t1);
+      if (mpz_cmp_si (t1, 0) != 0)
+	dump_abort ();
+
+      mpz_ior (t1, x, y);
+      MPZ_CHECK_FORMAT (t1);
+      if (mpz_cmp (t1, x) != 0)
+	dump_abort ();
+
+      mpz_xor (t2, x, y);
+      MPZ_CHECK_FORMAT (t2);
+      if (mpz_cmp (t2, x) != 0)
+	dump_abort ();
+
+      mpz_com (t2, x);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_xor (t3, t2, x);
+      MPZ_CHECK_FORMAT (t3);
+      if (mpz_cmp_si (t3, -1) != 0)
+	dump_abort ();
+    }
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 8 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      xsize = mpz_get_ui (bs);
+      mpz_rrandomb (x, rands, xsize);
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (x, x);
+
+      mpz_urandomb (bs, rands, size_range);
+      ysize = mpz_get_ui (bs);
+      mpz_rrandomb (y, rands, ysize);
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (y, y);
+
+      mpz_com (r1, x);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_com (r1, r1);
+      MPZ_CHECK_FORMAT (r1);
+      if (mpz_cmp (r1, x) != 0)
+	dump_abort ();
+
+      mpz_com (r1, y);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_com (r2, r1);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r2, y) != 0)
+	dump_abort ();
+
+      mpz_com (t1, x);
+      MPZ_CHECK_FORMAT (t1);
+      mpz_com (t2, y);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_and (t3, t1, t2);
+      MPZ_CHECK_FORMAT (t3);
+      mpz_com (r1, t3);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_ior (r2, x, y);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r1, r2) != 0)
+	dump_abort ();
+
+      mpz_com (t1, x);
+      MPZ_CHECK_FORMAT (t1);
+      mpz_com (t2, y);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_ior (t3, t1, t2);
+      MPZ_CHECK_FORMAT (t3);
+      mpz_com (r1, t3);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_and (r2, x, y);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r1, r2) != 0)
+	dump_abort ();
+
+      mpz_ior (t1, x, y);
+      MPZ_CHECK_FORMAT (t1);
+      mpz_and (t2, x, y);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_com (t3, t2);
+      MPZ_CHECK_FORMAT (t3);
+      mpz_and (r1, t1, t3);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_xor (r2, x, y);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r1, r2) != 0)
+	dump_abort ();
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x);
+  mpz_clear (y);
+  mpz_clear (r1);
+  mpz_clear (r2);
+  mpz_clear (t1);
+  mpz_clear (t2);
+  mpz_clear (t3);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort ()
+{
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/reuse.c b/tests/mpz/reuse.c
new file mode 100644
index 0000000..a8f2201
--- /dev/null
+++ b/tests/mpz/reuse.c
@@ -0,0 +1,786 @@
+/* Test that routines allow reusing a source variable as destination.
+
+   Test all relevant functions except:
+	mpz_bin_ui
+	mpz_nextprime
+	mpz_mul_si
+	mpz_addmul_ui (should this really allow a+=a*c?)
+
+Copyright 1996, 1999-2002, 2009, 2012, 2013, 2016, 2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMP_LIBGMP_DLL
+
+/* FIXME: When linking to a DLL libgmp, mpz_add etc can't be used as
+   initializers for global variables because they're effectively global
+   variables (function pointers) themselves.  Perhaps calling a test
+   function successively with mpz_add etc would be better.  */
+
+int
+main (void)
+{
+  printf ("Test suppressed for windows DLL\n");
+  exit (0);
+}
+
+
+#else /* ! DLL_EXPORT */
+
+void dump (const char *, mpz_t, mpz_t, mpz_t);
+
+typedef void (*dss_func) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+typedef void (*dsi_func) (mpz_ptr, mpz_srcptr, unsigned long int);
+typedef unsigned long int (*dsi_div_func) (mpz_ptr, mpz_srcptr, unsigned long int);
+typedef unsigned long int (*ddsi_div_func) (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+typedef void (*ddss_div_func) (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+typedef void (*ds_func) (mpz_ptr, mpz_srcptr);
+
+
+void
+mpz_xinvert (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
+{
+  int res;
+  res = mpz_invert (r, a, b);
+  if (res == 0)
+    mpz_set_ui (r, 0);
+}
+
+struct {
+  dss_func fptr;
+  const char *fname;
+  int isdivision;
+  int isslow;
+} static dss[] =
+  { { mpz_add,     "mpz_add",	  0, 0 },
+    { mpz_sub,     "mpz_sub",	  0, 0 },
+    { mpz_mul,     "mpz_mul",	  0, 0 },
+    { mpz_cdiv_q,  "mpz_cdiv_q",  1, 0 },
+    { mpz_cdiv_r,  "mpz_cdiv_r",  1, 0 },
+    { mpz_fdiv_q,  "mpz_fdiv_q",  1, 0 },
+    { mpz_fdiv_r,  "mpz_fdiv_r",  1, 0 },
+    { mpz_tdiv_q,  "mpz_tdiv_q",  1, 0 },
+    { mpz_tdiv_r,  "mpz_tdiv_r",  1, 0 },
+    { mpz_mod,     "mpz_mod",	  1, 0 },
+    { mpz_xinvert, "mpz_xinvert", 1, 1 },
+    { mpz_gcd,     "mpz_gcd",	  0, 1 },
+    { mpz_lcm,     "mpz_lcm",	  0, 1 },
+    { mpz_and,     "mpz_and",	  0, 0 },
+    { mpz_ior,     "mpz_ior",	  0, 0 },
+    { mpz_xor,     "mpz_xor",     0, 0 }
+  };
+
+
+struct {
+  dsi_func fptr;
+  const char *fname;
+  int mod;
+} static dsi[] =
+{
+  /* Don't change order here without changing the code in main(). */
+  { mpz_add_ui,         "mpz_add_ui",	     0 },
+  { mpz_mul_ui,		"mpz_mul_ui",	     0 },
+  { mpz_sub_ui,		"mpz_sub_ui",	     0 },
+  { mpz_fdiv_q_2exp,    "mpz_fdiv_q_2exp",   0x1000 },
+  { mpz_fdiv_r_2exp,    "mpz_fdiv_r_2exp",   0x1000 },
+  { mpz_cdiv_q_2exp,    "mpz_cdiv_q_2exp",   0x1000 },
+  { mpz_cdiv_r_2exp,    "mpz_cdiv_r_2exp",   0x1000 },
+  { mpz_tdiv_q_2exp,    "mpz_tdiv_q_2exp",   0x1000 },
+  { mpz_tdiv_r_2exp,    "mpz_tdiv_r_2exp",   0x1000 },
+  { mpz_mul_2exp,	"mpz_mul_2exp",      0x100 },
+  { mpz_pow_ui,		"mpz_pow_ui",        0x10 }
+};
+
+struct {
+  dsi_div_func fptr;
+  const char *fname;
+} static dsi_div[] =
+{
+  { mpz_cdiv_q_ui,       "mpz_cdiv_q_ui" },
+  { mpz_cdiv_r_ui,       "mpz_cdiv_r_ui" },
+  { mpz_fdiv_q_ui,       "mpz_fdiv_q_ui" },
+  { mpz_fdiv_r_ui,       "mpz_fdiv_r_ui" },
+  { mpz_tdiv_q_ui,       "mpz_tdiv_q_ui" },
+  { mpz_tdiv_r_ui,       "mpz_tdiv_r_ui" }
+};
+
+struct {
+  ddsi_div_func fptr;
+  const char *fname;
+  int isslow;
+} static ddsi_div[] =
+{
+  { mpz_cdiv_qr_ui,     "mpz_cdiv_qr_ui",    0 },
+  { mpz_fdiv_qr_ui,     "mpz_fdiv_qr_ui",    0 },
+  { mpz_tdiv_qr_ui,     "mpz_tdiv_qr_ui",    0 },
+};
+
+
+struct {
+  ddss_div_func fptr;
+  const char *fname;
+  int isslow;
+} static ddss_div[] =
+{
+  { mpz_cdiv_qr,  "mpz_cdiv_qr",    0 },
+  { mpz_fdiv_qr,  "mpz_fdiv_qr",    0 },
+  { mpz_tdiv_qr,  "mpz_tdiv_qr",    0 },
+};
+
+struct {
+  ds_func fptr;
+  const char *fname;
+  int nonneg;
+} static ds[] =
+{
+  { mpz_abs,    "mpz_abs",    0 },
+  { mpz_com,    "mpz_com",    0 },
+  { mpz_neg,    "mpz_neg",    0 },
+  { mpz_sqrt,   "mpz_sqrt",   1 },
+};
+
+#define FAIL(class,indx,op1,op2,op3)					\
+  do {									\
+    dump (class[indx].fname, op1, op2, op3);				\
+    exit (1);								\
+  } while (0)
+
+#define FAIL2(fname,op1,op2,op3)					\
+  do {									\
+    dump (#fname, op1, op2, op3);					\
+    exit (1);								\
+  } while (0)
+
+
+void
+realloc_if_reducing (mpz_ptr r)
+{
+  if (ABSIZ(r) < ALLOC(r))
+      _mpz_realloc (r, ABSIZ(r));
+}
+
+#define INVOKE_RRS(desc,r1,r2,i1)					\
+  do {									\
+    if (pass & 1) realloc_if_reducing (r1);				\
+    if (pass & 2) realloc_if_reducing (r2);				\
+    (desc).fptr (r1, r2, i1);						\
+  } while (0)
+#define INVOKE_RS(desc,r1,i1)						\
+  do {									\
+    if (pass & 1) realloc_if_reducing (r1);				\
+    (desc).fptr (r1, i1);						\
+  } while (0)
+#define INVOKE_RRSS(desc,r1,r2,i1,i2)					\
+  do {									\
+    if (pass & 1) realloc_if_reducing (r1);				\
+    if (pass & 2) realloc_if_reducing (r2);				\
+    (desc).fptr (r1, r2, i1, i2);					\
+  } while (0)
+#define INVOKE_RSS(desc,r1,i1,i2)					\
+  do {									\
+    if (pass & 1) realloc_if_reducing (r1);				\
+    (desc).fptr (r1, i1, i2);						\
+  } while (0)
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  unsigned int pass, reps = 400;
+  mpz_t in1, in2, in3;
+  unsigned long int in2i;
+  mpz_t res1, res2, res3;
+  mpz_t ref1, ref2, ref3;
+  mpz_t t;
+  unsigned long int r1, r2;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (in1);
+  mpz_init (in2);
+  mpz_init (in3);
+  mpz_init (ref1);
+  mpz_init (ref2);
+  mpz_init (ref3);
+  mpz_init (res1);
+  mpz_init (res2);
+  mpz_init (res3);
+  mpz_init (t);
+
+  mpz_set_ui (res1, 1);		/* force allocation */
+  mpz_set_ui (res2, 1);		/* force allocation */
+  mpz_set_ui (res3, 1);		/* force allocation */
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+#ifndef VERBOSE
+      if (isatty (STDOUT_FILENO))
+	{
+	  printf ("\r%d/%d passes", pass, reps);
+	  fflush (stdout);
+	}
+#endif
+
+      mpz_urandomb (bs, rands, 32);
+      /* Make size_range gradually bigger with each pass. */
+      size_range = mpz_get_ui (bs) % (pass * 15 / reps + 1) + 8;
+
+#define MAKE_RANDOM_OP(in, size_range, s)				\
+  do {									\
+    mpz_urandomb (bs, rands, size_range);				\
+    if (((pass >> s) & 3) == 3) /* conditional exponential dist */	\
+      mpz_urandomb (bs, rands, mpz_get_ui (bs) % (size_range - 7) + 7);	\
+    mpz_rrandomb (in, rands, mpz_get_ui (bs));				\
+  } while (0)
+
+      MAKE_RANDOM_OP (in1, size_range, 0);
+      MAKE_RANDOM_OP (in2, size_range, 2);
+      MAKE_RANDOM_OP (in3, size_range, 4);
+#undef MAKE_RANDOM_OP
+
+#ifdef VERBOSE
+      printf("%9d%9d%8d\n",
+	     mpz_sizeinbase(in1,2),
+	     mpz_sizeinbase(in2,2),
+	     mpz_sizeinbase(in3,2));
+#endif
+
+      mpz_urandomb (bs, rands, 3);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (in1, in1);
+      if ((bsi & 2) != 0)
+	mpz_neg (in2, in2);
+      if ((bsi & 4) != 0)
+	mpz_neg (in3, in3);
+
+      for (i = 0; i < numberof (dss); i++)
+	{
+	  if (dss[i].isdivision && mpz_sgn (in2) == 0)
+	    continue;
+	  if (dss[i].isslow && size_range > 19)
+	    continue;
+
+	  (dss[i].fptr) (ref1, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  INVOKE_RSS (dss[i], res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  INVOKE_RSS (dss[i], res1, in1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < numberof (ddss_div); i++)
+	{
+	  if (mpz_sgn (in2) == 0)
+	    continue;
+
+	  (ddss_div[i].fptr) (ref1, ref2, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, res2, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, in1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, in1, res2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < numberof (ds); i++)
+	{
+	  if (ds[i].nonneg && mpz_sgn (in1) < 0)
+	    continue;
+
+	  (ds[i].fptr) (ref1, in1);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  INVOKE_RS (ds[i], res1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (ds, i, in1, in2, NULL);
+	}
+
+      in2i = mpz_get_ui (in2);
+
+      for (i = 0; i < numberof (dsi); i++)
+	{
+	  if (dsi[i].mod != 0)
+	    in2i = mpz_get_ui (in2) % dsi[i].mod;
+
+	  (dsi[i].fptr) (ref1, in1, in2i);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  INVOKE_RRS (dsi[i], res1, res1, in2i);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dsi, i, in1, in2, NULL);
+	}
+
+      if (in2i != 0)	  /* Don't divide by 0.  */
+	{
+	  for (i = 0; i < numberof (dsi_div); i++)
+	    {
+	      r1 = (dsi_div[i].fptr) (ref1, in1, in2i);
+	      MPZ_CHECK_FORMAT (ref1);
+
+	      mpz_set (res1, in1);
+	      r2 = (dsi_div[i].fptr) (res1, res1, in2i);
+	      MPZ_CHECK_FORMAT (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || r1 != r2)
+		FAIL (dsi_div, i, in1, in2, NULL);
+	    }
+
+	  for (i = 0; i < numberof (ddsi_div); i++)
+	    {
+	      r1 = (ddsi_div[i].fptr) (ref1, ref2, in1, in2i);
+	      MPZ_CHECK_FORMAT (ref1);
+
+	      mpz_set (res1, in1);
+	      mpz_clobber (res2);
+	      r2 = (ddsi_div[i].fptr) (res1, res2, res1, in2i);
+	      MPZ_CHECK_FORMAT (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+
+	      mpz_clobber (res1);
+	      mpz_set (res2, in1);
+	      (ddsi_div[i].fptr) (res1, res2, res2, in2i);
+	      MPZ_CHECK_FORMAT (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+	    }
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_sqrtrem (ref1, ref2, in1);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_sqrtrem (res1, res2, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_sqrtrem (res1, res2, res2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+
+	  mpz_set (res1, in1);
+	  mpz_sqrtrem (res1, res1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref2, res1) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_root (ref1, in1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_root (res1, res1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_root, in1, in2, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_rootrem (ref1, ref2, in1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_rootrem (res1, res2, res1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_rootrem (res1, res2, res2, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+	}
+
+      if (size_range < 18)	/* run fewer tests since gcdext is slow */
+	{
+	  mpz_gcdext (ref1, ref2, ref3, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+	  MPZ_CHECK_FORMAT (ref3);
+
+#define GCDEXT_CHECK3(i1, i2) do {					\
+	    mpz_gcdext (res1, res2, res3, i1, i2);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    MPZ_CHECK_FORMAT (res3);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0	\
+		|| mpz_cmp (ref3, res3) != 0)				\
+	      FAIL2 (mpz_gcdext, i1, i2, NULL);				\
+	  } while (0)
+#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)
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res1, in2);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res2, in2);
+
+	  mpz_clobber (res1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK3 (res3, in2);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (in1, res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (in1, res2);
+
+	  mpz_clobber (res1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in2);
+	  GCDEXT_CHECK3 (in1, res3);
+
+	  mpz_set (res1, in1);
+	  mpz_set (res2, in2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res1, res2);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in2);
+	  GCDEXT_CHECK3 (res1, res3);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_set (res3, in2);
+	  GCDEXT_CHECK3 (res2, res3);
+
+	  mpz_set (res1, in2);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res2, res1);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK3 (res3, res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK3(res3, res2);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  GCDEXT_CHECK2 (res1, in2);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  GCDEXT_CHECK2 (res2, in2);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  GCDEXT_CHECK2 (in1, res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  GCDEXT_CHECK2 (in1, res2);
+#undef GCDEXT_CHECK
+	  /* Identical inputs, gcd(in1, in1). Then the result should be
+	     gcd = abs(in1), s = 0, t = sgn(in1). */
+	  mpz_abs (ref1, in1);
+	  mpz_set_ui (ref2, 0);
+	  mpz_set_si (ref3, mpz_sgn (in1));
+
+#define GCDEXT_CHECK_SAME3(in) do {					\
+	    mpz_gcdext (res1, res2, res3, in, in);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    MPZ_CHECK_FORMAT (res3);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0	\
+		|| mpz_cmp (ref3, res3) != 0)				\
+	      FAIL2 (mpz_gcdext, in, in, NULL);				\
+	  } while (0)
+#define GCDEXT_CHECK_SAME2(in) do {					\
+	    mpz_gcdext (res1, res2, NULL, in, in);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)	\
+	      FAIL2 (mpz_gcdext, in, in, NULL);				\
+	  } while (0)
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME3 (res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME3 (res2);
+
+	  mpz_clobber (res1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK_SAME3 (res3);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME2 (res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME2 (res2);
+#undef GCDEXT_CHECK_SAME
+	}
+
+      /* Don't run mpz_powm for huge exponents or when undefined.  */
+      if (size_range < 17 && mpz_sizeinbase (in2, 2) < 250 && mpz_sgn (in3) != 0
+	  && (mpz_sgn (in2) >= 0 || mpz_invert (t, in1, in3)))
+	{
+	  mpz_powm (ref1, in1, in2, in3);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm (res1, res1, in2, in3);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in2);
+	  mpz_powm (res1, in1, res1, in3);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm (res1, in1, in2, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+	}
+
+      /* Don't run mpz_powm_ui when undefined.  */
+      if (size_range < 17 && mpz_sgn (in3) != 0)
+	{
+	  mpz_powm_ui (ref1, in1, in2i, in3);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm_ui (res1, res1, in2i, in3);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm_ui (res1, in1, in2i, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+	}
+
+      {
+	r1 = mpz_gcd_ui (ref1, in1, in2i);
+	MPZ_CHECK_FORMAT (ref1);
+
+	mpz_set (res1, in1);
+	r2 = mpz_gcd_ui (res1, res1, in2i);
+	MPZ_CHECK_FORMAT (res1);
+	if (mpz_cmp (ref1, res1) != 0)
+	  FAIL2 (mpz_gcd_ui, in1, in2, NULL);
+      }
+
+      if (mpz_sgn (in2) != 0)
+	{
+	  /* Test mpz_remove */
+	  mp_bitcnt_t refretval, retval;
+	  refretval = mpz_remove (ref1, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  retval = mpz_remove (res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0 || refretval != retval)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  retval = mpz_remove (res1, in1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0 || refretval != retval)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+	}
+
+      if (mpz_sgn (in2) != 0)
+	{
+	  /* Test mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact (ref1, t, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact (res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact (res1, t, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+	}
+
+      if (mpz_sgn (in2) > 0)
+	{
+	  /* Test mpz_divexact_gcd, same as mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact_gcd (ref1, t, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact_gcd (res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact_gcd (res1, t, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+	}
+    }
+
+  if (isatty (STDOUT_FILENO))
+    printf ("\r%20s", "");
+
+  mpz_clear (bs);
+  mpz_clear (in1);
+  mpz_clear (in2);
+  mpz_clear (in3);
+  mpz_clear (ref1);
+  mpz_clear (ref2);
+  mpz_clear (ref3);
+  mpz_clear (res1);
+  mpz_clear (res2);
+  mpz_clear (res3);
+  mpz_clear (t);
+
+  if (isatty (STDOUT_FILENO))
+    printf ("\r");
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump (const char *name, mpz_t in1, mpz_t in2, mpz_t in3)
+{
+  printf ("failure in %s (", name);
+  mpz_out_str (stdout, -16, in1);
+  if (in2 != NULL)
+    {
+      printf (" ");
+      mpz_out_str (stdout, -16, in2);
+    }
+  if (in3 != NULL)
+    {
+      printf (" ");
+      mpz_out_str (stdout, -16, in3);
+    }
+  printf (")\n");
+}
+
+#endif /* ! DLL_EXPORT */
diff --git a/tests/mpz/t-addsub.c b/tests/mpz/t-addsub.c
new file mode 100644
index 0000000..aaa3188
--- /dev/null
+++ b/tests/mpz/t-addsub.c
@@ -0,0 +1,121 @@
+/* Test mpz_add, mpz_sub, mpz_add_ui, mpz_sub_ui, and mpz_ui_sub.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+void dump_abort (int, const char *, mpz_t, mpz_t);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, r1, r2;
+  mp_size_t op1n, op2n;
+  unsigned long int op2long;
+  int i;
+  int reps = 100000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (r1);
+  mpz_init (r2);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      op1n = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, op1n);
+
+      mpz_urandomb (bs, rands, size_range);
+      op2n = mpz_get_ui (bs);
+      mpz_rrandomb (op2, rands, op2n);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 2) != 0)
+	mpz_neg (op2, op2);
+
+      /* printf ("%ld %ld\n", SIZ (multiplier), SIZ (multiplicand)); */
+
+      mpz_add (r1, op1, op2);
+      mpz_sub (r2, r1, op2);
+      if (mpz_cmp (r2, op1) != 0)
+	dump_abort (i, "mpz_add or mpz_sub incorrect", op1, op2);
+
+      if (mpz_fits_ulong_p (op2))
+	{
+	  op2long = mpz_get_ui (op2);
+	  mpz_add_ui (r1, op1, op2long);
+	  mpz_sub_ui (r2, r1, op2long);
+	  if (mpz_cmp (r2, op1) != 0)
+	    dump_abort (i, "mpz_add_ui or mpz_sub_ui incorrect", op1, op2);
+
+	  mpz_ui_sub (r1, op2long, op1);
+	  mpz_sub_ui (r2, op1, op2long);
+	  mpz_neg (r2, r2);
+	  if (mpz_cmp (r1, r2) != 0)
+	    dump_abort (i, "mpz_add_ui or mpz_ui_sub incorrect", op1, op2);
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (r1);
+  mpz_clear (r2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (int i, const char *s, mpz_t op1, mpz_t op2)
+{
+  fprintf (stderr, "ERROR: %s in test %d\n", s, i);
+  fprintf (stderr, "op1 = "); debug_mp (op1, -16);
+  fprintf (stderr, "op2 = "); debug_mp (op2, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-aorsmul.c b/tests/mpz/t-aorsmul.c
new file mode 100644
index 0000000..4bd435d
--- /dev/null
+++ b/tests/mpz/t-aorsmul.c
@@ -0,0 +1,464 @@
+/* Test mpz_addmul, mpz_addmul_ui, mpz_submul, mpz_submul_ui.
+
+Copyright 2001, 2002, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define M GMP_NUMB_MAX
+
+
+void
+check_one_inplace (mpz_srcptr w, mpz_srcptr y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul (want, w, y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul (got, got, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul inplace fail\n");
+    fail:
+      mpz_trace ("w", w);
+      mpz_trace ("y", y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul (want, w, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul (got, got, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul inplace fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_one_ui_inplace (mpz_ptr w, unsigned long y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul_ui (want, w, (unsigned long) y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul_ui (got, got, (unsigned long) y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul_ui fail\n");
+    fail:
+      mpz_trace ("w", w);
+      printf    ("y=0x%lX   %lu\n", y, y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul_ui (want, w, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul_ui (got, got, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul_ui fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_all_inplace (mpz_ptr w, mpz_ptr y)
+{
+  int  wneg, yneg;
+
+  MPZ_CHECK_FORMAT (w);
+  MPZ_CHECK_FORMAT (y);
+
+  for (wneg = 0; wneg < 2; wneg++)
+    {
+      for (yneg = 0; yneg < 2; yneg++)
+        {
+          check_one_inplace (w, y);
+
+          if (mpz_fits_ulong_p (y))
+            check_one_ui_inplace (w, mpz_get_ui (y));
+
+          mpz_neg (y, y);
+        }
+      mpz_neg (w, w);
+    }
+}
+
+void
+check_one (mpz_srcptr w, mpz_srcptr x, mpz_srcptr y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul (want, x, y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul (got, x, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul fail\n");
+    fail:
+      mpz_trace ("w", w);
+      mpz_trace ("x", x);
+      mpz_trace ("y", y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+
+  mpz_sub (want, want, w);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul (got, x, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_sqr (mpz_srcptr w, mpz_srcptr x)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul (want, x, x);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul (got, x, x);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul xx fail\n");
+    sqrfail:
+      mpz_trace ("w", w);
+      mpz_trace ("x", x);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_sub (want, want, w);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul (got, x, x);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul xx fail\n");
+      goto sqrfail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_one_ui (mpz_ptr w, mpz_ptr x, unsigned long y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul_ui (want, x, (unsigned long) y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul_ui (got, x, (unsigned long) y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul_ui fail\n");
+    fail:
+      mpz_trace ("w", w);
+      mpz_trace ("x", x);
+      printf    ("y=0x%lX   %lu\n", y, y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul_ui (want, x, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul_ui (got, x, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul_ui fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+
+void
+check_all (mpz_ptr w, mpz_ptr x, mpz_ptr y)
+{
+  int    swap, wneg, xneg, yneg;
+
+  MPZ_CHECK_FORMAT (w);
+  MPZ_CHECK_FORMAT (x);
+  MPZ_CHECK_FORMAT (y);
+
+  for (swap = 0; swap < 2; swap++)
+    {
+      for (wneg = 0; wneg < 2; wneg++)
+        {
+          for (xneg = 0; xneg < 2; xneg++)
+            {
+              for (yneg = 0; yneg < 2; yneg++)
+                {
+                  check_one (w, x, y);
+
+                  if (mpz_fits_ulong_p (y))
+                    check_one_ui (w, x, mpz_get_ui (y));
+
+                  mpz_neg (y, y);
+                }
+
+	      check_sqr (w, x);
+
+              mpz_neg (x, x);
+            }
+          mpz_neg (w, w);
+        }
+      mpz_swap (x, y);
+    }
+}
+
+void
+check_data_inplace_ui (void)
+{
+  static const struct {
+    mp_limb_t      w[6];
+    unsigned long  y;
+
+  } data[] = {
+
+    { { 0 }, 0 },
+    { { 0 }, 1 },
+    { { 1 }, 1 },
+    { { 2 }, 1 },
+
+    { { 123 }, 1 },
+    { { 123 }, ULONG_MAX },
+    { { M }, 1 },
+    { { M }, ULONG_MAX },
+
+    { { 123, 456 }, 1 },
+    { { M, M }, 1 },
+    { { 123, 456 }, ULONG_MAX },
+    { { M, M }, ULONG_MAX },
+
+    { { 123, 456, 789 }, 1 },
+    { { M, M, M }, 1 },
+    { { 123, 456, 789 }, ULONG_MAX },
+    { { M, M, M }, ULONG_MAX },
+  };
+
+  mpz_t  w, y;
+  int    i;
+
+  mpz_init (w);
+  mpz_init (y);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
+      mpz_set_ui (y, data[i].y);
+      check_all_inplace (w, y);
+    }
+
+  mpz_clear (w);
+  mpz_clear (y);
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    mp_limb_t  w[6];
+    mp_limb_t  x[6];
+    mp_limb_t  y[6];
+
+  } data[] = {
+
+    /* reducing to zero */
+    { { 1 }, { 1 }, { 1 } },
+    { { 2 }, { 1 }, { 2 } },
+    { { 0,1 }, { 0,1 }, { 1 } },
+
+    /* reducing to 1 */
+    { { 0,1 },       { M },       { 1 } },
+    { { 0,0,1 },     { M,M },     { 1 } },
+    { { 0,0,0,1 },   { M,M,M },   { 1 } },
+    { { 0,0,0,0,1 }, { M,M,M,M }, { 1 } },
+
+    /* reducing to -1 */
+    { { M },       { 0,1 },       { 1 } },
+    { { M,M },     { 0,0,1 },     { 1 } },
+    { { M,M,M },   { 0,0,0,1 },   { 1 } },
+    { { M,M,M,M }, { 0,0,0,0,1 }, { 1 } },
+
+    /* carry out of addmul */
+    { { M },     { 1 }, { 1 } },
+    { { M,M },   { 1 }, { 1 } },
+    { { M,M,M }, { 1 }, { 1 } },
+
+    /* borrow from submul */
+    { { 0,1 },     { 1 }, { 1 } },
+    { { 0,0,1 },   { 1 }, { 1 } },
+    { { 0,0,0,1 }, { 1 }, { 1 } },
+
+    /* borrow from submul */
+    { { 0,0,1 },     { 0,1 }, { 1 } },
+    { { 0,0,0,1 },   { 0,1 }, { 1 } },
+    { { 0,0,0,0,1 }, { 0,1 }, { 1 } },
+
+    /* more borrow from submul */
+    { { M }, { 0,1 },       { 1 } },
+    { { M }, { 0,0,1 },     { 1 } },
+    { { M }, { 0,0,0,1 },   { 1 } },
+    { { M }, { 0,0,0,0,1 }, { 1 } },
+
+    /* big borrow from submul */
+    { { 0,0,1 },     { M,M }, { M } },
+    { { 0,0,0,1 },   { M,M }, { M } },
+    { { 0,0,0,0,1 }, { M,M }, { M } },
+
+    /* small w */
+    { { 0,1 }, { M,M },       { M } },
+    { { 0,1 }, { M,M,M },     { M } },
+    { { 0,1 }, { M,M,M,M },   { M } },
+    { { 0,1 }, { M,M,M,M,M }, { M } },
+  };
+
+  mpz_t  w, x, y;
+  int    i;
+
+  mpz_init (w);
+  mpz_init (x);
+  mpz_init (y);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
+      mpz_set_n (x, data[i].x, (mp_size_t) numberof(data[i].x));
+      mpz_set_n (y, data[i].y, (mp_size_t) numberof(data[i].y));
+      check_all (w, x, y);
+    }
+
+  mpz_clear (w);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t  w, x, y;
+  int    i, reps = 2000;
+
+  mpz_init (w);
+  mpz_init (x);
+  mpz_init (y);
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (y, rands, 5*GMP_LIMB_BITS);
+      check_all (w, x, y);
+      check_all_inplace (w, y);
+
+      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (y, rands, BITS_PER_ULONG);
+      check_all (w, x, y);
+      check_all_inplace (w, y);
+    }
+
+  mpz_clear (w);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_data ();
+  check_data_inplace_ui ();
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-bin.c b/tests/mpz/t-bin.c
new file mode 100644
index 0000000..b647be4
--- /dev/null
+++ b/tests/mpz/t-bin.c
@@ -0,0 +1,328 @@
+/* Exercise mpz_bin_ui and mpz_bin_uiui.
+
+Copyright 2000, 2001, 2010, 2012, 2018, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Default number of generated tests. */
+#define COUNT 700
+
+void
+try_mpz_bin_ui (mpz_srcptr want, mpz_srcptr n, unsigned long k)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+  mpz_bin_ui (got, n, k);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_bin_ui wrong\n");
+      printf ("  n="); mpz_out_str (stdout, 10, n); printf ("\n");
+      printf ("  k=%lu\n", k);
+      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
+      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
+      abort();
+    }
+  mpz_clear (got);
+}
+
+
+void
+try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+  mpz_bin_uiui (got, n, k);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_bin_uiui wrong\n");
+      printf ("  n=%lu\n", n);
+      printf ("  k=%lu\n", k);
+      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
+      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
+      abort();
+    }
+  mpz_clear (got);
+}
+
+
+void
+samples (void)
+{
+  static const struct {
+    const char     *n;
+    unsigned long  k;
+    const char     *want;
+  } data[] = {
+
+    {   "0", 123456, "0" },
+    {   "1", 543210, "0" },
+    {   "2", 123321, "0" },
+    {   "3", 234567, "0" },
+    {   "10", 23456, "0" },
+
+    /* negatives, using bin(-n,k)=bin(n+k-1,k) */
+    {   "-1",  0,  "1"  },
+    {   "-1",  1, "-1"  },
+    {   "-1",  2,  "1"  },
+    {   "-1",  3, "-1"  },
+    {   "-1",  4,  "1"  },
+
+    {   "-2",  0,  "1"  },
+    {   "-2",  1, "-2"  },
+    {   "-2",  2,  "3"  },
+    {   "-2",  3, "-4"  },
+    {   "-2",  4,  "5"  },
+    {   "-2",  5, "-6"  },
+    {   "-2",  6,  "7"  },
+
+    {   "-3",  0,   "1"  },
+    {   "-3",  1,  "-3"  },
+    {   "-3",  2,   "6"  },
+    {   "-3",  3, "-10"  },
+    {   "-3",  4,  "15"  },
+    {   "-3",  5, "-21"  },
+    {   "-3",  6,  "28"  },
+
+    /* A few random values */
+    {   "41", 20,  "269128937220" },
+    {   "62", 37,  "147405545359541742" },
+    {   "50", 18,  "18053528883775" },
+    {  "149", 21,  "19332950844468483467894649" },
+  };
+
+  mpz_t  n, want;
+  int    i;
+
+  mpz_init (n);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+      mpz_set_str_or_abort (want, data[i].want, 0);
+
+      try_mpz_bin_ui (want, n, data[i].k);
+
+      if (mpz_fits_ulong_p (n))
+	try_mpz_bin_uiui (want, mpz_get_ui (n), data[i].k);
+    }
+
+  mpz_clear (n);
+  mpz_clear (want);
+}
+
+
+/* Test some bin(2k,k) cases.  This produces some biggish numbers to
+   exercise the limb accumulating code.  */
+void
+twos (int count)
+{
+  mpz_t          n, want;
+  unsigned long  k;
+
+  mpz_init (n);
+
+  mpz_init_set_ui (want, (unsigned long) 2);
+  for (k = 1; k < count; k++)
+    {
+      mpz_set_ui (n, 2*k);
+      try_mpz_bin_ui (want, n, k);
+
+      try_mpz_bin_uiui (want, 2*k, k);
+
+      mpz_mul_ui (want, want, 2*(2*k+1));
+      mpz_fdiv_q_ui (want, want, k+1);
+    }
+
+  mpz_clear (n);
+  mpz_clear (want);
+}
+
+/* Test some random bin(n,k) cases.  This produces some biggish
+   numbers to exercise the limb accumulating code.  */
+void
+randomwalk (int count)
+{
+  mpz_t          n_z, want, tmp;
+  unsigned long  n, k, i, r;
+  int            tests;
+  gmp_randstate_ptr rands;
+
+  rands = RANDS;
+  mpz_init (n_z);
+
+  k = 3;
+  n = 12;
+  mpz_init_set_ui (want, (unsigned long) 220); /* binomial(12,3) = 220 */
+
+  for (tests = 1; tests < count; tests++)
+    {
+      r = gmp_urandomm_ui (rands, 62) + 1;
+      for (i = r & 7; i > 0; i--)
+	{
+	  n++; k++;
+	  mpz_mul_ui (want, want, n);
+	  mpz_divexact_ui (want, want, k);
+	}
+      for (i = r >> 3; i > 0; i--)
+	{
+	  n++;
+	  mpz_mul_ui (want, want, n);
+	  mpz_divexact_ui (want, want, n - k);
+	}
+
+      mpz_set_ui (n_z, n);
+      try_mpz_bin_ui (want, n_z, k);
+
+      try_mpz_bin_uiui (want, n, k);
+    }
+
+  k = 2;
+  mpz_urandomb (n_z, rands, 200);
+  mpz_mul (want, n_z, n_z); /* want = n_z ^ 2 */
+  mpz_sub (want, want, n_z); /* want = n_z ^ 2 - n_z = n_z (n_z- 1) */
+  mpz_tdiv_q_2exp (want, want, 1); /* want = n_z (n_z- 1) / 2 = binomial (n_z, 2) */
+  mpz_init (tmp);
+  for (tests = 1; tests < count; tests++)
+    {
+      r = gmp_urandomm_ui (rands, 62) + 1;
+      for (i = r & 7; i > 0; i--)
+	{
+	  k++;
+	  mpz_add_ui (n_z, n_z, 1);
+	  mpz_mul (want, want, n_z);
+	  mpz_divexact_ui (want, want, k);
+	}
+      for (i = r >> 3; i > 0; i--)
+	{
+	  mpz_add_ui (n_z, n_z, 1);
+	  mpz_mul (want, want, n_z);
+	  mpz_sub_ui (tmp, n_z, k);
+	  mpz_divexact (want, want, tmp);
+	}
+
+      try_mpz_bin_ui (want, n_z, k);
+    }
+
+  mpz_clear (tmp);
+  mpz_clear (n_z);
+  mpz_clear (want);
+}
+
+/* Test some random bin(n,k) cases.  This produces some biggish
+   numbers to exercise the limb accumulating code.  */
+void
+randomwalk_down (int count)
+{
+  mpz_t          n_z, want, tmp;
+  unsigned long  n, k, i, r;
+  int            tests;
+  gmp_randstate_ptr rands;
+
+  rands = RANDS;
+  mpz_init (n_z);
+  mpz_init (tmp);
+
+  k = 2;
+  n = ULONG_MAX;
+  mpz_init_set_ui (want, n);
+  mpz_mul_ui (want, want, n >> 1);
+
+  for (tests = 1; tests < count; tests++)
+    {
+      r = gmp_urandomm_ui (rands, 62) + 1;
+      for (i = r & 7; i > 0; i--)
+	{
+	  mpz_mul_ui (want, want, n - k);
+	  ++k;
+	  mpz_divexact_ui (want, want, k);
+	}
+      for (i = r >> 3; i > 0; i--)
+	{
+	  mpz_mul_ui (want, want, n - k);
+	  mpz_divexact_ui (want, want, n);
+	  --n;
+	}
+
+      mpz_set_ui (n_z, n);
+      try_mpz_bin_ui (want, n_z, n - k);
+
+      try_mpz_bin_uiui (want, n, n - k);
+    }
+
+  mpz_clear (tmp);
+  mpz_clear (n_z);
+  mpz_clear (want);
+}
+
+
+/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count.  */
+void
+smallexaustive (unsigned int count)
+{
+  mpz_t          n_z, want;
+  unsigned long  n, k;
+
+  mpz_init (n_z);
+  mpz_init (want);
+
+  for (n = 0; n < count; n++)
+    {
+      mpz_set_ui (want, (unsigned long) 1);
+      mpz_set_ui (n_z, n);
+      for (k = 0; k <= n; k++)
+	{
+	  try_mpz_bin_ui (want, n_z, k);
+	  try_mpz_bin_uiui (want, n, k);
+	  mpz_mul_ui (want, want, n - k);
+	  mpz_fdiv_q_ui (want, want, k + 1);
+	}
+      try_mpz_bin_ui (want, n_z, k);
+      try_mpz_bin_uiui (want, n, k);
+    }
+
+  mpz_clear (n_z);
+  mpz_clear (want);
+}
+
+int
+main (int argc, char **argv)
+{
+  int count;
+
+  count = COUNT;
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+
+  samples ();
+  smallexaustive (count >> 4);
+  twos (count >> 1);
+  randomwalk (count - (count >> 1));
+  randomwalk_down (count >> 1);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-bit.c b/tests/mpz/t-bit.c
new file mode 100644
index 0000000..cfcdeea
--- /dev/null
+++ b/tests/mpz/t-bit.c
@@ -0,0 +1,405 @@
+/* Test mpz_setbit, mpz_clrbit, mpz_tstbit.
+
+Copyright 1997, 2000-2003, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 4
+#endif
+
+
+void
+debug_mp (mpz_srcptr x, int base)
+{
+  mpz_out_str (stdout, base, x); fputc ('\n', stdout);
+}
+
+
+/* exercise the case where mpz_clrbit or mpz_combit ends up extending a
+   value like -2^(k*GMP_NUMB_BITS-1) when clearing bit k*GMP_NUMB_BITS-1.  */
+/* And vice-versa. */
+void
+check_clr_extend (void)
+{
+  mpz_t          got, want;
+  unsigned long  i;
+  int            f;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 1; i < 5; i++)
+    {
+      for (f = 0; f <= 1; f++)
+	{
+	  /* lots of 1 bits in _mp_d */
+	  mpz_set_si (got, 1L);
+	  mpz_mul_2exp (got, got, 10*GMP_NUMB_BITS);
+	  mpz_sub_ui (got, got, 1L);
+
+	  /* value -2^(n-1) representing ..11100..00 */
+	  mpz_set_si (got, -1L);
+	  mpz_mul_2exp (got, got, i*GMP_NUMB_BITS-1);
+
+	  /* complement bit n, giving ..11000..00 which is -2^n */
+	  if (f == 0)
+	    mpz_clrbit (got, i*GMP_NUMB_BITS-1);
+	  else
+	    mpz_combit (got, i*GMP_NUMB_BITS-1);
+	  MPZ_CHECK_FORMAT (got);
+
+	  mpz_set_si (want, -1L);
+	  mpz_mul_2exp (want, want, i*GMP_NUMB_BITS);
+
+	  if (mpz_cmp (got, want) != 0)
+	    {
+	      if (f == 0)
+		printf ("mpz_clrbit: ");
+	      else
+		printf ("mpz_combit: ");
+	      printf ("wrong after extension\n");
+	      mpz_trace ("got ", got);
+	      mpz_trace ("want", want);
+	      abort ();
+	    }
+
+	  /* complement bit n, going back to ..11100..00 which is -2^(n-1) */
+	  if (f == 0)
+	    mpz_setbit (got, i*GMP_NUMB_BITS-1);
+	  else
+	    mpz_combit (got, i*GMP_NUMB_BITS-1);
+	  MPZ_CHECK_FORMAT (got);
+
+	  mpz_set_si (want, -1L);
+	  mpz_mul_2exp (want, want, i*GMP_NUMB_BITS - 1);
+
+	  if (mpz_cmp (got, want) != 0)
+	    {
+	      if (f == 0)
+		printf ("mpz_setbit: ");
+	      else
+		printf ("mpz_combit: ");
+	      printf ("wrong after shrinking\n");
+	      mpz_trace ("got ", got);
+	      mpz_trace ("want", want);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+void
+check_com_negs (void)
+{
+  static const struct {
+    unsigned long  bit;
+    mp_size_t      inp_size;
+    mp_limb_t      inp_n[5];
+    mp_size_t      want_size;
+    mp_limb_t      want_n[5];
+  } data[] = {
+    { GMP_NUMB_BITS,   2, { 1, 1 },  1, { 1 } },
+    { GMP_NUMB_BITS+1, 2, { 1, 1 },  2, { 1, 3 } },
+
+    { GMP_NUMB_BITS,   2, { 0, 1 },  2, { 0, 2 } },
+    { GMP_NUMB_BITS+1, 2, { 0, 1 },  2, { 0, 3 } },
+  };
+  mpz_t  inp, got, want;
+  int    i;
+
+  mpz_init (got);
+  mpz_init (want);
+  mpz_init (inp);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_n (inp, data[i].inp_n, data[i].inp_size);
+      mpz_neg (inp, inp);
+
+      mpz_set_n (want, data[i].want_n, data[i].want_size);
+      mpz_neg (want, want);
+
+      mpz_set (got, inp);
+      mpz_combit (got, data[i].bit);
+
+      if (mpz_cmp (got, want) != 0)
+	{
+	  printf ("mpz_combit: wrong on neg data[%d]\n", i);
+	  mpz_trace ("inp ", inp);
+	  printf    ("bit %lu\n", data[i].bit);
+	  mpz_trace ("got ", got);
+	  mpz_trace ("want", want);
+	  abort ();
+	}
+    }
+
+  mpz_clear (inp);
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+/* See that mpz_tstbit matches a twos complement calculated explicitly, for
+   various low zeros.  */
+void
+check_tstbit (void)
+{
+#define MAX_ZEROS  3
+#define NUM_LIMBS  3
+
+  mp_limb_t      pos[1+NUM_LIMBS+MAX_ZEROS];
+  mp_limb_t      neg[1+NUM_LIMBS+MAX_ZEROS];
+  mpz_t          z;
+  unsigned long  i;
+  int            zeros, low1;
+  int            got, want;
+
+  mpz_init (z);
+  for (zeros = 0; zeros <= MAX_ZEROS; zeros++)
+    {
+      MPN_ZERO (pos, numberof(pos));
+      mpn_random2 (pos+zeros, (mp_size_t) NUM_LIMBS);
+
+      for (low1 = 0; low1 <= 1; low1++)
+	{
+	  if (low1)
+	    pos[0] |= 1;
+
+	  refmpn_neg (neg, pos, (mp_size_t) numberof(neg));
+	  mpz_set_n (z, neg, (mp_size_t) numberof(neg));
+	  mpz_neg (z, z);
+
+	  for (i = 0; i < numberof(pos)*GMP_NUMB_BITS; i++)
+	    {
+	      got = mpz_tstbit (z, i);
+	      want = refmpn_tstbit (pos, i);
+	      if (got != want)
+		{
+		  printf ("wrong at bit %lu, with %d zeros\n", i, zeros);
+		  printf ("z neg "); debug_mp (z, -16);
+		  mpz_set_n (z, pos, (mp_size_t) numberof(pos));
+		  printf ("pos   "); debug_mp (z, -16);
+		  mpz_set_n (z, neg, (mp_size_t) numberof(neg));
+		  printf ("neg   "); debug_mp (z, -16);
+		  exit (1);
+		}
+	    }
+	}
+    }
+  mpz_clear (z);
+}
+
+
+void
+check_single (void)
+{
+  mpz_t  x;
+  int    limb, offset, initial;
+  unsigned long  bit;
+
+  mpz_init (x);
+
+  for (limb = 0; limb < 4; limb++)
+    {
+      for (offset = (limb==0 ? 0 : -2); offset <= 2; offset++)
+	{
+	  for (initial = 1; initial >= -1; initial--)
+	    {
+	      mpz_set_si (x, (long) initial);
+
+	      bit = (unsigned long) limb*GMP_LIMB_BITS + offset;
+
+	      mpz_clrbit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 0)
+		{
+		  printf ("check_single(): expected 0\n");
+		  abort ();
+		}
+
+	      mpz_setbit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 1)
+		{
+		  printf ("check_single(): expected 1\n");
+		  abort ();
+		}
+
+	      mpz_clrbit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 0)
+		{
+		  printf ("check_single(): expected 0\n");
+		  abort ();
+		}
+
+	      mpz_combit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 1)
+		{
+		  printf ("check_single(): expected 1\n");
+		  abort ();
+		}
+
+	      mpz_combit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 0)
+		{
+		  printf ("check_single(): expected 0\n");
+		  abort ();
+		}
+	    }
+	}
+    }
+
+  mpz_clear (x);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  mpz_t x, s0, s1, s2, s3, m;
+  mp_size_t xsize;
+  int i;
+  int reps = 100000;
+  int bit0, bit1, bit2, bit3;
+  unsigned long int bitindex;
+  const char  *s = "";
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (x);
+  mpz_init (s0);
+  mpz_init (s1);
+  mpz_init (s2);
+  mpz_init (s3);
+  mpz_init (m);
+
+  for (i = 0; i < reps; i++)
+    {
+      xsize = urandom () % (2 * SIZE) - SIZE;
+      mpz_random2 (x, xsize);
+      bitindex = urandom () % SIZE;
+
+      mpz_set (s0, x);
+      bit0 = mpz_tstbit (x, bitindex);
+      mpz_setbit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+
+      mpz_set (s1, x);
+      bit1 = mpz_tstbit (x, bitindex);
+      mpz_clrbit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+
+      mpz_set (s2, x);
+      bit2 = mpz_tstbit (x, bitindex);
+      mpz_combit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+
+      mpz_set (s3, x);
+      bit3 = mpz_tstbit (x, bitindex);
+
+#define FAIL(str) do { s = str; goto fail; } while (0)
+
+      if (bit1 != 1)  FAIL ("bit1 != 1");
+      if (bit2 != 0)  FAIL ("bit2 != 0");
+      if (bit3 != 1)  FAIL ("bit3 != 1");
+
+      if (bit0 == 0)
+	{
+	  if (mpz_cmp (s0, s1) == 0 || mpz_cmp (s0, s2) != 0 || mpz_cmp (s0, s3) == 0)
+	    abort ();
+	}
+      else
+	{
+	  if (mpz_cmp (s0, s1) != 0 || mpz_cmp (s0, s2) == 0 || mpz_cmp (s0, s3) != 0)
+	    abort ();
+	}
+
+      if (mpz_cmp (s1, s2) == 0 || mpz_cmp (s1, s3) != 0)
+	abort ();
+      if (mpz_cmp (s2, s3) == 0)
+	abort ();
+
+      mpz_combit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (s2, x) != 0)
+	abort ();
+
+      mpz_clrbit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (s2, x) != 0)
+	abort ();
+
+      mpz_ui_pow_ui (m, 2L, bitindex);
+      MPZ_CHECK_FORMAT (m);
+      mpz_ior (x, s0, m);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (x, s3) != 0)
+	abort ();
+
+      mpz_com (m, m);
+      MPZ_CHECK_FORMAT (m);
+      mpz_and (x, s0, m);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (x, s2) != 0)
+	abort ();
+    }
+
+  mpz_clear (x);
+  mpz_clear (s0);
+  mpz_clear (s1);
+  mpz_clear (s2);
+  mpz_clear (s3);
+  mpz_clear (m);
+  return;
+
+
+ fail:
+  printf ("%s\n", s);
+  printf ("bitindex = %lu\n", bitindex);
+  printf ("x = "); mpz_out_str (stdout, -16, x); printf (" hex\n");
+  exit (1);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_clr_extend ();
+  check_com_negs ();
+  check_tstbit ();
+  check_random (argc, argv);
+  check_single ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-cdiv_ui.c b/tests/mpz/t-cdiv_ui.c
new file mode 100644
index 0000000..91559ea
--- /dev/null
+++ b/tests/mpz/t-cdiv_ui.c
@@ -0,0 +1,158 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_cdiv_qr_ui, mpz_cdiv_q_ui,
+   mpz_cdiv_r_ui, , mpz_cdiv_ui, mpz_mul_ui.
+
+Copyright 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (const char *, mpz_t, unsigned long);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size;
+  unsigned long divisor;
+  int i;
+  int reps = 10000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned long r_rq, r_q, r_r, r;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */
+
+      do
+	{
+	  mpz_rrandomb (bs, rands, 64);
+	  divisor = mpz_get_ui (bs);
+	}
+      while (divisor == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs);
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+
+      /* printf ("%ld\n", SIZ (dividend)); */
+
+      r_rq = mpz_cdiv_qr_ui (quotient, remainder, dividend, divisor);
+      r_q = mpz_cdiv_q_ui (quotient2, dividend, divisor);
+      r_r = mpz_cdiv_r_ui (remainder2, dividend, divisor);
+      r = mpz_cdiv_ui (dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort ("quotients from mpz_cdiv_qr_ui and mpz_cdiv_q_ui differ",
+		    dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort ("remainders from mpz_cdiv_qr_ui and mpz_cdiv_r_ui differ",
+		    dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != (mpz_cmp_ui (dividend, 0) < 0))
+	dump_abort ("quotient sign wrong", dividend, divisor);
+
+      /* Check if the remainder has the opposite sign as the (positive) divisor
+	 (quotient rounded towards minus infinity).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if (mpz_cmp_ui (remainder, 0) > 0)
+	  dump_abort ("remainder sign wrong", dividend, divisor);
+
+      mpz_mul_ui (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort ("n mod d != n - [n/d]*d", dividend, divisor);
+
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp_ui (remainder, divisor) >= 0)
+	dump_abort ("remainder greater than divisor", dividend, divisor);
+
+      if (mpz_cmp_ui (remainder, r_rq) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_qr_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_q) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_q_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_r) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_r_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_ui is wrong",
+		    dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *str, mpz_t dividend, unsigned long divisor)
+{
+  fprintf (stderr, "ERROR: %s\n", str);
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = %lX\n", divisor);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-cmp.c b/tests/mpz/t-cmp.c
new file mode 100644
index 0000000..1ae2517
--- /dev/null
+++ b/tests/mpz/t-cmp.c
@@ -0,0 +1,181 @@
+/* Test mpz_cmp and mpz_cmpabs.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Nothing sophisticated here, just exercise some combinations of sizes and
+   signs.  */
+
+
+void
+check_one (mpz_ptr x, mpz_ptr y, int want_cmp, int want_cmpabs)
+{
+  int  got;
+
+  got = mpz_cmp (x, y);
+  if ((   got <  0) != (want_cmp <  0)
+      || (got == 0) != (want_cmp == 0)
+      || (got >  0) != (want_cmp >  0))
+    {
+      printf ("mpz_cmp got %d want %d\n", got, want_cmp);
+      mpz_trace ("x", x);
+      mpz_trace ("y", y);
+      abort ();
+    }
+
+  got = mpz_cmpabs (x, y);
+  if ((   got <  0) != (want_cmpabs <  0)
+      || (got == 0) != (want_cmpabs == 0)
+      || (got >  0) != (want_cmpabs >  0))
+    {
+      printf ("mpz_cmpabs got %d want %d\n", got, want_cmpabs);
+      mpz_trace ("x", x);
+      mpz_trace ("y", y);
+      abort ();
+    }
+}
+
+
+void
+check_all (mpz_ptr x, mpz_ptr y, int want_cmp, int want_cmpabs)
+{
+  check_one (x, y,  want_cmp,  want_cmpabs);
+  check_one (y, x, -want_cmp, -want_cmpabs);
+
+  mpz_neg (x, x);
+  mpz_neg (y, y);
+  want_cmp = -want_cmp;
+
+  check_one (x, y,  want_cmp,  want_cmpabs);
+  check_one (y, x, -want_cmp, -want_cmpabs);
+}
+
+
+#define SET1(z,size, n) \
+  SIZ(z) = size; PTR(z)[0] = n
+
+#define SET2(z,size, n1,n0) \
+  SIZ(z) = size; PTR(z)[1] = n1; PTR(z)[0] = n0
+
+#define SET4(z,size, n3,n2,n1,n0) \
+  SIZ(z) = size; PTR(z)[3] = n3; PTR(z)[2] = n2; PTR(z)[1] = n1; PTR(z)[0] = n0
+
+void
+check_various (void)
+{
+  mpz_t  x, y;
+
+  mpz_init (x);
+  mpz_init (y);
+
+  mpz_realloc (x, (mp_size_t) 20);
+  mpz_realloc (y, (mp_size_t) 20);
+
+  /* 0 cmp 0, junk in low limbs */
+  SET1 (x,0, 123);
+  SET1 (y,0, 456);
+  check_all (x, y, 0, 0);
+
+
+  /* 123 cmp 0 */
+  SET1 (x,1, 123);
+  SET1 (y,0, 456);
+  check_all (x, y, 1, 1);
+
+  /* 123:456 cmp 0 */
+  SET2 (x,2, 456,123);
+  SET1 (y,0, 9999);
+  check_all (x, y, 1, 1);
+
+
+  /* 123 cmp 123 */
+  SET1(x,1, 123);
+  SET1(y,1, 123);
+  check_all (x, y, 0, 0);
+
+  /* -123 cmp 123 */
+  SET1(x,-1, 123);
+  SET1(y,1,  123);
+  check_all (x, y, -1, 0);
+
+
+  /* 123 cmp 456 */
+  SET1(x,1, 123);
+  SET1(y,1, 456);
+  check_all (x, y, -1, -1);
+
+  /* -123 cmp 456 */
+  SET1(x,-1, 123);
+  SET1(y,1,  456);
+  check_all (x, y, -1, -1);
+
+  /* 123 cmp -456 */
+  SET1(x,1,  123);
+  SET1(y,-1, 456);
+  check_all (x, y, 1, -1);
+
+
+  /* 1:0 cmp 1:0 */
+  SET2 (x,2, 1,0);
+  SET2 (y,2, 1,0);
+  check_all (x, y, 0, 0);
+
+  /* -1:0 cmp 1:0 */
+  SET2 (x,-2, 1,0);
+  SET2 (y,2,  1,0);
+  check_all (x, y, -1, 0);
+
+
+  /* 2:0 cmp 1:0 */
+  SET2 (x,2, 2,0);
+  SET2 (y,2, 1,0);
+  check_all (x, y, 1, 1);
+
+
+  /* 4:3:2:1 cmp 2:1 */
+  SET4 (x,4, 4,3,2,1);
+  SET2 (y,2, 2,1);
+  check_all (x, y, 1, 1);
+
+  /* -4:3:2:1 cmp 2:1 */
+  SET4 (x,-4, 4,3,2,1);
+  SET2 (y,2,  2,1);
+  check_all (x, y, -1, 1);
+
+
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-cmp_d.c b/tests/mpz/t-cmp_d.c
new file mode 100644
index 0000000..d7b9895
--- /dev/null
+++ b/tests/mpz/t-cmp_d.c
@@ -0,0 +1,292 @@
+/* Test mpz_cmp_d and mpz_cmpabs_d.
+
+Copyright 2001-2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* FIXME: Not sure if the tests here are exhaustive.  Ought to try to get
+   each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised.  */
+
+
+#define SGN(n)  ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
+
+
+void
+check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs)
+{
+  int   got;
+
+  got = mpz_cmp_d (x, y);
+  if (SGN(got) != cmp)
+    {
+      int i;
+      printf    ("mpz_cmp_d wrong (from %s)\n", name);
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmp);
+    fail:
+      mpz_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      mp_trace_base=-16;
+      mpz_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      printf    ("  y");
+      for (i = 0; i < sizeof(y); i++)
+        printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
+      printf ("\n");
+      abort ();
+    }
+
+  got = mpz_cmpabs_d (x, y);
+  if (SGN(got) != cmpabs)
+    {
+      printf    ("mpz_cmpabs_d wrong\n");
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmpabs);
+      goto fail;
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *x;
+    double      y;
+    int         cmp, cmpabs;
+
+  } data[] = {
+
+    {  "0",  0.0,  0,  0 },
+
+    {  "1",  0.0,  1,  1 },
+    { "-1",  0.0, -1,  1 },
+
+    {  "1",  0.5,  1,  1 },
+    { "-1", -0.5, -1,  1 },
+
+    {  "0",  1.0, -1, -1 },
+    {  "0", -1.0,  1, -1 },
+
+    {  "0x1000000000000000000000000000000000000000000000000", 1.0,  1, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 },
+
+    {  "0",  1e100, -1, -1 },
+    {  "0", -1e100,  1, -1 },
+
+    {  "2",  1.5,   1,  1 },
+    {  "2", -1.5,   1,  1 },
+    { "-2",  1.5,  -1,  1 },
+    { "-2", -1.5,  -1,  1 },
+  };
+
+  mpz_t  x;
+  int    i;
+
+  mpz_init (x);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (x, data[i].x, 0);
+      check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs);
+    }
+
+  mpz_clear (x);
+}
+
+
+/* Equality of integers with up to 53 bits */
+void
+check_onebits (void)
+{
+  mpz_t   x, x2;
+  double  y;
+  int     i;
+
+  mpz_init_set_ui (x, 0L);
+  mpz_init (x2);
+
+  for (i = 0; i < 512; i++)
+    {
+      mpz_mul_2exp (x, x, 1);
+      mpz_add_ui (x, x, 1L);
+
+      y = mpz_get_d (x);
+      mpz_set_d (x2, y);
+
+      /* stop if any truncation is occurring */
+      if (mpz_cmp (x, x2) != 0)
+        break;
+
+      check_one ("check_onebits", x, y, 0, 0);
+      check_one ("check_onebits", x, -y, 1, 0);
+      mpz_neg (x, x);
+      check_one ("check_onebits", x, y, -1, 0);
+      check_one ("check_onebits", x, -y, 0, 0);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+  mpz_clear (x2);
+}
+
+
+/* With the mpz differing by 1, in a limb position possibly below the double */
+void
+check_low_z_one (void)
+{
+  mpz_t          x;
+  double         y;
+  unsigned long  i;
+
+  mpz_init (x);
+
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+#define LIM 127			/* vax fp numbers have limited range */
+#else
+#define LIM 512
+#endif
+
+  for (i = 1; i < LIM; i++)
+    {
+      mpz_set_ui (x, 1L);
+      mpz_mul_2exp (x, x, i);
+      y = mpz_get_d (x);
+
+      check_one ("check_low_z_one", x, y,   0, 0);
+      check_one ("check_low_z_one", x, -y,  1, 0);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 0);
+      check_one ("check_low_z_one", x, -y,  0, 0);
+      mpz_neg (x, x);
+
+      mpz_sub_ui (x, x, 1);
+
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+
+      mpz_add_ui (x, x, 2);
+
+      check_one ("check_low_z_one", x, y,   1, 1);
+      check_one ("check_low_z_one", x, -y,  1, 1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 1);
+      check_one ("check_low_z_one", x, -y, -1, 1);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+}
+
+/* Comparing 1 and 1+2^-n.  "y" is volatile to make gcc store and fetch it,
+   which forces it to a 64-bit double, whereas on x86 it would otherwise
+   remain on the float stack as an 80-bit long double.  */
+void
+check_one_2exp (void)
+{
+  double           e;
+  mpz_t            x;
+  volatile double  y;
+  int              i;
+
+  mpz_init (x);
+
+  e = 1.0;
+  for (i = 0; i < 128; i++)
+    {
+      e /= 2.0;
+      y = 1.0 + e;
+      if (y == 1.0)
+        break;
+
+      mpz_set_ui (x, 1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+
+      mpz_set_si (x, -1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+    }
+
+  mpz_clear (x);
+}
+
+void
+check_infinity (void)
+{
+  mpz_t   x;
+  double  y = tests_infinity_d ();
+  if (y == 0.0)
+    return;
+
+  mpz_init (x);
+
+  /* 0 cmp inf */
+  mpz_set_ui (x, 0L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 123 cmp inf */
+  mpz_set_ui (x, 123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -123 cmp inf */
+  mpz_set_si (x, -123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 2^5000 cmp inf */
+  mpz_set_ui (x, 1L);
+  mpz_mul_2exp (x, x, 5000L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -2^5000 cmp inf */
+  mpz_neg (x, x);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  mpz_clear (x);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_data ();
+  check_onebits ();
+  check_low_z_one ();
+  check_one_2exp ();
+  check_infinity ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-cmp_si.c b/tests/mpz/t-cmp_si.c
new file mode 100644
index 0000000..7667d3e
--- /dev/null
+++ b/tests/mpz/t-cmp_si.c
@@ -0,0 +1,101 @@
+/* Test mpz_cmp_si.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x)       ((x) < 0 ? -1 : (x) == 0 ? 0 : 1)
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *a, *b;
+    int         want;
+  } data[] = {
+    { "0",  "1", -1 },
+    { "0",  "0",  0 },
+    { "0", "-1",  1 },
+
+    { "1",  "1", 0 },
+    { "1",  "0", 1 },
+    { "1", "-1", 1 },
+
+    { "-1",  "1", -1 },
+    { "-1",  "0", -1 },
+    { "-1", "-1", 0 },
+
+    {           "0", "-0x80000000",  1 },
+    {  "0x80000000", "-0x80000000",  1 },
+    {  "0x80000001", "-0x80000000",  1 },
+    { "-0x80000000", "-0x80000000",  0 },
+    { "-0x80000001", "-0x80000000", -1 },
+
+    {                   "0", "-0x8000000000000000",  1 },
+    {  "0x8000000000000000", "-0x8000000000000000",  1 },
+    {  "0x8000000000000001", "-0x8000000000000000",  1 },
+    { "-0x8000000000000000", "-0x8000000000000000",  0 },
+    { "-0x8000000000000001", "-0x8000000000000000", -1 },
+  };
+
+  mpz_t  a, bz;
+  long   b;
+  int    got;
+  int    i;
+
+  mpz_init (a);
+  mpz_init (bz);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (bz, data[i].b, 0);
+
+      if (mpz_fits_slong_p (bz))
+	{
+	  b = mpz_get_si (bz);
+	  got = mpz_cmp_si (a, b);
+	  if (SGN (got) != data[i].want)
+	    {
+	      printf ("mpz_cmp_si wrong on data[%d]\n", i);
+	      printf ("  a="); mpz_out_str (stdout, 10, a); printf ("\n");
+	      printf ("  b=%ld\n", b);
+	      printf ("  got=%d\n", got);
+	      printf ("  want=%d\n", data[i].want);
+	      abort();
+	    }
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (bz);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-cong.c b/tests/mpz/t-cong.c
new file mode 100644
index 0000000..59d8526
--- /dev/null
+++ b/tests/mpz/t-cong.c
@@ -0,0 +1,226 @@
+/* test mpz_congruent_p and mpz_congruent_ui_p
+
+Copyright 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want)
+{
+  int   got;
+  int   swap;
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      got = (mpz_congruent_p (a, c, d) != 0);
+      if (want != got)
+	{
+	  printf ("mpz_congruent_p wrong\n");
+	  printf ("   expected %d got %d\n", want, got);
+	  mpz_trace ("	 a", a);
+	  mpz_trace ("	 c", c);
+	  mpz_trace ("	 d", d);
+	  mp_trace_base = -16;
+	  mpz_trace ("	 a", a);
+	  mpz_trace ("	 c", c);
+	  mpz_trace ("	 d", d);
+	  abort ();
+	}
+
+      if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d))
+	{
+	  unsigned long	 uc = mpz_get_ui (c);
+	  unsigned long	 ud = mpz_get_ui (d);
+	  got = (mpz_congruent_ui_p (a, uc, ud) != 0);
+	  if (want != got)
+	    {
+	      printf	("mpz_congruent_ui_p wrong\n");
+	      printf	("   expected %d got %d\n", want, got);
+	      mpz_trace ("   a", a);
+	      printf	("   c=%lu\n", uc);
+	      printf	("   d=%lu\n", ud);
+	      mp_trace_base = -16;
+	      mpz_trace ("   a", a);
+	      printf	("   c=0x%lX\n", uc);
+	      printf	("   d=0x%lX\n", ud);
+	      abort ();
+	    }
+	}
+
+      MPZ_SRCPTR_SWAP (a, c);
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *c;
+    const char *d;
+    int        want;
+
+  } data[] = {
+
+    /* strict equality mod 0 */
+    { "0", "0", "0", 1 },
+    { "11", "11", "0", 1 },
+    { "3", "11", "0", 0 },
+
+    /* anything congruent mod 1 */
+    { "0", "0", "1", 1 },
+    { "1", "0", "1", 1 },
+    { "0", "1", "1", 1 },
+    { "123", "456", "1", 1 },
+    { "0x123456789123456789", "0x987654321987654321", "1", 1 },
+
+    /* csize==1, dsize==2 changing to 1 after stripping 2s */
+    { "0x3333333333333333",  "0x33333333",
+      "0x180000000", 1 },
+    { "0x33333333333333333333333333333333", "0x3333333333333333",
+      "0x18000000000000000", 1 },
+
+    /* another dsize==2 becoming 1, with opposite signs this time */
+    {  "0x444444441",
+      "-0x22222221F",
+       "0x333333330", 1 },
+    {  "0x44444444444444441",
+      "-0x2222222222222221F",
+       "0x33333333333333330", 1 },
+  };
+
+  mpz_t   a, c, d;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (c, data[i].c, 0);
+      mpz_set_str_or_abort (d, data[i].d, 0);
+      check_one (a, c, d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t   a, c, d, ra, rc;
+  int     i;
+  int     want;
+  int     reps = 10000;
+  mpz_t bs;
+  unsigned long size_range, size;
+
+  if (argc >= 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (bs);
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+  mpz_init (ra);
+  mpz_init (rc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 1; /* 0..65536 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (a, rands, size);
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 1; /* 0..65536 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (c, rands, size);
+
+      do
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  size_range = mpz_get_ui (bs) % 16 + 1; /* 0..65536 bit operands */
+
+	  mpz_urandomb (bs, rands, size_range);
+	  size = mpz_get_ui (bs);
+	  mpz_rrandomb (d, rands, size);
+	}
+      while (SIZ(d) == 0);
+
+      mpz_negrandom (a, rands);
+      MPZ_CHECK_FORMAT (a);
+      mpz_negrandom (c, rands);
+      MPZ_CHECK_FORMAT (c);
+      mpz_negrandom (d, rands);
+
+      mpz_fdiv_r (ra, a, d);
+      mpz_fdiv_r (rc, c, d);
+
+      want = (mpz_cmp (ra, rc) == 0);
+      check_one (a, c, d, want);
+
+      mpz_sub (ra, ra, rc);
+      mpz_sub (a, a, ra);
+      MPZ_CHECK_FORMAT (a);
+      check_one (a, c, d, 1);
+
+      if (! mpz_pow2abs_p (d))
+        {
+	  refmpz_combit (a, urandom() % (8*GMP_LIMB_BITS));
+	  check_one (a, c, d, 0);
+        }
+    }
+
+  mpz_clear (bs);
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+  mpz_clear (ra);
+  mpz_clear (rc);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_data ();
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-cong_2exp.c b/tests/mpz/t-cong_2exp.c
new file mode 100644
index 0000000..5ffe2d1
--- /dev/null
+++ b/tests/mpz/t-cong_2exp.c
@@ -0,0 +1,207 @@
+/* test mpz_congruent_2exp_p */
+
+/*
+Copyright 2001, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, mpz_srcptr c, unsigned long d, int want)
+{
+  mpz_t  diff, d2exp;
+  int    got;
+  int    swap;
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      got = (mpz_congruent_2exp_p (a, c, d) != 0);
+      if (want != got)
+        {
+          mpz_init (diff);
+          mpz_init (d2exp);
+
+          mpz_sub (diff, a, c);
+          mpz_set_ui (d2exp, 1L);
+          mpz_mul_2exp (d2exp, d2exp, d);
+
+          printf ("mpz_congruent_2exp_p wrong\n");
+          printf ("   expected %d got %d\n", want, got);
+          mpz_trace ("   a", a);
+          mpz_trace ("   c", c);
+          mpz_trace (" a-c", diff);
+          mpz_trace (" 2^d", d2exp);
+          printf    ("   d=%lu\n", d);
+
+          mp_trace_base = -16;
+          mpz_trace ("   a", a);
+          mpz_trace ("   c", c);
+          mpz_trace (" a-c", diff);
+          mpz_trace (" 2^d", d2exp);
+          printf    ("   d=0x%lX\n", d);
+          abort ();
+        }
+
+      MPZ_SRCPTR_SWAP (a, c);
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char     *a;
+    const char     *c;
+    unsigned long  d;
+    int            want;
+
+  } data[] = {
+
+    /* anything is congruent mod 1 */
+    { "0", "0", 0, 1 },
+    { "1", "0", 0, 1 },
+    { "0", "1", 0, 1 },
+    { "123", "-456", 0, 1 },
+    { "0x123456789123456789", "0x987654321987654321", 0, 1 },
+    { "0xfffffffffffffffffffffffffffffff7", "-0x9", 129, 0 },
+    { "0xfffffffffffffffffffffffffffffff6", "-0xa", 128, 1 },
+
+  };
+
+  mpz_t   a, c;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (c);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (c, data[i].c, 0);
+      check_one (a, c, data[i].d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+}
+
+
+void
+check_random (int reps)
+{
+  gmp_randstate_ptr rands = RANDS;
+  unsigned long  d;
+  mpz_t  a, c, ra, rc;
+  int    i;
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (ra);
+  mpz_init (rc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_errandomb (a, rands, 8*GMP_LIMB_BITS);
+      mpz_errandomb (c, rands, 8*GMP_LIMB_BITS);
+      d = urandom() % (8*GMP_LIMB_BITS);
+
+      mpz_mul_2exp (a, a, urandom() % (2*GMP_LIMB_BITS));
+      mpz_mul_2exp (c, c, urandom() % (2*GMP_LIMB_BITS));
+
+      mpz_negrandom (a, rands);
+      mpz_negrandom (c, rands);
+
+      mpz_fdiv_r_2exp (ra, a, d);
+      mpz_fdiv_r_2exp (rc, c, d);
+
+      mpz_sub (ra, ra, rc);
+      if (mpz_cmp_ui (ra, 0) != 0)
+	{
+	  check_one (a, c, d, 0);
+	  mpz_sub (a, a, ra);
+	}
+      check_one (a, c, d, 1);
+      if (d != 0)
+	{
+	  mpz_combit (a, urandom() % d);
+	  check_one (a, c, d, 0);
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (ra);
+  mpz_clear (rc);
+}
+
+void
+check_random_bits (int reps)
+{
+  mp_bitcnt_t ea, ec, en, d;
+  mp_bitcnt_t m = 10 * GMP_LIMB_BITS;
+  mpz_t  a, c;
+  int    i;
+
+  mpz_init2 (a, m + 1);
+  mpz_init2 (c, m);
+
+  for (i = 0; i < reps; i++)
+    {
+      d  = urandom() % m;
+      ea = urandom() % m;
+      ec = urandom() % m;
+      en = urandom() % m;
+
+      mpz_set_ui (c, 0);
+      mpz_setbit (c, en);
+
+      mpz_set_ui (a, 0);
+      mpz_setbit (a, ec);
+      mpz_sub (c , a, c);
+
+      mpz_set_ui (a, 0);
+      mpz_setbit (a, ea);
+      mpz_add (a , a, c);
+
+      check_one (a, c, d, ea >= d);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int    reps = 5000;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  check_data ();
+  check_random (reps);
+  check_random_bits (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-div_2exp.c b/tests/mpz/t-div_2exp.c
new file mode 100644
index 0000000..d012aae
--- /dev/null
+++ b/tests/mpz/t-div_2exp.c
@@ -0,0 +1,223 @@
+/* Test mpz_[cft]div_[qr]_2exp.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* If the remainder is in the correct range and q*d+r is correct, then q
+   must have rounded correctly.  */
+
+void
+check_one (mpz_srcptr a, unsigned long d)
+{
+  mpz_t  q, r, p, d2exp;
+  int    inplace;
+
+  mpz_init (d2exp);
+  mpz_init (q);
+  mpz_init (r);
+  mpz_init (p);
+
+  mpz_set_ui (d2exp, 1L);
+  mpz_mul_2exp (d2exp, d2exp, d);
+
+#define INPLACE(fun,dst,src,d)  \
+  if (inplace)                  \
+    {                           \
+      mpz_set (dst, src);       \
+      fun (dst, dst, d);        \
+    }                           \
+  else                          \
+    fun (dst, src, d);
+
+  for (inplace = 0; inplace <= 1; inplace++)
+    {
+      INPLACE (mpz_fdiv_q_2exp, q, a, d);
+      INPLACE (mpz_fdiv_r_2exp, r, a, d);
+
+      mpz_mul_2exp (p, q, d);
+      mpz_add (p, p, r);
+      if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0)
+	{
+	  printf ("mpz_fdiv_r_2exp result out of range\n");
+	  goto error;
+	}
+      if (mpz_cmp (p, a) != 0)
+	{
+	  printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n");
+	  goto error;
+	}
+
+
+      INPLACE (mpz_cdiv_q_2exp, q, a, d);
+      INPLACE (mpz_cdiv_r_2exp, r, a, d);
+
+      mpz_mul_2exp (p, q, d);
+      mpz_add (p, p, r);
+      if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0)
+	{
+	  printf ("mpz_cdiv_r_2exp result out of range\n");
+	  goto error;
+	}
+      if (mpz_cmp (p, a) != 0)
+	{
+	  printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n");
+	  goto error;
+	}
+
+
+      INPLACE (mpz_tdiv_q_2exp, q, a, d);
+      INPLACE (mpz_tdiv_r_2exp, r, a, d);
+
+      mpz_mul_2exp (p, q, d);
+      mpz_add (p, p, r);
+      if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a))
+	{
+	  printf ("mpz_tdiv_r_2exp result wrong sign\n");
+	  goto error;
+	}
+      if (mpz_cmpabs (r, d2exp) >= 0)
+	{
+	  printf ("mpz_tdiv_r_2exp result out of range\n");
+	  goto error;
+	}
+      if (mpz_cmp (p, a) != 0)
+	{
+	  printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n");
+	  goto error;
+	}
+    }
+
+  mpz_clear (d2exp);
+  mpz_clear (q);
+  mpz_clear (r);
+  mpz_clear (p);
+  return;
+
+
+ error:
+  mpz_trace ("a", a);
+  printf    ("d=%lu\n", d);
+  mpz_trace ("q", q);
+  mpz_trace ("r", r);
+  mpz_trace ("p", p);
+
+  mp_trace_base = -16;
+  mpz_trace ("a", a);
+  printf    ("d=0x%lX\n", d);
+  mpz_trace ("q", q);
+  mpz_trace ("r", r);
+  mpz_trace ("p", p);
+
+  abort ();
+}
+
+
+void
+check_all (mpz_ptr a, unsigned long d)
+{
+  check_one (a, d);
+  mpz_neg (a, a);
+  check_one (a, d);
+}
+
+
+void
+check_various (void)
+{
+  static const unsigned long  table[] = {
+    0, 1, 2, 3, 4, 5,
+    GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
+    2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
+    3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
+    4*GMP_NUMB_BITS-1, 4*GMP_NUMB_BITS, 4*GMP_NUMB_BITS+1
+  };
+
+  int            i, j;
+  unsigned long  n, d;
+  mpz_t          a;
+
+  mpz_init (a);
+
+  /* a==0, and various d */
+  mpz_set_ui (a, 0L);
+  for (i = 0; i < numberof (table); i++)
+    check_one (a, table[i]);
+
+  /* a==2^n, and various d */
+  for (i = 0; i < numberof (table); i++)
+    {
+      n = table[i];
+      mpz_set_ui (a, 1L);
+      mpz_mul_2exp (a, a, n);
+
+      for (j = 0; j < numberof (table); j++)
+	{
+	  d = table[j];
+	  check_all (a, d);
+	}
+    }
+
+  mpz_clear (a);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr  rands = RANDS;
+  int            reps = 100;
+  mpz_t          a;
+  unsigned long  d;
+  int            i;
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (a);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* exponentially within 2 to 257 bits */
+      mpz_erandomb (a, rands, urandom () % 8 + 2);
+
+      d = urandom () % 256;
+
+      check_all (a, d);
+    }
+
+  mpz_clear (a);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_various ();
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-divis.c b/tests/mpz/t-divis.c
new file mode 100644
index 0000000..fe8186a
--- /dev/null
+++ b/tests/mpz/t-divis.c
@@ -0,0 +1,166 @@
+/* test mpz_divisible_p and mpz_divisible_ui_p
+
+Copyright 2001, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, mpz_srcptr d, int want)
+{
+  int   got;
+
+  if (mpz_fits_ulong_p (d))
+    {
+      unsigned long  u = mpz_get_ui (d);
+      got = (mpz_divisible_ui_p (a, u) != 0);
+      if (want != got)
+        {
+          printf ("mpz_divisible_ui_p wrong\n");
+          printf ("   expected %d got %d\n", want, got);
+          mpz_trace ("   a", a);
+          printf ("   d=%lu\n", u);
+          mp_trace_base = -16;
+          mpz_trace ("   a", a);
+          printf ("   d=0x%lX\n", u);
+          abort ();
+        }
+    }
+
+  got = (mpz_divisible_p (a, d) != 0);
+  if (want != got)
+    {
+      printf ("mpz_divisible_p wrong\n");
+      printf ("   expected %d got %d\n", want, got);
+      mpz_trace ("   a", a);
+      mpz_trace ("   d", d);
+      mp_trace_base = -16;
+      mpz_trace ("   a", a);
+      mpz_trace ("   d", d);
+      abort ();
+    }
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *d;
+    int        want;
+
+  } data[] = {
+
+    { "0",    "0", 1 },
+    { "17",   "0", 0 },
+    { "0",    "1", 1 },
+    { "123",  "1", 1 },
+    { "-123", "1", 1 },
+
+    { "0",  "2", 1 },
+    { "1",  "2", 0 },
+    { "2",  "2", 1 },
+    { "-2", "2", 1 },
+    { "0x100000000000000000000000000000000", "2", 1 },
+    { "0x100000000000000000000000000000001", "2", 0 },
+
+    { "0x3333333333333333", "3", 1 },
+    { "0x3333333333333332", "3", 0 },
+    { "0x33333333333333333333333333333333", "3", 1 },
+    { "0x33333333333333333333333333333332", "3", 0 },
+
+    /* divisor changes from 2 to 1 limb after stripping 2s */
+    {          "0x3333333300000000",         "0x180000000",         1 },
+    {  "0x33333333333333330000000000000000", "0x18000000000000000", 1 },
+    { "0x133333333333333330000000000000000", "0x18000000000000000", 0 },
+  };
+
+  mpz_t   a, d;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (d, data[i].d, 0);
+      check_one (a, d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (d);
+}
+
+void
+check_random (int reps)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t   a, d, r;
+  int     i;
+  int     want;
+
+  mpz_init (a);
+  mpz_init (d);
+  mpz_init (r);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_erandomb (a, rands, 1 << 19);
+      mpz_erandomb_nonzero (d, rands, 1 << 18);
+
+      mpz_fdiv_r (r, a, d);
+
+      want = (mpz_sgn (r) == 0);
+      check_one (a, d, want);
+
+      mpz_sub (a, a, r);
+      check_one (a, d, 1);
+
+      if (mpz_cmpabs_ui (d, 1L) == 0)
+        continue;
+
+      mpz_add_ui (a, a, 1L);
+      check_one (a, d, 0);
+    }
+
+  mpz_clear (a);
+  mpz_clear (d);
+  mpz_clear (r);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  reps = 100;
+
+  tests_start ();
+
+  TESTS_REPS (reps, argv, argc);
+
+  check_data ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-divis_2exp.c b/tests/mpz/t-divis_2exp.c
new file mode 100644
index 0000000..636c751
--- /dev/null
+++ b/tests/mpz/t-divis_2exp.c
@@ -0,0 +1,132 @@
+/* test mpz_divisible_2exp_p */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, unsigned long d, int want)
+{
+  int   got;
+
+  got = (mpz_divisible_2exp_p (a, d) != 0);
+  if (want != got)
+    {
+      printf ("mpz_divisible_2exp_p wrong\n");
+      printf ("   expected %d got %d\n", want, got);
+      mpz_trace ("   a", a);
+      printf    ("   d=%lu\n", d);
+      mp_trace_base = -16;
+      mpz_trace ("   a", a);
+      printf    ("   d=0x%lX\n", d);
+      abort ();
+    }
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    const char    *a;
+    unsigned long d;
+    int           want;
+
+  } data[] = {
+
+    { "0", 0, 1 },
+    { "0", 1, 1 },
+    { "0", 2, 1 },
+    { "0", 3, 1 },
+
+    { "1", 0, 1 },
+    { "1", 1, 0 },
+    { "1", 2, 0 },
+    { "1", 3, 0 },
+    { "1", 10000, 0 },
+
+    { "4", 0, 1 },
+    { "4", 1, 1 },
+    { "4", 2, 1 },
+    { "4", 3, 0 },
+    { "4", 4, 0 },
+    { "4", 10000, 0 },
+
+    { "0x80000000", 31, 1 },
+    { "0x80000000", 32, 0 },
+    { "0x80000000", 64, 0 },
+
+    { "0x100000000", 32, 1 },
+    { "0x100000000", 33, 0 },
+    { "0x100000000", 64, 0 },
+
+    { "0x8000000000000000", 63, 1 },
+    { "0x8000000000000000", 64, 0 },
+    { "0x8000000000000000", 128, 0 },
+
+    { "0x10000000000000000", 64, 1 },
+    { "0x10000000000000000", 65, 0 },
+    { "0x10000000000000000", 128, 0 },
+    { "0x10000000000000000", 256, 0 },
+
+    { "0x10000000000000000100000000", 32, 1 },
+    { "0x10000000000000000100000000", 33, 0 },
+    { "0x10000000000000000100000000", 64, 0 },
+
+    { "0x1000000000000000010000000000000000", 64, 1 },
+    { "0x1000000000000000010000000000000000", 65, 0 },
+    { "0x1000000000000000010000000000000000", 128, 0 },
+    { "0x1000000000000000010000000000000000", 256, 0 },
+    { "0x1000000000000000010000000000000000", 1024, 0 },
+
+  };
+
+  mpz_t   a, d;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      check_one (a, data[i].d, data[i].want);
+
+      mpz_neg (a, a);
+      check_one (a, data[i].d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (d);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-export.c b/tests/mpz/t-export.c
new file mode 100644
index 0000000..fa411e3
--- /dev/null
+++ b/tests/mpz/t-export.c
@@ -0,0 +1,205 @@
+/* Test mpz_export.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *src;
+    size_t      want_count;
+    int         order;
+    size_t      size;
+    int         endian;
+    int         nail;
+    char        want_data[64];
+
+  } data[] = {
+
+    { "0", 0,1, 1,1, 0 },
+    { "0", 0,1, 2,1, 0 },
+    { "0", 0,1, 3,1, 0 },
+
+    { "0x12345678", 4,1,  1,1, 0, { '\022', '\064', '\126', '\170' } },
+    { "0x12345678", 1,1,  4,1, 0, { '\022', '\064', '\126', '\170' } },
+    { "0x12345678", 1,-1, 4,1, 0, { '\022', '\064', '\126', '\170' } },
+
+    { "0x12345678", 4,-1, 1,-1, 0, { '\170', '\126', '\064', '\022' } },
+    { "0x12345678", 1,1,  4,-1, 0, { '\170', '\126', '\064', '\022' } },
+    { "0x12345678", 1,-1, 4,-1, 0, { '\170', '\126', '\064', '\022' } },
+
+    { "0x15", 5,1,  1,1, 7, { '\001', '\000', '\001', '\000', '\001' } },
+
+    { "0x1FFFFFFFFFFF", 3,1,  2,1,   1, {
+	'\177','\377', '\177','\377', '\177','\377' } },
+    { "0x1FFFFFFFFFFF", 3,1,  2,-1,  1, {
+	'\377','\177', '\377','\177', '\377','\177' } },
+    { "0x7",            3,1,  2,1,  15, {
+	'\000','\001', '\000','\001', '\000','\001' } },
+    { "0x7",            3,1,  2,-1, 15, {
+	'\001','\000', '\001','\000', '\001','\000' } },
+
+    { "0x24", 3,1,  2,1,  14, { '\000','\002', '\000','\001', '\000','\000' }},
+    { "0x24", 3,1,  2,-1, 14, { '\002','\000', '\001','\000', '\000','\000' }},
+    { "0x24", 3,-1, 2,-1, 14, { '\000','\000', '\001','\000', '\002','\000' }},
+    { "0x24", 3,-1, 2,1,  14, { '\000','\000', '\000','\001', '\000','\002' }},
+
+    { "0x123456789ABC", 3,1,  2,1,  0, {
+	'\022','\064', '\126','\170', '\232','\274' } },
+    { "0x123456789ABC", 3,-1, 2,1,  0, {
+	'\232','\274', '\126','\170', '\022','\064' } },
+    { "0x123456789ABC", 3,1,  2,-1, 0, {
+	'\064','\022', '\170','\126', '\274','\232' } },
+    { "0x123456789ABC", 3,-1, 2,-1, 0, {
+	'\274','\232', '\170','\126', '\064','\022' } },
+
+    { "0x112233445566778899AABBCC", 3,1,  4,1,  0,
+      { '\021','\042','\063','\104',
+	'\125','\146','\167','\210',
+	'\231','\252','\273','\314' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,1,  0,
+      { '\231','\252','\273','\314',
+	'\125','\146','\167','\210',
+	'\021','\042','\063','\104' } },
+    { "0x112233445566778899AABBCC", 3,1,  4,-1, 0,
+      { '\104','\063','\042','\021',
+	'\210','\167','\146','\125',
+	'\314','\273','\252','\231' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,-1, 0,
+      { '\314','\273','\252','\231',
+	'\210','\167','\146','\125',
+	'\104','\063','\042','\021' } },
+
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,1,  0,
+      { '\020','\001','\040','\002','\060','\003','\100','\004',
+	'\120','\005','\140','\006','\160','\007','\200','\010',
+	'\220','\011','\240','\012','\260','\013','\300','\014' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,1,  0,
+      { '\220','\011','\240','\012','\260','\013','\300','\014',
+	'\120','\005','\140','\006','\160','\007','\200','\010',
+	'\020','\001','\040','\002','\060','\003','\100','\004' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,-1, 0,
+      { '\004','\100','\003','\060','\002','\040','\001','\020',
+	'\010','\200','\007','\160','\006','\140','\005','\120',
+	'\014','\300','\013','\260','\012','\240','\011','\220' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,-1, 0,
+      { '\014','\300','\013','\260','\012','\240','\011','\220',
+	'\010','\200','\007','\160','\006','\140','\005','\120',
+	'\004','\100','\003','\060','\002','\040','\001','\020' } },
+
+    { "0x155555555555555555555555", 3,1,  4,1,  1,
+      { '\125','\125','\125','\125',
+	'\052','\252','\252','\252',
+	'\125','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,-1,  4,1,  1,
+      { '\125','\125','\125','\125',
+	'\052','\252','\252','\252',
+	'\125','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,1,  4,-1,  1,
+      { '\125','\125','\125','\125',
+	'\252','\252','\252','\052',
+	'\125','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,-1,  4,-1,  1,
+      { '\125','\125','\125','\125',
+	'\252','\252','\252','\052',
+	'\125','\125','\125','\125' } },
+  };
+
+  char    buf[sizeof(data[0].src) + sizeof (mp_limb_t) + 128];
+  char    *got_data;
+  void    *ret;
+  size_t  align, got_count, j;
+  int     i, error = 0;
+  mpz_t   src;
+
+  mpz_init (src);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (align = 0; align < sizeof (mp_limb_t); align++)
+	{
+	  mpz_set_str_or_abort (src, data[i].src, 0);
+	  MPZ_CHECK_FORMAT (src);
+	  got_data = buf + align;
+
+	  ASSERT_ALWAYS (data[i].want_count * data[i].size + align
+			 <= sizeof (buf));
+
+	  memset (got_data, '\0', data[i].want_count * data[i].size);
+	  ret = mpz_export (got_data, &got_count, data[i].order,
+			    data[i].size, data[i].endian, data[i].nail, src);
+
+	  if (ret != got_data)
+	    {
+	      printf ("return doesn't equal given pointer\n");
+	      error = 1;
+	    }
+	  if (got_count != data[i].want_count)
+	    {
+	      printf ("wrong count\n");
+	      error = 1;
+	    }
+	  if (memcmp (got_data, data[i].want_data, got_count * data[i].size) != 0)
+	    {
+	      printf ("wrong result data\n");
+	      error = 1;
+	    }
+	  if (error)
+	    {
+	      printf ("    at data[%d]  align=%d\n", i, (int) align);
+	      printf ("    src \"%s\"\n", data[i].src);
+	      mpz_trace ("    src", src);
+	      printf ("    order=%d  size=%lu endian=%d nail=%u\n",
+		      data[i].order,
+		      (unsigned long) data[i].size, data[i].endian, data[i].nail);
+	      printf ("    want count %lu\n", (unsigned long) data[i].want_count);
+	      printf ("    got count  %lu\n", (unsigned long) got_count);
+	      printf ("    want");
+	      for (j = 0; j < data[i].want_count*data[i].size; j++)
+		printf (" 0x%02X,", (unsigned) (unsigned char) data[i].want_data[j]);
+	      printf ("\n");
+	      printf ("    got ");
+	      for (j = 0; j < got_count*data[i].size; j++)
+		printf (" 0x%02X,", (unsigned) (unsigned char) got_data[j]);
+	      printf ("\n");
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (src);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  mp_trace_base = -16;
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-fac_ui.c b/tests/mpz/t-fac_ui.c
new file mode 100644
index 0000000..15b6070
--- /dev/null
+++ b/tests/mpz/t-fac_ui.c
@@ -0,0 +1,108 @@
+/* Exercise mpz_fac_ui and mpz_2fac_ui.
+
+Copyright 2000-2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-fac_ui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long  n, m;
+  unsigned long  limit = 2222;
+  mpz_t          df[2], f, r;
+
+  tests_start ();
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* for small limb testing */
+  limit = MIN (limit, MP_LIMB_T_MAX);
+
+  mpz_init_set_ui (df[0], 1);  /* 0!! = 1 */
+  mpz_init_set_ui (df[1], 1);  /* -1!! = 1 */
+  mpz_init_set_ui (f, 1);  /* 0! = 1 */
+  mpz_init (r);
+
+  for (n = 0, m = 0; n < limit; n++)
+    {
+      mpz_fac_ui (r, n);
+      MPZ_CHECK_FORMAT (r);
+
+      if (mpz_cmp (f, r) != 0)
+        {
+          printf ("mpz_fac_ui(%lu) wrong\n", n);
+          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+          abort ();
+        }
+
+      mpz_2fac_ui (r, n);
+      MPZ_CHECK_FORMAT (r);
+
+      if (mpz_cmp (df[m], r) != 0)
+        {
+          printf ("mpz_2fac_ui(%lu) wrong\n", n);
+          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, df[m]); printf("\n");
+          abort ();
+        }
+
+      m ^= 1;
+      mpz_mul_ui (df[m], df[m], n+1);  /* (n+1)!! = (n-1)!! * (n+1) */
+      mpz_mul_ui (f, f, n+1);  /* (n+1)! = n! * (n+1) */
+    }
+
+  n = 2097169; /* a prime = 1 mod 4*/
+  if (n / 2 > MP_LIMB_T_MAX)
+    n = 131041; /* a smaller prime :-) */
+  mpz_fac_ui (f, n / 2); /* ((n-1)/2)! */
+  m = mpz_fdiv_ui (f, n); /* ((n-1)/2)! mod n*/
+  mpz_set_ui (f, m);
+  mpz_mul_ui (f, f, m); /* (((n-1)/2)!)^2 */
+  m = mpz_fdiv_ui (f, n); /* (((n-1)/2)!)^2 mod n*/
+  if ( m != n - 1)
+    {
+      printf ("mpz_fac_ui(%lu) wrong\n", n / 2);
+      printf (" al-Haytham's theorem not verified: got %lu, expected %lu.\n", m, n - 1);
+      abort ();
+    }
+
+  mpz_clear (df[0]);
+  mpz_clear (df[1]);
+  mpz_clear (f);
+  mpz_clear (r);
+
+  tests_end ();
+
+  exit (0);
+}
diff --git a/tests/mpz/t-fdiv.c b/tests/mpz/t-fdiv.c
new file mode 100644
index 0000000..71503df
--- /dev/null
+++ b/tests/mpz/t-fdiv.c
@@ -0,0 +1,146 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_fdiv_qr, mpz_fdiv_q,
+   mpz_fdiv_r, mpz_mul.
+
+Copyright 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (mpz_t, mpz_t);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend, divisor;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size, divisor_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (divisor);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 2; /* 0..131071 bit operands */
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  divisor_size = mpz_get_ui (bs);
+	  mpz_rrandomb (divisor, rands, divisor_size);
+	}
+      while (mpz_sgn (divisor) == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs) + divisor_size;
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+      if ((bsi & 2) != 0)
+	mpz_neg (divisor, divisor);
+
+      /* printf ("%ld %ld\n", SIZ (dividend), SIZ (divisor)); */
+
+      mpz_fdiv_qr (quotient, remainder, dividend, divisor);
+      mpz_fdiv_q (quotient2, dividend, divisor);
+      mpz_fdiv_r (remainder2, dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort (dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort (dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != ((mpz_cmp_ui (dividend, 0) ^ mpz_cmp_ui (divisor, 0)) < 0))
+	dump_abort (dividend, divisor);
+
+      /* Check if the remainder has the same sign as the divisor
+	 (quotient rounded towards minus infinity).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (divisor, 0) < 0))
+	  dump_abort (dividend, divisor);
+
+      mpz_mul (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort (dividend, divisor);
+
+      mpz_abs (temp, divisor);
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp (remainder, temp) >= 0)
+	dump_abort (dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (divisor);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (mpz_t dividend, mpz_t divisor)
+{
+  fprintf (stderr, "ERROR\n");
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = "); debug_mp (divisor, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-fdiv_ui.c b/tests/mpz/t-fdiv_ui.c
new file mode 100644
index 0000000..87620ca
--- /dev/null
+++ b/tests/mpz/t-fdiv_ui.c
@@ -0,0 +1,158 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_fdiv_qr_ui, mpz_fdiv_q_ui,
+   mpz_fdiv_r_ui, mpz_fdiv_ui, mpz_mul_ui.
+
+Copyright 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (const char *, mpz_t, unsigned long);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size;
+  unsigned long divisor;
+  int i;
+  int reps = 10000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned long r_rq, r_q, r_r, r;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */
+
+      do
+	{
+	  mpz_rrandomb (bs, rands, 64);
+	  divisor = mpz_get_ui (bs);
+	}
+      while (divisor == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs);
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+
+      /* printf ("%ld\n", SIZ (dividend)); */
+
+      r_rq = mpz_fdiv_qr_ui (quotient, remainder, dividend, divisor);
+      r_q = mpz_fdiv_q_ui (quotient2, dividend, divisor);
+      r_r = mpz_fdiv_r_ui (remainder2, dividend, divisor);
+      r = mpz_fdiv_ui (dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort ("quotients from mpz_fdiv_qr_ui and mpz_fdiv_q_ui differ",
+		    dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort ("remainders from mpz_fdiv_qr_ui and mpz_fdiv_r_ui differ",
+		    dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != (mpz_cmp_ui (dividend, 0) < 0))
+	dump_abort ("quotient sign wrong", dividend, divisor);
+
+      /* Check if the remainder has the same sign as the (positive) divisor
+	 (quotient rounded towards minus infinity).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if (mpz_cmp_ui (remainder, 0) < 0)
+	  dump_abort ("remainder sign wrong", dividend, divisor);
+
+      mpz_mul_ui (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort ("n mod d != n - [n/d]*d", dividend, divisor);
+
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp_ui (remainder, divisor) >= 0)
+	dump_abort ("remainder greater than divisor", dividend, divisor);
+
+      if (mpz_cmp_ui (remainder, r_rq) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_qr_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_q) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_q_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_r) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_r_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_ui is wrong",
+		    dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *str, mpz_t dividend, unsigned long divisor)
+{
+  fprintf (stderr, "ERROR: %s\n", str);
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = %lX\n", divisor);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-fib_ui.c b/tests/mpz/t-fib_ui.c
new file mode 100644
index 0000000..ec9425c
--- /dev/null
+++ b/tests/mpz/t-fib_ui.c
@@ -0,0 +1,155 @@
+/* Test mpz_fib_ui and mpz_fib2_ui.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-fib_ui [x|num]
+
+   Run with no arguments, tests goes up to the initial value of "limit"
+   below.  With a number argument tests are carried up that far, or with a
+   literal "x" tests are continued without limit (this being only meant for
+   development purposes).
+
+   The size tests performed are designed to partially replicate what will be
+   going on in mpz_fib_ui.  There's plenty of ASSERTs there, but of course
+   they're not normally enabled.
+
+   Misfeatures:
+
+   The tests on MPN_FIB2_SIZE are a bit useless, since that macro includes a
+   +2 for the internal purposes of mpn_fib2_ui.  It's probably better to
+   give mpn_fib2_ui a run with assertion checking enabled.  */
+
+
+#define MPZ_FIB_SIZE_FLOAT(n) \
+  ((mp_size_t) ((n) * 0.6942419 / GMP_NUMB_BITS + 1))
+
+
+void
+check_fib_table (void)
+{
+  int        i;
+  mp_limb_t  want;
+
+  ASSERT_ALWAYS (FIB_TABLE(-1) == 1);
+  ASSERT_ALWAYS (FIB_TABLE(0) == 0);
+
+  for (i = 1; i <= FIB_TABLE_LIMIT; i++)
+    {
+      want = FIB_TABLE(i-1) + FIB_TABLE(i-2);
+      if (FIB_TABLE(i) != want)
+        {
+          printf ("FIB_TABLE(%d) wrong\n", i);
+          gmp_printf ("  got  %#Nx\n", &FIB_TABLE(i), 1);
+          gmp_printf ("  want %#Nx\n", &want, 1);
+          abort ();
+        }
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long  n;
+  unsigned long  limit = 100 * GMP_LIMB_BITS;
+  mpz_t          want_fn, want_fn1, got_fn, got_fn1;
+
+  tests_start ();
+  mp_trace_base = -16;
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  check_fib_table ();
+
+  /* start at n==0 */
+  mpz_init_set_ui (want_fn1, 1);  /* F[-1] */
+  mpz_init_set_ui (want_fn,  0);  /* F[0]   */
+  mpz_init (got_fn);
+  mpz_init (got_fn1);
+
+  for (n = 0; n < limit; n++)
+    {
+      /* check our float formula seems right */
+      if (MPZ_FIB_SIZE_FLOAT (n) < SIZ(want_fn))
+        {
+          printf ("MPZ_FIB_SIZE_FLOAT wrong at n=%lu\n", n);
+          printf ("  MPZ_FIB_SIZE_FLOAT  %ld\n", MPZ_FIB_SIZE_FLOAT (n));
+          printf ("  SIZ(want_fn)        %d\n", SIZ(want_fn));
+          abort ();
+        }
+
+      /* check MPN_FIB2_SIZE seems right, compared to actual size and
+         compared to our float formula */
+      if (MPN_FIB2_SIZE (n) < MPZ_FIB_SIZE_FLOAT (n))
+        {
+          printf ("MPN_FIB2_SIZE wrong at n=%lu\n", n);
+          printf ("  MPN_FIB2_SIZE       %ld\n", MPN_FIB2_SIZE (n));
+          printf ("  MPZ_FIB_SIZE_FLOAT  %ld\n", MPZ_FIB_SIZE_FLOAT (n));
+          abort ();
+        }
+      if (MPN_FIB2_SIZE (n) < SIZ(want_fn))
+        {
+          printf ("MPN_FIB2_SIZE wrong at n=%lu\n", n);
+          printf ("  MPN_FIB2_SIZE  %ld\n", MPN_FIB2_SIZE (n));
+          printf ("  SIZ(want_fn)   %d\n", SIZ(want_fn));
+          abort ();
+        }
+
+      mpz_fib2_ui (got_fn, got_fn1, n);
+      MPZ_CHECK_FORMAT (got_fn);
+      MPZ_CHECK_FORMAT (got_fn1);
+      if (mpz_cmp (got_fn, want_fn) != 0 || mpz_cmp (got_fn1, want_fn1) != 0)
+        {
+          printf ("mpz_fib2_ui(%lu) wrong\n", n);
+          mpz_trace ("want fn ", want_fn);
+          mpz_trace ("got  fn ",  got_fn);
+          mpz_trace ("want fn1", want_fn1);
+          mpz_trace ("got  fn1",  got_fn1);
+          abort ();
+        }
+
+      mpz_fib_ui (got_fn, n);
+      MPZ_CHECK_FORMAT (got_fn);
+      if (mpz_cmp (got_fn, want_fn) != 0)
+        {
+          printf ("mpz_fib_ui(%lu) wrong\n", n);
+          mpz_trace ("want fn", want_fn);
+          mpz_trace ("got  fn", got_fn);
+          abort ();
+        }
+
+      mpz_add (want_fn1, want_fn1, want_fn);  /* F[n+1] = F[n] + F[n-1] */
+      mpz_swap (want_fn1, want_fn);
+    }
+
+  mpz_clear (want_fn);
+  mpz_clear (want_fn1);
+  mpz_clear (got_fn);
+  mpz_clear (got_fn1);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-fits.c b/tests/mpz/t-fits.c
new file mode 100644
index 0000000..6819588
--- /dev/null
+++ b/tests/mpz/t-fits.c
@@ -0,0 +1,197 @@
+/* Test mpz_fits_*_p */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Nothing sophisticated here, just exercise mpz_fits_*_p on a small amount
+   of data. */
+
+#define EXPECT_S(fun,name,answer)                                       \
+  got = fun (z);                                                        \
+  if (got != answer)                                                    \
+    {                                                                   \
+      printf ("%s (%s) got %d want %d\n", name, expr, got, answer);     \
+      printf (" z size %d\n", SIZ(z));                                  \
+      printf (" z dec "); mpz_out_str (stdout, 10, z); printf ("\n");   \
+      printf (" z hex "); mpz_out_str (stdout, 16, z); printf ("\n");   \
+      error = 1;                                                        \
+    }
+
+#define EXPECT(fun,answer)  EXPECT_S(fun,#fun,answer)
+
+int
+main (void)
+{
+  mpz_t       z;
+  int         got;
+  const char  *expr;
+  int         error = 0;
+
+  tests_start ();
+  mpz_init (z);
+
+  mpz_set_ui (z, 0L);
+  expr = "0";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+  EXPECT (mpz_fits_ushort_p, 1);
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_ui (z, 1L);
+  expr = "1";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+  EXPECT (mpz_fits_ushort_p, 1);
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_si (z, -1L);
+  expr = "-1";
+  EXPECT (mpz_fits_ulong_p, 0);
+  EXPECT (mpz_fits_uint_p, 0);
+  EXPECT (mpz_fits_ushort_p, 0);
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_ui (z, 1L);
+  mpz_mul_2exp (z, z, 5L*GMP_LIMB_BITS);
+  expr = "2^(5*BPML)";
+  EXPECT (mpz_fits_ulong_p, 0);
+  EXPECT (mpz_fits_uint_p, 0);
+  EXPECT (mpz_fits_ushort_p, 0);
+  EXPECT (mpz_fits_slong_p, 0);
+  EXPECT (mpz_fits_sint_p, 0);
+  EXPECT (mpz_fits_sshort_p, 0);
+
+
+  mpz_set_ui (z, (unsigned long) USHRT_MAX);
+  expr = "USHRT_MAX";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+  EXPECT (mpz_fits_ushort_p, 1);
+
+  mpz_set_ui (z, (unsigned long) USHRT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "USHRT_MAX + 1";
+  EXPECT (mpz_fits_ushort_p, 0);
+
+
+  mpz_set_ui (z, (unsigned long) UINT_MAX);
+  expr = "UINT_MAX";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+
+  mpz_set_ui (z, (unsigned long) UINT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "UINT_MAX + 1";
+  EXPECT (mpz_fits_uint_p, 0);
+
+
+  mpz_set_ui (z, ULONG_MAX);
+  expr = "ULONG_MAX";
+  EXPECT (mpz_fits_ulong_p, 1);
+
+  mpz_set_ui (z, ULONG_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "ULONG_MAX + 1";
+  EXPECT (mpz_fits_ulong_p, 0);
+
+
+  mpz_set_si (z, (long) SHRT_MAX);
+  expr = "SHRT_MAX";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_si (z, (long) SHRT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "SHRT_MAX + 1";
+  EXPECT (mpz_fits_sshort_p, 0);
+
+
+  mpz_set_si (z, (long) INT_MAX);
+  expr = "INT_MAX";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+
+  mpz_set_si (z, (long) INT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "INT_MAX + 1";
+  EXPECT (mpz_fits_sint_p, 0);
+
+
+  mpz_set_si (z, LONG_MAX);
+  expr = "LONG_MAX";
+  EXPECT (mpz_fits_slong_p, 1);
+
+  mpz_set_si (z, LONG_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "LONG_MAX + 1";
+  EXPECT (mpz_fits_slong_p, 0);
+
+
+  mpz_set_si (z, (long) SHRT_MIN);
+  expr = "SHRT_MIN";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_si (z, (long) SHRT_MIN);
+  mpz_sub_ui (z, z, 1L);
+  expr = "SHRT_MIN + 1";
+  EXPECT (mpz_fits_sshort_p, 0);
+
+
+  mpz_set_si (z, (long) INT_MIN);
+  expr = "INT_MIN";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+
+  mpz_set_si (z, (long) INT_MIN);
+  mpz_sub_ui (z, z, 1L);
+  expr = "INT_MIN + 1";
+  EXPECT (mpz_fits_sint_p, 0);
+
+
+  mpz_set_si (z, LONG_MIN);
+  expr = "LONG_MIN";
+  EXPECT (mpz_fits_slong_p, 1);
+
+  mpz_set_si (z, LONG_MIN);
+  mpz_sub_ui (z, z, 1L);
+  expr = "LONG_MIN + 1";
+  EXPECT (mpz_fits_slong_p, 0);
+
+
+  if (error)
+    abort ();
+
+  mpz_clear (z);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-gcd.c b/tests/mpz/t-gcd.c
new file mode 100644
index 0000000..46b278a
--- /dev/null
+++ b/tests/mpz/t-gcd.c
@@ -0,0 +1,467 @@
+/* Test mpz_gcd, mpz_gcdext, and mpz_gcd_ui.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2005, 2008, 2009, 2012 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void one_test (mpz_t, mpz_t, mpz_t, int);
+void debug_mp (mpz_t, int);
+
+static int gcdext_valid_p (const mpz_t, const mpz_t, const mpz_t, const mpz_t);
+
+/* Keep one_test's variables global, so that we don't need
+   to reinitialize them for each test.  */
+mpz_t gcd1, gcd2, s, temp1, temp2, temp3;
+
+#define MAX_SCHOENHAGE_THRESHOLD HGCD_REDUCE_THRESHOLD
+
+/* Define this to make all operands be large enough for Schoenhage gcd
+   to be used.  */
+#ifndef WHACK_SCHOENHAGE
+#define WHACK_SCHOENHAGE 0
+#endif
+
+#if WHACK_SCHOENHAGE
+#define MIN_OPERAND_BITSIZE (MAX_SCHOENHAGE_THRESHOLD * GMP_NUMB_BITS)
+#else
+#define MIN_OPERAND_BITSIZE 1
+#endif
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *b;
+    const char *want;
+  } data[] = {
+    /* This tickled a bug in gmp 4.1.2 mpn/x86/k6/gcd_finda.asm. */
+    { "0x3FFC000007FFFFFFFFFF00000000003F83FFFFFFFFFFFFFFF80000000000000001",
+      "0x1FFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000000000000000001",
+      "5" }
+  };
+
+  mpz_t  a, b, got, want;
+  int    i;
+
+  mpz_inits (a, b, got, want, NULL);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (b, data[i].b, 0);
+      mpz_set_str_or_abort (want, data[i].want, 0);
+      mpz_gcd (got, a, b);
+      MPZ_CHECK_FORMAT (got);
+      if (mpz_cmp (got, want) != 0)
+	{
+	  printf    ("mpz_gcd wrong on data[%d]\n", i);
+	  printf    (" a  %s\n", data[i].a);
+	  printf    (" b  %s\n", data[i].b);
+	  mpz_trace (" a", a);
+	  mpz_trace (" b", b);
+	  mpz_trace (" want", want);
+	  mpz_trace (" got ", got);
+	  abort ();
+	}
+    }
+
+  mpz_clears (a, b, got, want, NULL);
+}
+
+void
+make_chain_operands (mpz_t ref, mpz_t a, mpz_t b, gmp_randstate_t rs, int nb1, int nb2, int chain_len)
+{
+  mpz_t bs, temp1, temp2;
+  int j;
+
+  mpz_inits (bs, temp1, temp2, NULL);
+
+  /* Generate a division chain backwards, allowing otherwise unlikely huge
+     quotients.  */
+
+  mpz_set_ui (a, 0);
+  mpz_urandomb (bs, rs, 32);
+  mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb1 + 1);
+  mpz_rrandomb (b, rs, mpz_get_ui (bs));
+  mpz_add_ui (b, b, 1);
+  mpz_set (ref, b);
+
+  for (j = 0; j < chain_len; j++)
+    {
+      mpz_urandomb (bs, rs, 32);
+      mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
+      mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
+      mpz_add_ui (temp2, temp2, 1);
+      mpz_mul (temp1, b, temp2);
+      mpz_add (a, a, temp1);
+
+      mpz_urandomb (bs, rs, 32);
+      mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
+      mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
+      mpz_add_ui (temp2, temp2, 1);
+      mpz_mul (temp1, a, temp2);
+      mpz_add (b, b, temp1);
+    }
+
+  mpz_clears (bs, temp1, temp2, NULL);
+}
+
+/* Test operands from a table of seed data.  This variant creates the operands
+   using plain ol' mpz_rrandomb.  This is a hack for better coverage of the gcd
+   code, which depends on that the random number generators give the exact
+   numbers we expect.  */
+void
+check_kolmo1 (void)
+{
+  static const struct {
+    unsigned int seed;
+    int nb;
+    const char *want;
+  } data[] = {
+    { 59618, 38208, "5"},
+    { 76521, 49024, "3"},
+    { 85869, 54976, "1"},
+    { 99449, 63680, "1"},
+    {112453, 72000, "1"}
+  };
+
+  gmp_randstate_t rs;
+  mpz_t  bs, a, b, want;
+  int    i, unb, vnb, nb;
+
+  gmp_randinit_default (rs);
+
+  mpz_inits (bs, a, b, want, NULL);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      nb = data[i].nb;
+
+      gmp_randseed_ui (rs, data[i].seed);
+
+      mpz_urandomb (bs, rs, 32);
+      unb = mpz_get_ui (bs) % nb;
+      mpz_urandomb (bs, rs, 32);
+      vnb = mpz_get_ui (bs) % nb;
+
+      mpz_rrandomb (a, rs, unb);
+      mpz_rrandomb (b, rs, vnb);
+
+      mpz_set_str_or_abort (want, data[i].want, 0);
+
+      one_test (a, b, want, -1);
+    }
+
+  mpz_clears (bs, a, b, want, NULL);
+  gmp_randclear (rs);
+}
+
+/* Test operands from a table of seed data.  This variant creates the operands
+   using a division chain.  This is a hack for better coverage of the gcd
+   code, which depends on that the random number generators give the exact
+   numbers we expect.  */
+void
+check_kolmo2 (void)
+{
+  static const struct {
+    unsigned int seed;
+    int nb, chain_len;
+  } data[] = {
+    {  917, 15, 5 },
+    { 1032, 18, 6 },
+    { 1167, 18, 6 },
+    { 1174, 18, 6 },
+    { 1192, 18, 6 },
+  };
+
+  gmp_randstate_t rs;
+  mpz_t  bs, a, b, want;
+  int    i;
+
+  gmp_randinit_default (rs);
+
+  mpz_inits (bs, a, b, want, NULL);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      gmp_randseed_ui (rs, data[i].seed);
+      make_chain_operands (want, a, b, rs, data[i].nb, data[i].nb, data[i].chain_len);
+      one_test (a, b, want, -1);
+    }
+
+  mpz_clears (bs, a, b, want, NULL);
+  gmp_randclear (rs);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, ref;
+  int i, chain_len;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  long int reps = 200;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_inits (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
+
+  check_data ();
+  check_kolmo1 ();
+  check_kolmo2 ();
+
+  /* Testcase to exercise the u0 == u1 case in mpn_gcdext_lehmer_n. */
+  /* mpz_set_ui (op2, GMP_NUMB_MAX); */ /* FIXME: Huge limb doesn't always fit */
+  mpz_set_ui (op2, 0);
+  mpz_setbit (op2, GMP_NUMB_BITS);
+  mpz_sub_ui (op2, op2, 1);
+  mpz_mul_2exp (op1, op2, 100);
+  mpz_add (op1, op1, op2);
+  mpz_mul_ui (op2, op2, 2);
+  one_test (op1, op2, NULL, -1);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* Generate plain operands with unknown gcd.  These types of operands
+	 have proven to trigger certain bugs in development versions of the
+	 gcd code.  The "hgcd->row[3].rsize > M" ASSERT is not triggered by
+	 the division chain code below, but that is most likely just a result
+	 of that other ASSERTs are triggered before it.  */
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
+
+      mpz_urandomb (bs, rands, 8);
+      bsi = mpz_get_ui (bs);
+
+      if ((bsi & 0x3c) == 4)
+	mpz_mul (op1, op1, op2);	/* make op1 a multiple of op2 */
+      else if ((bsi & 0x3c) == 8)
+	mpz_mul (op2, op1, op2);	/* make op2 a multiple of op1 */
+
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 2) != 0)
+	mpz_neg (op2, op2);
+
+      one_test (op1, op2, NULL, i);
+
+      /* Generate a division chain backwards, allowing otherwise unlikely huge
+	 quotients.  */
+
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % LOG2C (GMP_NUMB_BITS * MAX_SCHOENHAGE_THRESHOLD);
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % (1 << chain_len) / 32;
+
+      make_chain_operands (ref, op1, op2, rands, 16, 12, chain_len);
+
+      one_test (op1, op2, ref, i);
+    }
+
+  /* Check that we can use NULL as first argument of mpz_gcdext.  */
+  mpz_set_si (op1, -10);
+  mpz_set_si (op2, 0);
+  mpz_gcdext (NULL, temp1, temp2, op1, op2);
+  ASSERT_ALWAYS (mpz_cmp_si (temp1, -1) == 0);
+  ASSERT_ALWAYS (mpz_cmp_si (temp2, 0) == 0);
+  mpz_set_si (op2, 6);
+  mpz_gcdext (NULL, temp1, temp2, op1, op2);
+  ASSERT_ALWAYS (mpz_cmp_si (temp1, 1) == 0);
+  ASSERT_ALWAYS (mpz_cmp_si (temp2, 2) == 0);
+
+  mpz_clears (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
+
+void
+one_test (mpz_t op1, mpz_t op2, mpz_t ref, int i)
+{
+  /*
+  printf ("%d %d %d\n", SIZ (op1), SIZ (op2), ref != NULL ? SIZ (ref) : 0);
+  fflush (stdout);
+  */
+
+  /*
+  fprintf (stderr, "op1=");  debug_mp (op1, -16);
+  fprintf (stderr, "op2=");  debug_mp (op2, -16);
+  */
+
+  mpz_gcdext (gcd1, s, NULL, op1, op2);
+  MPZ_CHECK_FORMAT (gcd1);
+  MPZ_CHECK_FORMAT (s);
+
+  if (ref && mpz_cmp (ref, gcd1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcdext returned incorrect result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "expected result:\n");   debug_mp (ref, -16);
+      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
+      abort ();
+    }
+
+  if (!gcdext_valid_p(op1, op2, gcd1, s))
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcdext returned invalid result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
+      fprintf (stderr, "s=");                   debug_mp (s, -16);
+      abort ();
+    }
+
+  mpz_gcd (gcd2, op1, op2);
+  MPZ_CHECK_FORMAT (gcd2);
+
+  if (mpz_cmp (gcd2, gcd1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcd returned incorrect result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
+      fprintf (stderr, "mpz_gcd returns:\n");   debug_mp (gcd2, -16);
+      abort ();
+    }
+
+  /* This should probably move to t-gcd_ui.c */
+  if (mpz_fits_ulong_p (op1) || mpz_fits_ulong_p (op2))
+    {
+      if (mpz_fits_ulong_p (op1))
+	mpz_gcd_ui (gcd2, op2, mpz_get_ui (op1));
+      else
+	mpz_gcd_ui (gcd2, op1, mpz_get_ui (op2));
+      if (mpz_cmp (gcd2, gcd1))
+	{
+	  fprintf (stderr, "ERROR in test %d\n", i);
+	  fprintf (stderr, "mpz_gcd_ui returned incorrect result\n");
+	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+	  fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
+	  fprintf (stderr, "mpz_gcd_ui returns:\n");   debug_mp (gcd2, -16);
+	  abort ();
+	}
+    }
+
+  mpz_gcdext (gcd2, temp1, temp2, op1, op2);
+  MPZ_CHECK_FORMAT (gcd2);
+  MPZ_CHECK_FORMAT (temp1);
+  MPZ_CHECK_FORMAT (temp2);
+
+  mpz_mul (temp1, temp1, op1);
+  mpz_mul (temp2, temp2, op2);
+  mpz_add (temp1, temp1, temp2);
+
+  if (mpz_cmp (gcd1, gcd2) != 0
+      || mpz_cmp (gcd2, temp1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcdext returned incorrect result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
+      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd2, -16);
+      abort ();
+    }
+}
+
+/* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t.
+   Uses temp1, temp2 and temp3. */
+static int
+gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s)
+{
+  /* It's not clear that gcd(0,0) is well defined, but we allow it and require that
+     gcd(0,0) = 0. */
+  if (mpz_sgn (g) < 0)
+    return 0;
+
+  if (mpz_sgn (a) == 0)
+    {
+      /* Must have g == abs (b). Any value for s is in some sense "correct",
+	 but it makes sense to require that s == 0. */
+      return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0;
+    }
+  else if (mpz_sgn (b) == 0)
+    {
+      /* Must have g == abs (a), s == sign (a) */
+      return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0;
+    }
+
+  if (mpz_sgn (g) <= 0)
+    return 0;
+
+  mpz_tdiv_qr (temp1, temp3, a, g);
+  if (mpz_sgn (temp3) != 0)
+    return 0;
+
+  mpz_tdiv_qr (temp2, temp3, b, g);
+  if (mpz_sgn (temp3) != 0)
+    return 0;
+
+  /* Require that 2 |s| < |b/g|, or |s| == 1. */
+  if (mpz_cmpabs_ui (s, 1) > 0)
+    {
+      mpz_mul_2exp (temp3, s, 1);
+      if (mpz_cmpabs (temp3, temp2) >= 0)
+	return 0;
+    }
+
+  /* Compute the other cofactor. */
+  mpz_mul(temp2, s, a);
+  mpz_sub(temp2, g, temp2);
+  mpz_tdiv_qr(temp2, temp3, temp2, b);
+
+  if (mpz_sgn (temp3) != 0)
+    return 0;
+
+  /* Require that 2 |t| < |a/g| or |t| == 1*/
+  if (mpz_cmpabs_ui (temp2, 1) > 0)
+    {
+      mpz_mul_2exp (temp2, temp2, 1);
+      if (mpz_cmpabs (temp2, temp1) >= 0)
+	return 0;
+    }
+  return 1;
+}
diff --git a/tests/mpz/t-gcd_ui.c b/tests/mpz/t-gcd_ui.c
new file mode 100644
index 0000000..3f56a97
--- /dev/null
+++ b/tests/mpz/t-gcd_ui.c
@@ -0,0 +1,156 @@
+/* Test mpz_gcd_ui.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Check mpz_gcd_ui doesn't try to return a value out of range.
+   This was wrong in gmp 4.1.2 with a long long limb.  */
+static void
+check_ui_range (void)
+{
+  unsigned long  got;
+  mpz_t  x;
+  int  i;
+
+  mpz_init_set_ui (x, ULONG_MAX);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_mul_2exp (x, x, 1L);
+      got = mpz_gcd_ui (NULL, x, 0L);
+      if (got != 0)
+        {
+          printf ("mpz_gcd_ui (ULONG_MAX*2^%d, 0)\n", i);
+          printf ("   return %#lx\n", got);
+          printf ("   should be 0\n");
+          abort ();
+        }
+    }
+
+  mpz_clear (x);
+}
+
+static void
+check_ui_factors (void)
+{
+#define NUM_FACTORS 9
+  static const char* factors[NUM_FACTORS] = {
+    "641", "274177", "3", "5", "17", "257", "65537",
+    "59649589127497217", "1238926361552897" };
+  unsigned long  got;
+  mpz_t  x, b, d, f, g;
+  int  i, j;
+  gmp_randstate_ptr rands;
+
+  if (GMP_NUMB_BITS < 5 || GMP_NUMB_BITS == 8
+      || GMP_NUMB_BITS == 16 || GMP_NUMB_BITS > 511)
+    {
+      printf ("No usable factors for 2^%i+1.\n", GMP_NUMB_BITS);
+      return;
+    }
+
+  mpz_init (x);
+  mpz_init (d);
+  mpz_init (f);
+  mpz_init (g);
+
+  mpz_setbit (x, GMP_NUMB_BITS);
+  mpz_add_ui (x, x, 1);
+
+  for (i = 0; i < NUM_FACTORS; ++i)
+    {
+      mpz_set_str (f, factors[i], 10);
+      if (mpz_divisible_p (x, f))
+	{
+	  mpz_mul_2exp (f, f, 1);
+	  /* d is an odd multiple of the factor f, exactly filling a limb. */
+	  mpz_sub (d, x, f);
+	  /* f = 2^GMP_NUMB_BITS mod d. */
+	  mpz_sub_ui (f, f, 1);
+	  break;
+	}
+    }
+
+  mpz_gcd (g, f, d);
+  if (mpz_even_p (d) || mpz_cmp (d, f) <= 0 || mpz_cmp_ui (g, 1) != 0)
+    {
+      printf ("No usable factor found.\n");
+      abort ();
+    }
+
+  rands = RANDS;
+  mpz_mul_ui (x, d, gmp_urandomm_ui (rands, 30000) + 1);
+
+  mpz_init (b);
+  mpz_setbit (b, GMP_NUMB_BITS - 1);
+  for (j = 0; j < 4; ++j)
+    {
+      mpz_add (x, x, b);
+
+      for (i = 1; i >= -1; --i)
+	{
+	  if (mpz_fits_ulong_p (d)
+	      && ((got = mpz_gcd_ui (NULL, x, mpz_get_ui (d)))
+		  != (i != 0 ? 1 : mpz_get_ui (d))))
+	    {
+	      printf ("mpz_gcd_ui (f, kV+%i*2^%i, V): error (j = %i)\n", i, GMP_NUMB_BITS - 1, j);
+	      printf ("   return %#lx\n", got);
+	      printf ("   should be %#lx\n", (i != 0 ? 1 : mpz_get_ui (d)));
+	      abort ();
+	    }
+
+	  mpz_gcd (g, x, d);
+	  if ((mpz_cmp_ui (g, 1) == 0) != (i != 0))
+	    {
+	      printf ("mpz_gcd (f, kV+%i*2^%i, V): error (j = %i)\n", i, GMP_NUMB_BITS - 1, j);
+	      printf ("   should%s be one.\n",(i != 0 ? "" : " not"));
+	      abort ();
+	    }
+
+	  mpz_sub (x, x, b);
+	}
+      /* Back to the original x. */
+      mpz_addmul_ui (x, b, 2);
+      mpz_mul (b, b, f);
+      mpz_mod (b, b, d);
+    }
+
+  mpz_clear (g);
+  mpz_clear (x);
+  mpz_clear (f);
+  mpz_clear (d);
+  mpz_clear (b);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_ui_range ();
+  check_ui_factors ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-get_d.c b/tests/mpz/t-get_d.c
new file mode 100644
index 0000000..f4c839f
--- /dev/null
+++ b/tests/mpz/t-get_d.c
@@ -0,0 +1,80 @@
+/* Test mpz_get_d.
+
+Copyright 2002, 2012, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_onebit (void)
+{
+  int     i;
+  mpz_t   z;
+  double  got, want;
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+  int     limit = 127 - 1;  /* vax fp numbers have limited range */
+#else
+  int     limit = 512;
+#endif
+
+  mpz_init (z);
+
+  got = mpz_get_d (z);
+  if (got != 0)
+    {
+      printf    ("mpz_get_d wrong on zero\n");
+      abort();
+    }
+
+  mpz_set_ui (z, 1L);
+  want = 1.0;
+
+  for (i = 0; i < limit; i++)
+    {
+      got = mpz_get_d (z);
+
+      if (got != want)
+        {
+          printf    ("mpz_get_d wrong on 2**%d\n", i);
+          mpz_trace ("   z    ", z);
+          printf    ("   want  %.20g\n", want);
+          printf    ("   got   %.20g\n", got);
+          abort();
+        }
+
+      mpz_mul_2exp (z, z, 1L);
+      want *= 2.0;
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_onebit ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-get_d_2exp.c b/tests/mpz/t-get_d_2exp.c
new file mode 100644
index 0000000..04cf1a4
--- /dev/null
+++ b/tests/mpz/t-get_d_2exp.c
@@ -0,0 +1,222 @@
+/* Test mpz_get_d_2exp.
+
+Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+static void
+check_zero (void)
+{
+  mpz_t   z;
+  double  got, want;
+  long    got_exp, want_exp;
+
+  mpz_init_set_ui (z, 0);
+
+  want = 0.0;
+  want_exp = 0;
+  got = mpz_get_d_2exp (&got_exp, z);
+  if (got != want || got_exp != want_exp)
+    {
+      printf    ("mpz_get_d_2exp wrong on zero\n");
+      mpz_trace ("   z    ", z);
+      d_trace   ("   want ", want);
+      d_trace   ("   got  ", got);
+      printf    ("   want exp %ld\n", want_exp);
+      printf    ("   got exp  %ld\n", got_exp);
+      abort();
+    }
+
+  mpz_clear (z);
+}
+
+static void
+check_onebit (void)
+{
+  static const unsigned long data[] = {
+    1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513
+  };
+  mpz_t   z;
+  double  got, want;
+  long    got_exp, want_exp;
+  int     i;
+
+  mpz_init (z);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_ui (z, 1L);
+      mpz_mul_2exp (z, z, data[i]);
+      want = 0.5;
+      want_exp = data[i] + 1;
+      got = mpz_get_d_2exp (&got_exp, z);
+      if (got != want || got_exp != want_exp)
+        {
+          printf    ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]);
+          mpz_trace ("   z    ", z);
+          d_trace   ("   want ", want);
+          d_trace   ("   got  ", got);
+          printf    ("   want exp %ld\n", want_exp);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+
+      mpz_set_si (z, -1L);
+      mpz_mul_2exp (z, z, data[i]);
+      want = -0.5;
+      want_exp = data[i] + 1;
+      got = mpz_get_d_2exp (&got_exp, z);
+      if (got != want || got_exp != want_exp)
+        {
+          printf    ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]);
+          mpz_trace ("   z    ", z);
+          d_trace   ("   want ", want);
+          d_trace   ("   got  ", got);
+          printf    ("   want exp %ld\n", want_exp);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+    }
+  mpz_clear (z);
+}
+
+/* Check that hardware rounding doesn't make mpz_get_d_2exp return a value
+   outside its defined range. */
+static void
+check_round (void)
+{
+  static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
+  mpz_t   z;
+  double  got;
+  long    got_exp;
+  int     i, rnd_mode, old_rnd_mode;
+
+  mpz_init (z);
+  old_rnd_mode = tests_hardware_getround ();
+
+  for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
+    {
+      tests_hardware_setround (rnd_mode);
+
+      for (i = 0; i < numberof (data); i++)
+        {
+          mpz_set_ui (z, 1L);
+          mpz_mul_2exp (z, z, data[i]);
+          mpz_sub_ui (z, z, 1L);
+
+          got = mpz_get_d_2exp (&got_exp, z);
+          if (got < 0.5 || got >= 1.0)
+            {
+              printf    ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]);
+              printf    ("result out of range, expect 0.5 <= got < 1.0\n");
+              printf    ("   rnd_mode = %d\n", rnd_mode);
+              printf    ("   data[i]  = %lu\n", data[i]);
+              mpz_trace ("   z    ", z);
+              d_trace   ("   got  ", got);
+              printf    ("   got exp  %ld\n", got_exp);
+              abort();
+            }
+
+          mpz_neg (z, z);
+          got = mpz_get_d_2exp (&got_exp, z);
+          if (got <= -1.0 || got > -0.5)
+            {
+              printf    ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]);
+              printf    ("result out of range, expect -1.0 < got <= -0.5\n");
+              printf    ("   rnd_mode = %d\n", rnd_mode);
+              printf    ("   data[i]  = %lu\n", data[i]);
+              mpz_trace ("   z    ", z);
+              d_trace   ("   got  ", got);
+              printf    ("   got exp  %ld\n", got_exp);
+              abort();
+            }
+        }
+    }
+
+  mpz_clear (z);
+  tests_hardware_setround (old_rnd_mode);
+}
+
+static void
+check_rand (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  int     i;
+  mpz_t   z;
+  double  got;
+  long    got_exp;
+  unsigned long  bits;
+
+  mpz_init (z);
+
+  for (i = 0; i < 200; i++)
+    {
+      bits = gmp_urandomm_ui (rands, 512L);
+      mpz_urandomb (z, rands, bits);
+
+      got = mpz_get_d_2exp (&got_exp, z);
+      if (mpz_sgn (z) == 0)
+        continue;
+      bits = mpz_sizeinbase (z, 2);
+
+      if (got < 0.5 || got >= 1.0)
+        {
+          printf    ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n");
+          mpz_trace ("   z    ", z);
+          d_trace   ("   got  ", got);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+
+      /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp ==
+         bits+1, so leave this test disabled until we decide if that's what
+         should happen, or not.  */
+#if 0
+      if (got_exp != bits)
+        {
+          printf    ("mpz_get_d_2exp wrong exponent\n", i);
+          mpz_trace ("   z    ", z);
+          d_trace   ("   bits ", bits);
+          d_trace   ("   got  ", got);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+#endif
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_zero ();
+  check_onebit ();
+  check_round ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-get_si.c b/tests/mpz/t-get_si.c
new file mode 100644
index 0000000..51f104a
--- /dev/null
+++ b/tests/mpz/t-get_si.c
@@ -0,0 +1,121 @@
+/* Exercise mpz_get_si.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *n;
+    long        want;
+  } data[] = {
+    { "0",      0L },
+    { "1",      1L },
+    { "-1",     -1L },
+    { "2",      2L },
+    { "-2",     -2L },
+    { "12345",  12345L },
+    { "-12345", -12345L },
+  };
+
+  int    i;
+  mpz_t  n;
+  long   got;
+
+  mpz_init (n);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+
+      got = mpz_get_si (n);
+      if (got != data[i].want)
+	{
+	  printf ("mpz_get_si wrong at data[%d]\n", i);
+	  printf ("   n     \"%s\" (", data[i].n);
+	  mpz_out_str (stdout, 10, n); printf (", hex ");
+	  mpz_out_str (stdout, 16, n); printf (")\n");
+	  printf ("   got   %ld (0x%lX)\n", got, got);
+	  printf ("   want  %ld (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+  mpz_clear (n);
+}
+
+
+void
+check_max (void)
+{
+  mpz_t  n;
+  long   want;
+  long   got;
+
+  mpz_init (n);
+
+#define CHECK_MAX(name)                                 \
+  if (got != want)                                      \
+    {                                                   \
+      printf ("mpz_get_si wrong on %s\n", name);        \
+      printf ("   n    ");                              \
+      mpz_out_str (stdout, 10, n); printf (", hex ");   \
+      mpz_out_str (stdout, 16, n); printf ("\n");       \
+      printf ("   got  %ld, hex %lX\n", got, got);      \
+      printf ("   want %ld, hex %lX\n", want, want);    \
+      abort();                                          \
+    }
+
+  want = LONG_MAX;
+  mpz_set_si (n, want);
+  got = mpz_get_si (n);
+  CHECK_MAX ("LONG_MAX");
+
+  want = LONG_MIN;
+  mpz_set_si (n, want);
+  got = mpz_get_si (n);
+  CHECK_MAX ("LONG_MIN");
+
+  /* The following checks that -0x100000000 gives -0x80000000.  This doesn't
+     actually fit in a long and the result from mpz_get_si() is undefined,
+     but -0x80000000 is what comes out currently, and it should be that
+     value irrespective of the mp_limb_t size (long or long long).  */
+
+  want = LONG_MIN;
+  mpz_mul_2exp (n, n, 1);
+  CHECK_MAX ("-0x100...00");
+
+  mpz_clear (n);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_max ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-hamdist.c b/tests/mpz/t-hamdist.c
new file mode 100644
index 0000000..544a03f
--- /dev/null
+++ b/tests/mpz/t-hamdist.c
@@ -0,0 +1,123 @@
+/* Test mpz_hamdist.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_twobits (void)
+{
+  unsigned long  i, j, got, want;
+  mpz_t  x, y;
+
+  mpz_init (x);
+  mpz_init (y);
+  for (i = 0; i < 5 * GMP_NUMB_BITS; i++)
+    {
+      for (j = 0; j < 5 * GMP_NUMB_BITS; j++)
+        {
+          mpz_set_ui (x, 0L);
+          mpz_setbit (x, i);
+          mpz_set_ui (y, 0L);
+          mpz_setbit (y, j);
+
+          want = 2 * (i != j);
+          got = mpz_hamdist (x, y);
+          if (got != want)
+            {
+              printf    ("mpz_hamdist wrong on 2 bits pos/pos\n");
+            wrong:
+              printf    ("  i    %lu\n", i);
+              printf    ("  j    %lu\n", j);
+              printf    ("  got  %lu\n", got);
+              printf    ("  want %lu\n", want);
+              mpz_trace ("  x   ", x);
+              mpz_trace ("  y   ", y);
+              abort();
+            }
+
+          mpz_neg (x, x);
+          mpz_neg (y, y);
+          want = ABS ((long) (i-j));
+          got = mpz_hamdist (x, y);
+          if (got != want)
+            {
+              printf    ("mpz_hamdist wrong on 2 bits neg/neg\n");
+              goto wrong;
+            }
+        }
+
+    }
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+void
+check_rand (void)
+{
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  got, want;
+  int    i;
+  mpz_t  x, y;
+
+  mpz_init (x);
+  mpz_init (y);
+
+  for (i = 0; i < 2000; i++)
+    {
+      mpz_erandomb (x, rands, 6 * GMP_NUMB_BITS);
+      mpz_negrandom (x, rands);
+      mpz_mul_2exp (x, x, urandom() % (4 * GMP_NUMB_BITS));
+
+      mpz_erandomb (y, rands, 6 * GMP_NUMB_BITS);
+      mpz_negrandom (y, rands);
+      mpz_mul_2exp (y, y, urandom() % (4 * GMP_NUMB_BITS));
+
+      want = refmpz_hamdist (x, y);
+      got = mpz_hamdist (x, y);
+      if (got != want)
+        {
+          printf    ("mpz_hamdist wrong on random\n");
+          printf    ("  got  %lu\n", got);
+          printf    ("  want %lu\n", want);
+          mpz_trace ("  x   ", x);
+          mpz_trace ("  y   ", y);
+          abort();
+        }
+    }
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_twobits ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-import.c b/tests/mpz/t-import.c
new file mode 100644
index 0000000..a295317
--- /dev/null
+++ b/tests/mpz/t-import.c
@@ -0,0 +1,175 @@
+/* Test mpz_import.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *want;
+    size_t      count;
+    int         order;
+    size_t      size;
+    int         endian;
+    int         nail;
+    char        src[64];
+
+  } data[] = {
+
+    { "0", 0,1, 1,1, 0 },
+    { "0", 1,1, 0,1, 0 },
+
+    { "0x12345678", 4,1,  1,1, 0, { '\22', '\64', '\126', '\170' } },
+    { "0x12345678", 1,1,  4,1, 0, { '\22', '\64', '\126', '\170' } },
+    { "0x12345678", 1,-1, 4,1, 0, { '\22', '\64', '\126', '\170' } },
+
+    { "0x12345678", 4,-1, 1,-1, 0, { '\170', '\126', '\064', '\22' } },
+    { "0x12345678", 1,1,  4,-1, 0, { '\170', '\126', '\064', '\22' } },
+    { "0x12345678", 1,-1, 4,-1, 0, { '\170', '\126', '\064', '\22' } },
+
+    { "0",    5,1,  1,1, 7, { '\376', '\376', '\376', '\376', '\376' } },
+    { "0",    5,-1, 1,1, 7, { '\376', '\376', '\376', '\376', '\376' } },
+    { "0x15", 5,1,  1,1, 7, { '\377', '\376', '\377', '\376', '\377' } },
+
+    { "0",    3,1,  2,1,   1, { '\200','\000', '\200','\000', '\200','\000' }},
+    { "0",    3,1,  2,-1,  1, { '\000','\200', '\000','\200', '\000','\200' }},
+    { "0",    3,1,  2,1,  15, { '\377','\376', '\377','\376', '\377','\376' }},
+
+    { "0x2A", 3,1,  2,1, 14, { '\377','\376', '\377','\376', '\377','\376' } },
+    { "0x06", 3,1,  2,1, 14, { '\377','\374', '\377','\375', '\377','\376' } },
+    { "0x24", 3,-1, 2,1, 14, { '\377','\374', '\377','\375', '\377','\376' } },
+
+    { "0x123456789ABC", 3,1,  2,1,  0, {
+        '\022','\064', '\126','\170', '\232','\274' } },
+    { "0x123456789ABC", 3,-1, 2,1,  0, {
+        '\232','\274', '\126','\170', '\022','\064' } },
+    { "0x123456789ABC", 3,1,  2,-1, 0, {
+        '\064','\022', '\170','\126', '\274','\232' } },
+    { "0x123456789ABC", 3,-1, 2,-1, 0, {
+        '\274','\232', '\170','\126', '\064','\022' } },
+
+    { "0x112233445566778899AABBCC", 3,1,  4,1,  0,
+      { '\021','\042','\063','\104',
+        '\125','\146','\167','\210',
+        '\231','\252','\273','\314' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,1,  0,
+      { '\231','\252','\273','\314',
+        '\125','\146','\167','\210',
+        '\021','\042','\063','\104' } },
+    { "0x112233445566778899AABBCC", 3,1,  4,-1, 0,
+      { '\104','\063','\042','\021',
+        '\210','\167','\146','\125',
+        '\314','\273','\252','\231' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,-1, 0,
+      { '\314','\273','\252','\231',
+        '\210','\167','\146','\125',
+        '\104','\063','\042','\021' } },
+
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,1,  0,
+      { '\020','\001','\040','\002','\060','\003','\100','\004',
+        '\120','\005','\140','\006','\160','\007','\200','\010',
+        '\220','\011','\240','\012','\260','\013','\300','\014' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,1,  0,
+      { '\220','\011','\240','\012','\260','\013','\300','\014',
+        '\120','\005','\140','\006','\160','\007','\200','\010',
+        '\020','\001','\040','\002','\060','\003','\100','\004' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,-1, 0,
+      { '\004','\100','\003','\060','\002','\040','\001','\020',
+        '\010','\200','\007','\160','\006','\140','\005','\120',
+        '\014','\300','\013','\260','\012','\240','\011','\220' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,-1, 0,
+      { '\014','\300','\013','\260','\012','\240','\011','\220',
+        '\010','\200','\007','\160','\006','\140','\005','\120',
+        '\004','\100','\003','\060','\002','\040','\001','\020' } },
+
+    { "0x155555555555555555555555", 3,1,  4,1,  1,
+      { '\325','\125','\125','\125',
+        '\252','\252','\252','\252',
+        '\325','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,-1,  4,1,  1,
+      { '\325','\125','\125','\125',
+        '\252','\252','\252','\252',
+        '\325','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,1,  4,-1,  1,
+      { '\125','\125','\125','\325',
+        '\252','\252','\252','\252',
+        '\125','\125','\125','\325' } },
+    { "0x155555555555555555555555", 3,-1,  4,-1,  1,
+      { '\125','\125','\125','\325',
+        '\252','\252','\252','\252',
+        '\125','\125','\125','\325' } },
+  };
+
+  char    buf[sizeof(data[0].src) + sizeof (mp_limb_t)];
+  char    *src;
+  size_t  align;
+  int     i;
+  mpz_t   got, want;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (align = 0; align < sizeof (mp_limb_t); align++)
+        {
+          mpz_set_str_or_abort (want, data[i].want, 0);
+          src = buf + align;
+          memcpy (src, data[i].src, data[i].count * data[i].size);
+
+          mpz_set_ui (got, 0L);
+          mpz_import (got, data[i].count, data[i].order,
+                      data[i].size, data[i].endian, data[i].nail, src);
+
+          MPZ_CHECK_FORMAT (got);
+          if (mpz_cmp (got, want) != 0)
+            {
+              printf ("wrong at data[%d]\n", i);
+              printf ("    count=%lu order=%d  size=%lu endian=%d nail=%u  align=%lu\n",
+                      (unsigned long) data[i].count, data[i].order,
+                      (unsigned long) data[i].size, data[i].endian, data[i].nail,
+                      (unsigned long) align);
+              mpz_trace ("    got ", got);
+              mpz_trace ("    want", want);
+              abort ();
+            }
+        }
+    }
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  mp_trace_base = -16;
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-inp_str.c b/tests/mpz/t-inp_str.c
new file mode 100644
index 0000000..6c1c0c4
--- /dev/null
+++ b/tests/mpz/t-inp_str.c
@@ -0,0 +1,198 @@
+/* Test mpz_inp_str.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define FILENAME  "/tmp/t-inp_str.tmp"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *inp;
+    int         base;
+    const char  *want;
+    int         want_nread;
+
+  } data[] = {
+
+    { "0",   10, "0", 1 },
+
+    { "abc", 10, "0", 0 },
+    { "0xf", 10, "0", 1 },
+    { "ghi", 16, "0", 0 },
+    { "100", 90, "0", 0 },
+
+    {  "ff", 16,  "255", 2 },
+    { "-ff", 16, "-255", 3 },
+    {  "FF", 16,  "255", 2 },
+    { "-FF", 16, "-255", 3 },
+
+    {  "z", 36, "35", 1 },
+    {  "Z", 36, "35", 1 },
+    { "1B", 59, "70", 2 },
+    {  "a", 60, "36", 1 },
+    {  "A", 61, "10", 1 },
+
+    {  "0x0",    0,   "0", 3 },
+    {  "0X10",   0,  "16", 4 },
+    { "-0X0",    0,   "0", 4 },
+    { "-0x10",   0, "-16", 5 },
+
+    {  "0b0",    0,  "0", 3 },
+    {  "0B10",   0,  "2", 4 },
+    { "-0B0",    0,  "0", 4 },
+    { "-0b10",   0, "-2", 5 },
+
+    {  "00",   0,  "0", 2 },
+    {  "010",  0,  "8", 3 },
+    { "-00",   0,  "0", 3 },
+    { "-010",  0, "-8", 4 },
+
+    {  "0x",     0,   "0", 2 },
+    {  "0",      0,   "0", 1 },
+    { " 030",   10,  "30", 4 },
+  };
+
+  mpz_t  got, want;
+  long   ftell_nread;
+  int    i, pre, post, j, got_nread, want_nread;
+  FILE   *fp;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (pre = 0; pre <= 3; pre++)
+	{
+	  for (post = 0; post <= 2; post++)
+	    {
+	      mpz_set_str_or_abort (want, data[i].want, 0);
+	      MPZ_CHECK_FORMAT (want);
+
+	      /* create the file new each time to ensure its length is what
+		 we want */
+	      fp = fopen (FILENAME, "w+");
+	      ASSERT_ALWAYS (fp != NULL);
+	      for (j = 0; j < pre; j++)
+		putc (' ', fp);
+	      fputs (data[i].inp, fp);
+	      for (j = 0; j < post; j++)
+		putc (' ', fp);
+	      fflush (fp);
+	      ASSERT_ALWAYS (! ferror(fp));
+
+	      rewind (fp);
+	      got_nread = mpz_inp_str (got, fp, data[i].base);
+
+	      if (got_nread != 0)
+		{
+		  ftell_nread = ftell (fp);
+		  if (got_nread != ftell_nread)
+		    {
+		      printf ("mpz_inp_str nread wrong\n");
+		      printf ("  inp          \"%s\"\n", data[i].inp);
+		      printf ("  base         %d\n", data[i].base);
+		      printf ("  pre          %d\n", pre);
+		      printf ("  post         %d\n", post);
+		      printf ("  got_nread    %d\n", got_nread);
+		      printf ("  ftell_nread  %ld\n", ftell_nread);
+		      abort ();
+		    }
+		}
+
+	      /* if data[i].inp is a whole string to read and there's no post
+		 whitespace then expect to have EOF */
+	      if (post == 0 && data[i].want_nread == strlen(data[i].inp))
+		{
+		  int  c = getc(fp);
+		  if (c != EOF)
+		    {
+		      printf ("mpz_inp_str didn't read to EOF\n");
+		      printf ("  inp   \"%s\"\n", data[i].inp);
+		      printf ("  base  %d\n", data[i].base);
+		      printf ("  pre   %d\n", pre);
+		      printf ("  post  %d\n", post);
+		      printf ("  c     '%c' %#x\n", c, c);
+		      abort ();
+		    }
+		}
+
+	      /* only expect "pre" included in the count when non-zero */
+	      want_nread = data[i].want_nread;
+	      if (want_nread != 0)
+		want_nread += pre;
+
+	      if (got_nread != want_nread)
+		{
+		  printf ("mpz_inp_str nread wrong\n");
+		  printf ("  inp         \"%s\"\n", data[i].inp);
+		  printf ("  base        %d\n", data[i].base);
+		  printf ("  pre         %d\n", pre);
+		  printf ("  post        %d\n", post);
+		  printf ("  got_nread   %d\n", got_nread);
+		  printf ("  want_nread  %d\n", want_nread);
+		  abort ();
+		}
+
+	      MPZ_CHECK_FORMAT (got);
+
+	      if (mpz_cmp (got, want) != 0)
+		{
+		  printf ("mpz_inp_str wrong result\n");
+		  printf ("  inp   \"%s\"\n", data[i].inp);
+		  printf ("  base  %d\n", data[i].base);
+		  mpz_trace ("  got ",  got);
+		  mpz_trace ("  want", want);
+		  abort ();
+		}
+
+	      ASSERT_ALWAYS (fclose (fp) == 0);
+	    }
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  unlink (FILENAME);
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-invert.c b/tests/mpz/t-invert.c
new file mode 100644
index 0000000..0081c49
--- /dev/null
+++ b/tests/mpz/t-invert.c
@@ -0,0 +1,117 @@
+/* Test mpz_invert.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2005, 2008, 2009, 2012, 2014 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, m, ainv, t;
+  int test, r;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  int reps = 1000;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (a);
+  mpz_init (m);
+  mpz_init (ainv);
+  mpz_init (t);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (a, rands, mpz_get_ui (bs));
+      do {
+	mpz_urandomb (bs, rands, size_range);
+	mpz_rrandomb (m, rands, mpz_get_ui (bs));
+      } while (mpz_sgn (m) == 0);
+
+      mpz_urandomb (bs, rands, 8);
+      bsi = mpz_get_ui (bs);
+
+      if ((bsi & 1) != 0)
+	mpz_neg (a, a);
+      if ((bsi & 2) != 0)
+	mpz_neg (m, m);
+
+      r = mpz_invert (ainv, a, m);
+      if (r != 0)
+	{
+	  MPZ_CHECK_FORMAT (ainv);
+
+	  if (mpz_cmp_ui (ainv, 0) < 0 || mpz_cmpabs (ainv, m) >= 0)
+	    {
+	      fprintf (stderr, "ERROR in test %d\n", test);
+	      gmp_fprintf (stderr, "Inverse out of range.\n");
+	      gmp_fprintf (stderr, "a = %Zx\n", a);
+	      gmp_fprintf (stderr, "1/a = %Zx\n", ainv);
+	      gmp_fprintf (stderr, "m = %Zx\n", m);
+	      abort ();
+	    }
+
+	  mpz_mul (t, ainv, a);
+	  mpz_mod (t, t, m);
+
+	  if (mpz_cmp_ui (t, mpz_cmpabs_ui (m, 1) != 0) != 0)
+	    {
+	      fprintf (stderr, "ERROR in test %d\n", test);
+	      gmp_fprintf (stderr, "a^(-1)*a != 1 (mod m)\n");
+	      gmp_fprintf (stderr, "a = %Zx\n", a);
+	      gmp_fprintf (stderr, "m = %Zx\n", m);
+	      abort ();
+	    }
+	}
+      else /* Inverse deos not exist */
+	{
+	  mpz_gcd (t, a, m);
+	  if (mpz_cmp_ui (t, 1) == 0)
+	    {
+	      fprintf (stderr, "ERROR in test %d\n", test);
+	      gmp_fprintf (stderr, "Inverse exists, but was not found.\n");
+	      gmp_fprintf (stderr, "a = %Zx\n", a);
+	      gmp_fprintf (stderr, "m = %Zx\n", m);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (a);
+  mpz_clear (m);
+  mpz_clear (ainv);
+  mpz_clear (t);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-io_raw.c b/tests/mpz/t-io_raw.c
new file mode 100644
index 0000000..b840b64
--- /dev/null
+++ b/tests/mpz/t-io_raw.c
@@ -0,0 +1,286 @@
+/* Test mpz_inp_raw and mpz_out_raw.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define FILENAME  "/tmp/t-io_raw.tmp"
+
+
+/* In the fopen, "b" selects binary mode on DOS systems, meaning no
+   conversion of '\n' to and from CRLF.  It's believed systems without such
+   nonsense will simply ignore the "b", but in case that's not so a plain
+   "w+" is attempted if "w+b" fails.  */
+
+FILE *
+fopen_wplusb_or_die (const char *filename)
+{
+  FILE  *fp;
+  fp = fopen (filename, "w+b");
+  if (fp == NULL)
+    fp = fopen (filename, "w+");
+
+  if (fp == NULL)
+    {
+      printf ("Cannot create file %s\n", filename);
+      abort ();
+    }
+  return fp;
+}
+
+/* use 0x80 to check nothing bad happens with sign extension etc */
+#define BYTEVAL(i)  (((i) + 1) | 0x80)
+
+void
+check_in (void)
+{
+  int        i, j, zeros, neg, error = 0;
+  mpz_t      want, got;
+  size_t     want_ret, got_ret;
+  mp_size_t  size;
+  FILE       *fp;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  for (i = 0; i < 32; i++)
+    {
+      for (zeros = 0; zeros < 8; zeros++)
+	{
+	  for (neg = 0; neg <= 1; neg++)
+	    {
+	      want_ret = i + zeros + 4;
+
+	      /* need this to get the twos complement right */
+	      ASSERT_ALWAYS (sizeof (size) >= 4);
+
+	      size = i + zeros;
+	      if (neg)
+		size = -size;
+
+	      fp = fopen_wplusb_or_die (FILENAME);
+	      for (j = 3; j >= 0; j--)
+		ASSERT_ALWAYS (putc ((size >> (j*8)) & 0xFF, fp) != EOF);
+	      for (j = 0; j < zeros; j++)
+		ASSERT_ALWAYS (putc ('\0', fp) != EOF);
+	      for (j = 0; j < i; j++)
+		ASSERT_ALWAYS (putc (BYTEVAL (j), fp) != EOF);
+	      /* and some trailing garbage */
+	      ASSERT_ALWAYS (putc ('x', fp) != EOF);
+	      ASSERT_ALWAYS (putc ('y', fp) != EOF);
+	      ASSERT_ALWAYS (putc ('z', fp) != EOF);
+	      ASSERT_ALWAYS (fflush (fp) == 0);
+	      rewind (fp);
+
+	      got_ret = mpz_inp_raw (got, fp);
+	      ASSERT_ALWAYS (! ferror(fp));
+	      ASSERT_ALWAYS (fclose (fp) == 0);
+
+	      MPZ_CHECK_FORMAT (got);
+
+	      if (got_ret != want_ret)
+		{
+		  printf ("check_in: return value wrong\n");
+		  error = 1;
+		}
+	      if (mpz_cmp (got, want) != 0)
+		{
+		  printf ("check_in: result wrong\n");
+		  error = 1;
+		}
+	      if (error)
+		{
+		  printf    ("  i=%d zeros=%d neg=%d\n", i, zeros, neg);
+		  printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
+		  printf    ("  want_ret %lu\n", (unsigned long) want_ret);
+		  mpz_trace ("  got      ", got);
+		  mpz_trace ("  want     ", want);
+		  abort ();
+		}
+
+	      mpz_neg (want, want);
+	    }
+	}
+      mpz_mul_2exp (want, want, 8);
+      mpz_add_ui (want, want, (unsigned long) BYTEVAL (i));
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+
+void
+check_out (void)
+{
+  int        i, j, neg, error = 0;
+  mpz_t      z;
+  char       want[256], got[256], *p;
+  size_t     want_len, got_ret, got_read;
+  mp_size_t  size;
+  FILE       *fp;
+
+  mpz_init (z);
+
+  for (i = 0; i < 32; i++)
+    {
+      for (neg = 0; neg <= 1; neg++)
+	{
+	  want_len = i + 4;
+
+	  /* need this to get the twos complement right */
+	  ASSERT_ALWAYS (sizeof (size) >= 4);
+
+	  size = i;
+	  if (neg)
+	    size = -size;
+
+	  p = want;
+	  for (j = 3; j >= 0; j--)
+	    *p++ = size >> (j*8);
+	  for (j = 0; j < i; j++)
+	    *p++ = BYTEVAL (j);
+	  ASSERT_ALWAYS (p <= want + sizeof (want));
+
+	  fp = fopen_wplusb_or_die (FILENAME);
+	  got_ret = mpz_out_raw (fp, z);
+	  ASSERT_ALWAYS (fflush (fp) == 0);
+	  rewind (fp);
+	  got_read = fread (got, 1, sizeof(got), fp);
+	  ASSERT_ALWAYS (! ferror(fp));
+	  ASSERT_ALWAYS (fclose (fp) == 0);
+
+	  if (got_ret != want_len)
+	    {
+	      printf ("check_out: wrong return value\n");
+	      error = 1;
+	    }
+	  if (got_read != want_len)
+	    {
+	      printf ("check_out: wrong number of bytes read back\n");
+	      error = 1;
+	    }
+	  if (memcmp (want, got, want_len) != 0)
+	    {
+	      printf ("check_out: wrong data\n");
+	      error = 1;
+	    }
+	  if (error)
+	    {
+	      printf    ("  i=%d neg=%d\n", i, neg);
+	      mpz_trace ("  z", z);
+	      printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
+	      printf    ("  got_read %lu\n", (unsigned long) got_read);
+	      printf    ("  want_len %lu\n", (unsigned long) want_len);
+	      printf    ("  want");
+	      for (j = 0; j < want_len; j++)
+		printf (" %02X", (unsigned) (unsigned char) want[j]);
+	      printf    ("\n");
+	      printf    ("  got ");
+	      for (j = 0; j < want_len; j++)
+		printf (" %02X", (unsigned) (unsigned char) got[j]);
+	      printf    ("\n");
+	      abort ();
+	    }
+
+	  mpz_neg (z, z);
+	}
+      mpz_mul_2exp (z, z, 8);
+      mpz_add_ui (z, z, (unsigned long) BYTEVAL (i));
+    }
+
+  mpz_clear (z);
+}
+
+
+void
+check_rand (void)
+{
+  gmp_randstate_ptr  rands = RANDS;
+  int        i, error = 0;
+  mpz_t      got, want;
+  size_t     inp_ret, out_ret;
+  FILE       *fp;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  for (i = 0; i < 500; i++)
+    {
+      mpz_erandomb (want, rands, 10*GMP_LIMB_BITS);
+      mpz_negrandom (want, rands);
+
+      fp = fopen_wplusb_or_die (FILENAME);
+      out_ret = mpz_out_raw (fp, want);
+      ASSERT_ALWAYS (fflush (fp) == 0);
+      rewind (fp);
+      inp_ret = mpz_inp_raw (got, fp);
+      ASSERT_ALWAYS (fclose (fp) == 0);
+
+      MPZ_CHECK_FORMAT (got);
+
+      if (inp_ret != out_ret)
+	{
+	  printf ("check_rand: different inp/out return values\n");
+	  error = 1;
+	}
+      if (mpz_cmp (got, want) != 0)
+	{
+	  printf ("check_rand: wrong result\n");
+	  error = 1;
+	}
+      if (error)
+	{
+	  printf    ("  out_ret %lu\n", (unsigned long) out_ret);
+	  printf    ("  inp_ret %lu\n", (unsigned long) inp_ret);
+	  mpz_trace ("  want", want);
+	  mpz_trace ("  got ", got);
+	  abort ();
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_in ();
+  check_out ();
+  check_rand ();
+
+  unlink (FILENAME);
+  tests_end ();
+
+  exit (0);
+}
diff --git a/tests/mpz/t-jac.c b/tests/mpz/t-jac.c
new file mode 100644
index 0000000..ed8aff8
--- /dev/null
+++ b/tests/mpz/t-jac.c
@@ -0,0 +1,1008 @@
+/* Exercise mpz_*_kronecker_*() and mpz_jacobi() functions.
+
+Copyright 1999-2004, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* With no arguments the various Kronecker/Jacobi symbol routines are
+   checked against some test data and a lot of derived data.
+
+   To check the test data against PARI-GP, run
+
+	   t-jac -p | gp -q
+
+   Enhancements:
+
+   More big test cases than those given by check_squares_zi would be good.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef _LONG_LONG_LIMB
+#define LL(l,ll)  ll
+#else
+#define LL(l,ll)  l
+#endif
+
+
+int option_pari = 0;
+
+
+unsigned long
+mpz_mod4 (mpz_srcptr z)
+{
+  mpz_t          m;
+  unsigned long  ret;
+
+  mpz_init (m);
+  mpz_fdiv_r_2exp (m, z, 2);
+  ret = mpz_get_ui (m);
+  mpz_clear (m);
+  return ret;
+}
+
+int
+mpz_fits_ulimb_p (mpz_srcptr z)
+{
+  return (SIZ(z) == 1 || SIZ(z) == 0);
+}
+
+mp_limb_t
+mpz_get_ulimb (mpz_srcptr z)
+{
+  if (SIZ(z) == 0)
+    return 0;
+  else
+    return PTR(z)[0];
+}
+
+
+void
+try_base (mp_limb_t a, mp_limb_t b, int answer)
+{
+  int  got;
+
+  if ((b & 1) == 0 || b == 1 || a > b)
+    return;
+
+  got = mpn_jacobi_base (a, b, 0);
+  if (got != answer)
+    {
+      printf (LL("mpn_jacobi_base (%lu, %lu) is %d should be %d\n",
+		 "mpn_jacobi_base (%llu, %llu) is %d should be %d\n"),
+	      a, b, got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_zi_ui (mpz_srcptr a, unsigned long b, int answer)
+{
+  int  got;
+
+  got = mpz_kronecker_ui (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_kronecker_ui (");
+      mpz_out_str (stdout, 10, a);
+      printf (", %lu) is %d should be %d\n", b, got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_zi_si (mpz_srcptr a, long b, int answer)
+{
+  int  got;
+
+  got = mpz_kronecker_si (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_kronecker_si (");
+      mpz_out_str (stdout, 10, a);
+      printf (", %ld) is %d should be %d\n", b, got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_ui_zi (unsigned long a, mpz_srcptr b, int answer)
+{
+  int  got;
+
+  got = mpz_ui_kronecker (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_ui_kronecker (%lu, ", a);
+      mpz_out_str (stdout, 10, b);
+      printf (") is %d should be %d\n", got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_si_zi (long a, mpz_srcptr b, int answer)
+{
+  int  got;
+
+  got = mpz_si_kronecker (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_si_kronecker (%ld, ", a);
+      mpz_out_str (stdout, 10, b);
+      printf (") is %d should be %d\n", got, answer);
+      abort ();
+    }
+}
+
+
+/* Don't bother checking mpz_jacobi, since it only differs for b even, and
+   we don't have an actual expected answer for it.  tests/devel/try.c does
+   some checks though.  */
+void
+try_zi_zi (mpz_srcptr a, mpz_srcptr b, int answer)
+{
+  int  got;
+
+  got = mpz_kronecker (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_kronecker (");
+      mpz_out_str (stdout, 10, a);
+      printf (", ");
+      mpz_out_str (stdout, 10, b);
+      printf (") is %d should be %d\n", got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_pari (mpz_srcptr a, mpz_srcptr b, int answer)
+{
+  printf ("try(");
+  mpz_out_str (stdout, 10, a);
+  printf (",");
+  mpz_out_str (stdout, 10, b);
+  printf (",%d)\n", answer);
+}
+
+
+void
+try_each (mpz_srcptr a, mpz_srcptr b, int answer)
+{
+#if 0
+  fprintf(stderr, "asize = %d, bsize = %d\n",
+	  mpz_sizeinbase (a, 2), mpz_sizeinbase (b, 2));
+#endif
+  if (option_pari)
+    {
+      try_pari (a, b, answer);
+      return;
+    }
+
+  if (mpz_fits_ulimb_p (a) && mpz_fits_ulimb_p (b))
+    try_base (mpz_get_ulimb (a), mpz_get_ulimb (b), answer);
+
+  if (mpz_fits_ulong_p (b))
+    try_zi_ui (a, mpz_get_ui (b), answer);
+
+  if (mpz_fits_slong_p (b))
+    try_zi_si (a, mpz_get_si (b), answer);
+
+  if (mpz_fits_ulong_p (a))
+    try_ui_zi (mpz_get_ui (a), b, answer);
+
+  if (mpz_fits_sint_p (a))
+    try_si_zi (mpz_get_si (a), b, answer);
+
+  try_zi_zi (a, b, answer);
+}
+
+
+/* Try (a/b) and (a/-b). */
+void
+try_pn (mpz_srcptr a, mpz_srcptr b_orig, int answer)
+{
+  mpz_t  b;
+
+  mpz_init_set (b, b_orig);
+  try_each (a, b, answer);
+
+  mpz_neg (b, b);
+  if (mpz_sgn (a) < 0)
+    answer = -answer;
+
+  try_each (a, b, answer);
+
+  mpz_clear (b);
+}
+
+
+/* Try (a+k*p/b) for various k, using the fact (a/b) is periodic in a with
+   period p.  For b>0, p=b if b!=2mod4 or p=4*b if b==2mod4. */
+
+void
+try_periodic_num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
+{
+  mpz_t  a, a_period;
+  int    i;
+
+  if (mpz_sgn (b) <= 0)
+    return;
+
+  mpz_init_set (a, a_orig);
+  mpz_init_set (a_period, b);
+  if (mpz_mod4 (b) == 2)
+    mpz_mul_ui (a_period, a_period, 4);
+
+  /* don't bother with these tests if they're only going to produce
+     even/even */
+  if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (a_period))
+    goto done;
+
+  for (i = 0; i < 6; i++)
+    {
+      mpz_add (a, a, a_period);
+      try_pn (a, b, answer);
+    }
+
+  mpz_set (a, a_orig);
+  for (i = 0; i < 6; i++)
+    {
+      mpz_sub (a, a, a_period);
+      try_pn (a, b, answer);
+    }
+
+ done:
+  mpz_clear (a);
+  mpz_clear (a_period);
+}
+
+
+/* Try (a/b+k*p) for various k, using the fact (a/b) is periodic in b of
+   period p.
+
+			       period p
+	   a==0,1mod4             a
+	   a==2mod4              4*a
+	   a==3mod4 and b odd    4*a
+	   a==3mod4 and b even   8*a
+
+   In Henri Cohen's book the period is given as 4*a for all a==2,3mod4, but
+   a counterexample would seem to be (3/2)=-1 which with (3/14)=+1 doesn't
+   have period 4*a (but rather 8*a with (3/26)=-1).  Maybe the plain 4*a is
+   to be read as applying to a plain Jacobi symbol with b odd, rather than
+   the Kronecker extension to b even. */
+
+void
+try_periodic_den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
+{
+  mpz_t  b, b_period;
+  int    i;
+
+  if (mpz_sgn (a) == 0 || mpz_sgn (b_orig) == 0)
+    return;
+
+  mpz_init_set (b, b_orig);
+
+  mpz_init_set (b_period, a);
+  if (mpz_mod4 (a) == 3 && mpz_even_p (b))
+    mpz_mul_ui (b_period, b_period, 8L);
+  else if (mpz_mod4 (a) >= 2)
+    mpz_mul_ui (b_period, b_period, 4L);
+
+  /* don't bother with these tests if they're only going to produce
+     even/even */
+  if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (b_period))
+    goto done;
+
+  for (i = 0; i < 6; i++)
+    {
+      mpz_add (b, b, b_period);
+      try_pn (a, b, answer);
+    }
+
+  mpz_set (b, b_orig);
+  for (i = 0; i < 6; i++)
+    {
+      mpz_sub (b, b, b_period);
+      try_pn (a, b, answer);
+    }
+
+ done:
+  mpz_clear (b);
+  mpz_clear (b_period);
+}
+
+
+static const unsigned long  ktable[] = {
+  0, 1, 2, 3, 4, 5, 6, 7,
+  GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
+  2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
+  3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1
+};
+
+
+/* Try (a/b*2^k) for various k. */
+void
+try_2den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
+{
+  mpz_t  b;
+  int    kindex;
+  int    answer_a2, answer_k;
+  unsigned long k;
+
+  /* don't bother when b==0 */
+  if (mpz_sgn (b_orig) == 0)
+    return;
+
+  mpz_init_set (b, b_orig);
+
+  /* (a/2) is 0 if a even, 1 if a==1 or 7 mod 8, -1 if a==3 or 5 mod 8 */
+  answer_a2 = (mpz_even_p (a) ? 0
+	       : (((SIZ(a) >= 0 ? PTR(a)[0] : -PTR(a)[0]) + 2) & 7) < 4 ? 1
+	       : -1);
+
+  for (kindex = 0; kindex < numberof (ktable); kindex++)
+    {
+      k = ktable[kindex];
+
+      /* answer_k = answer*(answer_a2^k) */
+      answer_k = (answer_a2 == 0 && k != 0 ? 0
+		  : (k & 1) == 1 && answer_a2 == -1 ? -answer
+		  : answer);
+
+      mpz_mul_2exp (b, b_orig, k);
+      try_pn (a, b, answer_k);
+    }
+
+  mpz_clear (b);
+}
+
+
+/* Try (a*2^k/b) for various k.  If it happens mpz_ui_kronecker() gets (2/b)
+   wrong it will show up as wrong answers demanded. */
+void
+try_2num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
+{
+  mpz_t  a;
+  int    kindex;
+  int    answer_2b, answer_k;
+  unsigned long  k;
+
+  /* don't bother when a==0 */
+  if (mpz_sgn (a_orig) == 0)
+    return;
+
+  mpz_init (a);
+
+  /* (2/b) is 0 if b even, 1 if b==1 or 7 mod 8, -1 if b==3 or 5 mod 8 */
+  answer_2b = (mpz_even_p (b) ? 0
+	       : (((SIZ(b) >= 0 ? PTR(b)[0] : -PTR(b)[0]) + 2) & 7) < 4 ? 1
+	       : -1);
+
+  for (kindex = 0; kindex < numberof (ktable); kindex++)
+    {
+      k = ktable[kindex];
+
+      /* answer_k = answer*(answer_2b^k) */
+      answer_k = (answer_2b == 0 && k != 0 ? 0
+		  : (k & 1) == 1 && answer_2b == -1 ? -answer
+		  : answer);
+
+	mpz_mul_2exp (a, a_orig, k);
+      try_pn (a, b, answer_k);
+    }
+
+  mpz_clear (a);
+}
+
+
+/* The try_2num() and try_2den() routines don't in turn call
+   try_periodic_num() and try_periodic_den() because it hugely increases the
+   number of tests performed, without obviously increasing coverage.
+
+   Useful extra derived cases can be added here. */
+
+void
+try_all (mpz_t a, mpz_t b, int answer)
+{
+  try_pn (a, b, answer);
+  try_periodic_num (a, b, answer);
+  try_periodic_den (a, b, answer);
+  try_2num (a, b, answer);
+  try_2den (a, b, answer);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *a;
+    const char  *b;
+    int         answer;
+
+  } data[] = {
+
+    /* Note that the various derived checks in try_all() reduce the cases
+       that need to be given here.  */
+
+    /* some zeros */
+    {  "0",  "0", 0 },
+    {  "0",  "2", 0 },
+    {  "0",  "6", 0 },
+    {  "5",  "0", 0 },
+    { "24", "60", 0 },
+
+    /* (a/1) = 1, any a
+       In particular note (0/1)=1 so that (a/b)=(a mod b/b). */
+    { "0", "1", 1 },
+    { "1", "1", 1 },
+    { "2", "1", 1 },
+    { "3", "1", 1 },
+    { "4", "1", 1 },
+    { "5", "1", 1 },
+
+    /* (0/b) = 0, b != 1 */
+    { "0",  "3", 0 },
+    { "0",  "5", 0 },
+    { "0",  "7", 0 },
+    { "0",  "9", 0 },
+    { "0", "11", 0 },
+    { "0", "13", 0 },
+    { "0", "15", 0 },
+
+    /* (1/b) = 1 */
+    { "1",  "1", 1 },
+    { "1",  "3", 1 },
+    { "1",  "5", 1 },
+    { "1",  "7", 1 },
+    { "1",  "9", 1 },
+    { "1", "11", 1 },
+
+    /* (-1/b) = (-1)^((b-1)/2) which is -1 for b==3 mod 4 */
+    { "-1",  "1",  1 },
+    { "-1",  "3", -1 },
+    { "-1",  "5",  1 },
+    { "-1",  "7", -1 },
+    { "-1",  "9",  1 },
+    { "-1", "11", -1 },
+    { "-1", "13",  1 },
+    { "-1", "15", -1 },
+    { "-1", "17",  1 },
+    { "-1", "19", -1 },
+
+    /* (2/b) = (-1)^((b^2-1)/8) which is -1 for b==3,5 mod 8.
+       try_2num() will exercise multiple powers of 2 in the numerator.  */
+    { "2",  "1",  1 },
+    { "2",  "3", -1 },
+    { "2",  "5", -1 },
+    { "2",  "7",  1 },
+    { "2",  "9",  1 },
+    { "2", "11", -1 },
+    { "2", "13", -1 },
+    { "2", "15",  1 },
+    { "2", "17",  1 },
+
+    /* (-2/b) = (-1)^((b^2-1)/8)*(-1)^((b-1)/2) which is -1 for b==5,7mod8.
+       try_2num() will exercise multiple powers of 2 in the numerator, which
+       will test that the shift in mpz_si_kronecker() uses unsigned not
+       signed.  */
+    { "-2",  "1",  1 },
+    { "-2",  "3",  1 },
+    { "-2",  "5", -1 },
+    { "-2",  "7", -1 },
+    { "-2",  "9",  1 },
+    { "-2", "11",  1 },
+    { "-2", "13", -1 },
+    { "-2", "15", -1 },
+    { "-2", "17",  1 },
+
+    /* (a/2)=(2/a).
+       try_2den() will exercise multiple powers of 2 in the denominator. */
+    {  "3",  "2", -1 },
+    {  "5",  "2", -1 },
+    {  "7",  "2",  1 },
+    {  "9",  "2",  1 },
+    {  "11", "2", -1 },
+
+    /* Harriet Griffin, "Elementary Theory of Numbers", page 155, various
+       examples.  */
+    {   "2", "135",  1 },
+    { "135",  "19", -1 },
+    {   "2",  "19", -1 },
+    {  "19", "135",  1 },
+    { "173", "135",  1 },
+    {  "38", "135",  1 },
+    { "135", "173",  1 },
+    { "173",   "5", -1 },
+    {   "3",   "5", -1 },
+    {   "5", "173", -1 },
+    { "173",   "3", -1 },
+    {   "2",   "3", -1 },
+    {   "3", "173", -1 },
+    { "253",  "21",  1 },
+    {   "1",  "21",  1 },
+    {  "21", "253",  1 },
+    {  "21",  "11", -1 },
+    {  "-1",  "11", -1 },
+
+    /* Griffin page 147 */
+    {  "-1",  "17",  1 },
+    {   "2",  "17",  1 },
+    {  "-2",  "17",  1 },
+    {  "-1",  "89",  1 },
+    {   "2",  "89",  1 },
+
+    /* Griffin page 148 */
+    {  "89",  "11",  1 },
+    {   "1",  "11",  1 },
+    {  "89",   "3", -1 },
+    {   "2",   "3", -1 },
+    {   "3",  "89", -1 },
+    {  "11",  "89",  1 },
+    {  "33",  "89", -1 },
+
+    /* H. Davenport, "The Higher Arithmetic", page 65, the quadratic
+       residues and non-residues mod 19.  */
+    {  "1", "19",  1 },
+    {  "4", "19",  1 },
+    {  "5", "19",  1 },
+    {  "6", "19",  1 },
+    {  "7", "19",  1 },
+    {  "9", "19",  1 },
+    { "11", "19",  1 },
+    { "16", "19",  1 },
+    { "17", "19",  1 },
+    {  "2", "19", -1 },
+    {  "3", "19", -1 },
+    {  "8", "19", -1 },
+    { "10", "19", -1 },
+    { "12", "19", -1 },
+    { "13", "19", -1 },
+    { "14", "19", -1 },
+    { "15", "19", -1 },
+    { "18", "19", -1 },
+
+    /* Residues and non-residues mod 13 */
+    {  "0",  "13",  0 },
+    {  "1",  "13",  1 },
+    {  "2",  "13", -1 },
+    {  "3",  "13",  1 },
+    {  "4",  "13",  1 },
+    {  "5",  "13", -1 },
+    {  "6",  "13", -1 },
+    {  "7",  "13", -1 },
+    {  "8",  "13", -1 },
+    {  "9",  "13",  1 },
+    { "10",  "13",  1 },
+    { "11",  "13", -1 },
+    { "12",  "13",  1 },
+
+    /* various */
+    {  "5",   "7", -1 },
+    { "15",  "17",  1 },
+    { "67",  "89",  1 },
+
+    /* special values inducing a==b==1 at the end of jac_or_kron() */
+    { "0x10000000000000000000000000000000000000000000000001",
+      "0x10000000000000000000000000000000000000000000000003", 1 },
+
+    /* Test for previous bugs in jacobi_2. */
+    { "0x43900000000", "0x42400000439", -1 }, /* 32-bit limbs */
+    { "0x4390000000000000000", "0x4240000000000000439", -1 }, /* 64-bit limbs */
+
+    { "198158408161039063", "198158360916398807", -1 },
+
+    /* Some tests involving large quotients in the continued fraction
+       expansion. */
+    { "37200210845139167613356125645445281805",
+      "451716845976689892447895811408978421929", -1 },
+    { "67674091930576781943923596701346271058970643542491743605048620644676477275152701774960868941561652032482173612421015",
+      "4902678867794567120224500687210807069172039735", 0 },
+    { "2666617146103764067061017961903284334497474492754652499788571378062969111250584288683585223600172138551198546085281683283672592", "2666617146103764067061017961903284334497474492754652499788571378062969111250584288683585223600172138551198546085281683290481773", 1 },
+
+    /* Exercises the case asize == 1, btwos > 0 in mpz_jacobi. */
+    { "804609", "421248363205206617296534688032638102314410556521742428832362659824", 1 } ,
+    { "4190209", "2239744742177804210557442048984321017460028974602978995388383905961079286530650825925074203175536427000", 1 },
+
+    /* Exercises the case asize == 1, btwos = 63 in mpz_jacobi
+       (relevant when GMP_LIMB_BITS == 64). */
+    { "17311973299000934401", "1675975991242824637446753124775689449936871337036614677577044717424700351103148799107651171694863695242089956242888229458836426332300124417011114380886016", 1 },
+    { "3220569220116583677", "41859917623035396746", -1 },
+
+    /* Other test cases that triggered bugs during development. */
+    { "37200210845139167613356125645445281805", "340116213441272389607827434472642576514", -1 },
+    { "74400421690278335226712251290890563610", "451716845976689892447895811408978421929", -1 },
+  };
+
+  int    i;
+  mpz_t  a, b;
+
+  mpz_init (a);
+  mpz_init (b);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (b, data[i].b, 0);
+      try_all (a, b, data[i].answer);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+
+/* (a^2/b)=1 if gcd(a,b)=1, or (a^2/b)=0 if gcd(a,b)!=1.
+   This includes when a=0 or b=0. */
+void
+check_squares_zi (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t  a, b, g;
+  int    i, answer;
+  mp_size_t size_range, an, bn;
+  mpz_t bs;
+
+  mpz_init (bs);
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (g);
+
+  for (i = 0; i < 50; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + i/8 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      an = mpz_get_ui (bs);
+      mpz_rrandomb (a, rands, an);
+
+      mpz_urandomb (bs, rands, size_range);
+      bn = mpz_get_ui (bs);
+      mpz_rrandomb (b, rands, bn);
+
+      mpz_gcd (g, a, b);
+      if (mpz_cmp_ui (g, 1L) == 0)
+	answer = 1;
+      else
+	answer = 0;
+
+      mpz_mul (a, a, a);
+
+      try_all (a, b, answer);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (g);
+}
+
+
+/* Check the handling of asize==0, make sure it isn't affected by the low
+   limb. */
+void
+check_a_zero (void)
+{
+  mpz_t  a, b;
+
+  mpz_init_set_ui (a, 0);
+  mpz_init (b);
+
+  mpz_set_ui (b, 1L);
+  PTR(a)[0] = 0;
+  try_all (a, b, 1);   /* (0/1)=1 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 1);   /* (0/1)=1 */
+
+  mpz_set_si (b, -1L);
+  PTR(a)[0] = 0;
+  try_all (a, b, 1);   /* (0/-1)=1 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 1);   /* (0/-1)=1 */
+
+  mpz_set_ui (b, 0);
+  PTR(a)[0] = 0;
+  try_all (a, b, 0);   /* (0/0)=0 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 0);   /* (0/0)=0 */
+
+  mpz_set_ui (b, 2);
+  PTR(a)[0] = 0;
+  try_all (a, b, 0);   /* (0/2)=0 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 0);   /* (0/2)=0 */
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+
+/* Assumes that b = prod p_k^e_k */
+int
+ref_jacobi (mpz_srcptr a, mpz_srcptr b, unsigned nprime,
+	    mpz_t prime[], unsigned *exp)
+{
+  unsigned i;
+  int res;
+
+  for (i = 0, res = 1; i < nprime; i++)
+    if (exp[i])
+      {
+	int legendre = refmpz_legendre (a, prime[i]);
+	if (!legendre)
+	  return 0;
+	if (exp[i] & 1)
+	  res *= legendre;
+      }
+  return res;
+}
+
+void
+check_jacobi_factored (void)
+{
+#define PRIME_N 10
+#define PRIME_MAX_SIZE 50
+#define PRIME_MAX_EXP 4
+#define PRIME_A_COUNT 10
+#define PRIME_B_COUNT 5
+#define PRIME_MAX_B_SIZE 2000
+
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t prime[PRIME_N];
+  unsigned exp[PRIME_N];
+  mpz_t a, b, t, bs;
+  unsigned i;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (t);
+  mpz_init (bs);
+
+  /* Generate primes */
+  for (i = 0; i < PRIME_N; i++)
+    {
+      mp_size_t size;
+      mpz_init (prime[i]);
+      mpz_urandomb (bs, rands, 32);
+      size = mpz_get_ui (bs) % PRIME_MAX_SIZE + 2;
+      mpz_rrandomb (prime[i], rands, size);
+      if (mpz_cmp_ui (prime[i], 3) <= 0)
+	mpz_set_ui (prime[i], 3);
+      else
+	mpz_nextprime (prime[i], prime[i]);
+    }
+
+  for (i = 0; i < PRIME_B_COUNT; i++)
+    {
+      unsigned j, k;
+      mp_bitcnt_t bsize;
+
+      mpz_set_ui (b, 1);
+      bsize = 1;
+
+      for (j = 0; j < PRIME_N && bsize < PRIME_MAX_B_SIZE; j++)
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  exp[j] = mpz_get_ui (bs) % PRIME_MAX_EXP;
+	  mpz_pow_ui (t, prime[j], exp[j]);
+	  mpz_mul (b, b, t);
+	  bsize = mpz_sizeinbase (b, 2);
+	}
+      for (k = 0; k < PRIME_A_COUNT; k++)
+	{
+	  int answer;
+	  mpz_rrandomb (a, rands, bsize + 2);
+	  answer = ref_jacobi (a, b, j, prime, exp);
+	  try_all (a, b, answer);
+	}
+    }
+  for (i = 0; i < PRIME_N; i++)
+    mpz_clear (prime[i]);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (t);
+  mpz_clear (bs);
+
+#undef PRIME_N
+#undef PRIME_MAX_SIZE
+#undef PRIME_MAX_EXP
+#undef PRIME_A_COUNT
+#undef PRIME_B_COUNT
+#undef PRIME_MAX_B_SIZE
+}
+
+/* These tests compute (a|n), where the quotient sequence includes
+   large quotients, and n has a known factorization. Such inputs are
+   generated as follows. First, construct a large n, as a power of a
+   prime p of moderate size.
+
+   Next, compute a matrix from factors (q,1;1,0), with q chosen with
+   uniformly distributed size. We must stop with matrix elements of
+   roughly half the size of n. Denote elements of M as M = (m00, m01;
+   m10, m11).
+
+   We now look for solutions to
+
+     n = m00 x + m01 y
+     a = m10 x + m11 y
+
+   with x,y > 0. Since n >= m00 * m01, there exists a positive
+   solution to the first equation. Find those x, y, and substitute in
+   the second equation to get a. Then the quotient sequence for (a|n)
+   is precisely the quotients used when constructing M, followed by
+   the quotient sequence for (x|y).
+
+   Numbers should also be large enough that we exercise hgcd_jacobi,
+   which means that they should be larger than
+
+     max (GCD_DC_THRESHOLD, 3 * HGCD_THRESHOLD)
+
+   With an n of roughly 40000 bits, this should hold on most machines.
+*/
+
+void
+check_large_quotients (void)
+{
+#define COUNT 50
+#define PBITS 200
+#define PPOWER 201
+#define MAX_QBITS 500
+
+  gmp_randstate_ptr rands = RANDS;
+
+  mpz_t p, n, q, g, s, t, x, y, bs;
+  mpz_t M[2][2];
+  mp_bitcnt_t nsize;
+  unsigned i;
+
+  mpz_init (p);
+  mpz_init (n);
+  mpz_init (q);
+  mpz_init (g);
+  mpz_init (s);
+  mpz_init (t);
+  mpz_init (x);
+  mpz_init (y);
+  mpz_init (bs);
+  mpz_init (M[0][0]);
+  mpz_init (M[0][1]);
+  mpz_init (M[1][0]);
+  mpz_init (M[1][1]);
+
+  /* First generate a number with known factorization, as a random
+     smallish prime raised to an odd power. Then (a|n) = (a|p). */
+  mpz_rrandomb (p, rands, PBITS);
+  mpz_nextprime (p, p);
+  mpz_pow_ui (n, p, PPOWER);
+
+  nsize = mpz_sizeinbase (n, 2);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      int answer;
+      mp_bitcnt_t msize;
+
+      mpz_set_ui (M[0][0], 1);
+      mpz_set_ui (M[0][1], 0);
+      mpz_set_ui (M[1][0], 0);
+      mpz_set_ui (M[1][1], 1);
+
+      for (msize = 1; 2*(msize + MAX_QBITS) + 1 < nsize ;)
+	{
+	  unsigned i;
+	  mpz_rrandomb (bs, rands, 32);
+	  mpz_rrandomb (q, rands, 1 + mpz_get_ui (bs) % MAX_QBITS);
+
+	  /* Multiply by (q, 1; 1,0) from the right */
+	  for (i = 0; i < 2; i++)
+	    {
+	      mp_bitcnt_t size;
+	      mpz_swap (M[i][0], M[i][1]);
+	      mpz_addmul (M[i][0], M[i][1], q);
+	      size = mpz_sizeinbase (M[i][0], 2);
+	      if (size > msize)
+		msize = size;
+	    }
+	}
+      mpz_gcdext (g, s, t, M[0][0], M[0][1]);
+      ASSERT_ALWAYS (mpz_cmp_ui (g, 1) == 0);
+
+      /* Solve n = M[0][0] * x + M[0][1] * y */
+      if (mpz_sgn (s) > 0)
+	{
+	  mpz_mul (x, n, s);
+	  mpz_fdiv_qr (q, x, x, M[0][1]);
+	  mpz_mul (y, q, M[0][0]);
+	  mpz_addmul (y, t, n);
+	  ASSERT_ALWAYS (mpz_sgn (y) > 0);
+	}
+      else
+	{
+	  mpz_mul (y, n, t);
+	  mpz_fdiv_qr (q, y, y, M[0][0]);
+	  mpz_mul (x, q, M[0][1]);
+	  mpz_addmul (x, s, n);
+	  ASSERT_ALWAYS (mpz_sgn (x) > 0);
+	}
+      mpz_mul (x, x, M[1][0]);
+      mpz_addmul (x, y, M[1][1]);
+
+      /* Now (x|n) has the selected large quotients */
+      answer = refmpz_legendre (x, p);
+      try_zi_zi (x, n, answer);
+    }
+  mpz_clear (p);
+  mpz_clear (n);
+  mpz_clear (q);
+  mpz_clear (g);
+  mpz_clear (s);
+  mpz_clear (t);
+  mpz_clear (x);
+  mpz_clear (y);
+  mpz_clear (bs);
+  mpz_clear (M[0][0]);
+  mpz_clear (M[0][1]);
+  mpz_clear (M[1][0]);
+  mpz_clear (M[1][1]);
+#undef COUNT
+#undef PBITS
+#undef PPOWER
+#undef MAX_QBITS
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  if (argc >= 2 && strcmp (argv[1], "-p") == 0)
+    {
+      option_pari = 1;
+
+      printf ("\
+try(a,b,answer) =\n\
+{\n\
+  if (kronecker(a,b) != answer,\n\
+    print(\"wrong at \", a, \",\", b,\n\
+      \" expected \", answer,\n\
+      \" pari says \", kronecker(a,b)))\n\
+}\n");
+    }
+
+  check_data ();
+  check_squares_zi ();
+  check_a_zero ();
+  check_jacobi_factored ();
+  check_large_quotients ();
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-lcm.c b/tests/mpz/t-lcm.c
new file mode 100644
index 0000000..1b45212
--- /dev/null
+++ b/tests/mpz/t-lcm.c
@@ -0,0 +1,184 @@
+/* Test mpz_lcm and mpz_lcm_ui.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_all (mpz_ptr want, mpz_srcptr x_orig, mpz_srcptr y_orig)
+{
+  mpz_t  got, x, y;
+  int    negx, negy, swap, inplace;
+
+  mpz_init (got);
+  mpz_init_set (x, x_orig);
+  mpz_init_set (y, y_orig);
+
+  for (swap = 0; swap < 2; swap++)
+    {
+      mpz_swap (x, y);
+
+      for (negx = 0; negx < 2; negx++)
+	{
+	  mpz_neg (x, x);
+
+	  for (negy = 0; negy < 2; negy++)
+	    {
+	      mpz_neg (y, y);
+
+	      for (inplace = 0; inplace <= 1; inplace++)
+		{
+		  if (inplace)
+		    { mpz_set (got, x); mpz_lcm (got, got, y); }
+		  else
+		    mpz_lcm (got, x, y);
+		  MPZ_CHECK_FORMAT (got);
+
+		  if (mpz_cmp (got, want) != 0)
+		    {
+		      printf ("mpz_lcm wrong, inplace=%d\n", inplace);
+		    fail:
+		      mpz_trace ("x", x);
+		      mpz_trace ("y", y);
+		      mpz_trace ("got", got);
+		      mpz_trace ("want", want);
+		      abort ();
+		    }
+
+		  if (mpz_fits_ulong_p (y))
+		    {
+		      unsigned long  yu = mpz_get_ui (y);
+		      if (inplace)
+			{ mpz_set (got, x); mpz_lcm_ui (got, got, yu); }
+		      else
+			mpz_lcm_ui (got, x, yu);
+
+		      if (mpz_cmp (got, want) != 0)
+			{
+			  printf ("mpz_lcm_ui wrong, inplace=%d\n", inplace);
+			  printf    ("yu=%lu\n", yu);
+			  goto fail;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+void
+check_primes (void)
+{
+  static unsigned long  prime[] = {
+    2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
+    101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,
+    191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,
+    281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,
+    389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,
+  };
+  mpz_t  want, x, y;
+  int    i;
+
+  mpz_init (want);
+  mpz_init (x);
+  mpz_init (y);
+
+  /* Check zeros. */
+  mpz_set_ui (want, 0);
+  mpz_set_ui (x, 1);
+  check_all (want, want, want);
+  check_all (want, want, x);
+  check_all (want, x, want);
+
+  /* New prime each time. */
+  mpz_set_ui (want, 1L);
+  for (i = 0; i < numberof (prime); i++)
+    {
+      mpz_set (x, want);
+      mpz_set_ui (y, prime[i]);
+      mpz_mul_ui (want, want, prime[i]);
+      check_all (want, x, y);
+    }
+
+  /* Old prime each time. */
+  mpz_set (x, want);
+  for (i = 0; i < numberof (prime); i++)
+    {
+      mpz_set_ui (y, prime[i]);
+      check_all (want, x, y);
+    }
+
+  /* One old, one new each time. */
+  mpz_set_ui (want, prime[0]);
+  for (i = 1; i < numberof (prime); i++)
+    {
+      mpz_set (x, want);
+      mpz_set_ui (y, prime[i] * prime[i-1]);
+      mpz_mul_ui (want, want, prime[i]);
+      check_all (want, x, y);
+    }
+
+  /* Triplets with A,B in x and B,C in y. */
+  mpz_set_ui (want, 1L);
+  mpz_set_ui (x, 1L);
+  mpz_set_ui (y, 1L);
+  for (i = 0; i+2 < numberof (prime); i += 3)
+    {
+      mpz_mul_ui (want, want, prime[i]);
+      mpz_mul_ui (want, want, prime[i+1]);
+      mpz_mul_ui (want, want, prime[i+2]);
+
+      mpz_mul_ui (x, x, prime[i]);
+      mpz_mul_ui (x, x, prime[i+1]);
+
+      mpz_mul_ui (y, y, prime[i+1]);
+      mpz_mul_ui (y, y, prime[i+2]);
+
+      check_all (want, x, y);
+    }
+
+
+  mpz_clear (want);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_primes ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-limbs.c b/tests/mpz/t-limbs.c
new file mode 100644
index 0000000..6526e92
--- /dev/null
+++ b/tests/mpz/t-limbs.c
@@ -0,0 +1,232 @@
+/* Test mpz_limbs_* functions
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define COUNT 100
+#define BITSIZE 500
+
+/* Like mpz_add. For simplicity, support positive inputs only. */
+static void
+alt_add (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
+{
+  mp_size_t an = mpz_size (a);
+  mp_size_t bn = mpz_size (b);
+  mp_ptr rp;
+
+  ASSERT (an > 0);
+  ASSERT (bn > 0);
+  if (an < bn)
+    {
+      MP_SIZE_T_SWAP (an, bn);
+      MPZ_SRCPTR_SWAP (a, b);
+    }
+  rp = mpz_limbs_modify (r, an + 1);
+  rp[an] = mpn_add (rp, mpz_limbs_read (a), an, mpz_limbs_read (b), bn);
+  mpz_limbs_finish (r, an + 1);
+}
+
+static void
+check_funcs (const char *name,
+	     void (*f)(mpz_ptr, mpz_srcptr, mpz_srcptr),
+	     void (*ref_f)(mpz_ptr, mpz_srcptr, mpz_srcptr),
+	     mpz_srcptr a, mpz_srcptr b)
+{
+  mpz_t r, ref;
+  mpz_inits (r, ref, NULL);
+
+  ref_f (ref, a, b);
+  MPZ_CHECK_FORMAT (ref);
+  f (r, a, b);
+  MPZ_CHECK_FORMAT (r);
+
+  if (mpz_cmp (r, ref) != 0)
+    {
+      printf ("%s failed, abits %u, bbits %u\n",
+	      name,
+	      (unsigned) mpz_sizeinbase (a, 2),
+	      (unsigned) mpz_sizeinbase (b, 2));
+      gmp_printf ("a = %Zx\n", a);
+      gmp_printf ("b = %Zx\n", b);
+      gmp_printf ("r = %Zx (bad)\n", r);
+      gmp_printf ("ref = %Zx\n", ref);
+      abort ();
+    }
+  mpz_clears (r, ref, NULL);
+}
+
+static void
+check_add (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs, a, b;
+  unsigned i;
+  mpz_inits (bs, a, b, NULL);
+  for (i = 0; i < COUNT; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+
+      check_funcs ("add", alt_add, mpz_add, a, b);
+    }
+  mpz_clears (bs, a, b, NULL);
+}
+
+static void
+alt_mul (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
+{
+  mp_size_t an = mpz_size (a);
+  mp_size_t bn = mpz_size (b);
+  mp_srcptr ap, bp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (an > 0);
+  ASSERT (bn > 0);
+  if (an < bn)
+    {
+      MP_SIZE_T_SWAP (an, bn);
+      MPZ_SRCPTR_SWAP (a, b);
+    }
+  /* NOTE: This copying seems unnecessary; better to allocate new
+     result area, and free the old area when done. */
+  if (r == a)
+    {
+      mp_ptr tp =  TMP_ALLOC_LIMBS (an);
+      MPN_COPY (tp, mpz_limbs_read (a), an);
+      ap = tp;
+      bp = (a == b) ? ap : mpz_limbs_read (b);
+    }
+  else if (r == b)
+    {
+      mp_ptr tp = TMP_ALLOC_LIMBS (bn);
+      MPN_COPY (tp, mpz_limbs_read (b), bn);
+      bp = tp;
+      ap = mpz_limbs_read (a);
+    }
+  else
+    {
+      ap = mpz_limbs_read (a);
+      bp = mpz_limbs_read (b);
+    }
+  mpn_mul (mpz_limbs_write (r, an + bn),
+	   ap, an, bp, bn);
+
+  mpz_limbs_finish (r, an + bn);
+}
+
+void
+check_mul (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs, a, b;
+  unsigned i;
+  mpz_inits (bs, a, b, NULL);
+  for (i = 0; i < COUNT; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+
+      check_funcs ("mul", alt_mul, mpz_mul, a, b);
+    }
+  mpz_clears (bs, a, b, NULL);
+}
+
+#define MAX_SIZE 100
+
+static void
+check_roinit (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs, a, b, r, ref;
+  unsigned i;
+
+  mpz_inits (bs, a, b, r, ref, NULL);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mp_srcptr ap, bp;
+      mp_size_t an, bn;
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+
+      an = mpz_size (a);
+      ap = mpz_limbs_read (a);
+      bn = mpz_size (b);
+      bp = mpz_limbs_read (b);
+
+      mpz_add (ref, a, b);
+      {
+	mpz_t a1, b1;
+#if __STDC_VERSION__ >= 199901
+	const mpz_t a2 = MPZ_ROINIT_N ( (mp_ptr) ap, an);
+	const mpz_t b2 = MPZ_ROINIT_N ( (mp_ptr) bp, bn);
+
+	mpz_set_ui (r, 0);
+	mpz_add (r, a2, b2);
+	if (mpz_cmp (r, ref) != 0)
+	  {
+	    printf ("MPZ_ROINIT_N failed\n");
+	    gmp_printf ("a = %Zx\n", a);
+	    gmp_printf ("b = %Zx\n", b);
+	    gmp_printf ("r = %Zx (bad)\n", r);
+	    gmp_printf ("ref = %Zx\n", ref);
+	    abort ();
+	  }
+#endif
+	mpz_set_ui (r, 0);
+	mpz_add (r, mpz_roinit_n (a1, ap, an), mpz_roinit_n (b1, bp, bn));
+	if (mpz_cmp (r, ref) != 0)
+	  {
+	    printf ("mpz_roinit_n failed\n");
+	    gmp_printf ("a = %Zx\n", a);
+	    gmp_printf ("b = %Zx\n", b);
+	    gmp_printf ("r = %Zx (bad)\n", r);
+	    gmp_printf ("ref = %Zx\n", ref);
+	    abort ();
+	  }
+      }
+    }
+  mpz_clears (bs, a, b, r, ref, NULL);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  tests_end ();
+
+  check_add ();
+  check_mul ();
+  check_roinit ();
+
+  return 0;
+
+}
diff --git a/tests/mpz/t-lucm.c b/tests/mpz/t-lucm.c
new file mode 100644
index 0000000..24be85b
--- /dev/null
+++ b/tests/mpz/t-lucm.c
@@ -0,0 +1,144 @@
+/* Test mpz_powm, mpz_lucas_mod.
+
+Copyright 1991, 1993, 1994, 1996, 1999-2001, 2009, 2012, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+#define SIZEM 8
+
+/* FIXME: Should we implement another sequence to test lucas mod?	*/
+/* Eg: a generalisation of what we use for Fibonacci:	*/
+/* U_{2n-1} = U_n^2 - Q*U_{n-1}^2	*/
+/* U_{2n+1} = D*U_n^2  + Q*U_{2n-1} + 2*Q^n ; whith D = (P^2-4*Q)	*/
+/* P*U_{2n} = U_{2n+1} + Q*U_{2n-1}	*/
+
+int
+main (int argc, char **argv)
+{
+  mpz_t base, exp, mod;
+  mpz_t r1, r2, t1, t2;
+  mp_size_t exp_size, mod_size;
+  int i, res;
+  int reps = 1000;
+  long Q;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (base);
+  mpz_init (exp);
+  mpz_init (mod);
+  mpz_init (r1);
+  mpz_init (r2);
+  mpz_init (t1);
+  mpz_init (t2);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % SIZEM + 1;
+
+      do  /* Loop until base >= 2 and fits in a long.  */
+	{
+	  mpz_urandomb (base, rands, BITS_PER_ULONG - 2);
+	}
+      while (mpz_cmp_ui (base, 2) < 0 || mpz_fits_slong_p (base) == 0);
+
+      Q = mpz_get_ui (base);
+
+      do
+        {
+	  ++size_range;
+	  size_range = MIN (size_range, SIZEM);
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mod, rands, mod_size);
+	  mpz_add_ui (mod, mod, 16);
+	}
+      while (mpz_gcd_ui (NULL, mod, Q) != 1);
+
+      mod_size = mpz_sizeinbase (mod, 2) - 3;
+      mpz_urandomb (bs, rands, 32);
+      exp_size = mpz_get_ui (bs) % mod_size + 2;
+
+      mpz_tdiv_q_2exp (exp, mod, exp_size);
+      mpz_add_ui (exp, exp, 1);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	{
+	  mpz_neg (base, base);
+	  Q = -Q;
+	}
+
+      res = mpz_lucas_mod (t1, r2, Q, exp_size, mod, t2, r1);
+      if (res && ++reps)
+	continue;
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp_ui (r2, 0) < 0)
+	mpz_add (r2, r2, mod);
+      mpz_powm (r1, base, exp, mod);
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\nIncorrect results in test %d for operands:\n", i);
+	  debug_mp (base, -16);
+	  debug_mp (exp, -16);
+	  debug_mp (mod, -16);
+	  fprintf (stderr, "mpz_powm result:\n");
+	  debug_mp (r1, -16);
+	  fprintf (stderr, "mpz_lucas_mod result (%d) Q=%ld:\n", res, Q);
+	  debug_mp (r2, -16);
+	  abort ();
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (base);
+  mpz_clear (exp);
+  mpz_clear (mod);
+  mpz_clear (r1);
+  mpz_clear (r2);
+  mpz_clear (t1);
+  mpz_clear (t2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-lucnum_ui.c b/tests/mpz/t-lucnum_ui.c
new file mode 100644
index 0000000..34c4315
--- /dev/null
+++ b/tests/mpz/t-lucnum_ui.c
@@ -0,0 +1,96 @@
+/* Test mpz_lucnum_ui and mpz_lucnum2_ui.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-lucnum_ui [n]
+
+   Test up to L[n], or if n is omitted then the default limit below.  A
+   literal "x" for the limit means continue forever, this being meant only
+   for development.  */
+
+
+void
+check_sequence (int argc, char *argv[])
+{
+  unsigned long  n;
+  unsigned long  limit = 100 * GMP_LIMB_BITS;
+  mpz_t          want_ln, want_ln1, got_ln, got_ln1;
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* start at n==0 */
+  mpz_init_set_si (want_ln1, -1); /* L[-1] */
+  mpz_init_set_ui (want_ln,  2);  /* L[0]   */
+  mpz_init (got_ln);
+  mpz_init (got_ln1);
+
+  for (n = 0; n < limit; n++)
+    {
+      mpz_lucnum2_ui (got_ln, got_ln1, n);
+      MPZ_CHECK_FORMAT (got_ln);
+      MPZ_CHECK_FORMAT (got_ln1);
+      if (mpz_cmp (got_ln, want_ln) != 0 || mpz_cmp (got_ln1, want_ln1) != 0)
+        {
+          printf ("mpz_lucnum2_ui(%lu) wrong\n", n);
+          mpz_trace ("want ln ", want_ln);
+          mpz_trace ("got  ln ",  got_ln);
+          mpz_trace ("want ln1", want_ln1);
+          mpz_trace ("got  ln1",  got_ln1);
+          abort ();
+        }
+
+      mpz_lucnum_ui (got_ln, n);
+      MPZ_CHECK_FORMAT (got_ln);
+      if (mpz_cmp (got_ln, want_ln) != 0)
+        {
+          printf ("mpz_lucnum_ui(%lu) wrong\n", n);
+          mpz_trace ("want ln", want_ln);
+          mpz_trace ("got  ln", got_ln);
+          abort ();
+        }
+
+      mpz_add (want_ln1, want_ln1, want_ln);  /* L[n+1] = L[n] + L[n-1] */
+      mpz_swap (want_ln1, want_ln);
+    }
+
+  mpz_clear (want_ln);
+  mpz_clear (want_ln1);
+  mpz_clear (got_ln);
+  mpz_clear (got_ln1);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_sequence (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-mfac_uiui.c b/tests/mpz/t-mfac_uiui.c
new file mode 100644
index 0000000..8bca2d7
--- /dev/null
+++ b/tests/mpz/t-mfac_uiui.c
@@ -0,0 +1,135 @@
+/* Exercise mpz_mfac_uiui.
+
+Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-mfac_uiui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+#define MULTIFAC_WHEEL (2*3*11)
+#define MULTIFAC_WHEEL2 (5*13)
+
+int
+main (int argc, char *argv[])
+{
+  mpz_t ref[MULTIFAC_WHEEL], ref2[MULTIFAC_WHEEL2], res;
+  unsigned long n, j, m, m2;
+  unsigned long limit = 2222, step = 1;
+
+  tests_start ();
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* for small limb testing */
+  limit = MIN (limit, MP_LIMB_T_MAX);
+
+  for (m = 0; m < MULTIFAC_WHEEL; m++)
+    mpz_init_set_ui(ref [m],1);
+  for (m2 = 0; m2 < MULTIFAC_WHEEL2; m2++)
+    mpz_init_set_ui(ref2 [m2],1);
+
+  mpz_init (res);
+
+  m = 0;
+  m2 = 0;
+  for (n = 0; n <= limit;)
+    {
+      mpz_mfac_uiui (res, n, MULTIFAC_WHEEL);
+      MPZ_CHECK_FORMAT (res);
+      if (mpz_cmp (ref[m], res) != 0)
+        {
+          printf ("mpz_mfac_uiui(%lu,%d) wrong\n", n, MULTIFAC_WHEEL);
+          printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, ref[m]); printf("\n");
+          abort ();
+        }
+      mpz_mfac_uiui (res, n, MULTIFAC_WHEEL2);
+      MPZ_CHECK_FORMAT (res);
+      if (mpz_cmp (ref2[m2], res) != 0)
+        {
+          printf ("mpz_mfac_uiui(%lu,%d) wrong\n", n, MULTIFAC_WHEEL2);
+          printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, ref2[m2]); printf("\n");
+          abort ();
+        }
+      if (n + step <= limit)
+	for (j = 0; j < step; j++) {
+	  n++; m++; m2++;
+	  if (m >= MULTIFAC_WHEEL) m -= MULTIFAC_WHEEL;
+	  if (m2 >= MULTIFAC_WHEEL2) m2 -= MULTIFAC_WHEEL2;
+	  mpz_mul_ui (ref[m], ref[m], n); /* Compute a reference, with current library */
+	  mpz_mul_ui (ref2[m2], ref2[m2], n); /* Compute a reference, with current library */
+	}
+      else n += step;
+    }
+  mpz_fac_ui (ref[0], n);
+  mpz_mfac_uiui (res, n, 1);
+  MPZ_CHECK_FORMAT (res);
+  if (mpz_cmp (ref[0], res) != 0)
+    {
+      printf ("mpz_mfac_uiui(%lu,1) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, ref[0]); printf("\n");
+      abort ();
+    }
+
+  mpz_2fac_ui (ref[0], n);
+  mpz_mfac_uiui (res, n, 2);
+  MPZ_CHECK_FORMAT (res);
+  if (mpz_cmp (ref[0], res) != 0)
+    {
+      printf ("mpz_mfac_uiui(%lu,1) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, ref[0]); printf("\n");
+      abort ();
+    }
+
+  n++;
+  mpz_2fac_ui (ref[0], n);
+  mpz_mfac_uiui (res, n, 2);
+  MPZ_CHECK_FORMAT (res);
+  if (mpz_cmp (ref[0], res) != 0)
+    {
+      printf ("mpz_mfac_uiui(%lu,2) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, ref[0]); printf("\n");
+      abort ();
+    }
+
+  for (m = 0; m < MULTIFAC_WHEEL; m++)
+    mpz_clear (ref[m]);
+  for (m2 = 0; m2 < MULTIFAC_WHEEL2; m2++)
+    mpz_clear (ref2[m2]);
+  mpz_clear (res);
+
+  tests_end ();
+
+  exit (0);
+}
diff --git a/tests/mpz/t-mul.c b/tests/mpz/t-mul.c
new file mode 100644
index 0000000..0dc22e9
--- /dev/null
+++ b/tests/mpz/t-mul.c
@@ -0,0 +1,221 @@
+/* Test mpz_cmp, mpz_mul.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+void debug_mp (mpz_t);
+static void refmpz_mul (mpz_t, const mpz_t, const mpz_t);
+void dump_abort (int, const char *, mpz_t, mpz_t, mpz_t, mpz_t);
+
+#define FFT_MIN_BITSIZE 100000
+
+char *extra_fft;
+
+void
+one (int i, mpz_t multiplicand, mpz_t multiplier)
+{
+  mpz_t product, ref_product;
+
+  mpz_init (product);
+  mpz_init (ref_product);
+
+  /* Test plain multiplication comparing results against reference code.  */
+  mpz_mul (product, multiplier, multiplicand);
+  refmpz_mul (ref_product, multiplier, multiplicand);
+  if (mpz_cmp (product, ref_product))
+    dump_abort (i, "incorrect plain product",
+		multiplier, multiplicand, product, ref_product);
+
+  /* Test squaring, comparing results against plain multiplication  */
+  mpz_mul (product, multiplier, multiplier);
+  mpz_set (multiplicand, multiplier);
+  mpz_mul (ref_product, multiplier, multiplicand);
+  if (mpz_cmp (product, ref_product))
+    dump_abort (i, "incorrect square product",
+		multiplier, multiplier, product, ref_product);
+
+  mpz_clear (product);
+  mpz_clear (ref_product);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  int i;
+  int fft_max_2exp;
+
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range, fsize_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  extra_fft = getenv ("GMP_CHECK_FFT");
+  fft_max_2exp = 0;
+  if (extra_fft != NULL)
+    {
+      fft_max_2exp = atoi (extra_fft);
+      printf ("GMP_CHECK_FFT=%d (include this in bug reports)\n", fft_max_2exp);
+    }
+
+  if (fft_max_2exp <= 1)	/* compat with old use of GMP_CHECK_FFT */
+    fft_max_2exp = 22;		/* default limit, good for any machine */
+
+  mpz_init (bs);
+  mpz_init (op1);
+  mpz_init (op2);
+
+  fsize_range = 4 << 8;		/* a fraction 1/256 of size_range */
+  for (i = 0;; i++)
+    {
+      size_range = fsize_range >> 8;
+      fsize_range = fsize_range * 33 / 32;
+
+      if (size_range > fft_max_2exp)
+	break;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs));
+      if (i & 1)
+	mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs));
+
+      mpz_urandomb (bs, rands, 4);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 0x3) == 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 0xC) == 0)
+	mpz_neg (op2, op2);
+
+      /* printf ("%d %d\n", SIZ (op1), SIZ (op2)); */
+      one (i, op2, op1);
+    }
+
+  for (i = -50; i < 0; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % fft_max_2exp;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + FFT_MIN_BITSIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + FFT_MIN_BITSIZE);
+
+      /* printf ("%d: %d %d\n", i, SIZ (op1), SIZ (op2)); */
+      fflush (stdout);
+      one (-1, op2, op1);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
+
+static void
+refmpz_mul (mpz_t w, const mpz_t u, const mpz_t v)
+{
+  mp_size_t usize = u->_mp_size;
+  mp_size_t vsize = v->_mp_size;
+  mp_size_t wsize;
+  mp_size_t sign_product;
+  mp_ptr up, vp;
+  mp_ptr wp;
+  mp_size_t talloc;
+
+  sign_product = usize ^ vsize;
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  if (usize == 0 || vsize == 0)
+    {
+      SIZ (w) = 0;
+      return;
+    }
+
+  talloc = usize + vsize;
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  wp = __GMP_ALLOCATE_FUNC_LIMBS (talloc);
+
+  if (usize > vsize)
+    refmpn_mul (wp, up, usize, vp, vsize);
+  else
+    refmpn_mul (wp, vp, vsize, up, usize);
+  wsize = usize + vsize;
+  wsize -= wp[wsize - 1] == 0;
+  MPZ_REALLOC (w, wsize);
+  MPN_COPY (PTR(w), wp, wsize);
+
+  SIZ(w) = sign_product < 0 ? -wsize : wsize;
+  __GMP_FREE_FUNC_LIMBS (wp, talloc);
+}
+
+void
+dump_abort (int i, const char *s,
+            mpz_t op1, mpz_t op2, mpz_t product, mpz_t ref_product)
+{
+  mp_size_t b, e;
+  fprintf (stderr, "ERROR: %s in test %d\n", s, i);
+  fprintf (stderr, "op1          = "); debug_mp (op1);
+  fprintf (stderr, "op2          = "); debug_mp (op2);
+  fprintf (stderr, "    product  = "); debug_mp (product);
+  fprintf (stderr, "ref_product  = "); debug_mp (ref_product);
+  for (b = 0; b < ABSIZ(ref_product); b++)
+    if (PTR(ref_product)[b] != PTR(product)[b])
+      break;
+  for (e = ABSIZ(ref_product) - 1; e >= 0; e--)
+    if (PTR(ref_product)[e] != PTR(product)[e])
+      break;
+  printf ("ERRORS in %ld--%ld\n", b, e);
+  abort();
+}
+
+void
+debug_mp (mpz_t x)
+{
+  size_t siz = mpz_sizeinbase (x, 16);
+
+  if (siz > 65)
+    {
+      mpz_t q;
+      mpz_init (q);
+      mpz_tdiv_q_2exp (q, x, 4 * (mpz_sizeinbase (x, 16) - 25));
+      gmp_fprintf (stderr, "%ZX...", q);
+      mpz_tdiv_r_2exp (q, x, 4 * 25);
+      gmp_fprintf (stderr, "%025ZX [%d]\n", q, (int) siz);
+      mpz_clear (q);
+    }
+  else
+    {
+      gmp_fprintf (stderr, "%ZX\n", x);
+    }
+}
diff --git a/tests/mpz/t-mul_i.c b/tests/mpz/t-mul_i.c
new file mode 100644
index 0000000..5f2dae2
--- /dev/null
+++ b/tests/mpz/t-mul_i.c
@@ -0,0 +1,134 @@
+/* Test mpz_mul_ui and mpz_mul_si.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+mpz_t got, want, x;
+
+void
+compare_si (long y)
+{
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf    ("mpz_mul_si wrong\n");
+      mpz_trace ("  x", x);
+      printf    ("  y=%ld (0x%lX)\n", y, y);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+}
+
+void
+compare_ui (unsigned long y)
+{
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf    ("mpz_mul_ui wrong\n");
+      mpz_trace ("  x", x);
+      printf    ("  y=%lu (0x%lX)\n", y, y);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+}
+
+void
+check_samples (void)
+{
+  {
+    long  y;
+
+    mpz_set_ui (x, 1L);
+    y = 0;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = 1;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = -1;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = LONG_MIN;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = LONG_MAX;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+  }
+
+  {
+    unsigned long y;
+
+    mpz_set_ui (x, 1L);
+    y = 0;
+    mpz_mul_ui (got, x, y);
+    mpz_set_ui (want, y);
+    compare_ui (y);
+
+    mpz_set_ui (x, 1L);
+    y = 1;
+    mpz_mul_ui (got, x, y);
+    mpz_set_ui (want, y);
+    compare_ui (y);
+
+    mpz_set_ui (x, 1L);
+    y = ULONG_MAX;
+    mpz_mul_ui (got, x, y);
+    mpz_set_ui (want, y);
+    compare_ui (y);
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  mpz_init (x);
+  mpz_init (got);
+  mpz_init (want);
+
+  check_samples ();
+
+  mpz_clear (x);
+  mpz_clear (got);
+  mpz_clear (want);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-nextprime.c b/tests/mpz/t-nextprime.c
new file mode 100644
index 0000000..d2fbaef
--- /dev/null
+++ b/tests/mpz/t-nextprime.c
@@ -0,0 +1,459 @@
+/* Test mpz_nextprime.
+
+Copyright 2009, 2015, 2018, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+refmpz_nextprime (mpz_ptr p, mpz_srcptr t)
+{
+  mpz_add_ui (p, t, 1L);
+  while (! mpz_probab_prime_p (p, 10))
+    mpz_add_ui (p, p, 1L);
+}
+
+void
+refmpz_prevprime (mpz_ptr p, mpz_srcptr t)
+{
+  if (mpz_cmp_ui(t, 2) <= 0)
+    return;
+
+  mpz_sub_ui (p, t, 1L);
+  while (! mpz_probab_prime_p (p, 10))
+    mpz_sub_ui (p, p, 1L);
+}
+
+void
+test_largegap (mpz_t low, const int gap)
+{
+  mpz_t t, nxt;
+  mpz_init (t);
+  mpz_init (nxt);
+
+  mpz_nextprime(nxt, low);
+  mpz_sub(t, nxt, low);
+
+  if (mpz_cmp_ui(t, gap) != 0)
+     {
+      gmp_printf ("nextprime gap %Zd => %Zd != %d\n", low, nxt, gap);
+      abort ();
+    }
+
+  mpz_prevprime(t, nxt);
+  if (mpz_cmp(t, low) != 0)
+    {
+      gmp_printf ("prevprime gap %Zd => %Zd != %d\n", nxt, t, gap);
+      abort ();
+    }
+
+  mpz_clear (t);
+  mpz_clear (nxt);
+}
+
+void
+test_largegaps ()
+{
+  mpz_t n;
+
+  mpz_init (n);
+
+  // largest gap with start < 2^32.
+  mpz_set_str (n, "3842610773", 10);
+  test_largegap (n, 336);
+
+  // largest gap with start < 2^64.
+  mpz_set_str (n, "18361375334787046697", 10);
+  test_largegap (n, 1550);
+
+  // test high merit primegap in the P30 digit range.
+  mpz_set_str (n, "3001549619028223830552751967", 10);
+  test_largegap (n, 2184);
+
+  // test high merit primegap in the P100 range.
+  mpz_primorial_ui (n, 257);
+  mpz_divexact_ui (n, n, 5610);
+  mpz_mul_ui (n, n, 4280516017UL);
+  mpz_sub_ui (n, n, 2560);
+  test_largegap (n, 9006);
+
+  // test high merit primegap in the P200 range.
+  mpz_primorial_ui (n, 409);
+  mpz_divexact_ui (n, n, 30);
+  mpz_mul_ui (n, n, 3483347771UL);
+  mpz_sub_ui (n, n, 7016);
+  test_largegap (n, 15900);
+
+  mpz_clear (n);
+}
+
+void
+test_bitboundaries ()
+{
+  mpz_t n;
+  mpz_init (n);
+
+  mpz_set_str (n, "0xfff1", 0);
+  test_largegap (n, 16);
+
+  mpz_set_str (n, "0xfffffffb", 0);
+  test_largegap (n, 20);
+
+  mpz_set_str (n, "0xffffffffffc5", 0);
+  test_largegap (n, 80);
+
+  mpz_set_str (n, "0xffffffffffffffc5", 0);
+  test_largegap (n, 72);
+
+  mpz_set_str (n, "0xffffffffffffffffffbf", 0);
+  test_largegap (n, 78);
+
+  mpz_set_str (n, "0xffffffffffffffffffffffef", 0);
+  test_largegap (n, 78);
+
+  mpz_set_str (n, "0xffffffffffffffffffffffffffb5", 0);
+  test_largegap (n, 100);
+
+  mpz_set_str (n, "0xffffffffffffffffffffffffffffff61", 0);
+  test_largegap (n, 210);
+
+  mpz_set_str (n, "0xffffffffffffffffffffffffffffffffffffffffffffff13", 0);
+  test_largegap (n, 370);
+
+  mpz_clear (n);
+}
+
+void
+run (const char *start, int reps, const char *end, short diffs[])
+{
+  mpz_t x, y;
+  int i;
+
+  mpz_init_set_str (x, start, 0);
+  mpz_init (y);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_nextprime (y, x);
+      mpz_sub (x, y, x);
+      if (diffs != NULL &&
+	  (! mpz_fits_sshort_p (x) || diffs[i] != (short) mpz_get_ui (x)))
+	{
+	  gmp_printf ("diff list discrepancy\n");
+	  abort ();
+	}
+      mpz_swap (x, y);
+    }
+
+  mpz_set_str (y, end, 0);
+
+  if (mpz_cmp (x, y) != 0)
+    {
+      gmp_printf ("got  %Zd\n", x);
+      gmp_printf ("want %Zd\n", y);
+      abort ();
+    }
+
+  mpz_clear (y);
+  mpz_clear (x);
+}
+
+void
+run_p (const char *start, int reps, const char *end, short diffs[])
+{
+  mpz_t x, y;
+  int i;
+
+  mpz_init_set_str (x, end, 0);
+  mpz_init (y);
+
+  // Last rep doesn't share same data with nextprime
+  for (i = 0; i < reps - 1; i++)
+    {
+      mpz_prevprime (y, x);
+      mpz_sub (x, x, y);
+      if (diffs != NULL &&
+	  (! mpz_fits_sshort_p (x) || diffs[reps - i - 1] != (short) mpz_get_ui (x)))
+	{
+	  gmp_printf ("diff list discrepancy %Zd, %d vs %d\n",
+                y, diffs[i], mpz_get_ui (x));
+	  abort ();
+	}
+      mpz_swap (x, y);
+    }
+
+  // starts aren't always prime, so check that result is less than or equal
+  mpz_prevprime(x, x);
+
+  mpz_set_str(y, start, 0);
+  if (mpz_cmp (x, y) > 0)
+    {
+      gmp_printf ("got  %Zd\n", x);
+      gmp_printf ("want %Zd\n", y);
+      abort ();
+    }
+
+  mpz_clear (y);
+  mpz_clear (x);
+}
+
+
+extern short diff1[];
+extern short diff3[];
+extern short diff4[];
+extern short diff5[];
+extern short diff6[];
+
+void
+test_ref (gmp_randstate_ptr rands, int reps,
+          void (*func)(mpz_t, const mpz_t),
+          void(*ref_func)(mpz_t, const mpz_t))
+{
+  int i;
+  mpz_t bs, x, test_p, ref_p;
+  unsigned long size_range;
+
+  mpz_init (bs);
+  mpz_init (x);
+  mpz_init (test_p);
+  mpz_init (ref_p);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 8 + 2; /* 0..1024 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (x, rands, mpz_get_ui (bs));
+
+      func (test_p, x);
+      ref_func (ref_p, x);
+      if (mpz_cmp (test_p, ref_p) != 0)
+        {
+          gmp_printf ("start %Zd\n", x);
+          gmp_printf ("got   %Zd\n", test_p);
+          gmp_printf ("want  %Zd\n", ref_p);
+	  abort ();
+        }
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x);
+  mpz_clear (test_p);
+  mpz_clear (ref_p);
+}
+
+void
+test_nextprime(gmp_randstate_ptr rands, int reps)
+{
+  run ("2", 1000, "0x1ef7", diff1);
+
+  run ("3", 1000 - 1, "0x1ef7", NULL);
+
+  run ("0x8a43866f5776ccd5b02186e90d28946aeb0ed914", 50,
+       "0x8a43866f5776ccd5b02186e90d28946aeb0eeec5", diff3);
+
+  run ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", 50, /* 2^148 - 148 */
+       "0x100000000000000000000000000000000010ab", diff4);
+
+  run ("0x1c2c26be55317530311facb648ea06b359b969715db83292ab8cf898d8b1b", 50,
+       "0x1c2c26be55317530311facb648ea06b359b969715db83292ab8cf898da957", diff5);
+
+  run ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80", 50, /* 2^128 - 128 */
+       "0x10000000000000000000000000000155B", diff6);
+
+  test_ref(
+      rands, reps,
+      (void (*)(mpz_t, const mpz_t)) mpz_nextprime,
+      refmpz_nextprime);
+}
+
+void
+test_prevprime (gmp_randstate_ptr rands, int reps)
+{
+  long i;
+  int retval;
+  mpz_t n, prvp;
+
+  mpz_init (n);
+  mpz_init (prvp);
+
+  /* Test mpz_prevprime(n <= 2) returns 0, leaves rop unchanged. */
+  {
+    int temp = 123;
+    mpz_set_ui (prvp, temp);
+    for (i = 0; i <= 2; i++)
+      {
+        mpz_set_si(n, i);
+        retval = mpz_prevprime (prvp, n);
+        if ( retval != 0 || mpz_cmp_ui (prvp, temp) != 0 )
+          {
+            gmp_printf ("mpz_prevprime(%Zd) return (%d) rop (%Zd)\n", n, retval, prvp);
+            abort ();
+          }
+      }
+  }
+
+  mpz_clear (n);
+  mpz_clear (prvp);
+
+  run_p ("2", 1000, "0x1ef7", diff1);
+
+  run_p ("3", 1000 - 1, "0x1ef7", NULL);
+
+  run_p ("0x8a43866f5776ccd5b02186e90d28946aeb0ed914", 50,
+         "0x8a43866f5776ccd5b02186e90d28946aeb0eeec5", diff3);
+
+  run_p ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", 50, /* 2^148 - 148 */
+         "0x100000000000000000000000000000000010ab", diff4);
+
+  run_p ("0x1c2c26be55317530311facb648ea06b359b969715db83292ab8cf898d8b1b", 50,
+         "0x1c2c26be55317530311facb648ea06b359b969715db83292ab8cf898da957", diff5);
+
+  run_p ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80", 50, /* 2^128 - 128 */
+         "0x10000000000000000000000000000155B", diff6);
+
+  // Cast away int return from mpz_prevprime for test ref.
+  test_ref(
+      rands, reps,
+      (void (*)(mpz_t, const mpz_t)) mpz_prevprime,
+      refmpz_prevprime);
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  int reps = 20;
+
+  tests_start();
+
+  rands = RANDS;
+  TESTS_REPS (reps, argv, argc);
+
+  test_nextprime(rands, reps);
+  test_prevprime(rands, reps);
+
+  test_largegaps ();
+  test_bitboundaries ();
+
+  tests_end ();
+  return 0;
+}
+
+short diff1[] =
+{
+  1,2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,
+  2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,
+  2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,
+  2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2,
+  4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,
+  2,10,2,6,4,6,8,4,2,4,12,8,4,8,4,6,
+  12,2,18,6,10,6,6,2,6,10,6,6,2,6,6,4,
+  2,12,10,2,4,6,6,2,12,4,6,8,10,8,10,8,
+  6,6,4,8,6,4,8,4,14,10,12,2,10,2,4,2,
+  10,14,4,2,4,14,4,2,4,20,4,8,10,8,4,6,
+  6,14,4,6,6,8,6,12,4,6,2,10,2,6,10,2,
+  10,2,6,18,4,2,4,6,6,8,6,6,22,2,10,8,
+  10,6,6,8,12,4,6,6,2,6,12,10,18,2,4,6,
+  2,6,4,2,4,12,2,6,34,6,6,8,18,10,14,4,
+  2,4,6,8,4,2,6,12,10,2,4,2,4,6,12,12,
+  8,12,6,4,6,8,4,8,4,14,4,6,2,4,6,2,
+  6,10,20,6,4,2,24,4,2,10,12,2,10,8,6,6,
+  6,18,6,4,2,12,10,12,8,16,14,6,4,2,4,2,
+  10,12,6,6,18,2,16,2,22,6,8,6,4,2,4,8,
+  6,10,2,10,14,10,6,12,2,4,2,10,12,2,16,2,
+  6,4,2,10,8,18,24,4,6,8,16,2,4,8,16,2,
+  4,8,6,6,4,12,2,22,6,2,6,4,6,14,6,4,
+  2,6,4,6,12,6,6,14,4,6,12,8,6,4,26,18,
+  10,8,4,6,2,6,22,12,2,16,8,4,12,14,10,2,
+  4,8,6,6,4,2,4,6,8,4,2,6,10,2,10,8,
+  4,14,10,12,2,6,4,2,16,14,4,6,8,6,4,18,
+  8,10,6,6,8,10,12,14,4,6,6,2,28,2,10,8,
+  4,14,4,8,12,6,12,4,6,20,10,2,16,26,4,2,
+  12,6,4,12,6,8,4,8,22,2,4,2,12,28,2,6,
+  6,6,4,6,2,12,4,12,2,10,2,16,2,16,6,20,
+  16,8,4,2,4,2,22,8,12,6,10,2,4,6,2,6,
+  10,2,12,10,2,10,14,6,4,6,8,6,6,16,12,2,
+  4,14,6,4,8,10,8,6,6,22,6,2,10,14,4,6,
+  18,2,10,14,4,2,10,14,4,8,18,4,6,2,4,6,
+  2,12,4,20,22,12,2,4,6,6,2,6,22,2,6,16,
+  6,12,2,6,12,16,2,4,6,14,4,2,18,24,10,6,
+  2,10,2,10,2,10,6,2,10,2,10,6,8,30,10,2,
+  10,8,6,10,18,6,12,12,2,18,6,4,6,6,18,2,
+  10,14,6,4,2,4,24,2,12,6,16,8,6,6,18,16,
+  2,4,6,2,6,6,10,6,12,12,18,2,6,4,18,8,
+  24,4,2,4,6,2,12,4,14,30,10,6,12,14,6,10,
+  12,2,4,6,8,6,10,2,4,14,6,6,4,6,2,10,
+  2,16,12,8,18,4,6,12,2,6,6,6,28,6,14,4,
+  8,10,8,12,18,4,2,4,24,12,6,2,16,6,6,14,
+  10,14,4,30,6,6,6,8,6,4,2,12,6,4,2,6,
+  22,6,2,4,18,2,4,12,2,6,4,26,6,6,4,8,
+  10,32,16,2,6,4,2,4,2,10,14,6,4,8,10,6,
+  20,4,2,6,30,4,8,10,6,6,8,6,12,4,6,2,
+  6,4,6,2,10,2,16,6,20,4,12,14,28,6,20,4,
+  18,8,6,4,6,14,6,6,10,2,10,12,8,10,2,10,
+  8,12,10,24,2,4,8,6,4,8,18,10,6,6,2,6,
+  10,12,2,10,6,6,6,8,6,10,6,2,6,6,6,10,
+  8,24,6,22,2,18,4,8,10,30,8,18,4,2,10,6,
+  2,6,4,18,8,12,18,16,6,2,12,6,10,2,10,2,
+  6,10,14,4,24,2,16,2,10,2,10,20,4,2,4,8,
+  16,6,6,2,12,16,8,4,6,30,2,10,2,6,4,6,
+  6,8,6,4,12,6,8,12,4,14,12,10,24,6,12,6,
+  2,22,8,18,10,6,14,4,2,6,10,8,6,4,6,30,
+  14,10,2,12,10,2,16,2,18,24,18,6,16,18,6,2,
+  18,4,6,2,10,8,10,6,6,8,4,6,2,10,2,12,
+  4,6,6,2,12,4,14,18,4,6,20,4,8,6,4,8,
+  4,14,6,4,14,12,4,2,30,4,24,6,6,12,12,14,
+  6,4,2,4,18,6,12,8
+};
+
+short diff3[] =
+{
+  33,32,136,116,24,22,104,114,76,278,238,162,36,44,388,134,
+  130,26,312,42,138,28,24,80,138,108,270,12,330,130,98,102,
+  162,34,36,170,90,34,14,6,24,66,154,218,70,132,188,88,
+  80,82
+};
+
+short diff4[] =
+{
+  239,92,64,6,104,24,46,258,68,18,54,100,68,154,26,4,
+  38,142,168,42,18,26,286,104,136,116,40,2,28,110,52,78,
+  104,24,54,96,4,626,196,24,56,36,52,102,48,156,26,18,
+  42,40
+};
+
+short diff5[] =
+{
+  268,120,320,184,396,2,94,108,20,318,274,14,64,122,220,108,
+  18,174,6,24,348,32,64,116,268,162,20,156,28,110,52,428,
+  196,14,262,30,194,120,300,66,268,12,428,370,212,198,192,130,
+  30,80
+};
+
+short diff6[] =
+{
+  179,30,84,108,112,36,42,110,52,132,60,30,326,114,496,92,100,
+  272,36,54,90,4,2,24,40,398,150,72,60,16,8,4,80,16,2,342,112,
+  14,136,236,40,18,50,192,198,204,40,266,42,274
+};
diff --git a/tests/mpz/t-oddeven.c b/tests/mpz/t-oddeven.c
new file mode 100644
index 0000000..eedad4b
--- /dev/null
+++ b/tests/mpz/t-oddeven.c
@@ -0,0 +1,87 @@
+/* Test mpz_odd_p and mpz_even_p.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *n;
+    int          odd, even;
+  } data[] = {
+    {   "0", 0, 1 },
+    {   "1", 1, 0 },
+    {   "2", 0, 1 },
+    {   "3", 1, 0 },
+    {   "4", 0, 1 },
+
+    {  "-4", 0, 1 },
+    {  "-3", 1, 0 },
+    {  "-2", 0, 1 },
+    {  "-1", 1, 0 },
+
+    {  "0x1000000000000000000000000000000000000000000000000000", 0, 1 },
+    {  "0x1000000000000000000000000000000000000000000000000001", 1, 0 },
+    {  "0x1000000000000000000000000000000000000000000000000002", 0, 1 },
+    {  "0x1000000000000000000000000000000000000000000000000003", 1, 0 },
+
+    { "-0x1000000000000000000000000000000000000000000000000004", 0, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000003", 1, 0 },
+    { "-0x1000000000000000000000000000000000000000000000000002", 0, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000001", 1, 0 },
+  };
+
+  mpz_t  n;
+  int    i;
+
+  mpz_init (n);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+
+      if ((mpz_odd_p (n) != 0) != data[i].odd)
+	{
+	  printf ("mpz_odd_p wrong on data[%d]\n", i);
+	  abort();
+	}
+
+      if ((mpz_even_p (n) != 0) != data[i].even)
+	{
+	  printf ("mpz_even_p wrong on data[%d]\n", i);
+	  abort();
+	}
+    }
+
+  mpz_clear (n);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-perfpow.c b/tests/mpz/t-perfpow.c
new file mode 100644
index 0000000..84f9c8e
--- /dev/null
+++ b/tests/mpz/t-perfpow.c
@@ -0,0 +1,247 @@
+/* Test mpz_perfect_power_p.
+
+   Contributed to the GNU project by Torbjorn Granlund and Martin Boij.
+
+Copyright 2008-2010, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+struct
+{
+  const char *num_as_str;
+  char want;
+} static tests[] =
+  {
+    { "0", 1},
+    { "1", 1},
+    {"-1", 1},
+    { "2", 0},
+    {"-2", 0},
+    { "3", 0},
+    {"-3", 0},
+    { "4", 1},
+    {"-4", 0},
+    { "64", 1},
+    {"-64", 1},
+    { "128", 1},
+    {"-128", 1},
+    { "256", 1},
+    {"-256", 0},
+    { "512", 1},
+    {"-512", 1},
+    { "0x4000000", 1},
+    {"-0x4000000", 1},
+    { "0x3cab640", 1},
+    {"-0x3cab640", 0},
+    { "0x3e23840", 1},
+    {"-0x3e23840", 0},
+    { "0x3d3a7ed1", 1},
+    {"-0x3d3a7ed1", 1},
+    { "0x30a7a6000", 1},
+    {"-0x30a7a6000", 1},
+    { "0xf33e5a5a59", 1},
+    {"-0xf33e5a5a59", 0},
+    { "0xed1b1182118135d", 1},
+    {"-0xed1b1182118135d", 1},
+    { "0xe71f6eb7689cc276b2f1", 1},
+    {"-0xe71f6eb7689cc276b2f1", 0},
+    { "0x12644507fe78cf563a4b342c92e7da9fe5e99cb75a01", 1},
+    {"-0x12644507fe78cf563a4b342c92e7da9fe5e99cb75a01", 0},
+    { "0x1ff2e7c581bb0951df644885bd33f50e472b0b73a204e13cbe98fdb424d66561e4000000", 1},
+    {"-0x1ff2e7c581bb0951df644885bd33f50e472b0b73a204e13cbe98fdb424d66561e4000000", 1},
+    { "0x2b9b44db2d91a6f8165c8c7339ef73633228ea29e388592e80354e4380004aad84000000", 1},
+    {"-0x2b9b44db2d91a6f8165c8c7339ef73633228ea29e388592e80354e4380004aad84000000", 1},
+    { "0x28d5a2b8f330910a9d3cda06036ae0546442e5b1a83b26a436efea5b727bf1bcbe7e12b47d81", 1},
+    {"-0x28d5a2b8f330910a9d3cda06036ae0546442e5b1a83b26a436efea5b727bf1bcbe7e12b47d81", 1},
+    {NULL, 0}
+  };
+
+
+void
+check_tests ()
+{
+  mpz_t x;
+  int i;
+  int got, want;
+
+  mpz_init (x);
+
+  for (i = 0; tests[i].num_as_str != NULL; i++)
+    {
+      mpz_set_str (x, tests[i].num_as_str, 0);
+      got = mpz_perfect_power_p (x);
+      want = tests[i].want;
+      if (got != want)
+	{
+	  fprintf (stderr, "mpz_perfect_power_p returns %d when %d was expected\n", got, want);
+	  fprintf (stderr, "fault operand: %s\n", tests[i].num_as_str);
+	  abort ();
+	}
+    }
+
+  mpz_clear (x);
+}
+
+#define NRP 15
+
+void
+check_random (int reps)
+{
+  mpz_t n, np, temp, primes[NRP];
+  int i, j, k, unique, destroy, res;
+  unsigned long int nrprimes, primebits;
+  mp_limb_t g, exp[NRP], e;
+  gmp_randstate_ptr rands;
+
+  rands = RANDS;
+
+  mpz_init (n);
+  mpz_init (np);
+  mpz_init (temp);
+
+  for (i = 0; i < NRP; i++)
+    mpz_init (primes[i]);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (np, rands, 32);
+      nrprimes = mpz_get_ui (np) % NRP + 1; /* 1-NRP unique primes */
+
+      mpz_urandomb (np, rands, 32);
+      g = mpz_get_ui (np) % 32 + 2; /* gcd 2-33 */
+
+      for (j = 0; j < nrprimes;)
+	{
+	  mpz_urandomb (np, rands, 32);
+	  primebits = mpz_get_ui (np) % 100 + 3; /* 3-102 bit primes */
+	  mpz_urandomb (primes[j], rands, primebits);
+	  mpz_nextprime (primes[j], primes[j]);
+	  unique = 1;
+	  for (k = 0; k < j; k++)
+	    {
+	      if (mpz_cmp (primes[j], primes[k]) == 0)
+		{
+		  unique = 0;
+		  break;
+		}
+	    }
+	  if (unique)
+	    {
+	      mpz_urandomb (np, rands, 32);
+	      e = 371 / (10 * primebits) + mpz_get_ui (np) % 11 + 1; /* Magic constants */
+	      exp[j++] = g * e;
+	    }
+	}
+
+      if (nrprimes > 1)
+	{
+	  /* Destroy d exponents, d in [1, nrprimes - 1] */
+	  if (nrprimes == 2)
+	    {
+	      destroy = 1;
+	    }
+	  else
+	    {
+	      mpz_urandomb (np, rands, 32);
+	      destroy = mpz_get_ui (np) % (nrprimes - 2);
+	    }
+
+	  g = exp[destroy];
+	  for (k = destroy + 1; k < nrprimes; k++)
+	    g = mpn_gcd_1 (&g, 1, exp[k]);
+
+	  for (j = 0; j < destroy; j++)
+	    {
+	      mpz_urandomb (np, rands, 32);
+	      e = mpz_get_ui (np) % 50 + 1;
+	      while (mpn_gcd_1 (&g, 1, e) > 1)
+		e++;
+
+	      exp[j] = e;
+	    }
+	}
+
+      /* Compute n */
+      mpz_pow_ui (n, primes[0], exp[0]);
+      for (j = 1; j < nrprimes; j++)
+	{
+	  mpz_pow_ui (temp, primes[j], exp[j]);
+	  mpz_mul (n, n, temp);
+	}
+
+      res = mpz_perfect_power_p (n);
+
+      if (nrprimes == 1)
+	{
+	if (res == 0 && exp[0] > 1)
+	  {
+	    printf("n is a perfect power, perfpow_p disagrees\n");
+	    gmp_printf("n = %Zu\nprimes[0] = %Zu\nexp[0] = %lu\n", n, primes[0], exp[0]);
+	    abort ();
+	  }
+	else if (res == 1 && exp[0] == 1)
+	  {
+	    gmp_printf("n = %Zu\n", n);
+	    printf("n is now a prime number, but perfpow_p still believes n is a perfect power\n");
+	    abort ();
+	  }
+	}
+      else
+	{
+	  if (res == 1 && destroy != 0)
+	    {
+	      gmp_printf("n = %Zu\nn was destroyed, but perfpow_p still believes n is a perfect power\n", n);
+	      abort ();
+	    }
+	  else if (res == 0 && destroy == 0)
+	    {
+	      gmp_printf("n = %Zu\nn is a perfect power, perfpow_p disagrees\n", n);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (n);
+  mpz_clear (np);
+  mpz_clear (temp);
+  for (i = 0; i < NRP; i++)
+    mpz_clear (primes[i]);
+}
+
+int
+main (int argc, char **argv)
+{
+  int n_tests;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_tests ();
+
+  n_tests = 500;
+  if (argc == 2)
+    n_tests = atoi (argv[1]);
+  check_random (n_tests);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-perfsqr.c b/tests/mpz/t-perfsqr.c
new file mode 100644
index 0000000..2223593
--- /dev/null
+++ b/tests/mpz/t-perfsqr.c
@@ -0,0 +1,154 @@
+/* Test mpz_perfect_square_p.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#include "mpn/perfsqr.h"
+
+
+/* check_modulo() exercises mpz_perfect_square_p on squares which cover each
+   possible quadratic residue to each divisor used within
+   mpn_perfect_square_p, ensuring those residues aren't incorrectly claimed
+   to be non-residues.
+
+   Each divisor is taken separately.  It's arranged that n is congruent to 0
+   modulo the other divisors, 0 of course being a quadratic residue to any
+   modulus.
+
+   The values "(j*others)^2" cover all quadratic residues mod divisor[i],
+   but in no particular order.  j is run from 1<=j<=divisor[i] so that zero
+   is excluded.  A literal n==0 doesn't reach the residue tests.  */
+
+void
+check_modulo (void)
+{
+  static const unsigned long  divisor[] = PERFSQR_DIVISORS;
+  unsigned long  i, j;
+
+  mpz_t  alldiv, others, n;
+
+  mpz_init (alldiv);
+  mpz_init (others);
+  mpz_init (n);
+
+  /* product of all divisors */
+  mpz_set_ui (alldiv, 1L);
+  for (i = 0; i < numberof (divisor); i++)
+    mpz_mul_ui (alldiv, alldiv, divisor[i]);
+
+  for (i = 0; i < numberof (divisor); i++)
+    {
+      /* product of all divisors except i */
+      mpz_set_ui (others, 1L);
+      for (j = 0; j < numberof (divisor); j++)
+        if (i != j)
+          mpz_mul_ui (others, others, divisor[j]);
+
+      for (j = 1; j <= divisor[i]; j++)
+        {
+          /* square */
+          mpz_mul_ui (n, others, j);
+          mpz_mul (n, n, n);
+          if (! mpz_perfect_square_p (n))
+            {
+              printf ("mpz_perfect_square_p got 0, want 1\n");
+              mpz_trace ("  n", n);
+              abort ();
+            }
+        }
+    }
+
+  mpz_clear (alldiv);
+  mpz_clear (others);
+  mpz_clear (n);
+}
+
+
+/* Exercise mpz_perfect_square_p compared to what mpz_sqrt says. */
+void
+check_sqrt (int reps)
+{
+  mpz_t x2, x2t, x;
+  mp_size_t x2n;
+  int res;
+  int i;
+  /* int cnt = 0; */
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs;
+
+  mpz_init (bs);
+
+  mpz_init (x2);
+  mpz_init (x);
+  mpz_init (x2t);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 9);
+      x2n = mpz_get_ui (bs);
+      mpz_rrandomb (x2, rands, x2n);
+      /* mpz_out_str (stdout, -16, x2); puts (""); */
+
+      res = mpz_perfect_square_p (x2);
+      mpz_sqrt (x, x2);
+      mpz_mul (x2t, x, x);
+
+      if (res != (mpz_cmp (x2, x2t) == 0))
+        {
+          printf    ("mpz_perfect_square_p and mpz_sqrt differ\n");
+          mpz_trace ("   x  ", x);
+          mpz_trace ("   x2 ", x2);
+          mpz_trace ("   x2t", x2t);
+          printf    ("   mpz_perfect_square_p %d\n", res);
+          printf    ("   mpz_sqrt             %d\n", mpz_cmp (x2, x2t) == 0);
+          abort ();
+        }
+
+      /* cnt += res != 0; */
+    }
+  /* printf ("%d/%d perfect squares\n", cnt, reps); */
+
+  mpz_clear (bs);
+  mpz_clear (x2);
+  mpz_clear (x);
+  mpz_clear (x2t);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int reps = 200000;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  check_modulo ();
+  check_sqrt (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-popcount.c b/tests/mpz/t-popcount.c
new file mode 100644
index 0000000..8952cc2
--- /dev/null
+++ b/tests/mpz/t-popcount.c
@@ -0,0 +1,167 @@
+/* Test mpz_popcount.
+
+Copyright 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+
+void
+check_onebit (void)
+{
+  mpz_t          n;
+  unsigned long  i, got;
+
+  mpz_init (n);
+  for (i = 0; i < 5 * GMP_LIMB_BITS; i++)
+    {
+      mpz_setbit (n, i);
+      got = mpz_popcount (n);
+      if (got != 1)
+	{
+	  printf ("mpz_popcount wrong on single bit at %lu\n", i);
+	  printf ("   got %lu, want 1\n", got);
+	  abort();
+	}
+      mpz_clrbit (n, i);
+    }
+  mpz_clear (n);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char     *n;
+    unsigned long  want;
+  } data[] = {
+    { "-1", ~ (unsigned long) 0 },
+    { "-12345678", ~ (unsigned long) 0 },
+    { "0", 0 },
+    { "1", 1 },
+    { "3", 2 },
+    { "5", 2 },
+    { "0xFFFF", 16 },
+    { "0xFFFFFFFF", 32 },
+    { "0xFFFFFFFFFFFFFFFF", 64 },
+    { "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 128 },
+  };
+
+  unsigned long   got;
+  int    i;
+  mpz_t  n;
+
+  mpz_init (n);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+      got = mpz_popcount (n);
+      if (got != data[i].want)
+	{
+	  printf ("mpz_popcount wrong at data[%d]\n", i);
+	  printf ("   n     \"%s\"\n", data[i].n);
+	  printf ("         ");   mpz_out_str (stdout, 10, n); printf ("\n");
+	  printf ("         0x"); mpz_out_str (stdout, 16, n); printf ("\n");
+	  printf ("   got   %lu\n", got);
+	  printf ("   want  %lu\n", data[i].want);
+	  abort ();
+	}
+    }
+  mpz_clear (n);
+}
+
+unsigned long
+refmpz_popcount (mpz_t arg)
+{
+  mp_size_t n, i;
+  unsigned long cnt;
+  mp_limb_t x;
+
+  n = SIZ(arg);
+  if (n < 0)
+    return ~(unsigned long) 0;
+
+  cnt = 0;
+  for (i = 0; i < n; i++)
+    {
+      x = PTR(arg)[i];
+      while (x != 0)
+	{
+	  cnt += (x & 1);
+	  x >>= 1;
+	}
+    }
+  return cnt;
+}
+
+void
+check_random (void)
+{
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  mpz_t arg;
+  unsigned long arg_size, size_range;
+  unsigned long got, ref;
+  int i;
+
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (arg);
+
+  for (i = 0; i < 10000; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 11 + 2; /* 0..4096 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      arg_size = mpz_get_ui (bs);
+      mpz_rrandomb (arg, rands, arg_size);
+
+      got = mpz_popcount (arg);
+      ref = refmpz_popcount (arg);
+      if (got != ref)
+	{
+	  printf ("mpz_popcount wrong on random\n");
+	  printf ("         ");   mpz_out_str (stdout, 10, arg); printf ("\n");
+	  printf ("         0x"); mpz_out_str (stdout, 16, arg); printf ("\n");
+	  printf ("   got   %lu\n", got);
+	  printf ("   want  %lu\n", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (arg);
+  mpz_clear (bs);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_onebit ();
+  check_data ();
+  check_random ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-pow.c b/tests/mpz/t-pow.c
new file mode 100644
index 0000000..ff41721
--- /dev/null
+++ b/tests/mpz/t-pow.c
@@ -0,0 +1,217 @@
+/* Test mpz_pow_ui and mpz_ui_pow_ui.
+
+Copyright 1997, 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr want, mpz_srcptr base, unsigned long exp)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+
+  MPZ_CHECK_FORMAT (want);
+
+  mpz_pow_ui (got, base, exp);
+  if (mpz_cmp (got, want))
+    {
+      printf ("mpz_pow_ui wrong\n");
+      mpz_trace ("  base", base);
+      printf    ("  exp = %lu (0x%lX)\n", exp, exp);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+
+  mpz_set (got, base);
+  mpz_pow_ui (got, got, exp);
+  if (mpz_cmp (got, want))
+    {
+      printf ("mpz_pow_ui wrong\n");
+      mpz_trace ("  base", base);
+      printf    ("  exp = %lu (0x%lX)\n", exp, exp);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+
+  if (mpz_fits_ulong_p (base))
+    {
+      unsigned long  base_u = mpz_get_ui (base);
+      mpz_ui_pow_ui (got, base_u, exp);
+      if (mpz_cmp (got, want))
+	{
+	  printf    ("mpz_ui_pow_ui wrong\n");
+	  printf    ("  base=%lu (0x%lX)\n", base_u, base_u);
+	  printf    ("  exp = %lu (0x%lX)\n", exp, exp);
+	  mpz_trace ("  got ", got);
+	  mpz_trace ("  want", want);
+	  abort ();
+	}
+    }
+
+  mpz_clear (got);
+}
+
+void
+check_base (mpz_srcptr base)
+{
+  unsigned long  exp;
+  mpz_t          want;
+
+  mpz_init (want);
+  mpz_set_ui (want, 1L);
+
+  for (exp = 0; exp < 20; exp++)
+    {
+      check_one (want, base, exp);
+      mpz_mul (want, want, base);
+    }
+
+  mpz_clear (want);
+}
+
+void
+check_various (void)
+{
+  static const struct {
+    const char *base;
+  } data[] = {
+    { "0" },
+    { "1" },
+    { "2" },
+    { "3" },
+    { "4" },
+    { "5" },
+    { "6" },
+    { "10" },
+    { "15" },
+    { "16" },
+
+    { "0x1F" },
+    { "0xFF" },
+    { "0x1001" },
+    { "0xFFFF" },
+    { "0x10000001" },
+    { "0x1000000000000001" },
+
+    /* actual size closest to estimate */
+    { "0xFFFFFFFF" },
+    { "0xFFFFFFFFFFFFFFFF" },
+
+    /* same after rshift */
+    { "0xFFFFFFFF0" },
+    { "0xFFFFFFFF00" },
+    { "0xFFFFFFFFFFFFFFFF0" },
+    { "0xFFFFFFFFFFFFFFFF00" },
+
+    /* change from 2 limbs to 1 after rshift */
+    { "0x180000000" },
+    { "0x18000000000000000" },
+
+    /* change from 3 limbs to 2 after rshift */
+    { "0x18000000100000000" },
+    { "0x180000000000000010000000000000000" },
+
+    /* handling of absolute value */
+    { "-0x80000000" },
+    { "-0x8000000000000000" },
+
+    /* low zero limb, and size>2, checking argument overlap detection */
+    { "0x3000000000000000300000000000000030000000000000000" },
+  };
+
+  mpz_t  base;
+  int    i;
+
+  mpz_init (base);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (base, data[i].base, 0);
+      check_base (base);
+    }
+
+  mpz_clear (base);
+}
+
+void
+check_random (int reps)
+{
+  mpz_t              base, want;
+  mp_size_t          base_size;
+  int                i;
+  unsigned long      size_range, exp;
+  gmp_randstate_ptr  rands = RANDS;
+
+  mpz_init (base);
+  mpz_init (want);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* exponentially random 0 to 2^13 bits for base */
+      mpz_urandomb (want, rands, 32);
+      size_range = mpz_get_ui (want) % 12 + 2;
+      mpz_urandomb (want, rands, size_range);
+      base_size = mpz_get_ui (want);
+      mpz_rrandomb (base, rands, base_size);
+
+      /* randomly signed base */
+      mpz_urandomb (want, rands, 2);
+      if ((mpz_get_ui (want) & 1) != 0)
+	mpz_neg (base, base);
+
+      /* random 5 bits for exponent */
+      mpz_urandomb (want, rands, 5L);
+      exp = mpz_get_ui (want);
+
+      refmpz_pow_ui (want, base, exp);
+      check_one (want, base, exp);
+    }
+
+  mpz_clear (base);
+  mpz_clear (want);
+}
+
+int
+main (int argc, char **argv)
+{
+  int reps = 5000;
+
+  /* dummy call to drag in refmpn.o for testing mpz/n_pow_ui.c with
+     refmpn_mul_2 */
+  refmpn_zero_p (NULL, (mp_size_t) 0);
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  check_various ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-powm.c b/tests/mpz/t-powm.c
new file mode 100644
index 0000000..1a25ed7
--- /dev/null
+++ b/tests/mpz/t-powm.c
@@ -0,0 +1,263 @@
+/* Test mpz_powm, mpz_mul, mpz_mod, mpz_mod_ui, mpz_div_ui.
+
+Copyright 1991, 1993, 1994, 1996, 1999-2001, 2009, 2012, 2019 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+#define SIZEM 13
+
+/* Check that all sizes up to just above MUL_TOOM22_THRESHOLD have been tested
+   a few times.  FIXME: If SIZEM is set too low, this will never happen.  */
+int
+allsizes_seen (unsigned int *allsizes)
+{
+  mp_size_t i;
+
+  for (i = 1; i < MUL_TOOM22_THRESHOLD + 4; i++)
+    if (allsizes[i] < 4)
+      return 0;
+  return 1;
+}
+
+void
+small_2pow (unsigned long reps)
+{
+  mpz_t du, exp, mod;
+  mpz_t r1;
+  unsigned long m, e, r;
+  mp_limb_t b0 = 2;
+
+  mpz_roinit_n (du, &b0, 1);
+  mpz_init (exp);
+  mpz_init (mod);
+  mpz_init (r1);
+
+  for (m = 3; m * m < reps; m += 2)
+    {
+      mpz_set_ui (mod, m);
+      r = 1;
+      for (e = 0; e < m; e += 1)
+	{
+	  mpz_set_ui (exp, e);
+	  mpz_powm (r1, du, exp, mod);
+	  MPZ_CHECK_FORMAT (r1);
+	  if (mpz_cmp_ui (r1, r) != 0)
+	    {
+	      fprintf (stderr, "\nIncorrect result for operands:\n");
+	      debug_mp (du, -16);
+	      debug_mp (exp, -16);
+	      debug_mp (mod, -16);
+	      fprintf (stderr, "mpz_powm result:\n");
+	      debug_mp (r1, -16);
+	      fprintf (stderr, "Should be 2 ^ 0x%lx = 0x%lx (mod 0x%lx)\n", e, r, m);
+	      abort ();
+	    }
+	  if (r > (m >> 1))
+	    r = (r << 1) - m;
+	  else
+	    r = r << 1;
+	}
+    }
+
+  mpz_clear (exp);
+  mpz_clear (mod);
+  mpz_clear (r1);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t base, exp, mod;
+  mpz_t r1, r2, t1, exp2, base2;
+  mp_size_t base_size, exp_size, mod_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned int allsizes[1 << (SIZEM + 2 - 1)];
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  small_2pow ((unsigned int) reps);
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (base);
+  mpz_init (exp);
+  mpz_init (mod);
+  mpz_init (r1);
+  mpz_init (r2);
+  mpz_init (t1);
+  mpz_init (exp2);
+  mpz_init (base2);
+
+  memset (allsizes, 0, (1 << (SIZEM + 2 - 1)) * sizeof (int));
+
+  reps += reps >> 3;
+  for (i = 0; i < reps || ! allsizes_seen (allsizes); i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % SIZEM + 2;
+
+      if ((i & 7) == 0)
+	{
+	  mpz_set_ui (exp, 1);
+
+	  do  /* Loop until mathematically well-defined.  */
+	    {
+	      mpz_urandomb (bs, rands, size_range / 2 + 2);
+	      base_size = mpz_get_ui (bs);
+	      mpz_rrandomb (base, rands, base_size);
+	    }
+	  while (mpz_cmp_ui (base, 0) == 0);
+
+	  mpz_urandomb (bs, rands, size_range / 2);
+	  mod_size = mpz_get_ui (bs);
+	  mod_size = MIN (mod_size, base_size);
+	  mpz_rrandomb (mod, rands, mod_size);
+
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs) + base_size + 2;
+	  if ((i & 8) == 0)
+	    mod_size += GMP_NUMB_BITS - mod_size % GMP_NUMB_BITS;
+	  mpz_setbit (mod, mod_size);
+
+	  mpz_sub (base, base, mod);
+	}
+      else
+	{
+      do  /* Loop until mathematically well-defined.  */
+	{
+	  if ((i & 7) == 4)
+	    mpz_set_ui (base, 2);
+	  else
+	    {
+	      mpz_urandomb (bs, rands, size_range);
+	      base_size = mpz_get_ui (bs);
+	      mpz_rrandomb (base, rands, base_size);
+	    }
+
+	  mpz_urandomb (bs, rands, 7L);
+	  exp_size = mpz_get_ui (bs);
+	  mpz_rrandomb (exp, rands, exp_size);
+	}
+      while (mpz_cmp_ui (base, 0) == 0 && mpz_cmp_ui (exp, 0) == 0);
+
+      do
+        {
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mod, rands, mod_size);
+	}
+      while (mpz_cmp_ui (mod, 0) == 0);
+
+      allsizes[SIZ(mod)] += 1;
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (base, base);
+
+      /* printf ("%ld %ld %ld\n", SIZ (base), SIZ (exp), SIZ (mod)); */
+	}
+
+      mpz_set_ui (r2, 1);
+      mpz_mod (base2, base, mod);
+      mpz_set (exp2, exp);
+      mpz_mod (r2, r2, mod);
+
+      for (;;)
+	{
+	  if (mpz_tstbit (exp2, 0))
+	    {
+	      mpz_mul (r2, r2, base2);
+	      mpz_mod (r2, r2, mod);
+	    }
+	  if  (mpz_cmp_ui (exp2, 1) <= 0)
+	    break;
+	  mpz_mul (base2, base2, base2);
+	  mpz_mod (base2, base2, mod);
+	  mpz_tdiv_q_2exp (exp2, exp2, 1);
+	}
+
+      mpz_powm (r1, base, exp, mod);
+      MPZ_CHECK_FORMAT (r1);
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\nIncorrect results in test %d for operands:\n", i);
+	  debug_mp (base, -16);
+	  debug_mp (exp, -16);
+	  debug_mp (mod, -16);
+	  fprintf (stderr, "mpz_powm result:\n");
+	  debug_mp (r1, -16);
+	  fprintf (stderr, "reference result:\n");
+	  debug_mp (r2, -16);
+	  abort ();
+	}
+
+      if (mpz_tdiv_ui (mod, 2) == 0)
+	continue;
+
+      mpz_powm_sec (r1, base, exp, mod);
+      MPZ_CHECK_FORMAT (r1);
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\nIncorrect results in test %d for operands:\n", i);
+	  debug_mp (base, -16);
+	  debug_mp (exp, -16);
+	  debug_mp (mod, -16);
+	  fprintf (stderr, "mpz_powm_sec result:\n");
+	  debug_mp (r1, -16);
+	  fprintf (stderr, "reference result:\n");
+	  debug_mp (r2, -16);
+	  abort ();
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (base);
+  mpz_clear (exp);
+  mpz_clear (mod);
+  mpz_clear (r1);
+  mpz_clear (r2);
+  mpz_clear (t1);
+  mpz_clear (exp2);
+  mpz_clear (base2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-powm_ui.c b/tests/mpz/t-powm_ui.c
new file mode 100644
index 0000000..5b446c5
--- /dev/null
+++ b/tests/mpz/t-powm_ui.c
@@ -0,0 +1,127 @@
+/* Test mpz_powm_ui, mpz_mul, mpz_mod.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpz_t base, exp, mod;
+  mpz_t r1, r2, base2;
+  mp_size_t base_size, exp_size, mod_size;
+  unsigned long int exp2;
+  int i;
+  int reps = 100;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  TESTS_REPS (reps, argv, argc);
+
+  mpz_inits (bs, base, exp, mod, r1, r2, base2, NULL);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 18 + 2;
+
+      do  /* Loop until mathematically well-defined.  */
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  base_size = mpz_get_ui (bs);
+	  mpz_rrandomb (base, rands, base_size);
+
+	  mpz_urandomb (bs, rands, 6L);
+	  exp_size = mpz_get_ui (bs);
+	  mpz_rrandomb (exp, rands, exp_size);
+	  exp2 = mpz_getlimbn (exp, (mp_size_t) 0);
+	}
+      while (mpz_cmp_ui (base, 0) == 0 && exp2 == 0);
+
+      do
+        {
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mod, rands, mod_size);
+	}
+      while (mpz_cmp_ui (mod, 0) == 0);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (base, base);
+
+      /* printf ("%ld %ld\n", SIZ (base), SIZ (mod)); */
+
+#if 0
+      putc ('\n', stderr);
+      gmp_fprintf (stderr, "B = 0x%Zx\n", base);
+      gmp_fprintf (stderr, "M = 0x%Zx\n", mod);
+#endif
+
+      exp2 = mpz_getlimbn (exp, (mp_size_t) 0);
+      mpz_set_ui (r2, 1);
+      mpz_set (base2, base);
+      mpz_mod (r2, r2, mod);	/* needed when exp==0 and mod==1 */
+      while (exp2 != 0)
+	{
+	  if (exp2 % 2 != 0)
+	    {
+	      mpz_mul (r2, r2, base2);
+	      mpz_mod (r2, r2, mod);
+	    }
+	  mpz_mul (base2, base2, base2);
+	  mpz_mod (base2, base2, mod);
+	  exp2 = exp2 / 2;
+	}
+
+      exp2 = mpz_getlimbn (exp, (mp_size_t) 0);
+      mpz_powm_ui (r1, base, exp2, mod);
+      MPZ_CHECK_FORMAT (r1);
+
+#if 0
+      gmp_fprintf (stderr, "R   = 0x%Zx\n", r1);
+      gmp_fprintf (stderr, "REF = 0x%Zx\n", r2);
+#endif
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\ntest %d: Incorrect results for operands:\n", i);
+	  gmp_fprintf (stderr, "B = 0x%Zx\n", base);
+	  gmp_fprintf (stderr, "E = 0x%Zx\n", exp);
+	  gmp_fprintf (stderr, "M = 0x%Zx\n", mod);
+	  gmp_fprintf (stderr, "R   = 0x%Zx\n", r1);
+	  gmp_fprintf (stderr, "REF = 0x%Zx\n", r2);
+	  abort ();
+	}
+    }
+
+  mpz_clears (bs, base, exp, mod, r1, r2, base2, NULL);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-pprime_p.c b/tests/mpz/t-pprime_p.c
new file mode 100644
index 0000000..dffe6ea
--- /dev/null
+++ b/tests/mpz/t-pprime_p.c
@@ -0,0 +1,243 @@
+/* Exercise mpz_probab_prime_p.
+
+Copyright 2002, 2018-2019, 2022 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Enhancements:
+
+   - Test some big primes don't come back claimed to be composite.
+   - Test some big composites don't come back claimed to be certainly prime.
+   - Test some big composites with small factors are identified as certainly
+     composite.  */
+
+
+/* return 2 if prime, 0 if composite */
+int
+isprime (unsigned long n)
+{
+  if (n < 4)
+    return (n & 2);
+  if ((n & 1) == 0)
+    return 0;
+
+  for (unsigned long i = 3; i*i <= n; i+=2)
+    if ((n % i) == 0)
+      return 0;
+
+  return 2;
+}
+
+void
+check_one (mpz_srcptr n, int want)
+{
+  int  got;
+
+  got = mpz_probab_prime_p (n, 25);
+
+  /* "definitely prime" (2) is fine if we only wanted "probably prime" (1) */
+  if ((got != want) && (got != want * 2))
+    {
+      printf ("mpz_probab_prime_p\n");
+      mpz_trace ("  n    ", n);
+      printf    ("  got =%d", got);
+      printf    ("  want=%d", want);
+      abort ();
+    }
+}
+
+void
+check_pn (mpz_ptr n, int want)
+{
+  check_one (n, want);
+  mpz_neg (n, n);
+  check_one (n, want);
+}
+
+/* expect certainty for small n */
+void
+check_small (void)
+{
+  mpz_t  n;
+  long   i;
+
+  mpz_init (n);
+
+  for (i = 0; i < 300; i++)
+    {
+      mpz_set_si (n, i);
+      check_pn (n, isprime (i));
+    }
+
+  mpz_clear (n);
+}
+
+void
+check_composites (int count)
+{
+  int i;
+  mpz_t a, b, n, bs;
+  unsigned long size_range, size;
+  gmp_randstate_ptr rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (n);
+  mpz_init (bs);
+
+  static const char * const composites[] = {
+    "225670644213750121",	/* n=61*C16, if D < 61, (n/D) = 1.	*/
+    "2386342059899637841",	/* n=61*C17, if D < 61, (n/D) = 1.	*/
+    "1194649",	/* A square, but strong base-2 pseudoprime,	*/
+    "12327121",	/* another base-2 pseudoprime square.	*/
+    "18446744066047760377",	/* Should trigger Fibonacci's test;	*/
+    "10323769",			/* &3==1, Lucas' test with D=37;	*/
+    "1397419",			/* &3==3, Lucas' test with D=43;	*/
+    "11708069165918597341",	/* &3==1, Lucas' test with large D=107;	*/
+    "395009109077493751",	/* &3==3, Lucas' test with large D=113.	*/
+    NULL
+  };
+
+  for (i = 0; composites[i]; i++)
+    {
+      mpz_set_str_or_abort (n, composites[i], 0);
+      check_one (n, 0);
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (a, rands, size);
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+      mpz_rrandomb (b, rands, size);
+
+      /* Exclude trivial factors */
+      if (mpz_cmp_ui (a, 1) == 0)
+	mpz_set_ui (a, 2);
+      if (mpz_cmp_ui (b, 1) == 0)
+	mpz_set_ui (b, 2);
+
+      mpz_mul (n, a, b);
+
+      check_pn (n, 0);
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (n);
+  mpz_clear (bs);
+}
+
+static void
+check_primes (void)
+{
+  static const char * const primes[] = {
+    "2", "53", "1234567891",
+    "2055693949", "1125899906842597", "16412292043871650369",
+    "18446744075358702679",	/* Lucas' test with large D=107.	*/
+    /* diffie-hellman-group1-sha1, also "Well known group 2" in RFC
+       2412, 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */
+    "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+    "FFFFFFFFFFFFFFFF",
+    NULL
+  };
+
+  mpz_t n;
+  int i;
+
+  mpz_init (n);
+
+  for (i = 0; primes[i]; i++)
+    {
+      mpz_set_str_or_abort (n, primes[i], 0);
+      check_one (n, 1);
+    }
+  mpz_clear (n);
+}
+
+static void
+check_fermat_mersenne (int count)
+{
+  int fermat_exponents [] = {1, 2, 4, 8, 16};
+  int mersenne_exponents [] = {2, 3, 5, 7, 13, 17, 19, 31, 61, 89,
+			       107, 127, 521, 607, 1279, 2203, 2281,
+			       3217, 4253, 4423, 9689, 9941, 11213,
+			       19937, 21701, 23209, 44497, 86243};
+  mpz_t pp;
+  int i, j, want;
+
+  mpz_init (pp);
+  count = MIN (110000, count);
+
+  for (i=1; i<count; ++i)
+    {
+      mpz_set_ui (pp, 1);
+      mpz_setbit (pp, i); /* 2^i + 1 */
+      want = 0;
+      for (j = 0; j < numberof (fermat_exponents); j++)
+	if (fermat_exponents[j] == i)
+	  {
+	    /* Fermat's primes are small enough for a definite answer. */
+	    want = 2;
+	    break;
+	  }
+      check_one (pp, want);
+
+      mpz_sub_ui (pp, pp, 2); /* 2^i - 1 */
+      want = 0;
+      for (j = 0; j < numberof (mersenne_exponents); j++)
+	if (mersenne_exponents[j] == i)
+	  {
+	    want = 1 << (i < 50);
+	    break;
+	  }
+      check_one (pp, want);
+    }
+  mpz_clear (pp);
+}
+
+int
+main (int argc, char **argv)
+{
+  int count = 1000;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+
+  check_small ();
+  check_fermat_mersenne (count >> 3);
+  check_composites (count);
+  check_primes ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-primorial_ui.c b/tests/mpz/t-primorial_ui.c
new file mode 100644
index 0000000..b4d2bfe
--- /dev/null
+++ b/tests/mpz/t-primorial_ui.c
@@ -0,0 +1,145 @@
+/* Exercise mpz_primorial_ui.
+
+Copyright 2000-2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-primorial_ui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+static int isprime (unsigned long int t);
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long  n;
+  unsigned long  limit = 2222;
+  gmp_randstate_ptr rands;
+  mpz_t          f, r, bs;
+
+  tests_start ();
+  rands = RANDS;
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* for small limb testing */
+  limit = MIN (limit, MP_LIMB_T_MAX);
+
+  mpz_init_set_ui (f, 1);  /* 0# = 1 */
+  mpz_init (r);
+
+  n = 0;
+  do
+    {
+      mpz_primorial_ui (r, n);
+      MPZ_CHECK_FORMAT (r);
+
+      if (mpz_cmp (f, r) != 0)
+	{
+	  printf ("mpz_primorial_ui(%lu) wrong\n", n);
+	  printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+	  printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+	  abort ();
+	}
+
+      if (isprime (++n))
+	mpz_mul_ui (f, f, n);  /* p# = (p-1)# * (p) */
+      if (n%16 == 0) { mpz_clear (r); mpz_init (r); }
+    } while (n < limit);
+
+  n = 0; limit =1;
+  mpz_init (bs);
+  do
+    {
+      unsigned long i, d;
+
+      mpz_urandomb (bs, rands, 21);
+      i = mpz_get_ui (bs);
+      mpz_urandomb (bs, rands, 9);
+      d = mpz_get_ui (bs) + 3*64;
+      mpz_primorial_ui (f, i);
+      MPZ_CHECK_FORMAT (f);
+      mpz_primorial_ui (r, i+d);
+      MPZ_CHECK_FORMAT (r);
+
+      do {
+	if (isprime (++i))
+	  mpz_mul_ui (f, f, i);
+      } while (--d != 0);
+
+      if (mpz_cmp (f, r) != 0)
+	{
+	  printf ("mpz_primorial_ui(%lu) wrong\n", i);
+	  printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+	  printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+	  abort ();
+	}
+    } while (++n < limit);
+  /* Chech a single "big" value, modulo a larger prime */
+  n = 2095637;
+  mpz_primorial_ui (r, n);
+  mpz_set_ui (f, 13);
+  mpz_setbit (f, 64); /* f = 2^64 + 13 */
+  mpz_tdiv_r (r, r, f);
+  mpz_set_str (f, "BAFCBF3C95B217D5", 16);
+
+  if (mpz_cmp (f, r) != 0)
+    {
+      printf ("mpz_primorial_ui(%lu) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+      abort ();
+    }
+
+  mpz_clear (bs);
+  mpz_clear (f);
+  mpz_clear (r);
+
+  tests_end ();
+
+  exit (0);
+}
+
+static int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  if (t < 3 || (t & 1) == 0)
+    return t == 2;
+
+  for (d = 3, r = 1; r != 0; d += 2)
+    {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+    }
+  return 0;
+}
diff --git a/tests/mpz/t-remove.c b/tests/mpz/t-remove.c
new file mode 100644
index 0000000..07ba918
--- /dev/null
+++ b/tests/mpz/t-remove.c
@@ -0,0 +1,146 @@
+/* Test mpz_remove.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2009, 2012, 2013 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t);
+unsigned long int mpz_refremove (mpz_t, const mpz_t, const mpz_t);
+
+int
+main (int argc, char **argv)
+{
+  unsigned long int exp;
+  mpz_t t, dest, refdest, dividend, divisor;
+  mp_size_t dividend_size, divisor_size;
+  int i;
+  int reps = 1000;
+  unsigned long int pwr, refpwr;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_inits (bs, t, dest, refdest, dividend, divisor, NULL);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 18 + 1; /* 1..524288 bit operands */
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  divisor_size = mpz_get_ui (bs);
+	  mpz_rrandomb (divisor, rands, divisor_size);
+	}
+      while (mpz_sgn (divisor) == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs) + divisor_size;
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 32);
+      exp = mpz_get_ui (bs) % (5 + 10000 / mpz_sizeinbase (divisor, 2));
+      if (mpz_get_ui (bs) & 2)
+	mpz_neg (divisor, divisor);
+      mpz_pow_ui (t, divisor, exp);
+      mpz_mul (dividend, dividend, t);
+
+      refpwr = mpz_refremove (refdest, dividend, divisor);
+      pwr = mpz_remove (dest, dividend, divisor);
+
+      if (refpwr != pwr || mpz_cmp (refdest, dest) != 0)
+	{
+	  fprintf (stderr, "ERROR after %d tests\n", i);
+	  fprintf (stderr, "refpower = %lu\n", refpwr);
+	  fprintf (stderr, "   power = %lu\n", pwr);
+	  fprintf (stderr, "    op1 = "); debug_mp (dividend);
+	  fprintf (stderr, "    op2 = "); debug_mp (divisor);
+	  fprintf (stderr, "refdest = "); debug_mp (refdest);
+	  fprintf (stderr, "   dest = "); debug_mp (dest);
+	  abort ();
+	}
+    }
+
+  mpz_clears (bs, t, dest, refdest, dividend, divisor, NULL);
+
+  tests_end ();
+  exit (0);
+}
+
+unsigned long int
+mpz_refremove (mpz_t dest, const mpz_t src, const mpz_t f)
+{
+  unsigned long int pwr;
+
+  pwr = 0;
+
+  mpz_set (dest, src);
+  if (mpz_cmpabs_ui (f, 1) > 0)
+    {
+      mpz_t rem, x;
+
+      mpz_init (x);
+      mpz_init (rem);
+
+      for (;; pwr++)
+	{
+	  mpz_tdiv_qr (x, rem, dest, f);
+	  if (mpz_cmp_ui (rem, 0) != 0)
+	    break;
+	  mpz_swap (dest, x);
+	}
+
+      mpz_clear (x);
+      mpz_clear (rem);
+    }
+
+  return pwr;
+}
+
+void
+debug_mp (mpz_t x)
+{
+  size_t siz = mpz_sizeinbase (x, 16);
+
+  if (siz > 65)
+    {
+      mpz_t q;
+      mpz_init (q);
+      mpz_tdiv_q_2exp (q, x, 4 * (mpz_sizeinbase (x, 16) - 25));
+      gmp_fprintf (stderr, "%ZX...", q);
+      mpz_tdiv_r_2exp (q, x, 4 * 25);
+      gmp_fprintf (stderr, "%025ZX [%d]\n", q, (int) siz);
+      mpz_clear (q);
+    }
+  else
+    {
+      gmp_fprintf (stderr, "%ZX\n", x);
+    }
+}
diff --git a/tests/mpz/t-root.c b/tests/mpz/t-root.c
new file mode 100644
index 0000000..e1ce159
--- /dev/null
+++ b/tests/mpz/t-root.c
@@ -0,0 +1,174 @@
+/* Test mpz_root, mpz_rootrem, and mpz_perfect_power_p.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2009, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+void
+check_one (mpz_t root1, mpz_t x2, unsigned long nth, int res, int i)
+{
+  mpz_t temp, temp2;
+  mpz_t root2, rem2;
+
+  mpz_init (root2);
+  mpz_init (rem2);
+  mpz_init (temp);
+  mpz_init (temp2);
+
+  MPZ_CHECK_FORMAT (root1);
+
+  mpz_rootrem (root2, rem2, x2, nth);
+  MPZ_CHECK_FORMAT (root2);
+  MPZ_CHECK_FORMAT (rem2);
+
+  mpz_pow_ui (temp, root1, nth);
+  MPZ_CHECK_FORMAT (temp);
+
+  mpz_add (temp2, temp, rem2);
+
+  /* Is power of result > argument?  */
+  if (mpz_cmp (root1, root2) != 0 || mpz_cmp (x2, temp2) != 0 || mpz_cmpabs (temp, x2) > 0 || res == mpz_cmp_ui (rem2, 0))
+    {
+      fprintf (stderr, "ERROR after test %d\n", i);
+      debug_mp (x2, 10);
+      debug_mp (root1, 10);
+      debug_mp (root2, 10);
+      fprintf (stderr, "nth: %lu ,res: %i\n", nth, res);
+      abort ();
+    }
+
+  if (nth > 1 && mpz_cmp_ui (temp, 1L) > 0 && ! mpz_perfect_power_p (temp))
+    {
+      fprintf (stderr, "ERROR in mpz_perfect_power_p after test %d\n", i);
+      debug_mp (temp, 10);
+      debug_mp (root1, 10);
+      fprintf (stderr, "nth: %lu\n", nth);
+      abort ();
+    }
+
+  if (nth <= 10000 && mpz_sgn(x2) > 0)		/* skip too expensive test */
+    {
+      mpz_add_ui (temp2, root1, 1L);
+      mpz_pow_ui (temp2, temp2, nth);
+      MPZ_CHECK_FORMAT (temp2);
+
+      /* Is square of (result + 1) <= argument?  */
+      if (mpz_cmp (temp2, x2) <= 0)
+	{
+	  fprintf (stderr, "ERROR after test %d\n", i);
+	  debug_mp (x2, 10);
+	  debug_mp (root1, 10);
+	  fprintf (stderr, "nth: %lu\n", nth);
+	  abort ();
+	}
+    }
+
+  mpz_clear (root2);
+  mpz_clear (rem2);
+  mpz_clear (temp);
+  mpz_clear (temp2);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t x2;
+  mpz_t root1;
+  mp_size_t x2_size;
+  int i, res;
+  int reps = 500;
+  unsigned long nth;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (x2);
+  mpz_init (root1);
+
+  /* This triggers a gcc 4.3.2 bug */
+  mpz_set_str (x2, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000002", 16);
+  res = mpz_root (root1, x2, 2);
+  check_one (root1, x2, 2, res, -1);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      x2_size = mpz_get_ui (bs) + 10;
+      mpz_rrandomb (x2, rands, x2_size);
+
+      mpz_urandomb (bs, rands, 15);
+      nth = mpz_getlimbn (bs, 0) % mpz_sizeinbase (x2, 2) + 2;
+
+      res = mpz_root (root1, x2, nth);
+
+      mpz_urandomb (bs, rands, 4);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	{
+	  /* With 50% probability, set x2 near a perfect power.  */
+	  mpz_pow_ui (x2, root1, nth);
+	  if ((bsi & 2) != 0)
+	    {
+	      mpz_sub_ui (x2, x2, bsi >> 2);
+	      mpz_abs (x2, x2);
+	    }
+	  else
+	    mpz_add_ui (x2, x2, bsi >> 2);
+	  res = mpz_root (root1, x2, nth);
+	}
+
+      check_one (root1, x2, nth, res, i);
+
+      if (((nth & 1) != 0) && ((bsi & 2) != 0))
+	{
+	  mpz_neg (x2, x2);
+	  mpz_neg (root1, root1);
+	  check_one (root1, x2, nth, res, i);
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x2);
+  mpz_clear (root1);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-scan.c b/tests/mpz/t-scan.c
new file mode 100644
index 0000000..ababcfa
--- /dev/null
+++ b/tests/mpz/t-scan.c
@@ -0,0 +1,131 @@
+/* Tests of mpz_scan0 and mpz_scan1.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+unsigned long
+refmpz_scan (mpz_srcptr z, unsigned long i, int sought)
+{
+  unsigned long  z_bits = (unsigned long) ABSIZ(z) * GMP_NUMB_BITS;
+
+  do
+    {
+      if (mpz_tstbit (z, i) == sought)
+        return i;
+      i++;
+    }
+  while (i <= z_bits);
+
+  return ULONG_MAX;
+}
+
+unsigned long
+refmpz_scan0 (mpz_srcptr z, unsigned long starting_bit)
+{
+  return refmpz_scan (z, starting_bit, 0);
+}
+
+unsigned long
+refmpz_scan1 (mpz_srcptr z, unsigned long starting_bit)
+{
+  return refmpz_scan (z, starting_bit, 1);
+}
+
+
+void
+check_ref (void)
+{
+  static const int offset[] = {
+    -2, -1, 0, 1, 2, 3
+  };
+
+  mpz_t          z;
+  int            test, neg, sought, oindex, o;
+  mp_size_t      size, isize;
+  unsigned long  start, got, want;
+
+  mpz_init (z);
+  for (test = 0; test < 5; test++)
+    {
+      for (size = 0; size < 5; size++)
+        {
+          mpz_random2 (z, size);
+
+          for (neg = 0; neg <= 1; neg++)
+            {
+              if (neg)
+                mpz_neg (z, z);
+
+              for (isize = 0; isize <= size; isize++)
+                {
+                  for (oindex = 0; oindex < numberof (offset); oindex++)
+                    {
+                      o = offset[oindex];
+                      if ((int) isize*GMP_NUMB_BITS < -o)
+                        continue;  /* start would be negative */
+
+                      start = isize*GMP_NUMB_BITS + o;
+
+                      for (sought = 0; sought <= 1; sought++)
+                        {
+                          if (sought == 0)
+                            {
+                              got = mpz_scan0 (z, start);
+                              want = refmpz_scan0 (z, start);
+                            }
+                          else
+                            {
+                              got = mpz_scan1 (z, start);
+                              want = refmpz_scan1 (z, start);
+                            }
+
+                          if (got != want)
+                            {
+                              printf ("wrong at test=%d, size=%ld, neg=%d, start=%lu, sought=%d\n",
+                                      test, size, neg, start, sought);
+                              printf ("   z 0x");
+                              mpz_out_str (stdout, -16, z);
+                              printf ("\n");
+                              printf ("   got=%lu, want=%lu\n", got, want);
+                              exit (1);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_ref ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-set_d.c b/tests/mpz/t-set_d.c
new file mode 100644
index 0000000..1fdfc02
--- /dev/null
+++ b/tests/mpz/t-set_d.c
@@ -0,0 +1,139 @@
+/* Test mpz_set_d and mpz_init_set_d.
+
+Copyright 2000-2003, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    double     d;
+    mp_size_t  want_size;
+    mp_limb_t  want_data[2];
+  } data[] = {
+
+    {  0.0,  0 },
+    {  1.0,  1, { 1 } },
+    { -1.0, -1, { 1 } },
+
+    {  123.0,  1, { 123 } },
+    { -123.0, -1, { 123 } },
+
+    { 1e-1, 0, { 0 } },
+    { -1e-1, 0, { 0 } },
+    { 2.328306436538696e-10, 0, { 0 } },
+    { -2.328306436538696e-10, 0, { 0 } },
+    { 5.421010862427522e-20, 0, { 0 } },
+    { -5.421010862427522e-20, 0, { 0 } },
+    { 2.938735877055719e-39, 0, { 0 } },
+    { -2.938735877055719e-39, 0, { 0 } },
+  };
+
+  mpz_t  z;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_init (z);
+      mpz_set_d (z, data[i].d);
+      MPZ_CHECK_FORMAT (z);
+      if (z->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (z->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_set_d wrong on data[%d]\n", i);
+        bad:
+          d_trace   ("  d  ", data[i].d);
+          printf    ("  got  size %ld\n", (long) z->_mp_size);
+          printf    ("  want size %ld\n", (long) data[i].want_size);
+          mpn_trace ("  got  z", z->_mp_d, z->_mp_size);
+          mpn_trace ("  want z", data[i].want_data, data[i].want_size);
+          abort();
+        }
+      mpz_clear (z);
+
+      mpz_init_set_d (z, data[i].d);
+      MPZ_CHECK_FORMAT (z);
+      if (z->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (z->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_init_set_d wrong on data[%d]\n", i);
+          goto bad;
+        }
+      mpz_clear (z);
+    }
+}
+
+/* Try mpz_set_d on values 2^i+1, while such a value fits a double. */
+void
+check_2n_plus_1 (void)
+{
+  volatile double  p, d, diff;
+  mpz_t  want, got;
+  int    i;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  p = 1.0;
+  mpz_set_ui (want, 2L);  /* gives 3 on first step */
+
+  for (i = 1; i < 500; i++)
+    {
+      mpz_mul_2exp (want, want, 1L);
+      mpz_sub_ui (want, want, 1L);   /* want = 2^i+1 */
+
+      p *= 2.0;  /* p = 2^i */
+      d = p + 1.0;
+      diff = d - p;
+      if (diff != 1.0)
+        break;   /* rounding occurred, stop now */
+
+      mpz_set_d (got, d);
+      MPZ_CHECK_FORMAT (got);
+      if (mpz_cmp (got, want) != 0)
+        {
+          printf ("mpz_set_d wrong on 2^%d+1\n", i);
+          d_trace   ("  d ", d);
+          mpz_trace ("  got  ", got);
+          mpz_trace ("  want ", want);
+          abort ();
+        }
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_2n_plus_1 ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-set_f.c b/tests/mpz/t-set_f.c
new file mode 100644
index 0000000..2671a86
--- /dev/null
+++ b/tests/mpz/t-set_f.c
@@ -0,0 +1,125 @@
+/* Test mpz_set_f.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr z)
+{
+  static const int shift[] = {
+    0, 1, GMP_LIMB_BITS, 2*GMP_LIMB_BITS, 5*GMP_LIMB_BITS
+  };
+
+  int    sh, shneg, neg;
+  mpf_t  f;
+  mpz_t  got, want;
+
+  mpf_init2 (f, mpz_sizeinbase(z,2));
+  mpz_init (got);
+  mpz_init (want);
+
+  for (sh = 0; sh < numberof(shift); sh++)
+    {
+      for (shneg = 0; shneg <= 1; shneg++)
+	{
+	  for (neg = 0; neg <= 1; neg++)
+	    {
+	      mpf_set_z (f, z);
+	      mpz_set (want, z);
+
+	      if (neg)
+		{
+		  mpf_neg (f, f);
+		  mpz_neg (want, want);
+		}
+
+	      if (shneg)
+		{
+		  mpz_tdiv_q_2exp (want, want, shift[sh]);
+		  mpf_div_2exp (f, f, shift[sh]);
+		}
+	      else
+		{
+		  mpz_mul_2exp (want, want, shift[sh]);
+		  mpf_mul_2exp (f, f, shift[sh]);
+		}
+
+	      mpz_set_f (got, f);
+	      MPZ_CHECK_FORMAT (got);
+
+	      if (mpz_cmp (got, want) != 0)
+		{
+		  printf ("wrong result\n");
+		  printf ("  shift  %d\n", shneg ? -shift[sh] : shift[sh]);
+		  printf ("  neg    %d\n", neg);
+		  mpf_trace ("     f", f);
+		  mpz_trace ("   got", got);
+		  mpz_trace ("  want", want);
+		  abort ();
+		}
+	    }
+	}
+    }
+
+  mpf_clear (f);
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+
+void
+check_various (void)
+{
+  mpz_t  z;
+
+  mpz_init (z);
+
+  mpz_set_ui (z, 0L);
+  check_one (z);
+
+  mpz_set_si (z, 123L);
+  check_one (z);
+
+  mpz_rrandomb (z, RANDS, 2*GMP_LIMB_BITS);
+  check_one (z);
+
+  mpz_rrandomb (z, RANDS, 5*GMP_LIMB_BITS);
+  check_one (z);
+
+  mpz_clear (z);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+#if GMP_NAIL_BITS == 0
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_various ();
+
+  tests_end ();
+#endif
+  exit (0);
+}
diff --git a/tests/mpz/t-set_si.c b/tests/mpz/t-set_si.c
new file mode 100644
index 0000000..4e8ed7a
--- /dev/null
+++ b/tests/mpz/t-set_si.c
@@ -0,0 +1,96 @@
+/* Test mpz_set_si and mpz_init_set_si.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+#if GMP_NUMB_BITS <= BITS_PER_ULONG
+#define ENTRY(n)   { n, { n, 0 } }
+#else
+#define ENTRY(n)   { n, { (n) & GMP_NUMB_MASK, (n) >> GMP_NUMB_BITS } }
+#endif
+
+  static const struct {
+    long       n;
+    mp_size_t  want_size;
+    mp_limb_t  want_data[2];
+  } data[] = {
+
+    {  0L,  0 },
+    {  1L,  1, { 1 } },
+    { -1L, -1, { 1 } },
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    { LONG_MAX,  1, { LONG_MAX, 0 } },
+    { -LONG_MAX,  -1, { LONG_MAX, 0 } },
+    { LONG_HIGHBIT,  -1, { ULONG_HIGHBIT, 0 } },
+#else
+    { LONG_MAX,  2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS } },
+    { -LONG_MAX,  -2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS }},
+    { LONG_HIGHBIT,  -2, { 0, ULONG_HIGHBIT >> GMP_NUMB_BITS } },
+#endif
+  };
+
+  mpz_t  n;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_init (n);
+      mpz_set_si (n, data[i].n);
+      MPZ_CHECK_FORMAT (n);
+      if (n->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (n->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpz_clear (n);
+
+      mpz_init_set_si (n, data[i].n);
+      MPZ_CHECK_FORMAT (n);
+      if (n->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (n->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_init_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpz_clear (n);
+    }
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-set_str.c b/tests/mpz/t-set_str.c
new file mode 100644
index 0000000..22d36d3
--- /dev/null
+++ b/tests/mpz/t-set_str.c
@@ -0,0 +1,108 @@
+/* Test mpz_set_str.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr want, int fail, int base, const char *str)
+{
+  mpz_t   got;
+
+  MPZ_CHECK_FORMAT (want);
+  mp_trace_base = (base == 0 ? 16 : base);
+
+  mpz_init (got);
+
+  if (mpz_set_str (got, str, base) != fail)
+    {
+      printf ("mpz_set_str unexpectedly failed\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      abort ();
+    }
+  MPZ_CHECK_FORMAT (got);
+
+  if (fail == 0 && mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_set_str wrong\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      mpz_trace ("got ", got);
+      mpz_trace ("want", want);
+      abort ();
+    }
+
+  mpz_clear (got);
+}
+
+void
+check_samples (void)
+{
+  mpz_t  z;
+
+  mpz_init (z);
+
+  mpz_set_ui (z, 0L);
+  check_one (z, 0, 0, "0 ");
+  check_one (z, 0, 0, " 0 0 0 ");
+  check_one (z, 0, 0, " -0B 0 ");
+  check_one (z, 0, 0, "  0X 0 ");
+  check_one (z, 0, 10, "0 ");
+  check_one (z, 0, 10, "-0   ");
+  check_one (z, 0, 10, " 0 000 000    ");
+
+  mpz_set_ui (z, 123L);
+  check_one (z, 0, 0, "123 ");
+  check_one (z, 0, 0, "123    ");
+  check_one (z, 0, 0, "0173   ");
+  check_one (z, 0, 0, " 0b 1 11 10 11  ");
+  check_one (z, 0, 0, " 0x 7b ");
+  check_one (z, 0, 0, "0x7B");
+  check_one (z, 0, 10, "123 ");
+  check_one (z, 0, 10, "123    ");
+  check_one (z, 0, 0, " 123 ");
+  check_one (z, 0, 0, "  123    ");
+  check_one (z, 0, 10, "  0000123 ");
+  check_one (z, 0, 10, "  123    ");
+  check_one (z,-1, 10, "1%");
+  check_one (z,-1, 0, "3!");
+  check_one (z,-1, 0, "0123456789");
+  check_one (z,-1, 0, "13579BDF");
+  check_one (z,-1, 0, "0b0102");
+  check_one (z,-1, 0, "0x010G");
+  check_one (z,-1, 37,"0x010G");
+  check_one (z,-1, 99,"0x010G");
+
+  mpz_clear (z);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_samples ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-sizeinbase.c b/tests/mpz/t-sizeinbase.c
new file mode 100644
index 0000000..936f2bd
--- /dev/null
+++ b/tests/mpz/t-sizeinbase.c
@@ -0,0 +1,89 @@
+/* Test mpz_sizeinbase.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#if 0
+  /* Disabled due to the bogosity of trying to fake an _mp_d pointer to
+     below an object.  Has been seen to fail on a hppa system and on ia64.  */
+
+
+/* Create a fake mpz consisting of just a single 1 bit, with totbits being
+   the total number of bits, inclusive of that 1 bit.  */
+void
+mpz_fake_bits (mpz_ptr z, unsigned long totbits)
+{
+  static mp_limb_t  n;
+  unsigned long     zero_bits, zero_limbs;
+
+  zero_bits = totbits - 1;
+  zero_limbs = zero_bits / GMP_NUMB_BITS;
+  zero_bits %= GMP_NUMB_BITS;
+
+  SIZ(z) = zero_limbs + 1;
+  PTR(z) = (&n) - (SIZ(z) - 1);
+  n = CNST_LIMB(1) << zero_bits;
+
+  ASSERT_ALWAYS (mpz_sizeinbase (z, 2) == totbits);
+}
+
+
+/* This was seen to fail on a GNU/Linux powerpc32 with gcc 2.95.2,
+   apparently due to a doubtful value of mp_bases[10].chars_per_bit_exactly
+   (0X1.34413509F79FDP-2 whereas 0X1.34413509F79FFP-2 is believed correct).
+   Presumably this is a glibc problem when gcc converts the decimal string
+   in mp_bases.c, or maybe it's only a function of the rounding mode during
+   compilation.  */
+void
+check_sample (void)
+{
+  unsigned long  totbits = 198096465;
+  int        base = 10;
+  size_t     want = 59632979;
+  size_t     got;
+  mpz_t      z;
+
+  mpz_fake_bits (z, totbits);
+  got = mpz_sizeinbase (z, base);
+  if (got != want)
+    {
+      printf ("mpz_sizeinbase\n");
+      printf ("  base    %d\n",  base);
+      printf ("  totbits %lu\n", totbits);
+      printf ("  got     %u\n",  got);
+      printf ("  want    %u\n",  want);
+      abort ();
+    }
+}
+#endif
+
+int
+main (void)
+{
+  tests_start ();
+
+  /* check_sample (); */
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/mpz/t-sqrtrem.c b/tests/mpz/t-sqrtrem.c
new file mode 100644
index 0000000..9db8a61
--- /dev/null
+++ b/tests/mpz/t-sqrtrem.c
@@ -0,0 +1,122 @@
+/* Test mpz_add, mpz_add_ui, mpz_cmp, mpz_cmp, mpz_mul, mpz_sqrtrem.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (mpz_t, mpz_t, mpz_t);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t x2;
+  mpz_t x, rem;
+  mpz_t temp, temp2;
+  mp_size_t x2_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (x2);
+  mpz_init (x);
+  mpz_init (rem);
+  mpz_init (temp);
+  mpz_init (temp2);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2; /* 0..262144 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      x2_size = mpz_get_ui (bs);
+      mpz_rrandomb (x2, rands, x2_size);
+
+      /* printf ("%ld\n", SIZ (x2)); */
+
+      mpz_sqrt (temp, x2);
+      MPZ_CHECK_FORMAT (temp);
+
+      mpz_sqrtrem (x, rem, x2);
+      MPZ_CHECK_FORMAT (x);
+      MPZ_CHECK_FORMAT (rem);
+
+      /* Are results different?  */
+      if (mpz_cmp (temp, x) != 0)
+	dump_abort (x2, x, rem);
+
+      mpz_mul (temp, x, x);
+
+      /* Is square of result > argument?  */
+      if (mpz_cmp (temp, x2) > 0)
+	dump_abort (x2, x, rem);
+
+      mpz_add_ui (temp2, x, 1);
+      mpz_mul (temp2, temp2, temp2);
+
+      /* Is square of (result + 1) <= argument?  */
+      if (mpz_cmp (temp2, x2) <= 0)
+	dump_abort (x2, x, rem);
+
+      mpz_add (temp2, temp, rem);
+
+      /* Is the remainder wrong?  */
+      if (mpz_cmp (x2, temp2) != 0)
+	dump_abort (x2, x, rem);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x2);
+  mpz_clear (x);
+  mpz_clear (rem);
+  mpz_clear (temp);
+  mpz_clear (temp2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (mpz_t x2, mpz_t x, mpz_t rem)
+{
+  fprintf (stderr, "ERROR\n");
+  fprintf (stderr, "x2        = "); debug_mp (x2, -16);
+  fprintf (stderr, "x         = "); debug_mp (x, -16);
+  fprintf (stderr, "remainder = "); debug_mp (rem, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-tdiv.c b/tests/mpz/t-tdiv.c
new file mode 100644
index 0000000..3d2eb36
--- /dev/null
+++ b/tests/mpz/t-tdiv.c
@@ -0,0 +1,145 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_tdiv_qr, mpz_tdiv_q,
+   mpz_tdiv_r, mpz_mul.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (mpz_t, mpz_t);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend, divisor;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size, divisor_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (dividend);
+  mpz_init (divisor);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 18 + 2; /* 0..524288 bit operands */
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  divisor_size = mpz_get_ui (bs);
+	  mpz_rrandomb (divisor, rands, divisor_size);
+	}
+      while (mpz_sgn (divisor) == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs) + divisor_size;
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+      if ((bsi & 2) != 0)
+	mpz_neg (divisor, divisor);
+
+      /* printf ("%ld %ld\n", SIZ (dividend), SIZ (divisor)); */
+
+      mpz_tdiv_qr (quotient, remainder, dividend, divisor);
+      mpz_tdiv_q (quotient2, dividend, divisor);
+      mpz_tdiv_r (remainder2, dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort (dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort (dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != ((mpz_cmp_ui (dividend, 0) ^ mpz_cmp_ui (divisor, 0)) < 0))
+	dump_abort (dividend, divisor);
+
+      /* Check if the remainder has the same sign as the dividend
+	 (quotient rounded towards 0).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (dividend, 0) < 0))
+	  dump_abort (dividend, divisor);
+
+      mpz_mul (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort (dividend, divisor);
+
+      mpz_abs (temp, divisor);
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp (remainder, temp) >= 0)
+	dump_abort (dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (divisor);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (mpz_t dividend, mpz_t divisor)
+{
+  fprintf (stderr, "ERROR\n");
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = "); debug_mp (divisor, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/mpz/t-tdiv_ui.c b/tests/mpz/t-tdiv_ui.c
new file mode 100644
index 0000000..6bbb947
--- /dev/null
+++ b/tests/mpz/t-tdiv_ui.c
@@ -0,0 +1,158 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_tdiv_qr_ui, mpz_tdiv_q_ui,
+   mpz_tdiv_r_ui, mpz_tdiv_ui, mpz_mul_ui.
+
+Copyright 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (const char *, mpz_t, unsigned long);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size;
+  unsigned long divisor;
+  int i;
+  int reps = 200000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned long r_rq, r_q, r_r, r;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */
+
+      do
+	{
+	  mpz_rrandomb (bs, rands, 64);
+	  divisor = mpz_get_ui (bs);
+	}
+      while (divisor == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs);
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+
+      /* printf ("%ld\n", SIZ (dividend)); */
+
+      r_rq = mpz_tdiv_qr_ui (quotient, remainder, dividend, divisor);
+      r_q = mpz_tdiv_q_ui (quotient2, dividend, divisor);
+      r_r = mpz_tdiv_r_ui (remainder2, dividend, divisor);
+      r = mpz_tdiv_ui (dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort ("quotients from mpz_tdiv_qr_ui and mpz_tdiv_q_ui differ",
+		    dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort ("remainders from mpz_tdiv_qr_ui and mpz_tdiv_r_ui differ",
+		    dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != (mpz_cmp_ui (dividend, 0) < 0))
+	dump_abort ("quotient sign wrong", dividend, divisor);
+
+      /* Check if the remainder has the same sign as the dividend
+	 (quotient rounded towards 0).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (dividend, 0) < 0))
+	  dump_abort ("remainder sign wrong", dividend, divisor);
+
+      mpz_mul_ui (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort ("n mod d != n - [n/d]*d", dividend, divisor);
+
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp_ui (remainder, divisor) >= 0)
+	dump_abort ("remainder greater than divisor", dividend, divisor);
+
+      if (mpz_cmp_ui (remainder, r_rq) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_qr_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_q) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_q_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_r) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_r_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_ui is wrong",
+		    dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *str, mpz_t dividend, unsigned long divisor)
+{
+  fprintf (stderr, "ERROR: %s\n", str);
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = %lX\n", divisor);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/tests/rand/findlc.c b/tests/rand/findlc.c
new file mode 100644
index 0000000..72fb12c
--- /dev/null
+++ b/tests/rand/findlc.c
@@ -0,0 +1,251 @@
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <math.h>
+#include "gmpstat.h"
+
+#define RCSID(msg) \
+static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
+
+RCSID("$Id$");
+
+int g_debug = 0;
+
+static mpz_t a;
+
+static void
+sh_status (int sig)
+{
+  printf ("sh_status: signal %d caught. dumping status.\n", sig);
+
+  printf ("  a = ");
+  mpz_out_str (stdout, 10, a);
+  printf ("\n");
+  fflush (stdout);
+
+  if (SIGSEGV == sig)		/* remove SEGV handler */
+    signal (SIGSEGV, SIG_DFL);
+}
+
+/* Input is a modulus (m).  We shall find multiplier (a) and adder (c)
+   conforming to the rules found in the first comment block in file
+   mpz/urandom.c.
+
+   Then run a spectral test on the generator and discard any
+   multipliers not passing.  */
+
+/* TODO:
+
+   . find a better algorithm than a+=8; bigger jumps perhaps?
+
+*/
+
+void
+mpz_true_random (mpz_t s, unsigned long int nbits)
+{
+#if __FreeBSD__
+  FILE *fs;
+  char c[1];
+  int i;
+
+  mpz_set_ui (s, 0);
+  for (i = 0; i < nbits; i += 8)
+    {
+      for (;;)
+	{
+	  int nread;
+	  fs = fopen ("/dev/random", "r");
+	  nread = fread (c, 1, 1, fs);
+	  fclose (fs);
+	  if (nread != 0)
+	    break;
+	  sleep (1);
+	}
+      mpz_mul_2exp (s, s, 8);
+      mpz_add_ui (s, s, ((unsigned long int) c[0]) & 0xff);
+      printf ("%d random bits\n", i + 8);
+    }
+  if (nbits % 8 != 0)
+    mpz_mod_2exp (s, s, nbits);
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+  const char usage[] = "usage: findlc [-dv] m2exp [low_merit [high_merit]]\n";
+  int f;
+  int v_lose, m_lose, v_best, m_best;
+  int c;
+  int debug = 1;
+  int cnt_high_merit;
+  mpz_t m;
+  unsigned long int m2exp;
+#define DIMS 6			/* dimensions run in spectral test */
+  mpf_t v[DIMS-1];		/* spectral test result (there's no v
+				   for 1st dimension */
+  mpf_t f_merit, low_merit, high_merit;
+  mpz_t acc, minus8;
+  mpz_t min, max;
+  mpz_t s;
+
+
+  mpz_init (m);
+  mpz_init (a);
+  for (f = 0; f < DIMS-1; f++)
+    mpf_init (v[f]);
+  mpf_init (f_merit);
+  mpf_init_set_d (low_merit, .1);
+  mpf_init_set_d (high_merit, .1);
+
+  while ((c = getopt (argc, argv, "a:di:hv")) != -1)
+    switch (c)
+      {
+      case 'd':			/* debug */
+	g_debug++;
+	break;
+
+      case 'v':			/* print version */
+	puts (rcsid[1]);
+	exit (0);
+
+      case 'h':
+      case '?':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 1)
+    {
+      fputs (usage, stderr);
+      exit (1);
+    }
+
+  /* Install signal handler. */
+  if (SIG_ERR == signal (SIGSEGV, sh_status))
+    {
+      perror ("signal (SIGSEGV)");
+      exit (1);
+    }
+  if (SIG_ERR == signal (SIGHUP, sh_status))
+    {
+      perror ("signal (SIGHUP)");
+      exit (1);
+    }
+
+  printf ("findlc: version: %s\n", rcsid[1]);
+  m2exp = atol (argv[0]);
+  mpz_init_set_ui (m, 1);
+  mpz_mul_2exp (m, m, m2exp);
+  printf ("m = 0x");
+  mpz_out_str (stdout, 16, m);
+  puts ("");
+
+  if (argc > 1)			/* have low_merit */
+    mpf_set_str (low_merit, argv[1], 0);
+  if (argc > 2)			/* have high_merit */
+    mpf_set_str (high_merit, argv[2], 0);
+
+  if (debug)
+    {
+      fprintf (stderr, "low_merit = ");
+      mpf_out_str (stderr, 10, 2, low_merit);
+      fprintf (stderr, "; high_merit = ");
+      mpf_out_str (stderr, 10, 2, high_merit);
+      fputs ("\n", stderr);
+    }
+
+  mpz_init (minus8);
+  mpz_set_si (minus8, -8L);
+  mpz_init_set_ui (acc, 0);
+  mpz_init (s);
+  mpz_init_set_d (min, 0.01 * pow (2.0, (double) m2exp));
+  mpz_init_set_d (max, 0.99 * pow (2.0, (double) m2exp));
+
+  mpz_true_random (s, m2exp);	/* Start.  */
+  mpz_setbit (s, 0);		/* Make it odd.  */
+
+  v_best = m_best = 2*(DIMS-1);
+  for (;;)
+    {
+      mpz_add (acc, acc, s);
+      mpz_mod_2exp (acc, acc, m2exp);
+#if later
+      mpz_and_si (a, acc, -8L);
+#else
+      mpz_and (a, acc, minus8);
+#endif
+      mpz_add_ui (a, a, 5);
+      if (mpz_cmp (a, min) <= 0 || mpz_cmp (a, max) >= 0)
+	continue;
+
+      spectral_test (v, DIMS, a, m);
+      for (f = 0, v_lose = m_lose = 0, cnt_high_merit = DIMS-1;
+	   f < DIMS-1; f++)
+	{
+	  merit (f_merit, f + 2, v[f], m);
+
+	  if (mpf_cmp_ui (v[f], 1 << (30 / (f + 2) + (f == 2))) < 0)
+	    v_lose++;
+
+	  if (mpf_cmp (f_merit, low_merit) < 0)
+	    m_lose++;
+
+	  if (mpf_cmp (f_merit, high_merit) >= 0)
+	    cnt_high_merit--;
+	}
+
+      if (0 == v_lose && 0 == m_lose)
+	{
+	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
+	  if (0 == cnt_high_merit)
+	    break;		/* leave loop */
+	}
+      if (v_lose < v_best)
+	{
+	  v_best = v_lose;
+	  printf ("best (v_lose=%d; m_lose=%d): ", v_lose, m_lose);
+	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
+	}
+      if (m_lose < m_best)
+	{
+	  m_best = m_lose;
+	  printf ("best (v_lose=%d; m_lose=%d): ", v_lose, m_lose);
+	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
+	}
+    }
+
+  mpz_clear (m);
+  mpz_clear (a);
+  for (f = 0; f < DIMS-1; f++)
+    mpf_clear (v[f]);
+  mpf_clear (f_merit);
+  mpf_clear (low_merit);
+  mpf_clear (high_merit);
+
+  printf ("done.\n");
+  return 0;
+}
diff --git a/tests/rand/gen.c b/tests/rand/gen.c
new file mode 100644
index 0000000..c8e6c67
--- /dev/null
+++ b/tests/rand/gen.c
@@ -0,0 +1,480 @@
+/* gen.c -- Generate pseudorandom numbers.
+
+Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Examples:
+
+  $ gen 10
+10 integers 0 <= X < 2^32 generated by mpz_urandomb()
+
+  $ gen -f mpf_urandomb 10
+10 real numbers 0 <= X < 1
+
+  $ gen -z 127 10
+10 integers 0 <= X < 2^127
+
+  $ gen -f mpf_urandomb -x .9,1 10
+10 real numbers 0 <= X < .9
+
+  $ gen -s 1 10
+10 integers, sequence seeded with 1
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#include "gmp-impl.h"
+
+int main (argc, argv)
+     int argc;
+     char *argv[];
+{
+  const char usage[] =
+    "usage: gen [-bhpq] [-a n] [-c a,c,m2exp] [-C a,c,m] [-f func] [-g alg] [-m n] [-s n] " \
+    "[-x f,t] [-z n] [n]\n" \
+    "  n        number of random numbers to generate\n" \
+    "  -a n     ASCII output in radix n (default, with n=10)\n" \
+    "  -b       binary output\n" \
+    "  -c a,c,m2exp use supplied LC scheme\n" \
+    "  -f func  random function, one of\n" \
+    "           mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \
+    "  -g alg   algorithm, one of mt (default), lc\n" \
+    "  -h       print this text and exit\n" \
+    "  -m n     maximum size of generated number plus 1 (0<= X < n) for mpz_urandomm\n" \
+    "  -p       print used seed on stderr\n" \
+    "  -q       quiet, no output\n" \
+    "  -s n     initial seed (default: output from time(3))\n" \
+    "  -x f,t   exclude all numbers f <= x <= t\n" \
+    "  -z n     size in bits of generated numbers (0<= X <2^n) (default 32)\n" \
+    "";
+
+  unsigned long int f;
+  unsigned long int n = 0;
+  unsigned long int seed;
+  unsigned long int m2exp = 0;
+  unsigned int size = 32;
+  int seed_from_user = 0;
+  int ascout = 1, binout = 0, printseed = 0;
+  int output_radix = 10;
+  int lc_scheme_from_user = 0;
+  int quiet_flag = 0;
+  mpz_t z_seed;
+  mpz_t z1;
+  mpf_t f1;
+  gmp_randstate_t rstate;
+  int c, i;
+  double drand;
+  long lrand;
+  int do_exclude = 0;
+  mpf_t f_xf, f_xt;		/* numbers to exclude from sequence */
+  char *str_xf, *str_xt;	/* numbers to exclude from sequence */
+  char *str_a, *str_adder, *str_m;
+  mpz_t z_a, z_m, z_mmax;
+  unsigned long int ul_adder;
+
+  enum
+  {
+    RFUNC_mpz_urandomb = 0,
+    RFUNC_mpz_urandomm,
+    RFUNC_mpf_urandomb,
+    RFUNC_rand,
+    RFUNC_random,
+  } rfunc = RFUNC_mpz_urandomb;
+  char *rfunc_str[] =  { "mpz_urandomb", "mpz_urandomm", "mpf_urandomb",
+			 "rand", "random" };
+  enum
+  {
+    RNG_MT = 0,
+    RNG_LC
+  };
+  gmp_randalg_t ralg = RNG_MT;
+  /* Texts for the algorithms.  The index of each must match the
+     corresponding algorithm in the enum above.  */
+  char *ralg_str[] = { "mt", "lc" };
+
+  mpf_init (f_xf);
+  mpf_init (f_xt);
+  mpf_init (f1);
+  mpz_init (z1);
+  mpz_init (z_seed);
+  mpz_init_set_ui (z_mmax, 0);
+
+
+  while ((c = getopt (argc, argv, "a:bc:f:g:hm:n:pqs:z:x:")) != -1)
+    switch (c)
+      {
+      case 'a':
+	ascout = 1;
+	binout = 0;
+	output_radix = atoi (optarg);
+	break;
+
+      case 'b':
+	ascout = 0;
+	binout = 1;
+	break;
+
+      case 'c':			/* User supplied LC scheme: a,c,m2exp */
+	if (NULL == (str_a = strtok (optarg, ","))
+	    || NULL == (str_adder = strtok (NULL, ","))
+	    || NULL == (str_m = strtok (NULL, ",")))
+	  {
+	    fprintf (stderr, "gen: bad LC scheme parameters: %s\n", optarg);
+	    exit (1);
+	  }
+#ifdef HAVE_STRTOUL
+	ul_adder = strtoul (str_adder, NULL, 0);
+#elif HAVE_STRTOL
+	ul_adder = (unsigned long int) strtol (str_adder, NULL, 0);
+#else
+	ul_adder = (unsigned long int) atoi (str_adder);
+#endif
+
+	if (mpz_init_set_str (z_a, str_a, 0))
+	  {
+	    fprintf (stderr, "gen: bad LC scheme parameter `a': %s\n", str_a);
+	    exit (1);
+	  }
+	if (ULONG_MAX == ul_adder)
+	  {
+	    fprintf (stderr, "gen: bad LC scheme parameter `c': %s\n",
+		     str_adder);
+	    exit (1);
+	  }
+	m2exp = atol (str_m);
+
+	lc_scheme_from_user = 1;
+	break;
+
+
+      case 'f':
+	rfunc = -1;
+	for (f = 0; f < sizeof (rfunc_str) / sizeof (*rfunc_str); f++)
+	    if (!strcmp (optarg, rfunc_str[f]))
+	      {
+		rfunc = f;
+		break;
+	      }
+	if (rfunc == -1)
+	  {
+	    fputs (usage, stderr);
+	    exit (1);
+	  }
+	break;
+
+      case 'g':			/* algorithm */
+	ralg = -1;
+	for (f = 0; f < sizeof (ralg_str) / sizeof (*ralg_str); f++)
+	    if (!strcmp (optarg, ralg_str[f]))
+	      {
+		ralg = f;
+		break;
+	      }
+	if (ralg == -1)
+	  {
+	    fputs (usage, stderr);
+	    exit (1);
+	  }
+	break;
+
+      case 'm':			/* max for mpz_urandomm() */
+	if (mpz_set_str (z_mmax, optarg, 0))
+	  {
+	    fprintf (stderr, "gen: bad max value: %s\n", optarg);
+	    exit (1);
+	  }
+	break;
+
+      case 'p':			/* print seed on stderr */
+	printseed = 1;
+	break;
+
+      case 'q':			/* quiet */
+	quiet_flag = 1;
+	break;
+
+      case 's':			/* user provided seed */
+	if (mpz_set_str (z_seed, optarg, 0))
+	  {
+	    fprintf (stderr, "gen: bad seed argument %s\n", optarg);
+	    exit (1);
+	  }
+	seed_from_user = 1;
+	break;
+
+      case 'z':
+	size = atoi (optarg);
+	if (size < 1)
+	  {
+	    fprintf (stderr, "gen: bad size argument (-z %u)\n", size);
+	    exit (1);
+	  }
+	break;
+
+      case 'x':			/* Exclude. from,to */
+	str_xf = optarg;
+	str_xt = strchr (optarg, ',');
+	if (NULL == str_xt)
+	  {
+	    fprintf (stderr, "gen: bad exclusion parameters: %s\n", optarg);
+	    exit (1);
+	  }
+	*str_xt++ = '\0';
+	do_exclude = 1;
+	break;
+
+      case 'h':
+      case '?':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+  argc -= optind;
+  argv += optind;
+
+  if (! seed_from_user)
+    mpz_set_ui (z_seed, (unsigned long int) time (NULL));
+  seed = mpz_get_ui (z_seed);
+  if (printseed)
+    {
+      fprintf (stderr, "gen: seed used: ");
+      mpz_out_str (stderr, output_radix, z_seed);
+      fprintf (stderr, "\n");
+    }
+
+  mpf_set_prec (f1, size);
+
+  /* init random state and plant seed */
+  switch (rfunc)
+    {
+    case RFUNC_mpf_urandomb:
+#if 0
+      /* Don't init a too small generator.  */
+      size = PREC (f1) * GMP_LIMB_BITS;
+      /* Fall through.  */
+#endif
+    case RFUNC_mpz_urandomb:
+    case RFUNC_mpz_urandomm:
+      switch (ralg)
+	{
+	case RNG_MT:
+	  gmp_randinit_mt (rstate);
+	  break;
+
+	case RNG_LC:
+	  if (! lc_scheme_from_user)
+	    gmp_randinit_lc_2exp_size (rstate, MIN (128, size));
+	  else
+	    gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp);
+	  break;
+
+	default:
+	  fprintf (stderr, "gen: unsupported algorithm\n");
+	  exit (1);
+	}
+
+      gmp_randseed (rstate, z_seed);
+      break;
+
+    case RFUNC_rand:
+      srand (seed);
+      break;
+
+    case RFUNC_random:
+#ifdef __FreeBSD__		/* FIXME */
+      if (seed_from_user)
+	srandom (seed);
+      else
+	srandomdev ();
+#else
+      fprintf (stderr, "gen: unsupported algorithm\n");
+#endif
+      break;
+
+    default:
+      fprintf (stderr, "gen: random function not implemented\n");
+      exit (1);
+    }
+
+  /* set up excludes */
+  if (do_exclude)
+    switch (rfunc)
+      {
+      case RFUNC_mpf_urandomb:
+
+	if (mpf_set_str (f_xf, str_xf, 10) ||
+	    mpf_set_str (f_xt, str_xt, 10))
+	  {
+	    fprintf (stderr, "gen: bad exclusion-from (\"%s\") " \
+		     "or exclusion-to (\"%s\") string.  no exclusion done.\n",
+		     str_xf, str_xt);
+	    do_exclude = 0;
+	  }
+	break;
+
+      default:
+	fprintf (stderr, "gen: exclusion not implemented for chosen " \
+		 "randomization function.  all numbers included in sequence.\n");
+      }
+
+  /* generate and print */
+  if (argc > 0)
+    {
+#if HAVE_STRTOUL
+      n = strtoul (argv[0], (char **) NULL, 10);
+#elif HAVE_STRTOL
+      n = (unsigned long int) strtol (argv[0], (char **) NULL, 10);
+#else
+      n = (unsigned long int) atoi (argv[0]);
+#endif
+    }
+
+  for (f = 0; n == 0 || f < n; f++)
+    {
+      switch (rfunc)
+	{
+	case RFUNC_mpz_urandomb:
+	  mpz_urandomb (z1, rstate, size);
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    {
+	      /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/
+	      fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n");
+	      exit (1);
+	    }
+	  else
+	    {
+	      mpz_out_str (stdout, output_radix, z1);
+	      puts ("");
+	    }
+	  break;
+
+	case RFUNC_mpz_urandomm:
+	  mpz_urandomm (z1, rstate, z_mmax);
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    {
+	      /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/
+	      fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n");
+	      exit (1);
+	    }
+	  else
+	    {
+	      mpz_out_str (stdout, output_radix, z1);
+	      puts ("");
+	    }
+	  break;
+
+	case RFUNC_mpf_urandomb:
+	  mpf_urandomb (f1, rstate, size);
+	  if (do_exclude)
+	    if (mpf_cmp (f1, f_xf) >= 0 && mpf_cmp (f1, f_xt) <= 0)
+		break;
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    {
+	      fprintf (stderr, "gen: binary output for floating point numbers "\
+		       "not implemented\n");
+	      exit (1);
+	    }
+	  else
+	    {
+	      mpf_out_str (stdout, output_radix, 0, f1);
+	      puts ("");
+	    }
+	  break;
+
+	case RFUNC_rand:
+	  i = rand ();
+#ifdef FLOAT_OUTPUT
+	  if (i)
+	    drand = (double) i / (double) RAND_MAX;
+	  else
+	    drand = 0.0;
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    fwrite (&drand, sizeof (drand), 1, stdout);
+	  else
+	    printf ("%e\n", drand);
+#else
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    fwrite (&i, sizeof (i), 1, stdout);
+	  else
+	    printf ("%d\n", i);
+#endif
+	  break;
+
+	case RFUNC_random:
+	  lrand = random ();
+	  if (lrand)
+	    drand = (double) lrand / (double) 0x7fffffff;
+	  else
+	    drand = 0;
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    fwrite (&drand, sizeof (drand), 1, stdout);
+	  else
+	    printf ("%e\n", drand);
+	  break;
+
+	default:
+	  fprintf (stderr, "gen: random function not implemented\n");
+	  exit (1);
+	}
+
+    }
+
+  /* clean up */
+  switch (rfunc)
+    {
+    case RFUNC_mpz_urandomb:
+    case RFUNC_mpf_urandomb:
+      gmp_randclear (rstate);
+      break;
+    default:
+      break;
+    }
+  mpf_clear (f1);
+  mpf_clear (f_xf);
+  mpf_clear (f_xt);
+  mpz_clear (z1);
+  mpz_clear (z_seed);
+
+  return 0;
+}
+
+static void *debug_dummyz = mpz_dump;
+static void *debug_dummyf = mpf_dump;
diff --git a/tests/rand/gmpstat.h b/tests/rand/gmpstat.h
new file mode 100644
index 0000000..99c5cca
--- /dev/null
+++ b/tests/rand/gmpstat.h
@@ -0,0 +1,75 @@
+/* gmpstat.h */
+
+/*
+Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* This file requires the following header files: gmp.h */
+
+#ifndef	__GMPSTAT_H__
+#define	__GMPSTAT_H__
+
+/* Global debug flag.  FIXME: Remove. */
+extern int g_debug;
+#define DEBUG_1 0
+#define DEBUG_2 1
+
+/* Max number of dimensions in spectral test.  FIXME: Makw dynamic. */
+#define GMP_SPECT_MAXT 10
+
+void
+mpf_freqt (mpf_t Kp,
+	   mpf_t Km,
+	   mpf_t X[],
+	   const unsigned long int n);
+unsigned long int
+mpz_freqt (mpf_t V,
+	   mpz_t X[],
+	   unsigned int imax,
+	   const unsigned long int n);
+
+/* Low level functions. */
+void
+ks (mpf_t Kp,
+    mpf_t Km,
+    mpf_t X[],
+    void (P) (mpf_t, mpf_t),
+    const unsigned long int n);
+
+void
+ks_table (mpf_t p, mpf_t val, const unsigned int n);
+
+void
+x2_table (double t[],
+	  unsigned int v);
+
+void
+spectral_test (mpf_t rop[], unsigned int T, mpz_t a, mpz_t m);
+void
+vz_dot (mpz_t rop, mpz_t V1[], mpz_t V2[], unsigned int n);
+void
+f_floor (mpf_t rop, mpf_t op);
+
+void
+merit (mpf_t rop, unsigned int t, mpf_t v, mpz_t m);
+double
+merit_u (unsigned int t, mpf_t v, mpz_t m);
+
+/* From separate source files: */
+void zdiv_round (mpz_t rop, mpz_t n, mpz_t d);
+
+#endif /* !__GMPSTAT_H__ */
diff --git a/tests/rand/spect.c b/tests/rand/spect.c
new file mode 100644
index 0000000..64de5a0
--- /dev/null
+++ b/tests/rand/spect.c
@@ -0,0 +1,136 @@
+/* spect.c -- the spectral test */
+
+/*
+Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* T is upper dimension.  Z_A is the LC multiplier, which is
+   relatively prime to Z_M, the LC modulus.  The result is put in
+   rop[] with v[t] in rop[t-2]. */
+
+/* BUGS: Due to lazy allocation scheme, maximum T is hard coded to MAXT. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "gmpstat.h"
+
+int g_debug = 0;
+
+int
+main (int argc, char *argv[])
+{
+  const char usage[] = "usage: spect [-d] a m n\n";
+  int c;
+  unsigned int n;
+  mpz_t a, m;
+  mpf_t res[GMP_SPECT_MAXT], res_min[GMP_SPECT_MAXT], f_tmp;
+  int f;
+
+
+  mpz_init (a);
+  mpz_init (m);
+  for (f = 0; f < GMP_SPECT_MAXT; f++)
+    {
+      mpf_init (res[f]);
+      mpf_init (res_min[f]);
+    }
+  mpf_init (f_tmp);
+  mpf_set_ui (res_min[0], 32768); /* 2^15 */
+  mpf_set_ui (res_min[1], 1024); /* 2^10 */
+  mpf_set_ui (res_min[2], 256); /* 2^8 */
+  mpf_set_ui (res_min[3], 64); /* 2^6 */
+  mpf_set_ui (res_min[4], 32); /* 2^5 */
+
+  while ((c = getopt (argc, argv, "dh")) != -1)
+    switch (c)
+      {
+      case 'd':			/* debug */
+	g_debug++;
+	break;
+      case 'h':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 3)
+    {
+      fputs (usage, stderr);
+      exit (1);
+    }
+
+  mpz_set_str (a, argv[0], 0);
+  mpz_set_str (m, argv[1], 0);
+  n = (unsigned int) atoi (argv[2]);
+  if (n + 1 > GMP_SPECT_MAXT)
+    n = GMP_SPECT_MAXT + 1;
+
+  spectral_test (res, n, a, m);
+
+  for (f = 0; f < n - 1; f++)
+    {
+      /* print v */
+      printf ("%d: v = ", f + 2);
+      mpf_out_str (stdout, 10, 4, res[f]);
+
+#ifdef PRINT_RAISED_BY_TWO_AS_WELL
+      printf (" (^2 = ");
+      mpf_mul (f_tmp, res[f], res[f]);
+      mpf_out_str (stdout, 10, 4, f_tmp);
+      printf (")");
+#endif /* PRINT_RAISED_BY_TWO_AS_WELL */
+
+      /* print merit */
+      printf (" m = ");
+      merit (f_tmp, f + 2, res[f], m);
+      mpf_out_str (stdout, 10, 4, f_tmp);
+
+      if (mpf_cmp (res[f], res_min[f]) < 0)
+	printf ("\t*** v too low ***");
+      if (mpf_get_d (f_tmp) < .1)
+	printf ("\t*** merit too low ***");
+
+      puts ("");
+    }
+
+  mpz_clear (a);
+  mpz_clear (m);
+  for (f = 0; f < GMP_SPECT_MAXT; f++)
+    {
+      mpf_clear (res[f]);
+      mpf_clear (res_min[f]);
+    }
+  mpf_clear (f_tmp);
+
+  return 0;
+}
+
+
+void
+debug_foo()
+{
+  if (0)
+    {
+      mpz_dump (0);
+      mpf_dump (0);
+    }
+}
diff --git a/tests/rand/stat.c b/tests/rand/stat.c
new file mode 100644
index 0000000..fa06f4c
--- /dev/null
+++ b/tests/rand/stat.c
@@ -0,0 +1,406 @@
+/* stat.c -- statistical tests of random number sequences. */
+
+/*
+Copyright 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Examples:
+
+  $ gen 1000 | stat
+Test 1000 real numbers.
+
+  $ gen 30000 | stat -2 1000
+Test 1000 real numbers 30 times and then test the 30 results in a
+``second level''.
+
+  $ gen -f mpz_urandomb 1000 | stat -i 0xffffffff
+Test 1000 integers 0 <= X <= 2^32-1.
+
+  $ gen -f mpz_urandomb -z 34 1000 | stat -i 0x3ffffffff
+Test 1000 integers 0 <= X <= 2^34-1.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include "gmpstat.h"
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#define FVECSIZ (100000L)
+
+int g_debug = 0;
+
+static void
+print_ks_results (mpf_t f_p, mpf_t f_p_prob,
+		  mpf_t f_m, mpf_t f_m_prob,
+		  FILE *fp)
+{
+  double p, pp, m, mp;
+
+  p = mpf_get_d (f_p);
+  m = mpf_get_d (f_m);
+  pp = mpf_get_d (f_p_prob);
+  mp = mpf_get_d (f_m_prob);
+
+  fprintf (fp, "%.4f (%.0f%%)\t", p, pp * 100.0);
+  fprintf (fp, "%.4f (%.0f%%)\n", m, mp * 100.0);
+}
+
+static void
+print_x2_table (unsigned int v, FILE *fp)
+{
+  double t[7];
+  int f;
+
+
+  fprintf (fp, "Chi-square table for v=%u\n", v);
+  fprintf (fp, "1%%\t5%%\t25%%\t50%%\t75%%\t95%%\t99%%\n");
+  x2_table (t, v);
+  for (f = 0; f < 7; f++)
+    fprintf (fp, "%.2f\t", t[f]);
+  fputs ("\n", fp);
+}
+
+
+
+/* Pks () -- Distribution function for KS results with a big n (like 1000
+   or so):  F(x) = 1 - pow(e, -2*x^2) [Knuth, vol 2, p.51]. */
+/* gnuplot: plot [0:1] Pks(x), Pks(x) = 1-exp(-2*x**2)  */
+
+static void
+Pks (mpf_t p, mpf_t x)
+{
+  double dt;			/* temp double */
+
+  mpf_set (p, x);
+  mpf_mul (p, p, p);		/* p = x^2 */
+  mpf_mul_ui (p, p, 2);		/* p = 2*x^2 */
+  mpf_neg (p, p);		/* p = -2*x^2 */
+  /* No pow() in gmp.  Use doubles. */
+  /* FIXME: Use exp()? */
+  dt = pow (M_E, mpf_get_d (p));
+  mpf_set_d (p, dt);
+  mpf_ui_sub (p, 1, p);
+}
+
+/* f_freq() -- frequency test on real numbers 0<=f<1*/
+static void
+f_freq (const unsigned l1runs, const unsigned l2runs,
+	mpf_t fvec[], const unsigned long n)
+{
+  unsigned f;
+  mpf_t f_p, f_p_prob;
+  mpf_t f_m, f_m_prob;
+  mpf_t *l1res;			/* level 1 result array */
+
+  mpf_init (f_p);  mpf_init (f_m);
+  mpf_init (f_p_prob);  mpf_init (f_m_prob);
+
+
+  /* Allocate space for 1st level results. */
+  l1res = (mpf_t *) malloc (l2runs * 2 * sizeof (mpf_t));
+  if (NULL == l1res)
+    {
+      fprintf (stderr, "stat: malloc failure\n");
+      exit (1);
+    }
+
+  printf ("\nEquidistribution/Frequency test on real numbers (0<=X<1):\n");
+  printf ("\tKp\t\tKm\n");
+
+  for (f = 0; f < l2runs; f++)
+    {
+      /*  f_printvec (fvec, n); */
+      mpf_freqt (f_p, f_m, fvec + f * n, n);
+
+      /* what's the probability of getting these results? */
+      ks_table (f_p_prob, f_p, n);
+      ks_table (f_m_prob, f_m, n);
+
+      if (l1runs == 0)
+	{
+	  /*printf ("%u:\t", f + 1);*/
+	  print_ks_results (f_p, f_p_prob, f_m, f_m_prob, stdout);
+	}
+      else
+	{
+	  /* save result */
+	  mpf_init_set (l1res[f], f_p);
+	  mpf_init_set (l1res[f + l2runs], f_m);
+	}
+    }
+
+  /* Now, apply the KS test on the results from the 1st level rounds
+     with the distribution
+     F(x) = 1 - pow(e, -2*x^2)	[Knuth, vol 2, p.51] */
+
+  if (l1runs != 0)
+    {
+      /*printf ("-------------------------------------\n");*/
+
+      /* The Kp's. */
+      ks (f_p, f_m, l1res, Pks, l2runs);
+      ks_table (f_p_prob, f_p, l2runs);
+      ks_table (f_m_prob, f_m, l2runs);
+      printf ("Kp:\t");
+      print_ks_results (f_p, f_p_prob, f_m, f_m_prob, stdout);
+
+      /* The Km's. */
+      ks (f_p, f_m, l1res + l2runs, Pks, l2runs);
+      ks_table (f_p_prob, f_p, l2runs);
+      ks_table (f_m_prob, f_m, l2runs);
+      printf ("Km:\t");
+      print_ks_results (f_p, f_p_prob, f_m, f_m_prob, stdout);
+    }
+
+  mpf_clear (f_p);  mpf_clear (f_m);
+  mpf_clear (f_p_prob);  mpf_clear (f_m_prob);
+  free (l1res);
+}
+
+/* z_freq(l1runs, l2runs, zvec, n, max) -- frequency test on integers
+   0<=z<=MAX */
+static void
+z_freq (const unsigned l1runs,
+	const unsigned l2runs,
+	mpz_t zvec[],
+	const unsigned long n,
+	unsigned int max)
+{
+  mpf_t V;			/* result */
+  double d_V;			/* result as a double */
+
+  mpf_init (V);
+
+
+  printf ("\nEquidistribution/Frequency test on integers (0<=X<=%u):\n", max);
+  print_x2_table (max, stdout);
+
+  mpz_freqt (V, zvec, max, n);
+
+  d_V = mpf_get_d (V);
+  printf ("V = %.2f (n = %lu)\n", d_V, n);
+
+  mpf_clear (V);
+}
+
+unsigned int stat_debug = 0;
+
+int
+main (argc, argv)
+     int argc;
+     char *argv[];
+{
+  const char usage[] =
+    "usage: stat [-d] [-2 runs] [-i max | -r max] [file]\n" \
+    "       file     filename\n" \
+    "       -2 runs  perform 2-level test with RUNS runs on 1st level\n" \
+    "       -d       increase debugging level\n" \
+    "       -i max   input is integers 0 <= Z <= MAX\n" \
+    "       -r max   input is real numbers 0 <= R < 1 and use MAX as\n" \
+    "                maximum value when converting real numbers to integers\n" \
+    "";
+
+  mpf_t fvec[FVECSIZ];
+  mpz_t zvec[FVECSIZ];
+  unsigned long int f, n, vecentries;
+  char *filen;
+  FILE *fp;
+  int c;
+  int omitoutput = 0;
+  int realinput = -1;		/* 1: input is real numbers 0<=R<1;
+				   0: input is integers 0 <= Z <= MAX. */
+  long l1runs = 0,		/* 1st level runs */
+    l2runs = 1;			/* 2nd level runs */
+  mpf_t f_temp;
+  mpz_t z_imax;			/* max value when converting between
+				   real number and integer. */
+  mpf_t f_imax_plus1;		/* f_imax + 1 stored in an mpf_t for
+				   convenience */
+  mpf_t f_imax_minus1;		/* f_imax - 1 stored in an mpf_t for
+				   convenience */
+
+
+  mpf_init (f_temp);
+  mpz_init_set_ui (z_imax, 0x7fffffff);
+  mpf_init (f_imax_plus1);
+  mpf_init (f_imax_minus1);
+
+  while ((c = getopt (argc, argv, "d2:i:r:")) != -1)
+    switch (c)
+      {
+      case '2':
+	l1runs = atol (optarg);
+	l2runs = -1;		/* set later on */
+	break;
+      case 'd':			/* increase debug level */
+	stat_debug++;
+	break;
+      case 'i':
+	if (1 == realinput)
+	  {
+	    fputs ("stat: options -i and -r are mutually exclusive\n", stderr);
+	    exit (1);
+	  }
+	if (mpz_set_str (z_imax, optarg, 0))
+	  {
+	    fprintf (stderr, "stat: bad max value %s\n", optarg);
+	    exit (1);
+	  }
+	realinput = 0;
+	break;
+      case 'r':
+	if (0 == realinput)
+	  {
+	    fputs ("stat: options -i and -r are mutually exclusive\n", stderr);
+	    exit (1);
+	  }
+	if (mpz_set_str (z_imax, optarg, 0))
+	  {
+	    fprintf (stderr, "stat: bad max value %s\n", optarg);
+	    exit (1);
+	  }
+	realinput = 1;
+	break;
+      case 'o':
+	omitoutput = atoi (optarg);
+	break;
+      case '?':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 1)
+    fp = stdin;
+  else
+    filen = argv[0];
+
+  if (fp != stdin)
+    if (NULL == (fp = fopen (filen, "r")))
+      {
+	perror (filen);
+	exit (1);
+      }
+
+  if (-1 == realinput)
+    realinput = 1;		/* default is real numbers */
+
+  /* read file and fill appropriate vec */
+  if (1 == realinput)		/* real input */
+    {
+      for (f = 0; f < FVECSIZ ; f++)
+	{
+	  mpf_init (fvec[f]);
+	  if (!mpf_inp_str (fvec[f], fp, 10))
+	    break;
+	}
+    }
+  else				/* integer input */
+    {
+      for (f = 0; f < FVECSIZ ; f++)
+	{
+	  mpz_init (zvec[f]);
+	  if (!mpz_inp_str (zvec[f], fp, 10))
+	    break;
+	}
+    }
+  vecentries = n = f;		/* number of entries read */
+  fclose (fp);
+
+  if (FVECSIZ == f)
+    fprintf (stderr, "stat: warning: discarding input due to lazy allocation "\
+	     "of only %ld entries.  sorry.\n", FVECSIZ);
+
+  printf ("Got %lu numbers.\n", n);
+
+  /* convert and fill the other vec */
+  /* since fvec[] contains 0<=f<1 and we want ivec[] to contain
+     0<=z<=imax and we are truncating all fractions when
+     converting float to int, we have to add 1 to imax.*/
+  mpf_set_z (f_imax_plus1, z_imax);
+  mpf_add_ui (f_imax_plus1, f_imax_plus1, 1);
+  if (1 == realinput)		/* fill zvec[] */
+    {
+      for (f = 0; f < n; f++)
+	{
+	  mpf_mul (f_temp, fvec[f], f_imax_plus1);
+	  mpz_init (zvec[f]);
+	  mpz_set_f (zvec[f], f_temp); /* truncating fraction */
+	  if (stat_debug > 1)
+	    {
+	      mpz_out_str (stderr, 10, zvec[f]);
+	      fputs ("\n", stderr);
+	    }
+	}
+    }
+  else				/* integer input; fill fvec[] */
+    {
+      /*    mpf_set_z (f_imax_minus1, z_imax);
+	    mpf_sub_ui (f_imax_minus1, f_imax_minus1, 1);*/
+      for (f = 0; f < n; f++)
+	{
+	  mpf_init (fvec[f]);
+	  mpf_set_z (fvec[f], zvec[f]);
+	  mpf_div (fvec[f], fvec[f], f_imax_plus1);
+	  if (stat_debug > 1)
+	    {
+	      mpf_out_str (stderr, 10, 0, fvec[f]);
+	      fputs ("\n", stderr);
+	    }
+	}
+    }
+
+  /* 2 levels? */
+  if (1 != l2runs)
+    {
+      l2runs = n / l1runs;
+      printf ("Doing %ld second level rounds "\
+	      "with %ld entries in each round", l2runs, l1runs);
+      if (n % l1runs)
+	printf (" (discarding %ld entr%s)", n % l1runs,
+		n % l1runs == 1 ? "y" : "ies");
+      puts (".");
+      n = l1runs;
+    }
+
+#ifndef DONT_FFREQ
+  f_freq (l1runs, l2runs, fvec, n);
+#endif
+#ifdef DO_ZFREQ
+  z_freq (l1runs, l2runs, zvec, n, mpz_get_ui (z_imax));
+#endif
+
+  mpf_clear (f_temp); mpz_clear (z_imax);
+  mpf_clear (f_imax_plus1);
+  mpf_clear (f_imax_minus1);
+  for (f = 0; f < vecentries; f++)
+    {
+      mpf_clear (fvec[f]);
+      mpz_clear (zvec[f]);
+    }
+
+  return 0;
+}
diff --git a/tests/rand/statlib.c b/tests/rand/statlib.c
new file mode 100644
index 0000000..db05380
--- /dev/null
+++ b/tests/rand/statlib.c
@@ -0,0 +1,836 @@
+/* statlib.c -- Statistical functions for testing the randomness of
+   number sequences. */
+
+/*
+Copyright 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* The theories for these functions are taken from D. Knuth's "The Art
+of Computer Programming: Volume 2, Seminumerical Algorithms", Third
+Edition, Addison Wesley, 1998. */
+
+/* Implementation notes.
+
+The Kolmogorov-Smirnov test.
+
+Eq. (13) in Knuth, p. 50, says that if X1, X2, ..., Xn are independent
+observations arranged into ascending order
+
+	Kp = sqr(n) * max(j/n - F(Xj))		for all 1<=j<=n
+	Km = sqr(n) * max(F(Xj) - (j-1)/n))	for all 1<=j<=n
+
+where F(x) = Pr(X <= x) = probability that (X <= x), which for a
+uniformly distributed random real number between zero and one is
+exactly the number itself (x).
+
+
+The answer to exercise 23 gives the following implementation, which
+doesn't need the observations to be sorted in ascending order:
+
+for (k = 0; k < m; k++)
+	a[k] = 1.0
+	b[k] = 0.0
+	c[k] = 0
+
+for (each observation Xj)
+	Y = F(Xj)
+	k = floor (m * Y)
+	a[k] = min (a[k], Y)
+	b[k] = max (b[k], Y)
+	c[k] += 1
+
+	j = 0
+	rp = rm = 0
+	for (k = 0; k < m; k++)
+		if (c[k] > 0)
+			rm = max (rm, a[k] - j/n)
+			j += c[k]
+			rp = max (rp, j/n - b[k])
+
+Kp = sqr (n) * rp
+Km = sqr (n) * rm
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "gmpstat.h"
+
+/* ks (Kp, Km, X, P, n) -- Perform a Kolmogorov-Smirnov test on the N
+   real numbers between zero and one in vector X.  P is the
+   distribution function, called for each entry in X, which should
+   calculate the probability of X being greater than or equal to any
+   number in the sequence.  (For a uniformly distributed sequence of
+   real numbers between zero and one, this is simply equal to X.)  The
+   result is put in Kp and Km.  */
+
+void
+ks (mpf_t Kp,
+    mpf_t Km,
+    mpf_t X[],
+    void (P) (mpf_t, mpf_t),
+    unsigned long int n)
+{
+  mpf_t Kt;			/* temp */
+  mpf_t f_x;
+  mpf_t f_j;			/* j */
+  mpf_t f_jnq;			/* j/n or (j-1)/n */
+  unsigned long int j;
+
+  /* Sort the vector in ascending order. */
+  qsort (X, n, sizeof (__mpf_struct), mpf_cmp);
+
+  /* K-S test. */
+  /*	Kp = sqr(n) * max(j/n - F(Xj))		for all 1<=j<=n
+	Km = sqr(n) * max(F(Xj) - (j-1)/n))	for all 1<=j<=n
+  */
+
+  mpf_init (Kt); mpf_init (f_x); mpf_init (f_j); mpf_init (f_jnq);
+  mpf_set_ui (Kp, 0);  mpf_set_ui (Km, 0);
+  for (j = 1; j <= n; j++)
+    {
+      P (f_x, X[j-1]);
+      mpf_set_ui (f_j, j);
+
+      mpf_div_ui (f_jnq, f_j, n);
+      mpf_sub (Kt, f_jnq, f_x);
+      if (mpf_cmp (Kt, Kp) > 0)
+	mpf_set (Kp, Kt);
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("j=%lu ", j);
+	  printf ("P()="); mpf_out_str (stdout, 10, 2, f_x); printf ("\t");
+
+	  printf ("jnq="); mpf_out_str (stdout, 10, 2, f_jnq); printf (" ");
+	  printf ("diff="); mpf_out_str (stdout, 10, 2, Kt); printf (" ");
+	  printf ("Kp="); mpf_out_str (stdout, 10, 2, Kp); printf ("\t");
+	}
+      mpf_sub_ui (f_j, f_j, 1);
+      mpf_div_ui (f_jnq, f_j, n);
+      mpf_sub (Kt, f_x, f_jnq);
+      if (mpf_cmp (Kt, Km) > 0)
+	mpf_set (Km, Kt);
+
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("jnq="); mpf_out_str (stdout, 10, 2, f_jnq); printf (" ");
+	  printf ("diff="); mpf_out_str (stdout, 10, 2, Kt); printf (" ");
+	  printf ("Km="); mpf_out_str (stdout, 10, 2, Km); printf (" ");
+	  printf ("\n");
+	}
+    }
+  mpf_sqrt_ui (Kt, n);
+  mpf_mul (Kp, Kp, Kt);
+  mpf_mul (Km, Km, Kt);
+
+  mpf_clear (Kt); mpf_clear (f_x); mpf_clear (f_j); mpf_clear (f_jnq);
+}
+
+/* ks_table(val, n) -- calculate probability for Kp/Km less than or
+   equal to VAL with N observations.  See [Knuth section 3.3.1] */
+
+void
+ks_table (mpf_t p, mpf_t val, const unsigned int n)
+{
+  /* We use Eq. (27), Knuth p.58, skipping O(1/n) for simplicity.
+     This shortcut will result in too high probabilities, especially
+     when n is small.
+
+     Pr(Kp(n) <= s) = 1 - pow(e, -2*s^2) * (1 - 2/3*s/sqrt(n) + O(1/n)) */
+
+  /* We have 's' in variable VAL and store the result in P. */
+
+  mpf_t t1, t2;
+
+  mpf_init (t1); mpf_init (t2);
+
+  /* t1 = 1 - 2/3 * s/sqrt(n) */
+  mpf_sqrt_ui (t1, n);
+  mpf_div (t1, val, t1);
+  mpf_mul_ui (t1, t1, 2);
+  mpf_div_ui (t1, t1, 3);
+  mpf_ui_sub (t1, 1, t1);
+
+  /* t2 = pow(e, -2*s^2) */
+#ifndef OLDGMP
+  mpf_pow_ui (t2, val, 2);	/* t2 = s^2 */
+  mpf_set_d (t2, exp (-(2.0 * mpf_get_d (t2))));
+#else
+  /* hmmm, gmp doesn't have pow() for floats.  use doubles. */
+  mpf_set_d (t2, pow (M_E, -(2 * pow (mpf_get_d (val), 2))));
+#endif
+
+  /* p = 1 - t1 * t2 */
+  mpf_mul (t1, t1, t2);
+  mpf_ui_sub (p, 1, t1);
+
+  mpf_clear (t1); mpf_clear (t2);
+}
+
+static double x2_table_X[][7] = {
+  { -2.33, -1.64, -.674, 0.0, 0.674, 1.64, 2.33 }, /* x */
+  { 5.4289, 2.6896, .454276, 0.0, .454276, 2.6896, 5.4289} /* x^2 */
+};
+
+#define _2D3 ((double) .6666666666)
+
+/* x2_table (t, v, n) -- return chi-square table row for V in T[]. */
+void
+x2_table (double t[],
+	  unsigned int v)
+{
+  int f;
+
+
+  /* FIXME: Do a table lookup for v <= 30 since the following formula
+     [Knuth, vol 2, 3.3.1] is only good for v > 30. */
+
+  /* value = v + sqrt(2*v) * X[p] + (2/3) * X[p]^2 - 2/3 + O(1/sqrt(t) */
+  /* NOTE: The O() term is ignored for simplicity. */
+
+  for (f = 0; f < 7; f++)
+      t[f] =
+	v +
+	sqrt (2 * v) * x2_table_X[0][f] +
+	_2D3 * x2_table_X[1][f] - _2D3;
+}
+
+
+/* P(p, x) -- Distribution function.  Calculate the probability of X
+being greater than or equal to any number in the sequence.  For a
+random real number between zero and one given by a uniformly
+distributed random number generator, this is simply equal to X. */
+
+static void
+P (mpf_t p, mpf_t x)
+{
+  mpf_set (p, x);
+}
+
+/* mpf_freqt() -- Frequency test using KS on N real numbers between zero
+   and one.  See [Knuth vol 2, p.61]. */
+void
+mpf_freqt (mpf_t Kp,
+	   mpf_t Km,
+	   mpf_t X[],
+	   const unsigned long int n)
+{
+  ks (Kp, Km, X, P, n);
+}
+
+
+/* The Chi-square test.  Eq. (8) in Knuth vol. 2 says that if Y[]
+   holds the observations and p[] is the probability for.. (to be
+   continued!)
+
+   V = 1/n * sum((s=1 to k) Y[s]^2 / p[s]) - n */
+
+void
+x2 (mpf_t V,			/* result */
+    unsigned long int X[],	/* data */
+    unsigned int k,		/* #of categories */
+    void (P) (mpf_t, unsigned long int, void *), /* probability func */
+    void *x,			/* extra user data passed to P() */
+    unsigned long int n)	/* #of samples */
+{
+  unsigned int f;
+  mpf_t f_t, f_t2;		/* temp floats */
+
+  mpf_init (f_t); mpf_init (f_t2);
+
+
+  mpf_set_ui (V, 0);
+  for (f = 0; f < k; f++)
+    {
+      if (g_debug > DEBUG_2)
+	fprintf (stderr, "%u: P()=", f);
+      mpf_set_ui (f_t, X[f]);
+      mpf_mul (f_t, f_t, f_t);	/* f_t = X[f]^2 */
+      P (f_t2, f, x);		/* f_t2 = Pr(f) */
+      if (g_debug > DEBUG_2)
+	mpf_out_str (stderr, 10, 2, f_t2);
+      mpf_div (f_t, f_t, f_t2);
+      mpf_add (V, V, f_t);
+      if (g_debug > DEBUG_2)
+	{
+	  fprintf (stderr, "\tV=");
+	  mpf_out_str (stderr, 10, 2, V);
+	  fprintf (stderr, "\t");
+	}
+    }
+  if (g_debug > DEBUG_2)
+    fprintf (stderr, "\n");
+  mpf_div_ui (V, V, n);
+  mpf_sub_ui (V, V, n);
+
+  mpf_clear (f_t); mpf_clear (f_t2);
+}
+
+/* Pzf(p, s, x) -- Probability for category S in mpz_freqt().  It's
+   1/d for all S.  X is a pointer to an unsigned int holding 'd'. */
+static void
+Pzf (mpf_t p, unsigned long int s, void *x)
+{
+  mpf_set_ui (p, 1);
+  mpf_div_ui (p, p, *((unsigned int *) x));
+}
+
+/* mpz_freqt(V, X, imax, n) -- Frequency test on integers.  [Knuth,
+   vol 2, 3.3.2].  Keep IMAX low on this one, since we loop from 0 to
+   IMAX.  128 or 256 could be nice.
+
+   X[] must not contain numbers outside the range 0 <= X <= IMAX.
+
+   Return value is number of observations actually used, after
+   discarding entries out of range.
+
+   Since X[] contains integers between zero and IMAX, inclusive, we
+   have IMAX+1 categories.
+
+   Note that N should be at least 5*IMAX.  Result is put in V and can
+   be compared to output from x2_table (v=IMAX). */
+
+unsigned long int
+mpz_freqt (mpf_t V,
+	   mpz_t X[],
+	   unsigned int imax,
+	   const unsigned long int n)
+{
+  unsigned long int *v;		/* result */
+  unsigned int f;
+  unsigned int d;		/* number of categories = imax+1 */
+  unsigned int uitemp;
+  unsigned long int usedn;
+
+
+  d = imax + 1;
+
+  v = (unsigned long int *) calloc (imax + 1, sizeof (unsigned long int));
+  if (NULL == v)
+    {
+      fprintf (stderr, "mpz_freqt(): out of memory\n");
+      exit (1);
+    }
+
+  /* count */
+  usedn = n;			/* actual number of observations */
+  for (f = 0; f < n; f++)
+    {
+      uitemp = mpz_get_ui(X[f]);
+      if (uitemp > imax)	/* sanity check */
+	{
+	  if (g_debug)
+	    fprintf (stderr, "mpz_freqt(): warning: input insanity: %u, "\
+		     "ignored.\n", uitemp);
+	  usedn--;
+	  continue;
+	}
+      v[uitemp]++;
+    }
+
+  if (g_debug > DEBUG_2)
+    {
+      fprintf (stderr, "counts:\n");
+      for (f = 0; f <= imax; f++)
+	fprintf (stderr, "%u:\t%lu\n", f, v[f]);
+    }
+
+  /* chi-square with k=imax+1 and P(x)=1/(imax+1) for all x.*/
+  x2 (V, v, d, Pzf, (void *) &d, usedn);
+
+  free (v);
+  return (usedn);
+}
+
+/* debug dummy to drag in dump funcs */
+void
+foo_debug ()
+{
+  if (0)
+    {
+      mpf_dump (0);
+#ifndef OLDGMP
+      mpz_dump (0);
+#endif
+    }
+}
+
+/* merit (rop, t, v, m) -- calculate merit for spectral test result in
+   dimension T, see Knuth p. 105.  BUGS: Only valid for 2 <= T <=
+   6. */
+void
+merit (mpf_t rop, unsigned int t, mpf_t v, mpz_t m)
+{
+  int f;
+  mpf_t f_m, f_const, f_pi;
+
+  mpf_init (f_m);
+  mpf_set_z (f_m, m);
+  mpf_init_set_d (f_const, M_PI);
+  mpf_init_set_d (f_pi, M_PI);
+
+  switch (t)
+    {
+    case 2:			/* PI */
+      break;
+    case 3:			/* PI * 4/3 */
+      mpf_mul_ui (f_const, f_const, 4);
+      mpf_div_ui (f_const, f_const, 3);
+      break;
+    case 4:			/* PI^2 * 1/2 */
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_div_ui (f_const, f_const, 2);
+      break;
+    case 5:			/* PI^2 * 8/15 */
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_mul_ui (f_const, f_const, 8);
+      mpf_div_ui (f_const, f_const, 15);
+      break;
+    case 6:			/* PI^3 * 1/6 */
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_div_ui (f_const, f_const, 6);
+      break;
+    default:
+      fprintf (stderr,
+	       "spect (merit): can't calculate merit for dimensions > 6\n");
+      mpf_set_ui (f_const, 0);
+      break;
+    }
+
+  /* rop = v^t */
+  mpf_set (rop, v);
+  for (f = 1; f < t; f++)
+    mpf_mul (rop, rop, v);
+  mpf_mul (rop, rop, f_const);
+  mpf_div (rop, rop, f_m);
+
+  mpf_clear (f_m);
+  mpf_clear (f_const);
+  mpf_clear (f_pi);
+}
+
+double
+merit_u (unsigned int t, mpf_t v, mpz_t m)
+{
+  mpf_t rop;
+  double res;
+
+  mpf_init (rop);
+  merit (rop, t, v, m);
+  res = mpf_get_d (rop);
+  mpf_clear (rop);
+  return res;
+}
+
+/* f_floor (rop, op) -- Set rop = floor (op). */
+void
+f_floor (mpf_t rop, mpf_t op)
+{
+  mpz_t z;
+
+  mpz_init (z);
+
+  /* No mpf_floor().  Convert to mpz and back. */
+  mpz_set_f (z, op);
+  mpf_set_z (rop, z);
+
+  mpz_clear (z);
+}
+
+
+/* vz_dot (rop, v1, v2, nelem) -- compute dot product of z-vectors V1,
+   V2.  N is number of elements in vectors V1 and V2. */
+
+void
+vz_dot (mpz_t rop, mpz_t V1[], mpz_t V2[], unsigned int n)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpz_set_ui (rop, 0);
+  while (n--)
+    {
+      mpz_mul (t, V1[n], V2[n]);
+      mpz_add (rop, rop, t);
+    }
+
+  mpz_clear (t);
+}
+
+void
+spectral_test (mpf_t rop[], unsigned int T, mpz_t a, mpz_t m)
+{
+  /* Knuth "Seminumerical Algorithms, Third Edition", section 3.3.4
+     (pp. 101-103). */
+
+  /* v[t] = min { sqrt (x[1]^2 + ... + x[t]^2) |
+     x[1] + a*x[2] + ... + pow (a, t-1) * x[t] is congruent to 0 (mod m) } */
+
+
+  /* Variables. */
+  unsigned int ui_t;
+  unsigned int ui_i, ui_j, ui_k, ui_l;
+  mpf_t f_tmp1, f_tmp2;
+  mpz_t tmp1, tmp2, tmp3;
+  mpz_t U[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
+    V[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
+    X[GMP_SPECT_MAXT],
+    Y[GMP_SPECT_MAXT],
+    Z[GMP_SPECT_MAXT];
+  mpz_t h, hp, r, s, p, pp, q, u, v;
+
+  /* GMP inits. */
+  mpf_init (f_tmp1);
+  mpf_init (f_tmp2);
+  for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++)
+    {
+      for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++)
+	{
+	  mpz_init_set_ui (U[ui_i][ui_j], 0);
+	  mpz_init_set_ui (V[ui_i][ui_j], 0);
+	}
+      mpz_init_set_ui (X[ui_i], 0);
+      mpz_init_set_ui (Y[ui_i], 0);
+      mpz_init (Z[ui_i]);
+    }
+  mpz_init (tmp1);
+  mpz_init (tmp2);
+  mpz_init (tmp3);
+  mpz_init (h);
+  mpz_init (hp);
+  mpz_init (r);
+  mpz_init (s);
+  mpz_init (p);
+  mpz_init (pp);
+  mpz_init (q);
+  mpz_init (u);
+  mpz_init (v);
+
+  /* Implementation inits. */
+  if (T > GMP_SPECT_MAXT)
+    T = GMP_SPECT_MAXT;			/* FIXME: Lazy. */
+
+  /* S1 [Initialize.] */
+  ui_t = 2 - 1;			/* NOTE: `t' in description == ui_t + 1
+				   for easy indexing */
+  mpz_set (h, a);
+  mpz_set (hp, m);
+  mpz_set_ui (p, 1);
+  mpz_set_ui (pp, 0);
+  mpz_set (r, a);
+  mpz_pow_ui (s, a, 2);
+  mpz_add_ui (s, s, 1);		/* s = 1 + a^2 */
+
+  /* S2 [Euclidean step.] */
+  while (1)
+    {
+      if (g_debug > DEBUG_1)
+	{
+	  mpz_mul (tmp1, h, pp);
+	  mpz_mul (tmp2, hp, p);
+	  mpz_sub (tmp1, tmp1, tmp2);
+	  if (mpz_cmpabs (m, tmp1))
+	    {
+	      printf ("***BUG***: h*pp - hp*p = ");
+	      mpz_out_str (stdout, 10, tmp1);
+	      printf ("\n");
+	    }
+	}
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("hp = ");
+	  mpz_out_str (stdout, 10, hp);
+	  printf ("\nh = ");
+	  mpz_out_str (stdout, 10, h);
+	  printf ("\n");
+	  fflush (stdout);
+	}
+
+      if (mpz_sgn (h))
+	mpz_tdiv_q (q, hp, h);	/* q = floor(hp/h) */
+      else
+	mpz_set_ui (q, 1);
+
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("q = ");
+	  mpz_out_str (stdout, 10, q);
+	  printf ("\n");
+	  fflush (stdout);
+	}
+
+      mpz_mul (tmp1, q, h);
+      mpz_sub (u, hp, tmp1);	/* u = hp - q*h */
+
+      mpz_mul (tmp1, q, p);
+      mpz_sub (v, pp, tmp1);	/* v = pp - q*p */
+
+      mpz_pow_ui (tmp1, u, 2);
+      mpz_pow_ui (tmp2, v, 2);
+      mpz_add (tmp1, tmp1, tmp2);
+      if (mpz_cmp (tmp1, s) < 0)
+	{
+	  mpz_set (s, tmp1);	/* s = u^2 + v^2 */
+	  mpz_set (hp, h);	/* hp = h */
+	  mpz_set (h, u);	/* h = u */
+	  mpz_set (pp, p);	/* pp = p */
+	  mpz_set (p, v);	/* p = v */
+	}
+      else
+	break;
+    }
+
+  /* S3 [Compute v2.] */
+  mpz_sub (u, u, h);
+  mpz_sub (v, v, p);
+
+  mpz_pow_ui (tmp1, u, 2);
+  mpz_pow_ui (tmp2, v, 2);
+  mpz_add (tmp1, tmp1, tmp2);
+  if (mpz_cmp (tmp1, s) < 0)
+    {
+      mpz_set (s, tmp1);	/* s = u^2 + v^2 */
+      mpz_set (hp, u);
+      mpz_set (pp, v);
+    }
+  mpf_set_z (f_tmp1, s);
+  mpf_sqrt (rop[ui_t - 1], f_tmp1);
+
+  /* S4 [Advance t.] */
+  mpz_neg (U[0][0], h);
+  mpz_set (U[0][1], p);
+  mpz_neg (U[1][0], hp);
+  mpz_set (U[1][1], pp);
+
+  mpz_set (V[0][0], pp);
+  mpz_set (V[0][1], hp);
+  mpz_neg (V[1][0], p);
+  mpz_neg (V[1][1], h);
+  if (mpz_cmp_ui (pp, 0) > 0)
+    {
+      mpz_neg (V[0][0], V[0][0]);
+      mpz_neg (V[0][1], V[0][1]);
+      mpz_neg (V[1][0], V[1][0]);
+      mpz_neg (V[1][1], V[1][1]);
+    }
+
+  while (ui_t + 1 != T)		/* S4 loop */
+    {
+      ui_t++;
+      mpz_mul (r, a, r);
+      mpz_mod (r, r, m);
+
+      /* Add new row and column to U and V.  They are initialized with
+	 all elements set to zero, so clearing is not necessary. */
+
+      mpz_neg (U[ui_t][0], r); /* U: First col in new row. */
+      mpz_set_ui (U[ui_t][ui_t], 1); /* U: Last col in new row. */
+
+      mpz_set (V[ui_t][ui_t], m); /* V: Last col in new row. */
+
+      /* "Finally, for 1 <= i < t,
+	   set q = round (vi1 * r / m),
+	   vit = vi1*r - q*m,
+	   and Ut=Ut+q*Ui */
+
+      for (ui_i = 0; ui_i < ui_t; ui_i++)
+	{
+	  mpz_mul (tmp1, V[ui_i][0], r); /* tmp1=vi1*r */
+	  zdiv_round (q, tmp1, m); /* q=round(vi1*r/m) */
+	  mpz_mul (tmp2, q, m);	/* tmp2=q*m */
+	  mpz_sub (V[ui_i][ui_t], tmp1, tmp2);
+
+	  for (ui_j = 0; ui_j <= ui_t; ui_j++) /* U[t] = U[t] + q*U[i] */
+	    {
+	      mpz_mul (tmp1, q, U[ui_i][ui_j]);	/* tmp=q*uij */
+	      mpz_add (U[ui_t][ui_j], U[ui_t][ui_j], tmp1); /* utj = utj + q*uij */
+	    }
+	}
+
+      /* s = min (s, zdot (U[t], U[t]) */
+      vz_dot (tmp1, U[ui_t], U[ui_t], ui_t + 1);
+      if (mpz_cmp (tmp1, s) < 0)
+	mpz_set (s, tmp1);
+
+      ui_k = ui_t;
+      ui_j = 0;			/* WARNING: ui_j no longer a temp. */
+
+      /* S5 [Transform.] */
+      if (g_debug > DEBUG_2)
+	printf ("(t, k, j, q1, q2, ...)\n");
+      do
+	{
+	  if (g_debug > DEBUG_2)
+	    printf ("(%u, %u, %u", ui_t + 1, ui_k + 1, ui_j + 1);
+
+	  for (ui_i = 0; ui_i <= ui_t; ui_i++)
+	    {
+	      if (ui_i != ui_j)
+		{
+		  vz_dot (tmp1, V[ui_i], V[ui_j], ui_t + 1); /* tmp1=dot(Vi,Vj). */
+		  mpz_abs (tmp2, tmp1);
+		  mpz_mul_ui (tmp2, tmp2, 2); /* tmp2 = 2*abs(dot(Vi,Vj) */
+		  vz_dot (tmp3, V[ui_j], V[ui_j], ui_t + 1); /* tmp3=dot(Vj,Vj). */
+
+		  if (mpz_cmp (tmp2, tmp3) > 0)
+		    {
+		      zdiv_round (q, tmp1, tmp3); /* q=round(Vi.Vj/Vj.Vj) */
+		      if (g_debug > DEBUG_2)
+			{
+			  printf (", ");
+			  mpz_out_str (stdout, 10, q);
+			}
+
+		      for (ui_l = 0; ui_l <= ui_t; ui_l++)
+			{
+			  mpz_mul (tmp1, q, V[ui_j][ui_l]);
+			  mpz_sub (V[ui_i][ui_l], V[ui_i][ui_l], tmp1); /* Vi=Vi-q*Vj */
+			  mpz_mul (tmp1, q, U[ui_i][ui_l]);
+			  mpz_add (U[ui_j][ui_l], U[ui_j][ui_l], tmp1); /* Uj=Uj+q*Ui */
+			}
+
+		      vz_dot (tmp1, U[ui_j], U[ui_j], ui_t + 1); /* tmp1=dot(Uj,Uj) */
+		      if (mpz_cmp (tmp1, s) < 0) /* s = min(s,dot(Uj,Uj)) */
+			mpz_set (s, tmp1);
+		      ui_k = ui_j;
+		    }
+		  else if (g_debug > DEBUG_2)
+		    printf (", #"); /* 2|Vi.Vj| <= Vj.Vj */
+		}
+	      else if (g_debug > DEBUG_2)
+		printf (", *");	/* i == j */
+	    }
+
+	  if (g_debug > DEBUG_2)
+	    printf (")\n");
+
+	  /* S6 [Advance j.] */
+	  if (ui_j == ui_t)
+	    ui_j = 0;
+	  else
+	    ui_j++;
+	}
+      while (ui_j != ui_k);	/* S5 */
+
+      /* From Knuth p. 104: "The exhaustive search in steps S8-S10
+	 reduces the value of s only rarely." */
+#ifdef DO_SEARCH
+      /* S7 [Prepare for search.] */
+      /* Find minimum in (x[1], ..., x[t]) satisfying condition
+	 x[k]^2 <= f(y[1], ...,y[t]) * dot(V[k],V[k]) */
+
+      ui_k = ui_t;
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("searching...");
+	  /*for (f = 0; f < ui_t*/
+	  fflush (stdout);
+	}
+
+      /* Z[i] = floor (sqrt (floor (dot(V[i],V[i]) * s / m^2))); */
+      mpz_pow_ui (tmp1, m, 2);
+      mpf_set_z (f_tmp1, tmp1);
+      mpf_set_z (f_tmp2, s);
+      mpf_div (f_tmp1, f_tmp2, f_tmp1);	/* f_tmp1 = s/m^2 */
+      for (ui_i = 0; ui_i <= ui_t; ui_i++)
+	{
+	  vz_dot (tmp1, V[ui_i], V[ui_i], ui_t + 1);
+	  mpf_set_z (f_tmp2, tmp1);
+	  mpf_mul (f_tmp2, f_tmp2, f_tmp1);
+	  f_floor (f_tmp2, f_tmp2);
+	  mpf_sqrt (f_tmp2, f_tmp2);
+	  mpz_set_f (Z[ui_i], f_tmp2);
+	}
+
+      /* S8 [Advance X[k].] */
+      do
+	{
+	  if (g_debug > DEBUG_2)
+	    {
+	      printf ("X[%u] = ", ui_k);
+	      mpz_out_str (stdout, 10, X[ui_k]);
+	      printf ("\tZ[%u] = ", ui_k);
+	      mpz_out_str (stdout, 10, Z[ui_k]);
+	      printf ("\n");
+	      fflush (stdout);
+	    }
+
+	  if (mpz_cmp (X[ui_k], Z[ui_k]))
+	    {
+	      mpz_add_ui (X[ui_k], X[ui_k], 1);
+	      for (ui_i = 0; ui_i <= ui_t; ui_i++)
+		mpz_add (Y[ui_i], Y[ui_i], U[ui_k][ui_i]);
+
+	      /* S9 [Advance k.] */
+	      while (++ui_k <= ui_t)
+		{
+		  mpz_neg (X[ui_k], Z[ui_k]);
+		  mpz_mul_ui (tmp1, Z[ui_k], 2);
+		  for (ui_i = 0; ui_i <= ui_t; ui_i++)
+		    {
+		      mpz_mul (tmp2, tmp1, U[ui_k][ui_i]);
+		      mpz_sub (Y[ui_i], Y[ui_i], tmp2);
+		    }
+		}
+	      vz_dot (tmp1, Y, Y, ui_t + 1);
+	      if (mpz_cmp (tmp1, s) < 0)
+		mpz_set (s, tmp1);
+	    }
+	}
+      while (--ui_k);
+#endif /* DO_SEARCH */
+      mpf_set_z (f_tmp1, s);
+      mpf_sqrt (rop[ui_t - 1], f_tmp1);
+#ifdef DO_SEARCH
+      if (g_debug > DEBUG_2)
+	printf ("done.\n");
+#endif /* DO_SEARCH */
+    } /* S4 loop */
+
+  /* Clear GMP variables. */
+
+  mpf_clear (f_tmp1);
+  mpf_clear (f_tmp2);
+  for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++)
+    {
+      for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++)
+	{
+	  mpz_clear (U[ui_i][ui_j]);
+	  mpz_clear (V[ui_i][ui_j]);
+	}
+      mpz_clear (X[ui_i]);
+      mpz_clear (Y[ui_i]);
+      mpz_clear (Z[ui_i]);
+    }
+  mpz_clear (tmp1);
+  mpz_clear (tmp2);
+  mpz_clear (tmp3);
+  mpz_clear (h);
+  mpz_clear (hp);
+  mpz_clear (r);
+  mpz_clear (s);
+  mpz_clear (p);
+  mpz_clear (pp);
+  mpz_clear (q);
+  mpz_clear (u);
+  mpz_clear (v);
+
+  return;
+}
diff --git a/tests/rand/t-iset.c b/tests/rand/t-iset.c
new file mode 100644
index 0000000..884220f
--- /dev/null
+++ b/tests/rand/t-iset.c
@@ -0,0 +1,67 @@
+/* Test gmp_randinit_set.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* expect after a gmp_randinit_set that the new and old generators will
+   produce the same sequence of numbers */
+void
+check_one (const char *name, gmp_randstate_ptr src)
+{
+  gmp_randstate_t dst;
+  mpz_t  sz, dz;
+  int    i;
+
+  gmp_randinit_set (dst, src);
+  mpz_init (sz);
+  mpz_init (dz);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_urandomb (sz, src, 123);
+      mpz_urandomb (dz, dst, 123);
+
+      if (mpz_cmp (sz, dz) != 0)
+        {
+          printf     ("gmp_randinit_set didn't duplicate randstate\n");
+          printf     ("  algorithm: %s\n", name);
+          gmp_printf ("  from src:  %#Zx\n", sz);
+          gmp_printf ("  from dst:  %#Zx\n", dz);
+          abort ();
+        }
+    }
+
+  mpz_clear (sz);
+  mpz_clear (dz);
+  gmp_randclear (dst);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  call_rand_algs (check_one);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/rand/t-lc2exp.c b/tests/rand/t-lc2exp.c
new file mode 100644
index 0000000..c66691d
--- /dev/null
+++ b/tests/rand/t-lc2exp.c
@@ -0,0 +1,216 @@
+/* Exercise the lc2exp random functions.
+
+Copyright 2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* a=0 and c=0 produces zero results always. */
+void
+check_zero (unsigned long m2exp)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c;
+  int              i;
+
+  mpz_init_set_ui (a, 0L);
+  c = 0L;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 5; i++)
+    {
+      mpz_urandomb (a, r, 123L);
+      if (mpz_sgn (a) != 0)
+        {
+          printf ("check_zero m2exp=%lu: didn't get zero\n", m2exp);
+          gmp_printf ("  rand=%#Zx\n", a);
+          abort ();
+        }
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+/* negative a */
+void
+check_nega (void)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c, m2exp;
+  int              i;
+
+  mpz_init (a);
+  mpz_setbit (a, 1000L);
+  mpz_neg (a, a);
+  c = 0L;
+  m2exp = 45L;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 5; i++)
+    {
+      mpz_urandomb (a, r, 123L);
+      if (mpz_sgn (a) != 0)
+        printf ("check_nega m2exp=%lu: didn't get zero\n", m2exp);
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+void
+check_bigc (void)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c, m2exp, bits;
+  int              i;
+
+  mpz_init_set_ui (a, 0L);
+  c = ULONG_MAX;
+  m2exp = 8;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 20; i++)
+    {
+      bits = 123L;
+      mpz_urandomb (a, r, bits);
+      if (mpz_sgn (a) < 0 || mpz_sizeinbase (a, 2) > bits)
+        {
+          printf     ("check_bigc: mpz_urandomb out of range\n");
+          printf     ("   m2exp=%lu\n", m2exp);
+          gmp_printf ("   rand=%#ZX\n", a);
+          gmp_printf ("   sizeinbase2=%u\n", mpz_sizeinbase (a, 2));
+	  abort ();
+        }
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+void
+check_bigc1 (void)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c, m2exp;
+  int              i;
+
+  mpz_init_set_ui (a, 0L);
+  c = ULONG_MAX;
+  m2exp = 2;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_urandomb (a, r, 1L);
+      if (mpz_cmp_ui (a, 1L) != 0)
+        {
+          printf     ("check_bigc1: mpz_urandomb didn't give 1\n");
+          printf     ("   m2exp=%lu\n", m2exp);
+          gmp_printf ("   got rand=%#ZX\n", a);
+          abort ();
+        }
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+/* Checks parameters which triggered an assertion failure in the past.
+   Happened when limbs(a)+limbs(c) < bits_to_limbs(m2exp).  */
+void
+check_bigm (void)
+{
+  gmp_randstate_t rstate;
+  mpz_t a;
+
+  mpz_init_set_ui (a, 5L);
+  gmp_randinit_lc_2exp (rstate, a, 1L, 384L);
+
+  mpz_urandomb (a, rstate, 20L);
+
+  gmp_randclear (rstate);
+  mpz_clear (a);
+}
+
+/* Checks for seeds bigger than the modulus.  */
+void
+check_bigs (void)
+{
+  gmp_randstate_t rstate;
+  mpz_t sd, a;
+  int i;
+
+  mpz_init (sd);
+  mpz_setbit (sd, 300L);
+  mpz_sub_ui (sd, sd, 1L);
+  mpz_clrbit (sd, 13L);
+  mpz_init_set_ui (a, 123456789L);
+
+  gmp_randinit_lc_2exp (rstate, a, 5L, 64L);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_neg (sd, sd);
+      gmp_randseed (rstate, sd);
+      mpz_mul_ui (sd, sd, 7L);
+
+      mpz_urandomb (a, rstate, 80L);
+    }
+
+  gmp_randclear (rstate);
+  mpz_clear (a);
+  mpz_clear (sd);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_zero (2L);
+  check_zero (7L);
+  check_zero (32L);
+  check_zero (64L);
+  check_zero (1000L);
+
+  check_nega ();
+  check_bigc ();
+  check_bigc1 ();
+
+  check_bigm ();
+  check_bigs ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/rand/t-mt.c b/tests/rand/t-mt.c
new file mode 100644
index 0000000..08ba7fc
--- /dev/null
+++ b/tests/rand/t-mt.c
@@ -0,0 +1,82 @@
+/* Test the Mersenne Twister random number generator.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* Test that the sequence without seeding equals the sequence with the
+   default seed.  */
+int
+chk_default_seed (void)
+{
+  gmp_randstate_t r1, r2;
+  mpz_t a, b;
+  int i;
+  int ok = TRUE;
+
+  mpz_init2 (a, 19936L);
+  mpz_init2 (b, 19936L);
+
+  gmp_randinit_mt (r1);
+  gmp_randinit_mt (r2);
+  gmp_randseed_ui (r2, 5489L); /* Must match DEFAULT_SEED in randmt.c */
+  for (i = 0; i < 3; i++)
+    {
+      /* Extract one whole buffer per iteration.  */
+      mpz_urandomb (a, r1, 19936L);
+      mpz_urandomb (b, r2, 19936L);
+      if (mpz_cmp (a, b) != 0)
+	{
+	  ok = FALSE;
+	  printf ("Default seed fails in iteration %d\n", i);
+	  break;
+	}
+    }
+  gmp_randclear (r1);
+  gmp_randclear (r2);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int ok;
+
+  tests_start ();
+
+  ok = chk_default_seed ();
+
+  tests_end ();
+
+  if (ok)
+    return 0; /* pass */
+  else
+    return 1; /* fail */
+}
diff --git a/tests/rand/t-rand.c b/tests/rand/t-rand.c
new file mode 100644
index 0000000..1265a0d
--- /dev/null
+++ b/tests/rand/t-rand.c
@@ -0,0 +1,290 @@
+/* t-rand -- Test random number generators.  */
+
+/*
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp.h"
+
+#define SEED 1
+#define BASE 16
+#define ENTS 10			/* Number of entries in array when
+				   printing.  */
+
+/* These were generated by this very program.  Do not edit!  */
+/* Integers.  */
+const char *z1[ENTS] = {"0", "1", "1", "1", "1", "0", "1", "1", "1", "1"};
+const char *z2[ENTS] = {"0", "3", "1", "3", "3", "0", "3", "3", "3", "1"};
+const char *z3[ENTS] = {"4", "3", "1", "7", "3", "0", "3", "3", "3", "1"};
+const char *z4[ENTS] = {"c", "3", "1", "f", "b", "8", "3", "3", "3", "1"};
+const char *z5[ENTS] = {"1c", "13", "11", "1f", "b", "18", "3", "13", "3", "1"};
+
+const char *z10[ENTS] = {"29c", "213", "f1", "17f", "12b", "178", "383", "d3", "3a3", "281"};
+
+const char *z15[ENTS] = {"29c", "1a13", "74f1", "257f", "592b", "4978", "4783", "7cd3", "5ba3", "4681"};
+const char *z16[ENTS] = {"29c", "9a13", "74f1", "a57f", "d92b", "4978", "c783", "fcd3", "5ba3", "c681"};
+const char *z17[ENTS] = {"51e", "f17a", "54ff", "1a335", "cf65", "5d6f", "583f", "618f", "1bc6", "98ff"};
+
+const char *z31[ENTS] = {"3aecd515", "13ae8ec6", "518c8090", "81ca077", "70b7134", "7ee78d71", "323a7636", "2122cb1a", "19811941", "41fd605"};
+const char *z32[ENTS] = {"baecd515", "13ae8ec6", "518c8090", "881ca077", "870b7134", "7ee78d71", "323a7636", "a122cb1a", "99811941", "841fd605"};
+const char *z33[ENTS] = {"1faf4cca", "15d6ef83b", "9095fe72", "1b6a3dff6", "b17cbddd", "16e5209d4", "6f65b12c", "493bbbc6", "abf2a5d5", "6d491a3c"};
+
+const char *z63[ENTS] = {"48a74f367fa7b5c8", "3ba9e9dc1b263076", "1e0ac84e7678e0fb", "11416581728b3e35", "36ab610523f0f1f7", "3e540e8e95c0eb4b", "439ae16057dbc9d3", "734fb260db243950", "7d3a317effc289bf", "1d80301fb3d1a0d1"};
+const char *z64[ENTS] = {"48a74f367fa7b5c8", "bba9e9dc1b263076", "9e0ac84e7678e0fb", "11416581728b3e35", "b6ab610523f0f1f7", "be540e8e95c0eb4b", "439ae16057dbc9d3", "f34fb260db243950", "fd3a317effc289bf", "1d80301fb3d1a0d1"};
+const char *z65[ENTS] = {"1ff77710d846d49f0", "1b1411701d709ee10", "31ffa81a208b6af4", "446638d431d3c681", "df5c569d5baa8b55", "197d99ea9bf28e5a0", "191ade09edd94cfae", "194acefa6dde5e18d", "1afc1167c56272d92", "d092994da72f206f"};
+
+const char *z127[ENTS] = {"2f66ba932aaf58a071fd8f0742a99a0c", "73cfa3c664c9c1753507ca60ec6b8425", "53ea074ca131dec12cd68b8aa8e20278", "3cf5ac8c343532f8a53cc0eb47581f73", "50c11d5869e208aa1b9aa317b8c2d0a9", "b23163c892876472b1ef19642eace09", "489f4c03d41f87509c8d6c90ce674f95", "2ab8748c96aa6762ea1932b44c9d7164", "98cb5591fc05ad31afbbc1d67b90edd", "77848bb991fd0be331adcf1457fbc672"};
+const char *z128[ENTS] = {"af66ba932aaf58a071fd8f0742a99a0c", "73cfa3c664c9c1753507ca60ec6b8425", "53ea074ca131dec12cd68b8aa8e20278", "3cf5ac8c343532f8a53cc0eb47581f73", "50c11d5869e208aa1b9aa317b8c2d0a9", "8b23163c892876472b1ef19642eace09", "489f4c03d41f87509c8d6c90ce674f95", "aab8748c96aa6762ea1932b44c9d7164", "98cb5591fc05ad31afbbc1d67b90edd", "f7848bb991fd0be331adcf1457fbc672"};
+
+/* Floats.  */
+const char *f1[ENTS] = {"0.@0", "0.8@0", "0.8@0", "0.8@0", "0.8@0", "0.@0", "0.8@0", "0.8@0", "0.8@0", "0.8@0"};
+const char *f2[ENTS] = {"0.@0", "0.c@0", "0.4@0", "0.c@0", "0.c@0", "0.@0", "0.c@0", "0.c@0", "0.c@0", "0.4@0"};
+const char *f3[ENTS] = {"0.8@0", "0.6@0", "0.2@0", "0.e@0", "0.6@0", "0.@0", "0.6@0", "0.6@0", "0.6@0", "0.2@0"};
+const char *f4[ENTS] = {"0.c@0", "0.3@0", "0.1@0", "0.f@0", "0.b@0", "0.8@0", "0.3@0", "0.3@0", "0.3@0", "0.1@0"};
+const char *f5[ENTS] = {"0.e@0", "0.98@0", "0.88@0", "0.f8@0", "0.58@0", "0.c@0", "0.18@0", "0.98@0", "0.18@0", "0.8@-1"};
+
+const char *f10[ENTS] = {"0.a7@0", "0.84c@0", "0.3c4@0", "0.5fc@0", "0.4ac@0", "0.5e@0", "0.e0c@0", "0.34c@0", "0.e8c@0", "0.a04@0"};
+
+const char *f15[ENTS] = {"0.538@-1", "0.3426@0", "0.e9e2@0", "0.4afe@0", "0.b256@0", "0.92f@0", "0.8f06@0", "0.f9a6@0", "0.b746@0", "0.8d02@0"};
+const char *f16[ENTS] = {"0.29c@-1", "0.9a13@0", "0.74f1@0", "0.a57f@0", "0.d92b@0", "0.4978@0", "0.c783@0", "0.fcd3@0", "0.5ba3@0", "0.c681@0"};
+const char *f17[ENTS] = {"0.28f@-1", "0.78bd@0", "0.2a7f8@0", "0.d19a8@0", "0.67b28@0", "0.2eb78@0", "0.2c1f8@0", "0.30c78@0", "0.de3@-1", "0.4c7f8@0"};
+
+const char *f31[ENTS] = {"0.75d9aa2a@0", "0.275d1d8c@0", "0.a319012@0", "0.103940ee@0", "0.e16e268@-1", "0.fdcf1ae2@0", "0.6474ec6c@0", "0.42459634@0", "0.33023282@0", "0.83fac0a@-1"};
+const char *f32[ENTS] = {"0.baecd515@0", "0.13ae8ec6@0", "0.518c809@0", "0.881ca077@0", "0.870b7134@0", "0.7ee78d71@0", "0.323a7636@0", "0.a122cb1a@0", "0.99811941@0", "0.841fd605@0"};
+const char *f33[ENTS] = {"0.fd7a665@-1", "0.aeb77c1d8@0", "0.484aff39@0", "0.db51effb@0", "0.58be5eee8@0", "0.b72904ea@0", "0.37b2d896@0", "0.249ddde3@0", "0.55f952ea8@0", "0.36a48d1e@0"};
+
+const char *f63[ENTS] = {"0.914e9e6cff4f6b9@0", "0.7753d3b8364c60ec@0", "0.3c15909cecf1c1f6@0", "0.2282cb02e5167c6a@0", "0.6d56c20a47e1e3ee@0", "0.7ca81d1d2b81d696@0", "0.8735c2c0afb793a6@0", "0.e69f64c1b64872a@0", "0.fa7462fdff85137e@0", "0.3b00603f67a341a2@0"};
+const char *f64[ENTS] = {"0.48a74f367fa7b5c8@0", "0.bba9e9dc1b263076@0", "0.9e0ac84e7678e0fb@0", "0.11416581728b3e35@0", "0.b6ab610523f0f1f7@0", "0.be540e8e95c0eb4b@0", "0.439ae16057dbc9d3@0", "0.f34fb260db24395@0", "0.fd3a317effc289bf@0", "0.1d80301fb3d1a0d1@0"};
+const char *f65[ENTS] = {"0.ffbbb886c236a4f8@0", "0.d8a08b80eb84f708@0", "0.18ffd40d1045b57a@0", "0.22331c6a18e9e3408@0", "0.6fae2b4eadd545aa8@0", "0.cbeccf54df9472d@0", "0.c8d6f04f6eca67d7@0", "0.ca5677d36ef2f0c68@0", "0.d7e08b3e2b1396c9@0", "0.68494ca6d39790378@0"};
+
+const char *f127[ENTS] = {"0.5ecd7526555eb140e3fb1e0e85533418@0", "0.e79f478cc99382ea6a0f94c1d8d7084a@0", "0.a7d40e994263bd8259ad171551c404f@0", "0.79eb5918686a65f14a7981d68eb03ee6@0", "0.a1823ab0d3c411543735462f7185a152@0", "0.16462c791250ec8e563de32c85d59c12@0", "0.913e9807a83f0ea1391ad9219cce9f2a@0", "0.5570e9192d54cec5d4326568993ae2c8@0", "0.13196ab23f80b5a635f7783acf721dba@0", "0.ef09177323fa17c6635b9e28aff78ce4@0"};
+const char *f128[ENTS] = {"0.af66ba932aaf58a071fd8f0742a99a0c@0", "0.73cfa3c664c9c1753507ca60ec6b8425@0", "0.53ea074ca131dec12cd68b8aa8e20278@0", "0.3cf5ac8c343532f8a53cc0eb47581f73@0", "0.50c11d5869e208aa1b9aa317b8c2d0a9@0", "0.8b23163c892876472b1ef19642eace09@0", "0.489f4c03d41f87509c8d6c90ce674f95@0", "0.aab8748c96aa6762ea1932b44c9d7164@0", "0.98cb5591fc05ad31afbbc1d67b90edd@-1", "0.f7848bb991fd0be331adcf1457fbc672@0"};
+
+
+struct rt
+{
+  const char **s;
+  int nbits;
+};
+
+static struct rt zarr[] =
+{
+  {z1, 1},
+  {z2, 2},
+  {z3, 3},
+  {z4, 4},
+  {z5, 5},
+  {z10, 10},
+  {z15, 15},
+  {z16, 16},
+  {z17, 17},
+  {z31, 31},
+  {z32, 32},
+  {z33, 33},
+  {z63, 63},
+  {z64, 64},
+  {z65, 65},
+  {z127, 127},
+  {z128, 128},
+  {NULL, 0}
+};
+
+static struct rt farr[] =
+{
+  {f1, 1},
+  {f2, 2},
+  {f3, 3},
+  {f4, 4},
+  {f5, 5},
+  {f10, 10},
+  {f15, 15},
+  {f16, 16},
+  {f17, 17},
+  {f31, 31},
+  {f32, 32},
+  {f33, 33},
+  {f63, 63},
+  {f64, 64},
+  {f65, 65},
+  {f127, 127},
+  {f128, 128},
+  {NULL, 0}
+};
+
+
+int
+main (int argc, char *argv[])
+{
+  static char usage[] = "\
+usage: t-rand [function nbits]\n\
+  function is one of z, f\n\
+  nbits is number of bits\n\
+";
+  gmp_randstate_t rstate;
+  mpz_t z, rz;
+  mpf_t f, rf;
+  enum { Z, F } func = Z;
+  int nbits = 1;
+  int verify_mode_flag = 1;
+  int i;
+  struct rt *a;
+
+
+  if (argc > 1)
+    {
+      if (argc < 3)
+	{
+	  fputs (usage, stderr);
+	  exit (1);
+	}
+      verify_mode_flag = 0;
+      if (*argv[1] == 'z')
+	func = Z;
+      if (*argv[1] == 'f')
+	func = F;
+      nbits = atoi (argv[2]);
+    }
+
+  mpz_init (rz);
+
+  if (verify_mode_flag)
+    {
+#ifdef VERBOSE
+      printf ("%s: verifying random numbers: ", argv[0]);
+#endif
+
+      /* Test z.  */
+      mpz_init (z);
+      for (a = zarr; a->s != NULL; a++)
+	{
+	  gmp_randinit (rstate, GMP_RAND_ALG_LC, a->nbits);
+	  if (gmp_errno != GMP_ERROR_NONE)
+	    exit (1);
+	  gmp_randseed_ui (rstate, SEED);
+
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpz_urandomb (rz, rstate, a->nbits);
+	      mpz_set_str (z, a->s[i], BASE);
+	      if (mpz_cmp (z, rz) != 0)
+		{
+		  printf ("z%d: ", a->nbits);
+		  mpz_out_str (stdout, BASE, rz);
+		  printf (" should be ");
+		  mpz_out_str (stdout, BASE, z);
+		  puts ("");
+		  exit (1);
+		}
+	    }
+#ifdef VERBOSE
+	  printf ("z%d ", a->nbits);
+#endif
+	  gmp_randclear (rstate);
+	}
+      mpz_clear (z);
+
+
+      /* Test f.  */
+      for (a = farr; a->s != NULL; a++)
+	{
+	  gmp_randinit (rstate, GMP_RAND_ALG_LC, a->nbits);
+	  if (gmp_errno != GMP_ERROR_NONE)
+	    exit (1);
+	  gmp_randseed_ui (rstate, SEED);
+
+	  mpf_init2 (f, a->nbits);
+	  mpf_init2 (rf, a->nbits);
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpf_urandomb (rf, rstate, a->nbits);
+	      mpf_set_str (f, a->s[i], BASE);
+	      if (mpf_cmp (f, rf) != 0)
+		{
+		  printf ("f%d: ", a->nbits);
+		  mpf_out_str (stdout, BASE, a->nbits, rf);
+		  printf (" should be ");
+		  mpf_out_str (stdout, BASE, a->nbits, f);
+		  puts ("");
+		  exit (1);
+		}
+	    }
+#ifdef VERBOSE
+	  printf ("f%d ", a->nbits);
+#endif
+	  gmp_randclear (rstate);
+	  mpf_clear (f);
+	  mpf_clear (rf);
+	}
+
+#ifdef VERBOSE
+      puts ("");
+#endif
+    }
+  else				/* Print mode.  */
+    {
+      gmp_randinit (rstate, GMP_RAND_ALG_LC, nbits);
+      if (gmp_errno != GMP_ERROR_NONE)
+	exit (1);
+      gmp_randseed_ui (rstate, SEED);
+
+      switch (func)
+	{
+	case Z:
+	  printf ("char *z%d[ENTS] = {", nbits);
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpz_urandomb (rz, rstate, nbits);
+	      printf ("\"");
+	      mpz_out_str (stdout, BASE, rz);
+	      printf ("\"");
+	      if (i != ENTS - 1)
+		printf (", ");
+	    }
+	  printf ("};\n");
+	  printf ("  {z%d, %d},\n", nbits, nbits);
+	  break;
+
+	case F:
+	  printf ("char *f%d[ENTS] = {", nbits);
+	  mpf_init2 (rf, nbits);
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpf_urandomb (rf, rstate, nbits);
+	      printf ("\"");
+	      mpf_out_str (stdout, BASE, nbits, rf);
+	      printf ("\"");
+	      if (i != ENTS - 1)
+		printf (", ");
+	    }
+	  printf ("};\n");
+	  printf ("  {f%d, %d},\n", nbits, nbits);
+	  mpf_clear (rf);
+	  break;
+
+	default:
+	  exit (1);
+	}
+
+      gmp_randclear (rstate);
+    }
+
+  mpz_clear (rz);
+
+  return 0;
+}
diff --git a/tests/rand/t-urbui.c b/tests/rand/t-urbui.c
new file mode 100644
index 0000000..f56f538
--- /dev/null
+++ b/tests/rand/t-urbui.c
@@ -0,0 +1,64 @@
+/* Test gmp_urandomb_ui.
+
+Copyright 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Expect numbers generated by rstate to obey the number of bits requested.
+   No point testing bits==BITS_PER_ULONG, since any return is acceptable in
+   that case.  */
+void
+check_one (const char *name, gmp_randstate_ptr rstate)
+{
+  unsigned long  bits, limit, got;
+  int    i;
+
+  for (bits = 0; bits < BITS_PER_ULONG; bits++)
+    {
+      /* will demand got < limit */
+      limit = (1UL << bits);
+
+      for (i = 0; i < 5; i++)
+        {
+          got = gmp_urandomb_ui (rstate, bits);
+          if (got >= limit)
+            {
+              printf ("Return value out of range:\n");
+              printf ("  algorithm: %s\n", name);
+              printf ("  bits:  %lu\n", bits);
+              printf ("  limit: %#lx\n", limit);
+              printf ("  got:   %#lx\n", got);
+              abort ();
+            }
+        }
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  call_rand_algs (check_one);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/rand/t-urmui.c b/tests/rand/t-urmui.c
new file mode 100644
index 0000000..cc8fedb
--- /dev/null
+++ b/tests/rand/t-urmui.c
@@ -0,0 +1,74 @@
+/* Test gmp_urandomm_ui.
+
+Copyright 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Expect numbers generated by rstate to obey the limit requested. */
+void
+check_one (const char *name, gmp_randstate_ptr rstate)
+{
+  static const unsigned long  n_table[] = {
+    1, 2, 3, 4, 5, 6, 7, 8,
+    123, 456, 789,
+
+    255, 256, 257,
+    1023, 1024, 1025,
+    32767, 32768, 32769,
+
+    ULONG_MAX/2-2, ULONG_MAX/2-1, ULONG_MAX/2, ULONG_MAX/2+1, ULONG_MAX/2+2,
+
+    ULONG_MAX-2, ULONG_MAX-1, ULONG_MAX,
+  };
+
+  unsigned long  got, n;
+  int    i, j;
+
+  for (i = 0; i < numberof (n_table); i++)
+    {
+      n = n_table[i];
+
+      for (j = 0; j < 5; j++)
+        {
+          got = gmp_urandomm_ui (rstate, n);
+          if (got >= n)
+            {
+              printf ("Return value out of range:\n");
+              printf ("  algorithm: %s\n", name);
+              printf ("  n:     %#lx\n", n);
+              printf ("  got:   %#lx\n", got);
+              abort ();
+            }
+        }
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  call_rand_algs (check_one);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/rand/t-urndmm.c b/tests/rand/t-urndmm.c
new file mode 100644
index 0000000..ae700dd
--- /dev/null
+++ b/tests/rand/t-urndmm.c
@@ -0,0 +1,158 @@
+/* Test mpz_urandomm.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+int
+check_params (void)
+{
+  gmp_randstate_t r1, r2;
+  mpz_t a, b, m;
+  int i;
+  int result;
+
+  result = TRUE;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (m);
+
+  if (result)
+    {
+      /* Test the consistency between urandomm and urandomb. */
+      gmp_randinit_default (r1);
+      gmp_randinit_default (r2);
+      gmp_randseed_ui (r1, 85L);
+      gmp_randseed_ui (r2, 85L);
+      mpz_set_ui (m, 0L);
+      mpz_setbit (m, 80L);
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  mpz_urandomb (b, r2, 80L);
+	  if (mpz_cmp (a, b) != 0)
+	    {
+	      result = FALSE;
+	      printf ("mpz_urandomm != mpz_urandomb\n");
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+      gmp_randclear (r2);
+    }
+
+  if (result)
+    {
+      /* Test that mpz_urandomm returns the correct result with a
+	 broken LC.  */
+      mpz_set_ui (a, 0L);
+      gmp_randinit_lc_2exp (r1, a, 0xffL, 8L);
+      mpz_set_ui (m, 5L);
+      /* Warning: This code hangs in gmp 4.1 and below */
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  if (mpz_cmp_ui (a, 2L) != 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("mpz_urandomm returns %Zd instead of 2\n", a);
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+    }
+
+  if (result)
+    {
+      /* Test that the results are always in range for either
+         positive or negative values of m.  */
+      gmp_randinit_default (r1);
+      mpz_set_ui (m, 5L);
+      mpz_set_si (b, -5L);
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  if (mpz_cmp_ui (a, 5L) >= 0 || mpz_sgn (a) < 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("Out-of-range or non-positive value: %Zd\n", a);
+	      break;
+	    }
+	  mpz_urandomm (a, r1, b);
+	  if (mpz_cmp_ui (a, 5L) >= 0 || mpz_sgn (a) < 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("Out-of-range or non-positive value (from negative modulus): %Zd\n", a);
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+    }
+
+  if (result)
+    {
+      /* Test that m=1 forces always result=0.  */
+      gmp_randinit_default (r1);
+      mpz_set_ui (m, 1L);
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  if (mpz_sgn (a) != 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("mpz_urandomm fails with m=1 (result=%Zd)\n", a);
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (m);
+  return result;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int result = TRUE;
+
+  tests_start ();
+
+  if (result)
+    if (!check_params ())
+      result = FALSE;
+
+  tests_end ();
+
+  if (result)
+    return 0; /* pass */
+  else
+    return 1; /* fail */
+}
diff --git a/tests/rand/zdiv_round.c b/tests/rand/zdiv_round.c
new file mode 100644
index 0000000..e42e694
--- /dev/null
+++ b/tests/rand/zdiv_round.c
@@ -0,0 +1,43 @@
+/* zdiv_round() -- divide integers, round to nearest */
+
+/*
+Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+void
+zdiv_round (mpz_t rop, mpz_t n, mpz_t d)
+{
+  mpf_t f_n, f_d;
+
+  mpf_init (f_n);
+  mpf_init (f_d);
+
+  mpf_set_z (f_d, d);
+  mpf_set_z (f_n, n);
+
+  mpf_div (f_n, f_n, f_d);
+  mpf_set_d (f_d, .5);
+  if (mpf_sgn (f_n) < 0)
+    mpf_neg (f_d, f_d);
+  mpf_add (f_n, f_n, f_d);
+  mpz_set_f (rop, f_n);
+
+  mpf_clear (f_n);
+  mpf_clear (f_d);
+  return;
+}
diff --git a/tests/refmpf.c b/tests/refmpf.c
new file mode 100644
index 0000000..bc955a5
--- /dev/null
+++ b/tests/refmpf.c
@@ -0,0 +1,427 @@
+/* Reference floating point routines.
+
+Copyright 1996, 2001, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+refmpf_add (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_size_t hi, lo, size;
+  mp_ptr ut, vt, wt;
+  int neg;
+  mp_exp_t exp;
+  mp_limb_t cy;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (SIZ (u) == 0)
+    {
+      size = ABSIZ (v);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (v), size);
+      exp = EXP (v);
+      neg = SIZ (v) < 0;
+      goto done;
+    }
+  if (SIZ (v) == 0)
+    {
+      size = ABSIZ (u);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (u), size);
+      exp = EXP (u);
+      neg = SIZ (u) < 0;
+      goto done;
+    }
+  if ((SIZ (u) ^ SIZ (v)) < 0)
+    {
+      mpf_t tmp;
+      SIZ (tmp) = -SIZ (v);
+      EXP (tmp) = EXP (v);
+      PTR (tmp) = PTR (v);
+      refmpf_sub (w, u, tmp);
+      return;
+    }
+  neg = SIZ (u) < 0;
+
+  /* Compute the significance of the hi and lo end of the result.  */
+  hi = MAX (EXP (u), EXP (v));
+  lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
+  size = hi - lo;
+  ut = TMP_ALLOC_LIMBS (size + 1);
+  vt = TMP_ALLOC_LIMBS (size + 1);
+  wt = TMP_ALLOC_LIMBS (size + 1);
+  MPN_ZERO (ut, size);
+  MPN_ZERO (vt, size);
+  {int off;
+  off = size + (EXP (u) - hi) - ABSIZ (u);
+  MPN_COPY (ut + off, PTR (u), ABSIZ (u));
+  off = size + (EXP (v) - hi) - ABSIZ (v);
+  MPN_COPY (vt + off, PTR (v), ABSIZ (v));
+  }
+
+  cy = mpn_add_n (wt, ut, vt, size);
+  wt[size] = cy;
+  size += cy;
+  exp = hi + cy;
+
+done:
+  if (size > PREC (w))
+    {
+      wt += size - PREC (w);
+      size = PREC (w);
+    }
+  MPN_COPY (PTR (w), wt, size);
+  SIZ (w) = neg == 0 ? size : -size;
+  EXP (w) = exp;
+  TMP_FREE;
+}
+
+
+/* Add 1 "unit in last place" (ie. in the least significant limb) to f.
+   f cannot be zero, since that has no well-defined "last place".
+
+   This routine is designed for use in cases where we pay close attention to
+   the size of the data value and are using that (and the exponent) to
+   indicate the accurate part of a result, or similar.  For this reason, if
+   there's a carry out we don't store 1 and adjust the exponent, we just
+   leave 100..00.  We don't even adjust if there's a carry out of prec+1
+   limbs, but instead give up in that case (which we intend shouldn't arise
+   in normal circumstances).  */
+
+void
+refmpf_add_ulp (mpf_ptr f)
+{
+  mp_ptr     fp = PTR(f);
+  mp_size_t  fsize = SIZ(f);
+  mp_size_t  abs_fsize = ABSIZ(f);
+  mp_limb_t  c;
+
+  if (fsize == 0)
+    {
+      printf ("Oops, refmpf_add_ulp called with f==0\n");
+      abort ();
+    }
+
+  c = refmpn_add_1 (fp, fp, abs_fsize, CNST_LIMB(1));
+  if (c != 0)
+    {
+      if (abs_fsize >= PREC(f) + 1)
+        {
+          printf ("Oops, refmpf_add_ulp carried out of prec+1 limbs\n");
+          abort ();
+        }
+
+      fp[abs_fsize] = c;
+      abs_fsize++;
+      SIZ(f) = (fsize > 0 ? abs_fsize : - abs_fsize);
+      EXP(f)++;
+    }
+}
+
+/* Fill f with size limbs of the given value, setup as an integer. */
+void
+refmpf_fill (mpf_ptr f, mp_size_t size, mp_limb_t value)
+{
+  ASSERT (size >= 0);
+  size = MIN (PREC(f) + 1, size);
+  SIZ(f) = size;
+  EXP(f) = size;
+  refmpn_fill (PTR(f), size, value);
+}
+
+/* Strip high zero limbs from the f data, adjusting exponent accordingly. */
+void
+refmpf_normalize (mpf_ptr f)
+{
+  while (SIZ(f) != 0 && PTR(f)[ABSIZ(f)-1] == 0)
+    {
+      SIZ(f) = (SIZ(f) >= 0 ? SIZ(f)-1 : SIZ(f)+1);
+      EXP(f) --;
+    }
+  if (SIZ(f) == 0)
+    EXP(f) = 0;
+}
+
+/* refmpf_set_overlap sets up dst as a copy of src, but with PREC(dst)
+   unchanged, in preparation for an overlap test.
+
+   The full value of src is copied, and the space at PTR(dst) is extended as
+   necessary.  The way PREC(dst) is unchanged is as per an mpf_set_prec_raw.
+   The return value is the new PTR(dst) space precision, in bits, ready for
+   a restoring mpf_set_prec_raw before mpf_clear.  */
+
+unsigned long
+refmpf_set_overlap (mpf_ptr dst, mpf_srcptr src)
+{
+  mp_size_t  dprec = PREC(dst);
+  mp_size_t  ssize = ABSIZ(src);
+  unsigned long  ret;
+
+  refmpf_set_prec_limbs (dst, (unsigned long) MAX (dprec, ssize));
+  mpf_set (dst, src);
+
+  ret = mpf_get_prec (dst);
+  PREC(dst) = dprec;
+  return ret;
+}
+
+/* Like mpf_set_prec, but taking a precision in limbs.
+   PREC(f) ends up as the given "prec" value.  */
+void
+refmpf_set_prec_limbs (mpf_ptr f, unsigned long prec)
+{
+  mpf_set_prec (f, __GMPF_PREC_TO_BITS (prec));
+}
+
+
+void
+refmpf_sub (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_size_t hi, lo, size;
+  mp_ptr ut, vt, wt;
+  int neg;
+  mp_exp_t exp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (SIZ (u) == 0)
+    {
+      size = ABSIZ (v);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (v), size);
+      exp = EXP (v);
+      neg = SIZ (v) > 0;
+      goto done;
+    }
+  if (SIZ (v) == 0)
+    {
+      size = ABSIZ (u);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (u), size);
+      exp = EXP (u);
+      neg = SIZ (u) < 0;
+      goto done;
+    }
+  if ((SIZ (u) ^ SIZ (v)) < 0)
+    {
+      mpf_t tmp;
+      SIZ (tmp) = -SIZ (v);
+      EXP (tmp) = EXP (v);
+      PTR (tmp) = PTR (v);
+      refmpf_add (w, u, tmp);
+      if (SIZ (u) < 0)
+	mpf_neg (w, w);
+      return;
+    }
+  neg = SIZ (u) < 0;
+
+  /* Compute the significance of the hi and lo end of the result.  */
+  hi = MAX (EXP (u), EXP (v));
+  lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
+  size = hi - lo;
+  ut = TMP_ALLOC_LIMBS (size + 1);
+  vt = TMP_ALLOC_LIMBS (size + 1);
+  wt = TMP_ALLOC_LIMBS (size + 1);
+  MPN_ZERO (ut, size);
+  MPN_ZERO (vt, size);
+  {int off;
+  off = size + (EXP (u) - hi) - ABSIZ (u);
+  MPN_COPY (ut + off, PTR (u), ABSIZ (u));
+  off = size + (EXP (v) - hi) - ABSIZ (v);
+  MPN_COPY (vt + off, PTR (v), ABSIZ (v));
+  }
+
+  if (mpn_cmp (ut, vt, size) >= 0)
+    mpn_sub_n (wt, ut, vt, size);
+  else
+    {
+      mpn_sub_n (wt, vt, ut, size);
+      neg ^= 1;
+    }
+  exp = hi;
+  while (size != 0 && wt[size - 1] == 0)
+    {
+      size--;
+      exp--;
+    }
+
+done:
+  if (size > PREC (w))
+    {
+      wt += size - PREC (w);
+      size = PREC (w);
+    }
+  MPN_COPY (PTR (w), wt, size);
+  SIZ (w) = neg == 0 ? size : -size;
+  EXP (w) = exp;
+  TMP_FREE;
+}
+
+
+/* Validate got by comparing to want.  Return 1 if good, 0 if bad.
+
+   The data in got is compared to that in want, up to either PREC(got) limbs
+   or the size of got, whichever is bigger.  Clearly we always demand
+   PREC(got) of accuracy, but we go further and say that if got is bigger
+   then any extra must be correct too.
+
+   want needs to have enough data to allow this comparison.  The size in
+   want doesn't have to be that big though, if it's smaller then further low
+   limbs are taken to be zero.
+
+   This validation approach is designed to allow some flexibility in exactly
+   how much data is generated by an mpf function, ie. either prec or prec+1
+   limbs.  We don't try to make a reference function that emulates that same
+   size decision, instead the idea is for a validation function to generate
+   at least as much data as the real function, then compare.  */
+
+int
+refmpf_validate (const char *name, mpf_srcptr got, mpf_srcptr want)
+{
+  int  bad = 0;
+  mp_size_t  gsize, wsize, cmpsize, i;
+  mp_srcptr  gp, wp;
+  mp_limb_t  glimb, wlimb;
+
+  MPF_CHECK_FORMAT (got);
+
+  if (EXP (got) != EXP (want))
+    {
+      printf ("%s: wrong exponent\n", name);
+      bad = 1;
+    }
+
+  gsize = SIZ (got);
+  wsize = SIZ (want);
+  if ((gsize < 0 && wsize > 0) || (gsize > 0 && wsize < 0))
+    {
+      printf ("%s: wrong sign\n", name);
+      bad = 1;
+    }
+
+  gsize = ABS (gsize);
+  wsize = ABS (wsize);
+
+  /* most significant limb of respective data */
+  gp = PTR (got) + gsize - 1;
+  wp = PTR (want) + wsize - 1;
+
+  /* compare limb data */
+  cmpsize = MAX (PREC (got), gsize);
+  for (i = 0; i < cmpsize; i++)
+    {
+      glimb = (i < gsize ? gp[-i] : 0);
+      wlimb = (i < wsize ? wp[-i] : 0);
+
+      if (glimb != wlimb)
+        {
+          printf ("%s: wrong data starting at index %ld from top\n",
+                  name, (long) i);
+          bad = 1;
+          break;
+        }
+    }
+
+  if (bad)
+    {
+      printf ("  prec       %d\n", PREC(got));
+      printf ("  exp got    %ld\n", (long) EXP(got));
+      printf ("  exp want   %ld\n", (long) EXP(want));
+      printf ("  size got   %d\n", SIZ(got));
+      printf ("  size want  %d\n", SIZ(want));
+      printf ("  limbs (high to low)\n");
+      printf ("   got  ");
+      for (i = ABSIZ(got)-1; i >= 0; i--)
+        {
+          gmp_printf ("%MX", PTR(got)[i]);
+          if (i != 0)
+            printf (",");
+        }
+      printf ("\n");
+      printf ("   want ");
+      for (i = ABSIZ(want)-1; i >= 0; i--)
+        {
+          gmp_printf ("%MX", PTR(want)[i]);
+          if (i != 0)
+            printf (",");
+        }
+      printf ("\n");
+      return 0;
+    }
+
+  return 1;
+}
+
+
+int
+refmpf_validate_division (const char *name, mpf_srcptr got,
+                          mpf_srcptr n, mpf_srcptr d)
+{
+  mp_size_t  nsize, dsize, sign, prec, qsize, tsize;
+  mp_srcptr  np, dp;
+  mp_ptr     tp, qp, rp;
+  mpf_t      want;
+  int        ret;
+
+  nsize = SIZ (n);
+  dsize = SIZ (d);
+  ASSERT_ALWAYS (dsize != 0);
+
+  sign = nsize ^ dsize;
+  nsize = ABS (nsize);
+  dsize = ABS (dsize);
+
+  np = PTR (n);
+  dp = PTR (d);
+  prec = PREC (got);
+
+  EXP (want) = EXP (n) - EXP (d) + 1;
+
+  qsize = prec + 2;            /* at least prec+1 limbs, after high zero */
+  tsize = qsize + dsize - 1;   /* dividend size to give desired qsize */
+
+  /* dividend n, extended or truncated */
+  tp = refmpn_malloc_limbs (tsize);
+  refmpn_copy_extend (tp, tsize, np, nsize);
+
+  qp = refmpn_malloc_limbs (qsize);
+  rp = refmpn_malloc_limbs (dsize);  /* remainder, unused */
+
+  ASSERT_ALWAYS (qsize == tsize - dsize + 1);
+  refmpn_tdiv_qr (qp, rp, (mp_size_t) 0, tp, tsize, dp, dsize);
+
+  PTR (want) = qp;
+  SIZ (want) = (sign >= 0 ? qsize : -qsize);
+  refmpf_normalize (want);
+
+  ret = refmpf_validate (name, got, want);
+
+  free (tp);
+  free (qp);
+  free (rp);
+
+  return ret;
+}
diff --git a/tests/refmpn.c b/tests/refmpn.c
new file mode 100644
index 0000000..42bb411
--- /dev/null
+++ b/tests/refmpn.c
@@ -0,0 +1,2630 @@
+/* Reference mpn functions, designed to be simple, portable and independent
+   of the normal gmp code.  Speed isn't a consideration.
+
+Copyright 1996-2009, 2011-2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Most routines have assertions representing what the mpn routines are
+   supposed to accept.  Many of these reference routines do sensible things
+   outside these ranges (eg. for size==0), but the assertions are present to
+   pick up bad parameters passed here that are about to be passed the same
+   to a real mpn routine being compared.  */
+
+/* always do assertion checking */
+#define WANT_ASSERT  1
+
+#include <stdio.h>  /* for NULL */
+#include <stdlib.h> /* for malloc */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "tests.h"
+
+
+
+/* Return non-zero if regions {xp,xsize} and {yp,ysize} overlap, with sizes
+   in bytes. */
+int
+byte_overlap_p (const void *v_xp, mp_size_t xsize,
+		const void *v_yp, mp_size_t ysize)
+{
+  const char *xp = (const char *) v_xp;
+  const char *yp = (const char *) v_yp;
+
+  ASSERT (xsize >= 0);
+  ASSERT (ysize >= 0);
+
+  /* no wraparounds */
+  ASSERT (xp+xsize >= xp);
+  ASSERT (yp+ysize >= yp);
+
+  if (xp + xsize <= yp)
+    return 0;
+
+  if (yp + ysize <= xp)
+    return 0;
+
+  return 1;
+}
+
+/* Return non-zero if limb regions {xp,xsize} and {yp,ysize} overlap. */
+int
+refmpn_overlap_p (mp_srcptr xp, mp_size_t xsize, mp_srcptr yp, mp_size_t ysize)
+{
+  return byte_overlap_p (xp, xsize * GMP_LIMB_BYTES,
+			 yp, ysize * GMP_LIMB_BYTES);
+}
+
+/* Check overlap for a routine defined to work low to high. */
+int
+refmpn_overlap_low_to_high_p (mp_srcptr dst, mp_srcptr src, mp_size_t size)
+{
+  return (dst <= src || ! refmpn_overlap_p (dst, size, src, size));
+}
+
+/* Check overlap for a routine defined to work high to low. */
+int
+refmpn_overlap_high_to_low_p (mp_srcptr dst, mp_srcptr src, mp_size_t size)
+{
+  return (dst >= src || ! refmpn_overlap_p (dst, size, src, size));
+}
+
+/* Check overlap for a standard routine requiring equal or separate. */
+int
+refmpn_overlap_fullonly_p (mp_srcptr dst, mp_srcptr src, mp_size_t size)
+{
+  return (dst == src || ! refmpn_overlap_p (dst, size, src, size));
+}
+int
+refmpn_overlap_fullonly_two_p (mp_srcptr dst, mp_srcptr src1, mp_srcptr src2,
+			       mp_size_t size)
+{
+  return (refmpn_overlap_fullonly_p (dst, src1, size)
+	  && refmpn_overlap_fullonly_p (dst, src2, size));
+}
+
+
+mp_ptr
+refmpn_malloc_limbs (mp_size_t size)
+{
+  mp_ptr  p;
+  ASSERT (size >= 0);
+  if (size == 0)
+    size = 1;
+  p = (mp_ptr) malloc ((size_t) (size * GMP_LIMB_BYTES));
+  ASSERT (p != NULL);
+  return p;
+}
+
+/* Free limbs allocated by refmpn_malloc_limbs. NOTE: Can't free
+ * memory allocated by refmpn_malloc_limbs_aligned. */
+void
+refmpn_free_limbs (mp_ptr p)
+{
+  free (p);
+}
+
+mp_ptr
+refmpn_memdup_limbs (mp_srcptr ptr, mp_size_t size)
+{
+  mp_ptr  p;
+  p = refmpn_malloc_limbs (size);
+  refmpn_copyi (p, ptr, size);
+  return p;
+}
+
+/* malloc n limbs on a multiple of m bytes boundary */
+mp_ptr
+refmpn_malloc_limbs_aligned (mp_size_t n, size_t m)
+{
+  return (mp_ptr) align_pointer (refmpn_malloc_limbs (n + m-1), m);
+}
+
+
+void
+refmpn_fill (mp_ptr ptr, mp_size_t size, mp_limb_t value)
+{
+  mp_size_t  i;
+  ASSERT (size >= 0);
+  for (i = 0; i < size; i++)
+    ptr[i] = value;
+}
+
+void
+refmpn_zero (mp_ptr ptr, mp_size_t size)
+{
+  refmpn_fill (ptr, size, CNST_LIMB(0));
+}
+
+void
+refmpn_zero_extend (mp_ptr ptr, mp_size_t oldsize, mp_size_t newsize)
+{
+  ASSERT (newsize >= oldsize);
+  refmpn_zero (ptr+oldsize, newsize-oldsize);
+}
+
+int
+refmpn_zero_p (mp_srcptr ptr, mp_size_t size)
+{
+  mp_size_t  i;
+  for (i = 0; i < size; i++)
+    if (ptr[i] != 0)
+      return 0;
+  return 1;
+}
+
+mp_size_t
+refmpn_normalize (mp_srcptr ptr, mp_size_t size)
+{
+  ASSERT (size >= 0);
+  while (size > 0 && ptr[size-1] == 0)
+    size--;
+  return size;
+}
+
+/* the highest one bit in x */
+mp_limb_t
+refmpn_msbone (mp_limb_t x)
+{
+  mp_limb_t  n = (mp_limb_t) 1 << (GMP_LIMB_BITS-1);
+
+  while (n != 0)
+    {
+      if (x & n)
+	break;
+      n >>= 1;
+    }
+  return n;
+}
+
+/* a mask of the highest one bit plus and all bits below */
+mp_limb_t
+refmpn_msbone_mask (mp_limb_t x)
+{
+  if (x == 0)
+    return 0;
+
+  return (refmpn_msbone (x) << 1) - 1;
+}
+
+/* How many digits in the given base will fit in a limb.
+   Notice that the product b is allowed to be equal to the limit
+   2^GMP_NUMB_BITS, this ensures the result for base==2 will be
+   GMP_NUMB_BITS (and similarly other powers of 2).  */
+int
+refmpn_chars_per_limb (int base)
+{
+  mp_limb_t  limit[2], b[2];
+  int        chars_per_limb;
+
+  ASSERT (base >= 2);
+
+  limit[0] = 0;  /* limit = 2^GMP_NUMB_BITS */
+  limit[1] = 1;
+  b[0] = 1;      /* b = 1 */
+  b[1] = 0;
+
+  chars_per_limb = 0;
+  for (;;)
+    {
+      if (refmpn_mul_1 (b, b, (mp_size_t) 2, (mp_limb_t) base))
+	break;
+      if (refmpn_cmp (b, limit, (mp_size_t) 2) > 0)
+	break;
+      chars_per_limb++;
+    }
+  return chars_per_limb;
+}
+
+/* The biggest value base**n which fits in GMP_NUMB_BITS. */
+mp_limb_t
+refmpn_big_base (int base)
+{
+  int        chars_per_limb = refmpn_chars_per_limb (base);
+  int        i;
+  mp_limb_t  bb;
+
+  ASSERT (base >= 2);
+  bb = 1;
+  for (i = 0; i < chars_per_limb; i++)
+    bb *= base;
+  return bb;
+}
+
+
+void
+refmpn_setbit (mp_ptr ptr, unsigned long bit)
+{
+  ptr[bit/GMP_NUMB_BITS] |= CNST_LIMB(1) << (bit%GMP_NUMB_BITS);
+}
+
+void
+refmpn_clrbit (mp_ptr ptr, unsigned long bit)
+{
+  ptr[bit/GMP_NUMB_BITS] &= ~ (CNST_LIMB(1) << (bit%GMP_NUMB_BITS));
+}
+
+#define REFMPN_TSTBIT(ptr,bit) \
+  (((ptr)[(bit)/GMP_NUMB_BITS] & (CNST_LIMB(1) << ((bit)%GMP_NUMB_BITS))) != 0)
+
+int
+refmpn_tstbit (mp_srcptr ptr, unsigned long bit)
+{
+  return REFMPN_TSTBIT (ptr, bit);
+}
+
+unsigned long
+refmpn_scan0 (mp_srcptr ptr, unsigned long bit)
+{
+  while (REFMPN_TSTBIT (ptr, bit) != 0)
+    bit++;
+  return bit;
+}
+
+unsigned long
+refmpn_scan1 (mp_srcptr ptr, unsigned long bit)
+{
+  while (REFMPN_TSTBIT (ptr, bit) == 0)
+    bit++;
+  return bit;
+}
+
+void
+refmpn_copy (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));
+  refmpn_copyi (rp, sp, size);
+}
+
+void
+refmpn_copyi (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  mp_size_t i;
+
+  ASSERT (refmpn_overlap_low_to_high_p (rp, sp, size));
+  ASSERT (size >= 0);
+
+  for (i = 0; i < size; i++)
+    rp[i] = sp[i];
+}
+
+void
+refmpn_copyd (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  mp_size_t i;
+
+  ASSERT (refmpn_overlap_high_to_low_p (rp, sp, size));
+  ASSERT (size >= 0);
+
+  for (i = size-1; i >= 0; i--)
+    rp[i] = sp[i];
+}
+
+/* Copy {xp,xsize} to {wp,wsize}.  If x is shorter, then pad w with low
+   zeros to wsize.  If x is longer, then copy just the high wsize limbs.  */
+void
+refmpn_copy_extend (mp_ptr wp, mp_size_t wsize, mp_srcptr xp, mp_size_t xsize)
+{
+  ASSERT (wsize >= 0);
+  ASSERT (xsize >= 0);
+
+  /* high part of x if x bigger than w */
+  if (xsize > wsize)
+    {
+      xp += xsize - wsize;
+      xsize = wsize;
+    }
+
+  refmpn_copy (wp + wsize-xsize, xp, xsize);
+  refmpn_zero (wp, wsize-xsize);
+}
+
+int
+refmpn_cmp (mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+  ASSERT_MPN (xp, size);
+  ASSERT_MPN (yp, size);
+
+  for (i = size-1; i >= 0; i--)
+    {
+      if (xp[i] > yp[i])  return 1;
+      if (xp[i] < yp[i])  return -1;
+    }
+  return 0;
+}
+
+int
+refmpn_cmp_allowzero (mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  if (size == 0)
+    return 0;
+  else
+    return refmpn_cmp (xp, yp, size);
+}
+
+int
+refmpn_cmp_twosizes (mp_srcptr xp, mp_size_t xsize,
+		     mp_srcptr yp, mp_size_t ysize)
+{
+  int  opp, cmp;
+
+  ASSERT_MPN (xp, xsize);
+  ASSERT_MPN (yp, ysize);
+
+  opp = (xsize < ysize);
+  if (opp)
+    MPN_SRCPTR_SWAP (xp,xsize, yp,ysize);
+
+  if (! refmpn_zero_p (xp+ysize, xsize-ysize))
+    cmp = 1;
+  else
+    cmp = refmpn_cmp (xp, yp, ysize);
+
+  return (opp ? -cmp : cmp);
+}
+
+int
+refmpn_equal_anynail (mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_size_t  i;
+  ASSERT (size >= 0);
+
+  for (i = 0; i < size; i++)
+      if (xp[i] != yp[i])
+	return 0;
+  return 1;
+}
+
+
+#define LOGOPS(operation)                                               \
+  {                                                                     \
+    mp_size_t  i;                                                       \
+									\
+    ASSERT (refmpn_overlap_fullonly_two_p (rp, s1p, s2p, size));        \
+    ASSERT (size >= 1);                                                 \
+    ASSERT_MPN (s1p, size);                                             \
+    ASSERT_MPN (s2p, size);                                             \
+									\
+    for (i = 0; i < size; i++)                                          \
+      rp[i] = operation;                                                \
+  }
+
+void
+refmpn_and_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] & s2p[i]);
+}
+void
+refmpn_andn_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] & ~s2p[i]);
+}
+void
+refmpn_nand_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS ((s1p[i] & s2p[i]) ^ GMP_NUMB_MASK);
+}
+void
+refmpn_ior_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] | s2p[i]);
+}
+void
+refmpn_iorn_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] | (s2p[i] ^ GMP_NUMB_MASK));
+}
+void
+refmpn_nior_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS ((s1p[i] | s2p[i]) ^ GMP_NUMB_MASK);
+}
+void
+refmpn_xor_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] ^ s2p[i]);
+}
+void
+refmpn_xnor_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS ((s1p[i] ^ s2p[i]) ^ GMP_NUMB_MASK);
+}
+
+
+/* set *dh,*dl to mh:ml - sh:sl, in full limbs */
+void
+refmpn_sub_ddmmss (mp_limb_t *dh, mp_limb_t *dl,
+		   mp_limb_t mh, mp_limb_t ml, mp_limb_t sh, mp_limb_t sl)
+{
+  *dl = ml - sl;
+  *dh = mh - sh - (ml < sl);
+}
+
+
+/* set *w to x+y, return 0 or 1 carry */
+mp_limb_t
+ref_addc_limb (mp_limb_t *w, mp_limb_t x, mp_limb_t y)
+{
+  mp_limb_t  sum, cy;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+
+  sum = x + y;
+#if GMP_NAIL_BITS == 0
+  *w = sum;
+  cy = (sum < x);
+#else
+  *w = sum & GMP_NUMB_MASK;
+  cy = (sum >> GMP_NUMB_BITS);
+#endif
+  return cy;
+}
+
+/* set *w to x-y, return 0 or 1 borrow */
+mp_limb_t
+ref_subc_limb (mp_limb_t *w, mp_limb_t x, mp_limb_t y)
+{
+  mp_limb_t  diff, cy;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+
+  diff = x - y;
+#if GMP_NAIL_BITS == 0
+  *w = diff;
+  cy = (diff > x);
+#else
+  *w = diff & GMP_NUMB_MASK;
+  cy = (diff >> GMP_NUMB_BITS) & 1;
+#endif
+  return cy;
+}
+
+/* set *w to x+y+c (where c is 0 or 1), return 0 or 1 carry */
+mp_limb_t
+adc (mp_limb_t *w, mp_limb_t x, mp_limb_t y, mp_limb_t c)
+{
+  mp_limb_t  r;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+  ASSERT (c == 0 || c == 1);
+
+  r = ref_addc_limb (w, x, y);
+  return r + ref_addc_limb (w, *w, c);
+}
+
+/* set *w to x-y-c (where c is 0 or 1), return 0 or 1 borrow */
+mp_limb_t
+sbb (mp_limb_t *w, mp_limb_t x, mp_limb_t y, mp_limb_t c)
+{
+  mp_limb_t  r;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+  ASSERT (c == 0 || c == 1);
+
+  r = ref_subc_limb (w, x, y);
+  return r + ref_subc_limb (w, *w, c);
+}
+
+
+#define AORS_1(operation)                               \
+  {                                                     \
+    mp_size_t  i;                                       \
+							\
+    ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));  \
+    ASSERT (size >= 1);                                 \
+    ASSERT_MPN (sp, size);                              \
+    ASSERT_LIMB (n);                                    \
+							\
+    for (i = 0; i < size; i++)                          \
+      n = operation (&rp[i], sp[i], n);                 \
+    return n;                                           \
+  }
+
+mp_limb_t
+refmpn_add_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t n)
+{
+  AORS_1 (ref_addc_limb);
+}
+mp_limb_t
+refmpn_sub_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t n)
+{
+  AORS_1 (ref_subc_limb);
+}
+
+#define AORS_NC(operation)                                              \
+  {                                                                     \
+    mp_size_t  i;                                                       \
+									\
+    ASSERT (refmpn_overlap_fullonly_two_p (rp, s1p, s2p, size));        \
+    ASSERT (carry == 0 || carry == 1);                                  \
+    ASSERT (size >= 1);                                                 \
+    ASSERT_MPN (s1p, size);                                             \
+    ASSERT_MPN (s2p, size);                                             \
+									\
+    for (i = 0; i < size; i++)                                          \
+      carry = operation (&rp[i], s1p[i], s2p[i], carry);                \
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_nc (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size,
+	       mp_limb_t carry)
+{
+  AORS_NC (adc);
+}
+mp_limb_t
+refmpn_sub_nc (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size,
+	       mp_limb_t carry)
+{
+  AORS_NC (sbb);
+}
+
+
+mp_limb_t
+refmpn_add_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  return refmpn_add_nc (rp, s1p, s2p, size, CNST_LIMB(0));
+}
+mp_limb_t
+refmpn_sub_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  return refmpn_sub_nc (rp, s1p, s2p, size, CNST_LIMB(0));
+}
+
+mp_limb_t
+refmpn_cnd_add_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  if (cnd != 0)
+    return refmpn_add_n (rp, s1p, s2p, size);
+  else
+    {
+      refmpn_copyi (rp, s1p, size);
+      return 0;
+    }
+}
+mp_limb_t
+refmpn_cnd_sub_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  if (cnd != 0)
+    return refmpn_sub_n (rp, s1p, s2p, size);
+  else
+    {
+      refmpn_copyi (rp, s1p, size);
+      return 0;
+    }
+}
+
+
+#define AORS_ERR1_N(operation)						\
+  {                                                                     \
+    mp_size_t  i;                                                       \
+    mp_limb_t carry2;							\
+									\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s1p, size));			\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, yp, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, s1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, yp, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, rp, size));			\
+									\
+    ASSERT (carry == 0 || carry == 1);					\
+    ASSERT (size >= 1);							\
+    ASSERT_MPN (s1p, size);						\
+    ASSERT_MPN (s2p, size);						\
+    ASSERT_MPN (yp, size);						\
+									\
+    ep[0] = ep[1] = CNST_LIMB(0);					\
+									\
+    for (i = 0; i < size; i++)                                          \
+      {									\
+	carry = operation (&rp[i], s1p[i], s2p[i], carry);		\
+	if (carry == 1)							\
+	  {								\
+	    carry2 = ref_addc_limb (&ep[0], ep[0], yp[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[1], ep[1], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	  }								\
+      }									\
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_err1_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr yp,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR1_N (adc);
+}
+mp_limb_t
+refmpn_sub_err1_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr yp,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR1_N (sbb);
+}
+
+
+#define AORS_ERR2_N(operation)						\
+  {                                                                     \
+    mp_size_t  i;                                                       \
+    mp_limb_t carry2;							\
+									\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s1p, size));			\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, s1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, rp, size));			\
+									\
+    ASSERT (carry == 0 || carry == 1);					\
+    ASSERT (size >= 1);							\
+    ASSERT_MPN (s1p, size);						\
+    ASSERT_MPN (s2p, size);						\
+    ASSERT_MPN (y1p, size);						\
+    ASSERT_MPN (y2p, size);						\
+									\
+    ep[0] = ep[1] = CNST_LIMB(0);					\
+    ep[2] = ep[3] = CNST_LIMB(0);					\
+									\
+    for (i = 0; i < size; i++)                                          \
+      {									\
+	carry = operation (&rp[i], s1p[i], s2p[i], carry);		\
+	if (carry == 1)							\
+	  {								\
+	    carry2 = ref_addc_limb (&ep[0], ep[0], y1p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[1], ep[1], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	    carry2 = ref_addc_limb (&ep[2], ep[2], y2p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[3], ep[3], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	  }								\
+      }									\
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_err2_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR2_N (adc);
+}
+mp_limb_t
+refmpn_sub_err2_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR2_N (sbb);
+}
+
+
+#define AORS_ERR3_N(operation)						\
+  {                                                                     \
+    mp_size_t  i;                                                       \
+    mp_limb_t carry2;							\
+									\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s1p, size));			\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y3p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, s1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, y3p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, rp, size));			\
+									\
+    ASSERT (carry == 0 || carry == 1);					\
+    ASSERT (size >= 1);							\
+    ASSERT_MPN (s1p, size);						\
+    ASSERT_MPN (s2p, size);						\
+    ASSERT_MPN (y1p, size);						\
+    ASSERT_MPN (y2p, size);						\
+    ASSERT_MPN (y3p, size);						\
+									\
+    ep[0] = ep[1] = CNST_LIMB(0);					\
+    ep[2] = ep[3] = CNST_LIMB(0);					\
+    ep[4] = ep[5] = CNST_LIMB(0);					\
+									\
+    for (i = 0; i < size; i++)                                          \
+      {									\
+	carry = operation (&rp[i], s1p[i], s2p[i], carry);		\
+	if (carry == 1)							\
+	  {								\
+	    carry2 = ref_addc_limb (&ep[0], ep[0], y1p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[1], ep[1], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	    carry2 = ref_addc_limb (&ep[2], ep[2], y2p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[3], ep[3], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	    carry2 = ref_addc_limb (&ep[4], ep[4], y3p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[5], ep[5], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	  }								\
+      }									\
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_err3_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p, mp_srcptr y3p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR3_N (adc);
+}
+mp_limb_t
+refmpn_sub_err3_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p, mp_srcptr y3p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR3_N (sbb);
+}
+
+
+mp_limb_t
+refmpn_addlsh_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		 mp_size_t n, unsigned int s)
+{
+  mp_limb_t cy;
+  mp_ptr tp;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT (0 < s && s < GMP_NUMB_BITS);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  tp = refmpn_malloc_limbs (n);
+  cy  = refmpn_lshift (tp, vp, n, s);
+  cy += refmpn_add_n (rp, up, tp, n);
+  free (tp);
+  return cy;
+}
+mp_limb_t
+refmpn_addlsh1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, up, vp, n, 1);
+}
+mp_limb_t
+refmpn_addlsh2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, up, vp, n, 2);
+}
+mp_limb_t
+refmpn_addlsh_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_addlsh_n (rp, rp, vp, n, s);
+}
+mp_limb_t
+refmpn_addlsh1_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, rp, vp, n, 1);
+}
+mp_limb_t
+refmpn_addlsh2_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, rp, vp, n, 2);
+}
+mp_limb_t
+refmpn_addlsh_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_addlsh_n (rp, vp, rp, n, s);
+}
+mp_limb_t
+refmpn_addlsh1_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, vp, rp, n, 1);
+}
+mp_limb_t
+refmpn_addlsh2_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, vp, rp, n, 2);
+}
+mp_limb_t
+refmpn_addlsh_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		  mp_size_t n, unsigned int s, mp_limb_t carry)
+{
+  mp_limb_t cy;
+
+  ASSERT (carry <= (CNST_LIMB(1) << s));
+
+  cy = refmpn_addlsh_n (rp, up, vp, n, s);
+  cy += refmpn_add_1 (rp, rp, n, carry);
+  return cy;
+}
+mp_limb_t
+refmpn_addlsh1_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_addlsh_nc (rp, up, vp, n, 1, carry);
+}
+mp_limb_t
+refmpn_addlsh2_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_addlsh_nc (rp, up, vp, n, 2, carry);
+}
+
+mp_limb_t
+refmpn_sublsh_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		 mp_size_t n, unsigned int s)
+{
+  mp_limb_t cy;
+  mp_ptr tp;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT (0 < s && s < GMP_NUMB_BITS);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  tp = refmpn_malloc_limbs (n);
+  cy  = mpn_lshift (tp, vp, n, s);
+  cy += mpn_sub_n (rp, up, tp, n);
+  free (tp);
+  return cy;
+}
+mp_limb_t
+refmpn_sublsh1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, up, vp, n, 1);
+}
+mp_limb_t
+refmpn_sublsh2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, up, vp, n, 2);
+}
+mp_limb_t
+refmpn_sublsh_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_sublsh_n (rp, rp, vp, n, s);
+}
+mp_limb_t
+refmpn_sublsh1_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, rp, vp, n, 1);
+}
+mp_limb_t
+refmpn_sublsh2_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, rp, vp, n, 2);
+}
+mp_limb_t
+refmpn_sublsh_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_sublsh_n (rp, vp, rp, n, s);
+}
+mp_limb_t
+refmpn_sublsh1_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, vp, rp, n, 1);
+}
+mp_limb_t
+refmpn_sublsh2_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, vp, rp, n, 2);
+}
+mp_limb_t
+refmpn_sublsh_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		  mp_size_t n, unsigned int s, mp_limb_t carry)
+{
+  mp_limb_t cy;
+
+  ASSERT (carry <= (CNST_LIMB(1) << s));
+
+  cy = refmpn_sublsh_n (rp, up, vp, n, s);
+  cy += refmpn_sub_1 (rp, rp, n, carry);
+  return cy;
+}
+mp_limb_t
+refmpn_sublsh1_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_sublsh_nc (rp, up, vp, n, 1, carry);
+}
+mp_limb_t
+refmpn_sublsh2_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_sublsh_nc (rp, up, vp, n, 2, carry);
+}
+
+mp_limb_signed_t
+refmpn_rsblsh_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		 mp_size_t n, unsigned int s)
+{
+  mp_limb_signed_t cy;
+  mp_ptr tp;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT (0 < s && s < GMP_NUMB_BITS);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  tp = refmpn_malloc_limbs (n);
+  cy  = mpn_lshift (tp, vp, n, s);
+  cy -= mpn_sub_n (rp, tp, up, n);
+  free (tp);
+  return cy;
+}
+mp_limb_signed_t
+refmpn_rsblsh1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_rsblsh_n (rp, up, vp, n, 1);
+}
+mp_limb_signed_t
+refmpn_rsblsh2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_rsblsh_n (rp, up, vp, n, 2);
+}
+mp_limb_signed_t
+refmpn_rsblsh_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		  mp_size_t n, unsigned int s, mp_limb_signed_t carry)
+{
+  mp_limb_signed_t cy;
+
+  ASSERT (carry == -1 || (carry >> s) == 0);
+
+  cy = refmpn_rsblsh_n (rp, up, vp, n, s);
+  if (carry > 0)
+    cy += refmpn_add_1 (rp, rp, n, carry);
+  else
+    cy -= refmpn_sub_1 (rp, rp, n, -carry);
+  return cy;
+}
+mp_limb_signed_t
+refmpn_rsblsh1_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_signed_t carry)
+{
+  return refmpn_rsblsh_nc (rp, up, vp, n, 1, carry);
+}
+mp_limb_signed_t
+refmpn_rsblsh2_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_signed_t carry)
+{
+  return refmpn_rsblsh_nc (rp, up, vp, n, 2, carry);
+}
+
+mp_limb_t
+refmpn_rsh1add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t cya, cys;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  cya = mpn_add_n (rp, up, vp, n);
+  cys = mpn_rshift (rp, rp, n, 1) >> (GMP_NUMB_BITS - 1);
+  rp[n - 1] |= cya << (GMP_NUMB_BITS - 1);
+  return cys;
+}
+mp_limb_t
+refmpn_rsh1sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t cya, cys;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  cya = mpn_sub_n (rp, up, vp, n);
+  cys = mpn_rshift (rp, rp, n, 1) >> (GMP_NUMB_BITS - 1);
+  rp[n - 1] |= cya << (GMP_NUMB_BITS - 1);
+  return cys;
+}
+
+/* Twos complement, return borrow. */
+mp_limb_t
+refmpn_neg (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr     zeros;
+  mp_limb_t  ret;
+
+  ASSERT (size >= 1);
+
+  zeros = refmpn_malloc_limbs (size);
+  refmpn_fill (zeros, size, CNST_LIMB(0));
+  ret = refmpn_sub_n (dst, zeros, src, size);
+  free (zeros);
+  return ret;
+}
+
+
+#define AORS(aors_n, aors_1)                                    \
+  {                                                             \
+    mp_limb_t  c;                                               \
+    ASSERT (s1size >= s2size);                                  \
+    ASSERT (s2size >= 1);                                       \
+    c = aors_n (rp, s1p, s2p, s2size);                          \
+    if (s1size-s2size != 0)                                     \
+      c = aors_1 (rp+s2size, s1p+s2size, s1size-s2size, c);     \
+    return c;                                                   \
+  }
+mp_limb_t
+refmpn_add (mp_ptr rp,
+	    mp_srcptr s1p, mp_size_t s1size,
+	    mp_srcptr s2p, mp_size_t s2size)
+{
+  AORS (refmpn_add_n, refmpn_add_1);
+}
+mp_limb_t
+refmpn_sub (mp_ptr rp,
+	    mp_srcptr s1p, mp_size_t s1size,
+	    mp_srcptr s2p, mp_size_t s2size)
+{
+  AORS (refmpn_sub_n, refmpn_sub_1);
+}
+
+
+#define SHIFTHIGH(x) ((x) << GMP_LIMB_BITS/2)
+#define SHIFTLOW(x)  ((x) >> GMP_LIMB_BITS/2)
+
+#define LOWMASK   (((mp_limb_t) 1 << GMP_LIMB_BITS/2)-1)
+#define HIGHMASK  SHIFTHIGH(LOWMASK)
+
+#define LOWPART(x)   ((x) & LOWMASK)
+#define HIGHPART(x)  SHIFTLOW((x) & HIGHMASK)
+
+/* Set return:*lo to x*y, using full limbs not nails. */
+mp_limb_t
+refmpn_umul_ppmm (mp_limb_t *lo, mp_limb_t x, mp_limb_t y)
+{
+  mp_limb_t  hi, s;
+
+  *lo = LOWPART(x) * LOWPART(y);
+  hi = HIGHPART(x) * HIGHPART(y);
+
+  s = LOWPART(x) * HIGHPART(y);
+  hi += HIGHPART(s);
+  s = SHIFTHIGH(LOWPART(s));
+  *lo += s;
+  hi += (*lo < s);
+
+  s = HIGHPART(x) * LOWPART(y);
+  hi += HIGHPART(s);
+  s = SHIFTHIGH(LOWPART(s));
+  *lo += s;
+  hi += (*lo < s);
+
+  return hi;
+}
+
+mp_limb_t
+refmpn_umul_ppmm_r (mp_limb_t x, mp_limb_t y, mp_limb_t *lo)
+{
+  return refmpn_umul_ppmm (lo, x, y);
+}
+
+mp_limb_t
+refmpn_mul_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier,
+	       mp_limb_t carry)
+{
+  mp_size_t  i;
+  mp_limb_t  hi, lo;
+
+  ASSERT (refmpn_overlap_low_to_high_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT_MPN (sp, size);
+  ASSERT_LIMB (multiplier);
+  ASSERT_LIMB (carry);
+
+  multiplier <<= GMP_NAIL_BITS;
+  for (i = 0; i < size; i++)
+    {
+      hi = refmpn_umul_ppmm (&lo, sp[i], multiplier);
+      lo >>= GMP_NAIL_BITS;
+      ASSERT_NOCARRY (ref_addc_limb (&hi, hi, ref_addc_limb (&lo, lo, carry)));
+      rp[i] = lo;
+      carry = hi;
+    }
+  return carry;
+}
+
+mp_limb_t
+refmpn_mul_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier)
+{
+  return refmpn_mul_1c (rp, sp, size, multiplier, CNST_LIMB(0));
+}
+
+
+mp_limb_t
+refmpn_mul_N (mp_ptr dst, mp_srcptr src, mp_size_t size,
+	      mp_srcptr mult, mp_size_t msize)
+{
+  mp_ptr     src_copy;
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (refmpn_overlap_fullonly_p (dst, src, size));
+  ASSERT (! refmpn_overlap_p (dst, size+msize-1, mult, msize));
+  ASSERT (size >= msize);
+  ASSERT_MPN (mult, msize);
+
+  /* in case dst==src */
+  src_copy = refmpn_malloc_limbs (size);
+  refmpn_copyi (src_copy, src, size);
+  src = src_copy;
+
+  dst[size] = refmpn_mul_1 (dst, src, size, mult[0]);
+  for (i = 1; i < msize-1; i++)
+    dst[size+i] = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+  ret = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+
+  free (src_copy);
+  return ret;
+}
+
+mp_limb_t
+refmpn_mul_2 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 2);
+}
+mp_limb_t
+refmpn_mul_3 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 3);
+}
+mp_limb_t
+refmpn_mul_4 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 4);
+}
+mp_limb_t
+refmpn_mul_5 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 5);
+}
+mp_limb_t
+refmpn_mul_6 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 6);
+}
+
+#define AORSMUL_1C(operation_n)                                 \
+  {                                                             \
+    mp_ptr     p;                                               \
+    mp_limb_t  ret;                                             \
+								\
+    ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));          \
+								\
+    p = refmpn_malloc_limbs (size);                             \
+    ret = refmpn_mul_1c (p, sp, size, multiplier, carry);       \
+    ret += operation_n (rp, rp, p, size);                       \
+								\
+    free (p);                                                   \
+    return ret;                                                 \
+  }
+
+mp_limb_t
+refmpn_addmul_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+		  mp_limb_t multiplier, mp_limb_t carry)
+{
+  AORSMUL_1C (refmpn_add_n);
+}
+mp_limb_t
+refmpn_submul_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+		  mp_limb_t multiplier, mp_limb_t carry)
+{
+  AORSMUL_1C (refmpn_sub_n);
+}
+
+
+mp_limb_t
+refmpn_addmul_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier)
+{
+  return refmpn_addmul_1c (rp, sp, size, multiplier, CNST_LIMB(0));
+}
+mp_limb_t
+refmpn_submul_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier)
+{
+  return refmpn_submul_1c (rp, sp, size, multiplier, CNST_LIMB(0));
+}
+
+
+mp_limb_t
+refmpn_addmul_N (mp_ptr dst, mp_srcptr src, mp_size_t size,
+		 mp_srcptr mult, mp_size_t msize)
+{
+  mp_ptr     src_copy;
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (dst == src || ! refmpn_overlap_p (dst, size+msize-1, src, size));
+  ASSERT (! refmpn_overlap_p (dst, size+msize-1, mult, msize));
+  ASSERT (size >= msize);
+  ASSERT_MPN (mult, msize);
+
+  /* in case dst==src */
+  src_copy = refmpn_malloc_limbs (size);
+  refmpn_copyi (src_copy, src, size);
+  src = src_copy;
+
+  for (i = 0; i < msize-1; i++)
+    dst[size+i] = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+  ret = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+
+  free (src_copy);
+  return ret;
+}
+
+mp_limb_t
+refmpn_addmul_2 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 2);
+}
+mp_limb_t
+refmpn_addmul_3 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 3);
+}
+mp_limb_t
+refmpn_addmul_4 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 4);
+}
+mp_limb_t
+refmpn_addmul_5 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 5);
+}
+mp_limb_t
+refmpn_addmul_6 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 6);
+}
+mp_limb_t
+refmpn_addmul_7 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 7);
+}
+mp_limb_t
+refmpn_addmul_8 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 8);
+}
+
+mp_limb_t
+refmpn_add_n_sub_nc (mp_ptr r1p, mp_ptr r2p,
+		  mp_srcptr s1p, mp_srcptr s2p, mp_size_t size,
+		  mp_limb_t carry)
+{
+  mp_ptr p;
+  mp_limb_t acy, scy;
+
+  /* Destinations can't overlap. */
+  ASSERT (! refmpn_overlap_p (r1p, size, r2p, size));
+  ASSERT (refmpn_overlap_fullonly_two_p (r1p, s1p, s2p, size));
+  ASSERT (refmpn_overlap_fullonly_two_p (r2p, s1p, s2p, size));
+  ASSERT (size >= 1);
+
+  /* in case r1p==s1p or r1p==s2p */
+  p = refmpn_malloc_limbs (size);
+
+  acy = refmpn_add_nc (p, s1p, s2p, size, carry >> 1);
+  scy = refmpn_sub_nc (r2p, s1p, s2p, size, carry & 1);
+  refmpn_copyi (r1p, p, size);
+
+  free (p);
+  return 2 * acy + scy;
+}
+
+mp_limb_t
+refmpn_add_n_sub_n (mp_ptr r1p, mp_ptr r2p,
+		 mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  return refmpn_add_n_sub_nc (r1p, r2p, s1p, s2p, size, CNST_LIMB(0));
+}
+
+
+/* Right shift hi,lo and return the low limb of the result.
+   Note a shift by GMP_LIMB_BITS isn't assumed to work (doesn't on x86). */
+mp_limb_t
+rshift_make (mp_limb_t hi, mp_limb_t lo, unsigned shift)
+{
+  ASSERT (shift < GMP_NUMB_BITS);
+  if (shift == 0)
+    return lo;
+  else
+    return ((hi << (GMP_NUMB_BITS-shift)) | (lo >> shift)) & GMP_NUMB_MASK;
+}
+
+/* Left shift hi,lo and return the high limb of the result.
+   Note a shift by GMP_LIMB_BITS isn't assumed to work (doesn't on x86). */
+mp_limb_t
+lshift_make (mp_limb_t hi, mp_limb_t lo, unsigned shift)
+{
+  ASSERT (shift < GMP_NUMB_BITS);
+  if (shift == 0)
+    return hi;
+  else
+    return ((hi << shift) | (lo >> (GMP_NUMB_BITS-shift))) & GMP_NUMB_MASK;
+}
+
+
+mp_limb_t
+refmpn_rshift (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (refmpn_overlap_low_to_high_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT (shift >= 1 && shift < GMP_NUMB_BITS);
+  ASSERT_MPN (sp, size);
+
+  ret = rshift_make (sp[0], CNST_LIMB(0), shift);
+
+  for (i = 0; i < size-1; i++)
+    rp[i] = rshift_make (sp[i+1], sp[i], shift);
+
+  rp[i] = rshift_make (CNST_LIMB(0), sp[i], shift);
+  return ret;
+}
+
+mp_limb_t
+refmpn_lshift (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (refmpn_overlap_high_to_low_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT (shift >= 1 && shift < GMP_NUMB_BITS);
+  ASSERT_MPN (sp, size);
+
+  ret = lshift_make (CNST_LIMB(0), sp[size-1], shift);
+
+  for (i = size-2; i >= 0; i--)
+    rp[i+1] = lshift_make (sp[i+1], sp[i], shift);
+
+  rp[i+1] = lshift_make (sp[i+1], CNST_LIMB(0), shift);
+  return ret;
+}
+
+void
+refmpn_com (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  mp_size_t i;
+
+  /* We work downwards since mpn_lshiftc needs that. */
+  ASSERT (refmpn_overlap_high_to_low_p (rp, sp, size));
+
+  for (i = size - 1; i >= 0; i--)
+    rp[i] = (~sp[i]) & GMP_NUMB_MASK;
+}
+
+mp_limb_t
+refmpn_lshiftc (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  mp_limb_t res;
+
+  /* No asserts here, refmpn_lshift will assert what we need. */
+
+  res = refmpn_lshift (rp, sp, size, shift);
+  refmpn_com (rp, rp, size);
+  return res;
+}
+
+/* accepting shift==0 and doing a plain copyi or copyd in that case */
+mp_limb_t
+refmpn_rshift_or_copy (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  if (shift == 0)
+    {
+      refmpn_copyi (rp, sp, size);
+      return 0;
+    }
+  else
+    {
+      return refmpn_rshift (rp, sp, size, shift);
+    }
+}
+mp_limb_t
+refmpn_lshift_or_copy (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  if (shift == 0)
+    {
+      refmpn_copyd (rp, sp, size);
+      return 0;
+    }
+  else
+    {
+      return refmpn_lshift (rp, sp, size, shift);
+    }
+}
+
+/* accepting size==0 too */
+mp_limb_t
+refmpn_rshift_or_copy_any (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+			   unsigned shift)
+{
+  return (size == 0 ? 0 : refmpn_rshift_or_copy (rp, sp, size, shift));
+}
+mp_limb_t
+refmpn_lshift_or_copy_any (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+			   unsigned shift)
+{
+  return (size == 0 ? 0 : refmpn_lshift_or_copy (rp, sp, size, shift));
+}
+
+/* Divide h,l by d, return quotient, store remainder to *rp.
+   Operates on full limbs, not nails.
+   Must have h < d.
+   __udiv_qrnnd_c isn't simple, and it's a bit slow, but it works. */
+mp_limb_t
+refmpn_udiv_qrnnd (mp_limb_t *rp, mp_limb_t h, mp_limb_t l, mp_limb_t d)
+{
+  mp_limb_t  q, r;
+  int  n;
+
+  ASSERT (d != 0);
+  ASSERT (h < d);
+
+#if 0
+  udiv_qrnnd (q, r, h, l, d);
+  *rp = r;
+  return q;
+#endif
+
+  n = refmpn_count_leading_zeros (d);
+  d <<= n;
+
+  if (n != 0)
+    {
+      h = (h << n) | (l >> (GMP_LIMB_BITS - n));
+      l <<= n;
+    }
+
+  __udiv_qrnnd_c (q, r, h, l, d);
+  r >>= n;
+  *rp = r;
+  return q;
+}
+
+mp_limb_t
+refmpn_udiv_qrnnd_r (mp_limb_t h, mp_limb_t l, mp_limb_t d, mp_limb_t *rp)
+{
+  return refmpn_udiv_qrnnd (rp, h, l, d);
+}
+
+/* This little subroutine avoids some bad code generation from i386 gcc 3.0
+   -fPIC -O2 -fomit-frame-pointer (%ebp being used uninitialized).  */
+static mp_limb_t
+refmpn_divmod_1c_workaround (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+			     mp_limb_t divisor, mp_limb_t carry)
+{
+  mp_size_t  i;
+  mp_limb_t rem[1];
+  for (i = size-1; i >= 0; i--)
+    {
+      rp[i] = refmpn_udiv_qrnnd (rem, carry,
+				 sp[i] << GMP_NAIL_BITS,
+				 divisor << GMP_NAIL_BITS);
+      carry = *rem >> GMP_NAIL_BITS;
+    }
+  return carry;
+}
+
+mp_limb_t
+refmpn_divmod_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+		  mp_limb_t divisor, mp_limb_t carry)
+{
+  mp_ptr     sp_orig;
+  mp_ptr     prod;
+  mp_limb_t  carry_orig;
+
+  ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));
+  ASSERT (size >= 0);
+  ASSERT (carry < divisor);
+  ASSERT_MPN (sp, size);
+  ASSERT_LIMB (divisor);
+  ASSERT_LIMB (carry);
+
+  if (size == 0)
+    return carry;
+
+  sp_orig = refmpn_memdup_limbs (sp, size);
+  prod = refmpn_malloc_limbs (size);
+  carry_orig = carry;
+
+  carry = refmpn_divmod_1c_workaround (rp, sp, size, divisor, carry);
+
+  /* check by multiplying back */
+#if 0
+  printf ("size=%ld divisor=0x%lX carry=0x%lX remainder=0x%lX\n",
+	  size, divisor, carry_orig, carry);
+  mpn_trace("s",sp_copy,size);
+  mpn_trace("r",rp,size);
+  printf ("mul_1c %lX\n", refmpn_mul_1c (prod, rp, size, divisor, carry));
+  mpn_trace("p",prod,size);
+#endif
+  ASSERT (refmpn_mul_1c (prod, rp, size, divisor, carry) == carry_orig);
+  ASSERT (refmpn_cmp (prod, sp_orig, size) == 0);
+  free (sp_orig);
+  free (prod);
+
+  return carry;
+}
+
+mp_limb_t
+refmpn_divmod_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t divisor)
+{
+  return refmpn_divmod_1c (rp, sp, size, divisor, CNST_LIMB(0));
+}
+
+
+mp_limb_t
+refmpn_mod_1c (mp_srcptr sp, mp_size_t size, mp_limb_t divisor,
+	       mp_limb_t carry)
+{
+  mp_ptr  p = refmpn_malloc_limbs (size);
+  carry = refmpn_divmod_1c (p, sp, size, divisor, carry);
+  free (p);
+  return carry;
+}
+
+mp_limb_t
+refmpn_mod_1 (mp_srcptr sp, mp_size_t size, mp_limb_t divisor)
+{
+  return refmpn_mod_1c (sp, size, divisor, CNST_LIMB(0));
+}
+
+mp_limb_t
+refmpn_preinv_mod_1 (mp_srcptr sp, mp_size_t size, mp_limb_t divisor,
+		     mp_limb_t inverse)
+{
+  ASSERT (divisor & GMP_NUMB_HIGHBIT);
+  ASSERT (inverse == refmpn_invert_limb (divisor));
+  return refmpn_mod_1 (sp, size, divisor);
+}
+
+/* This implementation will be rather slow, but has the advantage of being
+   in a different style than the libgmp versions.  */
+mp_limb_t
+refmpn_mod_34lsub1 (mp_srcptr p, mp_size_t n)
+{
+  ASSERT ((GMP_NUMB_BITS % 4) == 0);
+  return mpn_mod_1 (p, n, (CNST_LIMB(1) << (3 * GMP_NUMB_BITS / 4)) - 1);
+}
+
+
+mp_limb_t
+refmpn_divrem_1c (mp_ptr rp, mp_size_t xsize,
+		  mp_srcptr sp, mp_size_t size, mp_limb_t divisor,
+		  mp_limb_t carry)
+{
+  mp_ptr  z;
+
+  z = refmpn_malloc_limbs (xsize);
+  refmpn_fill (z, xsize, CNST_LIMB(0));
+
+  carry = refmpn_divmod_1c (rp+xsize, sp, size, divisor, carry);
+  carry = refmpn_divmod_1c (rp, z, xsize, divisor, carry);
+
+  free (z);
+  return carry;
+}
+
+mp_limb_t
+refmpn_divrem_1 (mp_ptr rp, mp_size_t xsize,
+		 mp_srcptr sp, mp_size_t size, mp_limb_t divisor)
+{
+  return refmpn_divrem_1c (rp, xsize, sp, size, divisor, CNST_LIMB(0));
+}
+
+mp_limb_t
+refmpn_preinv_divrem_1 (mp_ptr rp, mp_size_t xsize,
+			mp_srcptr sp, mp_size_t size,
+			mp_limb_t divisor, mp_limb_t inverse, unsigned shift)
+{
+  ASSERT (size >= 0);
+  ASSERT (shift == refmpn_count_leading_zeros (divisor));
+  ASSERT (inverse == refmpn_invert_limb (divisor << shift));
+
+  return refmpn_divrem_1 (rp, xsize, sp, size, divisor);
+}
+
+mp_limb_t
+refmpn_divrem_2 (mp_ptr qp, mp_size_t qxn,
+		 mp_ptr np, mp_size_t nn,
+		 mp_srcptr dp)
+{
+  mp_ptr tp;
+  mp_limb_t qh;
+
+  tp = refmpn_malloc_limbs (nn + qxn);
+  refmpn_zero (tp, qxn);
+  refmpn_copyi (tp + qxn, np, nn);
+  qh = refmpn_sb_div_qr (qp, tp, nn + qxn, dp, 2);
+  refmpn_copyi (np, tp, 2);
+  free (tp);
+  return qh;
+}
+
+/* Inverse is floor((b*(b-d)-1) / d), per division by invariant integers
+   paper, figure 8.1 m', where b=2^GMP_LIMB_BITS.  Note that -d-1 < d
+   since d has the high bit set. */
+
+mp_limb_t
+refmpn_invert_limb (mp_limb_t d)
+{
+  mp_limb_t r;
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+  return refmpn_udiv_qrnnd (&r, -d-1, MP_LIMB_T_MAX, d);
+}
+
+void
+refmpn_invert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch)
+{
+  mp_ptr qp, tp;
+  TMP_DECL;
+  TMP_MARK;
+
+  tp = TMP_ALLOC_LIMBS (2 * n);
+  qp = TMP_ALLOC_LIMBS (n + 1);
+
+  MPN_ZERO (tp, 2 * n);  mpn_sub_1 (tp, tp, 2 * n, 1);
+
+  refmpn_tdiv_qr (qp, rp, 0, tp, 2 * n, up, n);
+  refmpn_copyi (rp, qp, n);
+
+  TMP_FREE;
+}
+
+void
+refmpn_binvert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch)
+{
+  mp_ptr tp;
+  mp_limb_t binv;
+  TMP_DECL;
+  TMP_MARK;
+
+  /* We use the library mpn_sbpi1_bdiv_q here, which isn't kosher in testing
+     code.  To make up for it, we check that the inverse is correct using a
+     multiply.  */
+
+  tp = TMP_ALLOC_LIMBS (2 * n);
+
+  MPN_ZERO (tp, n);
+  tp[0] = 1;
+  binvert_limb (binv, up[0]);
+  mpn_sbpi1_bdiv_q (rp, tp, n, up, n, -binv);
+
+  refmpn_mul_n (tp, rp, up, n);
+  ASSERT_ALWAYS (tp[0] == 1 && mpn_zero_p (tp + 1, n - 1));
+
+  TMP_FREE;
+}
+
+/* The aim is to produce a dst quotient and return a remainder c, satisfying
+   c*b^n + src-i == 3*dst, where i is the incoming carry.
+
+   Some value c==0, c==1 or c==2 will satisfy, so just try each.
+
+   If GMP_NUMB_BITS is even then 2^GMP_NUMB_BITS==1mod3 and a non-zero
+   remainder from the first division attempt determines the correct
+   remainder (3-c), but don't bother with that, since we can't guarantee
+   anything about GMP_NUMB_BITS when using nails.
+
+   If the initial src-i produces a borrow then refmpn_sub_1 leaves a twos
+   complement negative, ie. b^n+a-i, and the calculation produces c1
+   satisfying c1*b^n + b^n+src-i == 3*dst, from which clearly c=c1+1.  This
+   means it's enough to just add any borrow back at the end.
+
+   A borrow only occurs when a==0 or a==1, and, by the same reasoning as in
+   mpn/generic/diveby3.c, the c1 that results in those cases will only be 0
+   or 1 respectively, so with 1 added the final return value is still in the
+   prescribed range 0 to 2. */
+
+mp_limb_t
+refmpn_divexact_by3c (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t carry)
+{
+  mp_ptr     spcopy;
+  mp_limb_t  c, cs;
+
+  ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT (carry <= 2);
+  ASSERT_MPN (sp, size);
+
+  spcopy = refmpn_malloc_limbs (size);
+  cs = refmpn_sub_1 (spcopy, sp, size, carry);
+
+  for (c = 0; c <= 2; c++)
+    if (refmpn_divmod_1c (rp, spcopy, size, CNST_LIMB(3), c) == 0)
+      goto done;
+  ASSERT_FAIL (no value of c satisfies);
+
+ done:
+  c += cs;
+  ASSERT (c <= 2);
+
+  free (spcopy);
+  return c;
+}
+
+mp_limb_t
+refmpn_divexact_by3 (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return refmpn_divexact_by3c (rp, sp, size, CNST_LIMB(0));
+}
+
+
+/* The same as mpn/generic/mul_basecase.c, but using refmpn functions. */
+void
+refmpn_mul_basecase (mp_ptr prodp,
+		     mp_srcptr up, mp_size_t usize,
+		     mp_srcptr vp, mp_size_t vsize)
+{
+  mp_size_t i;
+
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, up, usize));
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, vp, vsize));
+  ASSERT (usize >= vsize);
+  ASSERT (vsize >= 1);
+  ASSERT_MPN (up, usize);
+  ASSERT_MPN (vp, vsize);
+
+  prodp[usize] = refmpn_mul_1 (prodp, up, usize, vp[0]);
+  for (i = 1; i < vsize; i++)
+    prodp[usize+i] = refmpn_addmul_1 (prodp+i, up, usize, vp[i]);
+}
+
+
+/* The same as mpn/generic/mulmid_basecase.c, but using refmpn functions. */
+void
+refmpn_mulmid_basecase (mp_ptr rp,
+			mp_srcptr up, mp_size_t un,
+			mp_srcptr vp, mp_size_t vn)
+{
+  mp_limb_t cy;
+  mp_size_t i;
+
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! refmpn_overlap_p (rp, un - vn + 3, up, un));
+  ASSERT (! refmpn_overlap_p (rp, un - vn + 3, vp, vn));
+  ASSERT_MPN (up, un);
+  ASSERT_MPN (vp, vn);
+
+  rp[un - vn + 1] = refmpn_mul_1 (rp, up + vn - 1, un - vn + 1, vp[0]);
+  rp[un - vn + 2] = CNST_LIMB (0);
+  for (i = 1; i < vn; i++)
+    {
+      cy = refmpn_addmul_1 (rp, up + vn - i - 1, un - vn + 1, vp[i]);
+      cy = ref_addc_limb (&rp[un - vn + 1], rp[un - vn + 1], cy);
+      cy = ref_addc_limb (&rp[un - vn + 2], rp[un - vn + 2], cy);
+      ASSERT (cy == 0);
+    }
+}
+
+void
+refmpn_toom42_mulmid (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n,
+		      mp_ptr scratch)
+{
+  refmpn_mulmid_basecase (rp, up, 2*n - 1, vp, n);
+}
+
+void
+refmpn_mulmid_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  /* FIXME: this could be made faster by using refmpn_mul and then subtracting
+     off products near the middle product region boundary */
+  refmpn_mulmid_basecase (rp, up, 2*n - 1, vp, n);
+}
+
+void
+refmpn_mulmid (mp_ptr rp, mp_srcptr up, mp_size_t un,
+	       mp_srcptr vp, mp_size_t vn)
+{
+  /* FIXME: this could be made faster by using refmpn_mul and then subtracting
+     off products near the middle product region boundary */
+  refmpn_mulmid_basecase (rp, up, un, vp, vn);
+}
+
+
+
+#define TOOM3_THRESHOLD (MAX (MUL_TOOM33_THRESHOLD, SQR_TOOM3_THRESHOLD))
+#define TOOM4_THRESHOLD (MAX (MUL_TOOM44_THRESHOLD, SQR_TOOM4_THRESHOLD))
+#define TOOM6_THRESHOLD (MAX (MUL_TOOM6H_THRESHOLD, SQR_TOOM6_THRESHOLD))
+#if WANT_FFT
+#define FFT_THRESHOLD (MAX (MUL_FFT_THRESHOLD, SQR_FFT_THRESHOLD))
+#else
+#define FFT_THRESHOLD MP_SIZE_T_MAX /* don't use toom44 here */
+#endif
+
+void
+refmpn_mul (mp_ptr wp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
+{
+  mp_ptr tp, rp;
+  mp_size_t tn;
+
+  if (vn < TOOM3_THRESHOLD)
+    {
+      /* In the mpn_mul_basecase and toom2 ranges, use our own mul_basecase. */
+      if (vn != 0)
+	refmpn_mul_basecase (wp, up, un, vp, vn);
+      else
+	MPN_ZERO (wp, un);
+      return;
+    }
+
+  MPN_ZERO (wp, vn);
+  rp = refmpn_malloc_limbs (2 * vn);
+
+  if (vn < TOOM4_THRESHOLD)
+    tn = mpn_toom22_mul_itch (vn, vn);
+  else if (vn < TOOM6_THRESHOLD)
+    tn = mpn_toom33_mul_itch (vn, vn);
+  else if (vn < FFT_THRESHOLD)
+    tn = mpn_toom44_mul_itch (vn, vn);
+  else
+    tn = mpn_toom6h_mul_itch (vn, vn);
+  tp = refmpn_malloc_limbs (tn);
+
+  while (un >= vn)
+    {
+      if (vn < TOOM4_THRESHOLD)
+	/* In the toom3 range, use mpn_toom22_mul.  */
+	mpn_toom22_mul (rp, up, vn, vp, vn, tp);
+      else if (vn < TOOM6_THRESHOLD)
+	/* In the toom4 range, use mpn_toom33_mul.  */
+	mpn_toom33_mul (rp, up, vn, vp, vn, tp);
+      else if (vn < FFT_THRESHOLD)
+	/* In the toom6 range, use mpn_toom44_mul.  */
+	mpn_toom44_mul (rp, up, vn, vp, vn, tp);
+      else
+	/* For the largest operands, use mpn_toom6h_mul.  */
+	mpn_toom6h_mul (rp, up, vn, vp, vn, tp);
+
+      ASSERT_NOCARRY (refmpn_add (wp, rp, 2 * vn, wp, vn));
+      wp += vn;
+
+      up += vn;
+      un -= vn;
+    }
+
+  free (tp);
+
+  if (un != 0)
+    {
+      refmpn_mul (rp, vp, vn, up, un);
+      ASSERT_NOCARRY (refmpn_add (wp, rp, un + vn, wp, vn));
+    }
+  free (rp);
+}
+
+void
+refmpn_mul_n (mp_ptr prodp, mp_srcptr up, mp_srcptr vp, mp_size_t size)
+{
+  refmpn_mul (prodp, up, size, vp, size);
+}
+
+void
+refmpn_mullo_n (mp_ptr prodp, mp_srcptr up, mp_srcptr vp, mp_size_t size)
+{
+  mp_ptr tp = refmpn_malloc_limbs (2*size);
+  refmpn_mul (tp, up, size, vp, size);
+  refmpn_copyi (prodp, tp, size);
+  free (tp);
+}
+
+void
+refmpn_sqr (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  refmpn_mul (dst, src, size, src, size);
+}
+
+void
+refmpn_sqrlo (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  refmpn_mullo_n (dst, src, src, size);
+}
+
+/* Allowing usize<vsize, usize==0 or vsize==0. */
+void
+refmpn_mul_any (mp_ptr prodp,
+		     mp_srcptr up, mp_size_t usize,
+		     mp_srcptr vp, mp_size_t vsize)
+{
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, up, usize));
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, vp, vsize));
+  ASSERT (usize >= 0);
+  ASSERT (vsize >= 0);
+  ASSERT_MPN (up, usize);
+  ASSERT_MPN (vp, vsize);
+
+  if (usize == 0)
+    {
+      refmpn_fill (prodp, vsize, CNST_LIMB(0));
+      return;
+    }
+
+  if (vsize == 0)
+    {
+      refmpn_fill (prodp, usize, CNST_LIMB(0));
+      return;
+    }
+
+  if (usize >= vsize)
+    refmpn_mul (prodp, up, usize, vp, vsize);
+  else
+    refmpn_mul (prodp, vp, vsize, up, usize);
+}
+
+
+mp_limb_t
+refmpn_gcd_11 (mp_limb_t x, mp_limb_t y)
+{
+  /* The non-ref function also requires input operands to be odd, but
+     below refmpn_gcd_1 doesn't guarantee that. */
+  ASSERT (x > 0);
+  ASSERT (y > 0);
+  do
+    {
+      while ((x & 1) == 0)  x >>= 1;
+      while ((y & 1) == 0)  y >>= 1;
+
+      if (x < y)
+	MP_LIMB_T_SWAP (x, y);
+
+      x -= y;
+    }
+  while (x != 0);
+
+  return y;
+}
+
+mp_double_limb_t
+refmpn_gcd_22 (mp_limb_t x1, mp_limb_t x0, mp_limb_t y1, mp_limb_t y0)
+{
+  ASSERT ((x0 & 1) != 0);
+  ASSERT ((y0 & 1) != 0);
+  mp_double_limb_t g;
+  mp_limb_t cy;
+
+  do
+    {
+      while ((x0 & 1) == 0)
+	{
+	  x0 = (x1 << (GMP_NUMB_BITS - 1)) | (x0 >> 1);
+	  x1 >>= 1;
+	}
+      while ((y0 & 1) == 0)
+	{
+	  y0 = (y1 << (GMP_NUMB_BITS - 1)) | (y0 >> 1);
+	  y1 >>= 1;
+	}
+
+
+      if (x1 < y1 || (x1 == y1 && x0 < y0))
+	{
+	  mp_limb_t t;
+	  t = x1; x1 = y1; y1 = t;
+	  t = x0; x0 = y0; y0 = t;
+	}
+
+      cy = (x0 < y0);
+      x0 -= y0;
+      x1 -= y1 + cy;
+    }
+  while ((x1 | x0) != 0);
+
+  g.d1 = y1;
+  g.d0 = y0;
+  return g;
+}
+
+mp_limb_t
+refmpn_gcd_1 (mp_srcptr xp, mp_size_t xsize, mp_limb_t y)
+{
+  mp_limb_t  x;
+  int  twos;
+
+  ASSERT (y != 0);
+  ASSERT (! refmpn_zero_p (xp, xsize));
+  ASSERT_MPN (xp, xsize);
+  ASSERT_LIMB (y);
+
+  x = refmpn_mod_1 (xp, xsize, y);
+  if (x == 0)
+    return y;
+
+  twos = 0;
+  while ((x & 1) == 0 && (y & 1) == 0)
+    {
+      x >>= 1;
+      y >>= 1;
+      twos++;
+    }
+
+  return refmpn_gcd_11 (x, y) << twos;
+}
+
+
+/* Based on the full limb x, not nails. */
+unsigned
+refmpn_count_leading_zeros (mp_limb_t x)
+{
+  unsigned  n = 0;
+
+  ASSERT (x != 0);
+
+  while ((x & GMP_LIMB_HIGHBIT) == 0)
+    {
+      x <<= 1;
+      n++;
+    }
+  return n;
+}
+
+/* Full limbs allowed, not limited to nails. */
+unsigned
+refmpn_count_trailing_zeros (mp_limb_t x)
+{
+  unsigned  n = 0;
+
+  ASSERT (x != 0);
+  ASSERT_LIMB (x);
+
+  while ((x & 1) == 0)
+    {
+      x >>= 1;
+      n++;
+    }
+  return n;
+}
+
+/* Strip factors of two (low zero bits) from {p,size} by right shifting.
+   The return value is the number of twos stripped.  */
+mp_size_t
+refmpn_strip_twos (mp_ptr p, mp_size_t size)
+{
+  mp_size_t  limbs;
+  unsigned   shift;
+
+  ASSERT (size >= 1);
+  ASSERT (! refmpn_zero_p (p, size));
+  ASSERT_MPN (p, size);
+
+  for (limbs = 0; p[0] == 0; limbs++)
+    {
+      refmpn_copyi (p, p+1, size-1);
+      p[size-1] = 0;
+    }
+
+  shift = refmpn_count_trailing_zeros (p[0]);
+  if (shift)
+    refmpn_rshift (p, p, size, shift);
+
+  return limbs*GMP_NUMB_BITS + shift;
+}
+
+mp_limb_t
+refmpn_gcd (mp_ptr gp, mp_ptr xp, mp_size_t xsize, mp_ptr yp, mp_size_t ysize)
+{
+  int       cmp;
+
+  ASSERT (ysize >= 1);
+  ASSERT (xsize >= ysize);
+  ASSERT ((xp[0] & 1) != 0);
+  ASSERT ((yp[0] & 1) != 0);
+  /* ASSERT (xp[xsize-1] != 0); */  /* don't think x needs to be odd */
+  ASSERT (yp[ysize-1] != 0);
+  ASSERT (refmpn_overlap_fullonly_p (gp, xp, xsize));
+  ASSERT (refmpn_overlap_fullonly_p (gp, yp, ysize));
+  ASSERT (! refmpn_overlap_p (xp, xsize, yp, ysize));
+  if (xsize == ysize)
+    ASSERT (refmpn_msbone (xp[xsize-1]) >= refmpn_msbone (yp[ysize-1]));
+  ASSERT_MPN (xp, xsize);
+  ASSERT_MPN (yp, ysize);
+
+  refmpn_strip_twos (xp, xsize);
+  MPN_NORMALIZE (xp, xsize);
+  MPN_NORMALIZE (yp, ysize);
+
+  for (;;)
+    {
+      cmp = refmpn_cmp_twosizes (xp, xsize, yp, ysize);
+      if (cmp == 0)
+	break;
+      if (cmp < 0)
+	MPN_PTR_SWAP (xp,xsize, yp,ysize);
+
+      ASSERT_NOCARRY (refmpn_sub (xp, xp, xsize, yp, ysize));
+
+      refmpn_strip_twos (xp, xsize);
+      MPN_NORMALIZE (xp, xsize);
+    }
+
+  refmpn_copyi (gp, xp, xsize);
+  return xsize;
+}
+
+unsigned long
+ref_popc_limb (mp_limb_t src)
+{
+  unsigned long  count;
+  int  i;
+
+  count = 0;
+  for (i = 0; i < GMP_LIMB_BITS; i++)
+    {
+      count += (src & 1);
+      src >>= 1;
+    }
+  return count;
+}
+
+unsigned long
+refmpn_popcount (mp_srcptr sp, mp_size_t size)
+{
+  unsigned long  count = 0;
+  mp_size_t  i;
+
+  ASSERT (size >= 0);
+  ASSERT_MPN (sp, size);
+
+  for (i = 0; i < size; i++)
+    count += ref_popc_limb (sp[i]);
+  return count;
+}
+
+unsigned long
+refmpn_hamdist (mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  mp_ptr  d;
+  unsigned long  count;
+
+  ASSERT (size >= 0);
+  ASSERT_MPN (s1p, size);
+  ASSERT_MPN (s2p, size);
+
+  if (size == 0)
+    return 0;
+
+  d = refmpn_malloc_limbs (size);
+  refmpn_xor_n (d, s1p, s2p, size);
+  count = refmpn_popcount (d, size);
+  free (d);
+  return count;
+}
+
+
+/* set r to a%d */
+void
+refmpn_mod2 (mp_limb_t r[2], const mp_limb_t a[2], const mp_limb_t d[2])
+{
+  mp_limb_t  D[2];
+  int        n;
+
+  ASSERT (! refmpn_overlap_p (r, (mp_size_t) 2, d, (mp_size_t) 2));
+  ASSERT_MPN (a, 2);
+  ASSERT_MPN (d, 2);
+
+  D[1] = d[1], D[0] = d[0];
+  r[1] = a[1], r[0] = a[0];
+  n = 0;
+
+  for (;;)
+    {
+      if (D[1] & GMP_NUMB_HIGHBIT)
+	break;
+      if (refmpn_cmp (r, D, (mp_size_t) 2) <= 0)
+	break;
+      refmpn_lshift (D, D, (mp_size_t) 2, 1);
+      n++;
+      ASSERT (n <= GMP_NUMB_BITS);
+    }
+
+  while (n >= 0)
+    {
+      if (refmpn_cmp (r, D, (mp_size_t) 2) >= 0)
+	ASSERT_NOCARRY (refmpn_sub_n (r, r, D, (mp_size_t) 2));
+      refmpn_rshift (D, D, (mp_size_t) 2, 1);
+      n--;
+    }
+
+  ASSERT (refmpn_cmp (r, d, (mp_size_t) 2) < 0);
+}
+
+
+
+/* Similar to the old mpn/generic/sb_divrem_mn.c, but somewhat simplified, in
+   particular the trial quotient is allowed to be 2 too big. */
+mp_limb_t
+refmpn_sb_div_qr (mp_ptr qp,
+		  mp_ptr np, mp_size_t nsize,
+		  mp_srcptr dp, mp_size_t dsize)
+{
+  mp_limb_t  retval = 0;
+  mp_size_t  i;
+  mp_limb_t  d1 = dp[dsize-1];
+  mp_ptr     np_orig = refmpn_memdup_limbs (np, nsize);
+
+  ASSERT (nsize >= dsize);
+  /* ASSERT (dsize > 2); */
+  ASSERT (dsize >= 2);
+  ASSERT (dp[dsize-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! refmpn_overlap_p (qp, nsize-dsize, np, nsize) || qp+dsize >= np);
+  ASSERT_MPN (np, nsize);
+  ASSERT_MPN (dp, dsize);
+
+  i = nsize-dsize;
+  if (refmpn_cmp (np+i, dp, dsize) >= 0)
+    {
+      ASSERT_NOCARRY (refmpn_sub_n (np+i, np+i, dp, dsize));
+      retval = 1;
+    }
+
+  for (i--; i >= 0; i--)
+    {
+      mp_limb_t  n0 = np[i+dsize];
+      mp_limb_t  n1 = np[i+dsize-1];
+      mp_limb_t  q, dummy_r;
+
+      ASSERT (n0 <= d1);
+      if (n0 == d1)
+	q = GMP_NUMB_MAX;
+      else
+	q = refmpn_udiv_qrnnd (&dummy_r, n0, n1 << GMP_NAIL_BITS,
+			       d1 << GMP_NAIL_BITS);
+
+      n0 -= refmpn_submul_1 (np+i, dp, dsize, q);
+      ASSERT (n0 == 0 || n0 == MP_LIMB_T_MAX);
+      if (n0)
+	{
+	  q--;
+	  if (! refmpn_add_n (np+i, np+i, dp, dsize))
+	    {
+	      q--;
+	      ASSERT_CARRY (refmpn_add_n (np+i, np+i, dp, dsize));
+	    }
+	}
+      np[i+dsize] = 0;
+
+      qp[i] = q;
+    }
+
+  /* remainder < divisor */
+#if 0		/* ASSERT triggers gcc 4.2.1 bug */
+  ASSERT (refmpn_cmp (np, dp, dsize) < 0);
+#endif
+
+  /* multiply back to original */
+  {
+    mp_ptr  mp = refmpn_malloc_limbs (nsize);
+
+    refmpn_mul_any (mp, qp, nsize-dsize, dp, dsize);
+    if (retval)
+      ASSERT_NOCARRY (refmpn_add_n (mp+nsize-dsize,mp+nsize-dsize, dp, dsize));
+    ASSERT_NOCARRY (refmpn_add (mp, mp, nsize, np, dsize));
+    ASSERT (refmpn_cmp (mp, np_orig, nsize) == 0);
+
+    free (mp);
+  }
+
+  free (np_orig);
+  return retval;
+}
+
+/* Similar to the old mpn/generic/sb_divrem_mn.c, but somewhat simplified, in
+   particular the trial quotient is allowed to be 2 too big. */
+void
+refmpn_tdiv_qr (mp_ptr qp, mp_ptr rp, mp_size_t qxn,
+		mp_ptr np, mp_size_t nsize,
+		mp_srcptr dp, mp_size_t dsize)
+{
+  ASSERT (qxn == 0);
+  ASSERT_MPN (np, nsize);
+  ASSERT_MPN (dp, dsize);
+  ASSERT (dsize > 0);
+  ASSERT (dp[dsize-1] != 0);
+
+  if (dsize == 1)
+    {
+      rp[0] = refmpn_divmod_1 (qp, np, nsize, dp[0]);
+      return;
+    }
+  else
+    {
+      mp_ptr  n2p = refmpn_malloc_limbs (nsize+1);
+      mp_ptr  d2p = refmpn_malloc_limbs (dsize);
+      int     norm = refmpn_count_leading_zeros (dp[dsize-1]) - GMP_NAIL_BITS;
+
+      n2p[nsize] = refmpn_lshift_or_copy (n2p, np, nsize, norm);
+      ASSERT_NOCARRY (refmpn_lshift_or_copy (d2p, dp, dsize, norm));
+
+      refmpn_sb_div_qr (qp, n2p, nsize+1, d2p, dsize);
+      refmpn_rshift_or_copy (rp, n2p, dsize, norm);
+
+      /* ASSERT (refmpn_zero_p (tp+dsize, nsize-dsize)); */
+      free (n2p);
+      free (d2p);
+    }
+}
+
+mp_limb_t
+refmpn_redc_1 (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_limb_t invm)
+{
+  mp_size_t j;
+  mp_limb_t cy;
+
+  ASSERT_MPN (up, 2*n);
+  /* ASSERT about directed overlap rp, up */
+  /* ASSERT about overlap rp, mp */
+  /* ASSERT about overlap up, mp */
+
+  for (j = n - 1; j >= 0; j--)
+    {
+      up[0] = refmpn_addmul_1 (up, mp, n, (up[0] * invm) & GMP_NUMB_MASK);
+      up++;
+    }
+  cy = mpn_add_n (rp, up, up - n, n);
+  return cy;
+}
+
+size_t
+refmpn_get_str (unsigned char *dst, int base, mp_ptr src, mp_size_t size)
+{
+  unsigned char  *d;
+  size_t  dsize;
+
+  ASSERT (size >= 0);
+  ASSERT (base >= 2);
+  ASSERT (base < numberof (mp_bases));
+  ASSERT (size == 0 || src[size-1] != 0);
+  ASSERT_MPN (src, size);
+
+  MPN_SIZEINBASE (dsize, src, size, base);
+  ASSERT (dsize >= 1);
+  ASSERT (! byte_overlap_p (dst, (mp_size_t) dsize, src, size * GMP_LIMB_BYTES));
+
+  if (size == 0)
+    {
+      dst[0] = 0;
+      return 1;
+    }
+
+  /* don't clobber input for power of 2 bases */
+  if (POW2_P (base))
+    src = refmpn_memdup_limbs (src, size);
+
+  d = dst + dsize;
+  do
+    {
+      d--;
+      ASSERT (d >= dst);
+      *d = refmpn_divrem_1 (src, (mp_size_t) 0, src, size, (mp_limb_t) base);
+      size -= (src[size-1] == 0);
+    }
+  while (size != 0);
+
+  /* Move result back and decrement dsize if we didn't generate
+     the maximum possible digits.  */
+  if (d != dst)
+    {
+      size_t i;
+      dsize -= d - dst;
+      for (i = 0; i < dsize; i++)
+	dst[i] = d[i];
+    }
+
+  if (POW2_P (base))
+    free (src);
+
+  return dsize;
+}
+
+
+mp_limb_t
+ref_bswap_limb (mp_limb_t src)
+{
+  mp_limb_t  dst;
+  int        i;
+
+  dst = 0;
+  for (i = 0; i < GMP_LIMB_BYTES; i++)
+    {
+      dst = (dst << 8) + (src & 0xFF);
+      src >>= 8;
+    }
+  return dst;
+}
+
+
+/* These random functions are mostly for transitional purposes while adding
+   nail support, since they're independent of the normal mpn routines.  They
+   can probably be removed when those normal routines are reliable, though
+   perhaps something independent would still be useful at times.  */
+
+#if GMP_LIMB_BITS == 32
+#define RAND_A  CNST_LIMB(0x29CF535)
+#endif
+#if GMP_LIMB_BITS == 64
+#define RAND_A  CNST_LIMB(0xBAECD515DAF0B49D)
+#endif
+
+mp_limb_t  refmpn_random_seed;
+
+mp_limb_t
+refmpn_random_half (void)
+{
+  refmpn_random_seed = refmpn_random_seed * RAND_A + 1;
+  return (refmpn_random_seed >> GMP_LIMB_BITS/2);
+}
+
+mp_limb_t
+refmpn_random_limb (void)
+{
+  return ((refmpn_random_half () << (GMP_LIMB_BITS/2))
+	   | refmpn_random_half ()) & GMP_NUMB_MASK;
+}
+
+void
+refmpn_random (mp_ptr ptr, mp_size_t size)
+{
+  mp_size_t  i;
+  if (GMP_NAIL_BITS == 0)
+    {
+      mpn_random (ptr, size);
+      return;
+    }
+
+  for (i = 0; i < size; i++)
+    ptr[i] = refmpn_random_limb ();
+}
+
+void
+refmpn_random2 (mp_ptr ptr, mp_size_t size)
+{
+  mp_size_t  i;
+  mp_limb_t  bit, mask, limb;
+  int        run;
+
+  if (GMP_NAIL_BITS == 0)
+    {
+      mpn_random2 (ptr, size);
+      return;
+    }
+
+#define RUN_MODULUS  32
+
+  /* start with ones at a random pos in the high limb */
+  bit = CNST_LIMB(1) << (refmpn_random_half () % GMP_NUMB_BITS);
+  mask = 0;
+  run = 0;
+
+  for (i = size-1; i >= 0; i--)
+    {
+      limb = 0;
+      do
+	{
+	  if (run == 0)
+	    {
+	      run = (refmpn_random_half () % RUN_MODULUS) + 1;
+	      mask = ~mask;
+	    }
+
+	  limb |= (bit & mask);
+	  bit >>= 1;
+	  run--;
+	}
+      while (bit != 0);
+
+      ptr[i] = limb;
+      bit = GMP_NUMB_HIGHBIT;
+    }
+}
+
+/* This is a simple bitwise algorithm working high to low across "s" and
+   testing each time whether setting the bit would make s^2 exceed n.  */
+mp_size_t
+refmpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr np, mp_size_t nsize)
+{
+  mp_ptr     tp, dp;
+  mp_size_t  ssize, talloc, tsize, dsize, ret, ilimbs;
+  unsigned   ibit;
+  long       i;
+  mp_limb_t  c;
+
+  ASSERT (nsize >= 0);
+
+  /* If n==0, then s=0 and r=0.  */
+  if (nsize == 0)
+    return 0;
+
+  ASSERT (np[nsize - 1] != 0);
+  ASSERT (rp == NULL || MPN_SAME_OR_SEPARATE_P (np, rp, nsize));
+  ASSERT (rp == NULL || ! MPN_OVERLAP_P (sp, (nsize + 1) / 2, rp, nsize));
+  ASSERT (! MPN_OVERLAP_P (sp, (nsize + 1) / 2, np, nsize));
+
+  /* root */
+  ssize = (nsize+1)/2;
+  refmpn_zero (sp, ssize);
+
+  /* the remainder so far */
+  dp = refmpn_memdup_limbs (np, nsize);
+  dsize = nsize;
+
+  /* temporary */
+  talloc = 2*ssize + 1;
+  tp = refmpn_malloc_limbs (talloc);
+
+  for (i = GMP_NUMB_BITS * ssize - 1; i >= 0; i--)
+    {
+      /* t = 2*s*2^i + 2^(2*i), being the amount s^2 will increase by if 2^i
+	 is added to it */
+
+      ilimbs = (i+1) / GMP_NUMB_BITS;
+      ibit = (i+1) % GMP_NUMB_BITS;
+      refmpn_zero (tp, ilimbs);
+      c = refmpn_lshift_or_copy (tp+ilimbs, sp, ssize, ibit);
+      tsize = ilimbs + ssize;
+      tp[tsize] = c;
+      tsize += (c != 0);
+
+      ilimbs = (2*i) / GMP_NUMB_BITS;
+      ibit = (2*i) % GMP_NUMB_BITS;
+      if (ilimbs + 1 > tsize)
+	{
+	  refmpn_zero_extend (tp, tsize, ilimbs + 1);
+	  tsize = ilimbs + 1;
+	}
+      c = refmpn_add_1 (tp+ilimbs, tp+ilimbs, tsize-ilimbs,
+			CNST_LIMB(1) << ibit);
+      ASSERT (tsize < talloc);
+      tp[tsize] = c;
+      tsize += (c != 0);
+
+      if (refmpn_cmp_twosizes (dp, dsize, tp, tsize) >= 0)
+	{
+	  /* set this bit in s and subtract from the remainder */
+	  refmpn_setbit (sp, i);
+
+	  ASSERT_NOCARRY (refmpn_sub_n (dp, dp, tp, dsize));
+	  dsize = refmpn_normalize (dp, dsize);
+	}
+    }
+
+  if (rp == NULL)
+    {
+      ret = ! refmpn_zero_p (dp, dsize);
+    }
+  else
+    {
+      ASSERT (dsize == 0 || dp[dsize-1] != 0);
+      refmpn_copy (rp, dp, dsize);
+      ret = dsize;
+    }
+
+  free (dp);
+  free (tp);
+  return ret;
+}
diff --git a/tests/refmpq.c b/tests/refmpq.c
new file mode 100644
index 0000000..8a2fc7a
--- /dev/null
+++ b/tests/refmpq.c
@@ -0,0 +1,40 @@
+/* Reference rational routines.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+refmpq_add (mpq_ptr w, mpq_srcptr x, mpq_srcptr y)
+{
+  mpz_mul    (mpq_numref(w), mpq_numref(x), mpq_denref(y));
+  mpz_addmul (mpq_numref(w), mpq_denref(x), mpq_numref(y));
+  mpz_mul    (mpq_denref(w), mpq_denref(x), mpq_denref(y));
+  mpq_canonicalize (w);
+}
+
+void
+refmpq_sub (mpq_ptr w, mpq_srcptr x, mpq_srcptr y)
+{
+  mpz_mul    (mpq_numref(w), mpq_numref(x), mpq_denref(y));
+  mpz_submul (mpq_numref(w), mpq_denref(x), mpq_numref(y));
+  mpz_mul    (mpq_denref(w), mpq_denref(x), mpq_denref(y));
+  mpq_canonicalize (w);
+}
diff --git a/tests/refmpz.c b/tests/refmpz.c
new file mode 100644
index 0000000..167799f
--- /dev/null
+++ b/tests/refmpz.c
@@ -0,0 +1,343 @@
+/* Reference mpz functions.
+
+Copyright 1997, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* always do assertion checking */
+#define WANT_ASSERT  1
+
+#include <stdio.h>
+#include <stdlib.h> /* for free */
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* FIXME: Shouldn't use plain mpz functions in a reference routine. */
+void
+refmpz_combit (mpz_ptr r, unsigned long bit)
+{
+  if (mpz_tstbit (r, bit))
+    mpz_clrbit (r, bit);
+  else
+    mpz_setbit (r, bit);
+}
+
+
+unsigned long
+refmpz_hamdist (mpz_srcptr x, mpz_srcptr y)
+{
+  mp_size_t      xsize, ysize, tsize;
+  mp_ptr         xp, yp;
+  unsigned long  ret;
+
+  if ((SIZ(x) < 0 && SIZ(y) >= 0)
+      || (SIZ(y) < 0 && SIZ(x) >= 0))
+    return ULONG_MAX;
+
+  xsize = ABSIZ(x);
+  ysize = ABSIZ(y);
+  tsize = MAX (xsize, ysize);
+
+  xp = refmpn_malloc_limbs (tsize);
+  refmpn_zero (xp, tsize);
+  refmpn_copy (xp, PTR(x), xsize);
+
+  yp = refmpn_malloc_limbs (tsize);
+  refmpn_zero (yp, tsize);
+  refmpn_copy (yp, PTR(y), ysize);
+
+  if (SIZ(x) < 0)
+    refmpn_neg (xp, xp, tsize);
+
+  if (SIZ(x) < 0)
+    refmpn_neg (yp, yp, tsize);
+
+  ret = refmpn_hamdist (xp, yp, tsize);
+
+  free (xp);
+  free (yp);
+  return ret;
+}
+
+void
+refmpz_gcd (mpz_ptr g, mpz_srcptr a_orig, mpz_srcptr b_orig)
+{
+  mp_bitcnt_t a_twos, b_twos, common_twos;
+  mpz_t a;
+  mpz_t b;
+  mpz_init (a);
+  mpz_init (b);
+  mpz_abs (a, a_orig);
+  mpz_abs (b, b_orig);
+
+  if (mpz_sgn (a) == 0)
+    {
+      mpz_set (g, b);
+      return;
+    }
+  if (mpz_sgn (b) == 0)
+    {
+      mpz_set (g, a);
+      return;
+    }
+  a_twos = mpz_scan1 (a, 0);
+  mpz_tdiv_q_2exp (a, a, a_twos);
+
+  b_twos = mpz_scan1 (b, 0);
+  mpz_tdiv_q_2exp (b, b, b_twos);
+
+  common_twos = MIN(a_twos, b_twos);
+  for (;;)
+    {
+      int c;
+      mp_bitcnt_t twos;
+      c = mpz_cmp (a, b);
+      if (c == 0)
+	break;
+      if (c < 0)
+	mpz_swap (a, b);
+      mpz_sub (a, a, b);
+      twos = mpz_scan1 (a, 0);
+      mpz_tdiv_q_2exp (a, a, twos);
+    }
+  mpz_mul_2exp (g, a, common_twos);
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+/* (0/b), with mpz b; is 1 if b=+/-1, 0 otherwise */
+#define JACOBI_0Z(b)  JACOBI_0LS (PTR(b)[0], SIZ(b))
+
+/* (a/b) effect due to sign of b: mpz/mpz */
+#define JACOBI_BSGN_ZZ_BIT1(a, b)   JACOBI_BSGN_SS_BIT1 (SIZ(a), SIZ(b))
+
+/* (a/b) effect due to sign of a: mpz/unsigned-mpz, b odd;
+   is (-1/b) if a<0, or +1 if a>=0 */
+#define JACOBI_ASGN_ZZU_BIT1(a, b)  JACOBI_ASGN_SU_BIT1 (SIZ(a), PTR(b)[0])
+
+int
+refmpz_kronecker (mpz_srcptr a_orig, mpz_srcptr b_orig)
+{
+  unsigned long  twos;
+  mpz_t  a, b;
+  int    result_bit1 = 0;
+
+  if (mpz_sgn (b_orig) == 0)
+    return JACOBI_Z0 (a_orig);  /* (a/0) */
+
+  if (mpz_sgn (a_orig) == 0)
+    return JACOBI_0Z (b_orig);  /* (0/b) */
+
+  if (mpz_even_p (a_orig) && mpz_even_p (b_orig))
+    return 0;
+
+  if (mpz_cmp_ui (b_orig, 1) == 0)
+    return 1;
+
+  mpz_init_set (a, a_orig);
+  mpz_init_set (b, b_orig);
+
+  if (mpz_sgn (b) < 0)
+    {
+      result_bit1 ^= JACOBI_BSGN_ZZ_BIT1 (a, b);
+      mpz_neg (b, b);
+    }
+  if (mpz_even_p (b))
+    {
+      twos = mpz_scan1 (b, 0L);
+      mpz_tdiv_q_2exp (b, b, twos);
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(a)[0]);
+    }
+
+  if (mpz_sgn (a) < 0)
+    {
+      result_bit1 ^= JACOBI_N1B_BIT1 (PTR(b)[0]);
+      mpz_neg (a, a);
+    }
+  if (mpz_even_p (a))
+    {
+      twos = mpz_scan1 (a, 0L);
+      mpz_tdiv_q_2exp (a, a, twos);
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]);
+    }
+
+  for (;;)
+    {
+      ASSERT (mpz_odd_p (a));
+      ASSERT (mpz_odd_p (b));
+      ASSERT (mpz_sgn (a) > 0);
+      ASSERT (mpz_sgn (b) > 0);
+
+      TRACE (printf ("top\n");
+	     mpz_trace (" a", a);
+	     mpz_trace (" b", b));
+
+      if (mpz_cmp (a, b) < 0)
+	{
+	  TRACE (printf ("swap\n"));
+	  mpz_swap (a, b);
+	  result_bit1 ^= JACOBI_RECIP_UU_BIT1 (PTR(a)[0], PTR(b)[0]);
+	}
+
+      if (mpz_cmp_ui (b, 1) == 0)
+	break;
+
+      mpz_sub (a, a, b);
+      TRACE (printf ("sub\n");
+	     mpz_trace (" a", a));
+      if (mpz_sgn (a) == 0)
+	goto zero;
+
+      twos = mpz_scan1 (a, 0L);
+      mpz_fdiv_q_2exp (a, a, twos);
+      TRACE (printf ("twos %lu\n", twos);
+	     mpz_trace (" a", a));
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  return JACOBI_BIT1_TO_PN (result_bit1);
+
+ zero:
+  mpz_clear (a);
+  mpz_clear (b);
+  return 0;
+}
+
+/* Same as mpz_kronecker, but ignoring factors of 2 on b */
+int
+refmpz_jacobi (mpz_srcptr a, mpz_srcptr b)
+{
+  ASSERT_ALWAYS (mpz_sgn (b) > 0);
+  ASSERT_ALWAYS (mpz_odd_p (b));
+
+  return refmpz_kronecker (a, b);
+}
+
+/* Legendre symbol via powm. p must be an odd prime. */
+int
+refmpz_legendre (mpz_srcptr a, mpz_srcptr p)
+{
+  int res;
+
+  mpz_t r;
+  mpz_t e;
+
+  ASSERT_ALWAYS (mpz_sgn (p) > 0);
+  ASSERT_ALWAYS (mpz_odd_p (p));
+
+  mpz_init (r);
+  mpz_init (e);
+
+  mpz_fdiv_r (r, a, p);
+
+  mpz_set (e, p);
+  mpz_sub_ui (e, e, 1);
+  mpz_fdiv_q_2exp (e, e, 1);
+  mpz_powm (r, r, e, p);
+
+  /* Normalize to a more or less symmetric range around zero */
+  if (mpz_cmp (r, e) > 0)
+    mpz_sub (r, r, p);
+
+  ASSERT_ALWAYS (mpz_cmpabs_ui (r, 1) <= 0);
+
+  res = mpz_sgn (r);
+
+  mpz_clear (r);
+  mpz_clear (e);
+
+  return res;
+}
+
+
+int
+refmpz_kronecker_ui (mpz_srcptr a, unsigned long b)
+{
+  mpz_t  bz;
+  int    ret;
+  mpz_init_set_ui (bz, b);
+  ret = refmpz_kronecker (a, bz);
+  mpz_clear (bz);
+  return ret;
+}
+
+int
+refmpz_kronecker_si (mpz_srcptr a, long b)
+{
+  mpz_t  bz;
+  int    ret;
+  mpz_init_set_si (bz, b);
+  ret = refmpz_kronecker (a, bz);
+  mpz_clear (bz);
+  return ret;
+}
+
+int
+refmpz_ui_kronecker (unsigned long a, mpz_srcptr b)
+{
+  mpz_t  az;
+  int    ret;
+  mpz_init_set_ui (az, a);
+  ret = refmpz_kronecker (az, b);
+  mpz_clear (az);
+  return ret;
+}
+
+int
+refmpz_si_kronecker (long a, mpz_srcptr b)
+{
+  mpz_t  az;
+  int    ret;
+  mpz_init_set_si (az, a);
+  ret = refmpz_kronecker (az, b);
+  mpz_clear (az);
+  return ret;
+}
+
+
+void
+refmpz_pow_ui (mpz_ptr w, mpz_srcptr b, unsigned long e)
+{
+  mpz_t          s, t;
+  unsigned long  i;
+
+  mpz_init_set_ui (t, 1L);
+  mpz_init_set (s, b);
+
+  if ((e & 1) != 0)
+    mpz_mul (t, t, s);
+
+  for (i = 2; i <= e; i <<= 1)
+    {
+      mpz_mul (s, s, s);
+      if ((i & e) != 0)
+	mpz_mul (t, t, s);
+    }
+
+  mpz_set (w, t);
+
+  mpz_clear (s);
+  mpz_clear (t);
+}
diff --git a/tests/spinner.c b/tests/spinner.c
new file mode 100644
index 0000000..13448d0
--- /dev/null
+++ b/tests/spinner.c
@@ -0,0 +1,128 @@
+/* A stupid little spinning wheel designed to make it look like useful work
+   is being done.
+
+Copyright 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>     /* for isatty */
+#endif
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+/* "alarm" is not available on mingw32, and the SIGALRM constant is not
+   defined.  Don't bother with a spinner in this case.  */
+#if ! HAVE_ALARM || ! defined (SIGALRM)
+#define alarm(n)          abort()
+#define signal(sig,func)  SIG_ERR
+#endif
+
+
+/* An application can update this to get a count printed with the spinner.
+   If left at 0, no count is printed. */
+
+unsigned long  spinner_count = 0;
+
+
+int  spinner_wanted = -1;  /* -1 uninitialized, 1 wanted, 0 not */
+int  spinner_tick = 1;     /* 1 ready to print, 0 not */
+
+
+/*ARGSUSED*/
+RETSIGTYPE
+spinner_signal (int signum)
+{
+  spinner_tick = 1;
+
+  if (signal (SIGALRM, spinner_signal) == SIG_ERR)
+    {
+      printf ("spinner_signal(): Oops, cannot reinstall SIGALRM\n");
+      abort ();
+    }
+  alarm (1);
+}
+
+
+/* Initialize the spinner.
+
+   This is done the first time spinner() is called, so an application
+   doesn't need to call this directly.
+
+   The spinner is only wanted if the output is a tty.  */
+
+#define SPINNER_WANTED_INIT() \
+  if (spinner_wanted < 0) spinner_init ()
+
+void
+spinner_init (void)
+{
+  spinner_wanted = isatty (STDOUT_FILENO);
+  if (spinner_wanted == -1)
+    abort ();
+
+  if (!spinner_wanted)
+    return;
+
+  if (signal (SIGALRM, spinner_signal) == SIG_ERR)
+    {
+      printf ("(no spinner)\r");
+      spinner_tick = 0;
+      return;
+    }
+  alarm (1);
+
+  /* unbuffered output so the spinner will show up */
+  setbuf (stdout, NULL);
+}
+
+
+void
+spinner (void)
+{
+  static const char  data[] = { '|', '/', '-', '\\' };
+  static int         pos = 0;
+
+  char  buf[128];
+
+  SPINNER_WANTED_INIT ();
+
+  if (spinner_tick)
+    {
+      buf[0] = data[pos];
+      pos = (pos + 1) % numberof (data);
+      spinner_tick = 0;
+
+      if (spinner_count != 0)
+	{
+	  sprintf (buf+1, " %lu\r", spinner_count);
+	}
+      else
+	{
+	  buf[1] = '\r';
+	  buf[2] = '\0';
+	}
+      fputs (buf, stdout);
+    }
+}
diff --git a/tests/t-bswap.c b/tests/t-bswap.c
new file mode 100644
index 0000000..765ef8e
--- /dev/null
+++ b/tests/t-bswap.c
@@ -0,0 +1,70 @@
+/* Test BSWAP_LIMB.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+int
+main (void)
+{
+  mp_limb_t  src, want, got;
+  int        i;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  for (i = 0; i < 1000; i++)
+    {
+      mpn_random (&src, (mp_size_t) 1);
+
+      want = ref_bswap_limb (src);
+
+      BSWAP_LIMB (got, src);
+      if (got != want)
+        {
+          printf ("BSWAP_LIMB wrong result\n");
+        error:
+          mpn_trace ("  src ", &src,  (mp_size_t) 1);
+          mpn_trace ("  want", &want, (mp_size_t) 1);
+          mpn_trace ("  got ", &got,  (mp_size_t) 1);
+          abort ();
+        }
+
+      BSWAP_LIMB_FETCH (got, &src);
+      if (got != want)
+        {
+          printf ("BSWAP_LIMB_FETCH wrong result\n");
+          goto error;
+        }
+
+      BSWAP_LIMB_STORE (&got, src);
+      if (got != want)
+        {
+          printf ("BSWAP_LIMB_STORE wrong result\n");
+          goto error;
+        }
+    }
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/t-constants.c b/tests/t-constants.c
new file mode 100644
index 0000000..35714c7
--- /dev/null
+++ b/tests/t-constants.c
@@ -0,0 +1,343 @@
+/* Check the values of some constants.
+
+Copyright 2000-2003, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#ifdef ULONG_MAX
+const char *ulong_max_def = "defined";
+#else
+const char *ulong_max_def = "not defined";
+#endif
+#ifdef LONG_MAX
+const char *long_max_def = "defined";
+#else
+const char *long_max_def = "not defined";
+#endif
+
+#ifdef UINT_MAX
+const char *uint_max_def = "defined";
+#else
+const char *uint_max_def = "not defined";
+#endif
+#ifdef INT_MAX
+const char *int_max_def = "defined";
+#else
+const char *int_max_def = "not defined";
+#endif
+
+#ifdef USHRT_MAX
+const char *ushrt_max_def = "defined";
+#else
+const char *ushrt_max_def = "not defined";
+#endif
+#ifdef SHRT_MAX
+const char *shrt_max_def = "defined";
+#else
+const char *shrt_max_def = "not defined";
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#ifdef _LONG_LONG_LIMB
+#define LL(l,ll)  ll
+#else
+#define LL(l,ll)  l
+#endif
+
+#if __GMP_MP_SIZE_T_INT
+#define SS(i,l)   i
+#else
+#define SS(i,l)   l
+#endif
+
+
+#define CHECK_LIMB_S(x, xname, y, yname)                \
+  do {                                                  \
+    if ((x) != (y))                                     \
+      {                                                 \
+        printf (LL("%s == %lx, but %s == %lx\n",        \
+                   "%s == %llx, but %s == %llx\n"),     \
+                xname, x, yname, y);                    \
+        error = 1;                                      \
+      }                                                 \
+  } while (0)
+
+#define CHECK_INT_S(x, xname, y, yname)                                 \
+  do {                                                                  \
+    if ((x) != (y))                                                     \
+      {                                                                 \
+        printf ("%s == %d, but %s == %d\n", xname, x, yname, y);        \
+        error = 1;                                                      \
+      }                                                                 \
+  } while (0)
+
+
+
+#define CHECK_CONDITION_S(x, xname)             \
+  do {                                          \
+    if (!(x))                                   \
+      {                                         \
+        printf ("%s is false\n", xname);        \
+        error = 1;                              \
+      }                                         \
+  } while (0)
+
+
+/* How many bits seem to work in the given type. */
+#define CALC_BITS(result, type) \
+  do {                          \
+    type  n = 1;                \
+    result = 0;                 \
+    while (n != 0)              \
+      {                         \
+        n <<= 1;                \
+        result++;               \
+      }                         \
+  } while (0)
+
+#define CHECK_BITS_S(constant, constant_name, type)     \
+  do {                                                  \
+    int   calculated;                                   \
+    CALC_BITS (calculated, type);                       \
+    if (calculated != constant)                         \
+      {                                                 \
+        printf ("%s == %d, but calculated %d\n",        \
+                constant_name, constant, calculated);   \
+        error = 1;                                      \
+      }                                                 \
+  } while (0)
+
+
+#define CHECK_HIGHBIT_S(value, value_name, type, format)        \
+  do {                                                          \
+    type  n = value;                                            \
+    if (n == 0)                                                 \
+      {                                                         \
+        printf ("%s == 0\n", value_name);                       \
+        error = 1;                                              \
+      }                                                         \
+    n <<= 1;                                                    \
+    if (n != 0)                                                 \
+      {                                                         \
+        printf ("%s << 1 = ", value_name);                      \
+        printf (format, n);                                     \
+        printf (" != 0\n");                                     \
+        error = 1;                                              \
+      }                                                         \
+  } while (0)
+
+
+#define CHECK_MAX_S(max_val, max_name, min_val, min_name, type, format) \
+  do {                                                                  \
+    type  maxval = max_val;                                             \
+    type  minval = min_val;                                             \
+    type  n = maxval;                                                   \
+    n++;                                                                \
+    if (n != minval)                                                    \
+      {                                                                 \
+        printf ("%s + 1 = ", max_name);                                 \
+        printf (format, n);                                             \
+        printf (" != %s = ", min_name);                                 \
+        printf (format, minval);                                        \
+        printf ("\n");                                                  \
+        error = 1;                                                      \
+      }                                                                 \
+    if (maxval <= minval)                                               \
+      {                                                                 \
+        printf ("%s = ", max_name);                                     \
+        printf (format, maxval);                                        \
+        printf (" <= %s = ", min_name);                                 \
+        printf (format, minval);                                        \
+        printf ("\n");                                                  \
+        error = 1;                                                      \
+      }                                                                 \
+  } while (0)
+
+
+#define CHECK_LIMB(x,y)      CHECK_LIMB_S (x, #x, y, #y)
+#define CHECK_INT(x,y)       CHECK_INT_S (x, #x, y, #y)
+#define CHECK_CONDITION(x)   CHECK_CONDITION_S (x, #x)
+#define CHECK_BITS(c,t)      CHECK_BITS_S (c, #c, t)
+#define CHECK_MAX(m,n,t,f)   CHECK_MAX_S (m, #m, n, #n, t, f)
+#define CHECK_HIGHBIT(n,t,f) CHECK_HIGHBIT_S (n, #n, t, f)
+
+
+/* The tests below marked "Bad!" fail on Cray T90 systems, where int, short
+   and mp_size_t are 48 bits or some such but don't wraparound in a plain
+   twos complement fashion.  In particular,
+
+       INT_HIGHBIT << 1 = 0xFFFFC00000000000 != 0
+       INT_MAX + 1 = 35184372088832 != INT_MIN = -35184372088832
+
+   This is a bit bizarre, but doesn't matter because GMP doesn't rely on any
+   particular overflow behaviour for int or short, only for mp_limb_t.  */
+
+int
+main (int argc, char *argv[])
+{
+  int  error = 0;
+
+  CHECK_INT (GMP_LIMB_BYTES, (int) sizeof(mp_limb_t));
+  CHECK_INT (mp_bits_per_limb, GMP_LIMB_BITS);
+
+  CHECK_BITS (GMP_LIMB_BITS, mp_limb_t);
+  CHECK_BITS (BITS_PER_ULONG, unsigned long);
+
+  CHECK_HIGHBIT (GMP_LIMB_HIGHBIT, mp_limb_t,      LL("0x%lX","0x%llX"));
+  CHECK_HIGHBIT (ULONG_HIGHBIT,     unsigned long,  "0x%lX");
+  CHECK_HIGHBIT (UINT_HIGHBIT,      unsigned int,   "0x%X");
+  CHECK_HIGHBIT (USHRT_HIGHBIT,     unsigned short, "0x%hX");
+#if 0 /* Bad! */
+  CHECK_HIGHBIT (LONG_HIGHBIT,      long,           "0x%lX");
+  CHECK_HIGHBIT (INT_HIGHBIT,       int,            "0x%X");
+  CHECK_HIGHBIT (SHRT_HIGHBIT,      short,          "0x%hX");
+#endif
+
+#if 0 /* Bad! */
+  CHECK_MAX (LONG_MAX,      LONG_MIN,      long,           "%ld");
+  CHECK_MAX (INT_MAX,       INT_MIN,       int,            "%d");
+  CHECK_MAX (SHRT_MAX,      SHRT_MIN,      short,          "%hd");
+#endif
+  CHECK_MAX (ULONG_MAX,     0,             unsigned long,  "%lu");
+  CHECK_MAX (UINT_MAX,      0,             unsigned int,   "%u");
+  CHECK_MAX (USHRT_MAX,     0,             unsigned short, "%hu");
+#if 0 /* Bad! */
+  CHECK_MAX (MP_SIZE_T_MAX, MP_SIZE_T_MIN, mp_size_t,      SS("%d","%ld"));
+#endif
+
+  /* UHWtype should have at least enough bits for half a UWtype */
+  {
+    int  bits_per_UWtype, bits_per_UHWtype;
+    CALC_BITS (bits_per_UWtype,  UWtype);
+    CALC_BITS (bits_per_UHWtype, UHWtype);
+    CHECK_CONDITION (2*bits_per_UHWtype >= bits_per_UWtype);
+  }
+
+  ASSERT_ALWAYS_LIMB (MODLIMB_INVERSE_3);
+  {
+    mp_limb_t  modlimb_inverse_3_calc;
+    binvert_limb (modlimb_inverse_3_calc, CNST_LIMB(3));
+    ASSERT_ALWAYS_LIMB (modlimb_inverse_3_calc);
+    CHECK_LIMB (MODLIMB_INVERSE_3, modlimb_inverse_3_calc);
+  }
+  {
+    mp_limb_t  MODLIMB_INVERSE_3_times_3
+      = (MODLIMB_INVERSE_3 * CNST_LIMB(3)) & GMP_NUMB_MASK;
+    CHECK_LIMB (MODLIMB_INVERSE_3_times_3, CNST_LIMB(1));
+  }
+
+  {
+    mp_limb_t  hi, lo;
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_MAX_DIV3-1,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi < 1))
+      {
+        printf ("GMP_NUMB_CEIL_MAX_DIV3 too big\n");
+        error = 1;
+      }
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_MAX_DIV3,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi >= 1))
+      {
+        printf ("GMP_NUMB_CEIL_MAX_DIV3 too small\n");
+        error = 1;
+      }
+  }
+
+  {
+    mp_limb_t  hi, lo;
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_2MAX_DIV3-1,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi < 2))
+      {
+        printf ("GMP_NUMB_CEIL_2MAX_DIV3 too big\n");
+        error = 1;
+      }
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_2MAX_DIV3,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi >= 2))
+      {
+        printf ("GMP_NUMB_CEIL_2MAX_DIV3 too small\n");
+        error = 1;
+      }
+  }
+
+#ifdef PP_INVERTED
+  {
+    mp_limb_t  pp_inverted_calc;
+    invert_limb (pp_inverted_calc, PP);
+    CHECK_LIMB (PP_INVERTED, pp_inverted_calc);
+  }
+#endif
+
+  if (argc >= 2 || error)
+    {
+      int  bits;
+
+      printf ("\n");
+      printf ("After gmp.h,\n");
+      printf ("  ULONG_MAX  %s\n", ulong_max_def);
+      printf ("  LONG_MAX   %s\n", long_max_def);
+      printf ("  UINT_MAX   %s\n", uint_max_def);
+      printf ("  INT_MAX    %s\n", int_max_def);
+      printf ("  USHRT_MAX  %s\n", ushrt_max_def);
+      printf ("  SHRT_MAX   %s\n", shrt_max_def);
+      printf ("\n");
+
+#ifdef _CRAY
+      printf ("_CRAY is defined, so limits.h is being used\n");
+#endif
+
+      printf ("ULONG_MAX      %lX\n", ULONG_MAX);
+      printf ("ULONG_HIGHBIT  %lX\n", ULONG_HIGHBIT);
+      printf ("LONG_MAX       %lX\n", LONG_MAX);
+      printf ("LONG_MIN       %lX\n", LONG_MIN);
+
+      printf ("UINT_MAX       %X\n", UINT_MAX);
+      printf ("UINT_HIGHBIT   %X\n", UINT_HIGHBIT);
+      printf ("INT_MAX        %X\n", INT_MAX);
+      printf ("INT_MIN        %X\n", INT_MIN);
+
+      printf ("USHRT_MAX      %X\n", USHRT_MAX);
+      printf ("USHRT_HIGHBIT  %X\n", USHRT_HIGHBIT);
+      printf ("SHRT_MAX       %X\n", SHRT_MAX);
+      printf ("SHRT_MIN       %X\n", SHRT_MIN);
+
+      printf ("\n");
+      printf ("Bits\n");
+      CALC_BITS (bits, long);           printf ("  long           %d\n", bits);
+      CALC_BITS (bits, int);            printf ("  int            %d\n", bits);
+      CALC_BITS (bits, short);          printf ("  short          %d\n", bits);
+      CALC_BITS (bits, unsigned long);  printf ("  unsigned long  %d\n", bits);
+      CALC_BITS (bits, unsigned int);   printf ("  unsigned int   %d\n", bits);
+      CALC_BITS (bits, unsigned short); printf ("  unsigned short %d\n", bits);
+      CALC_BITS (bits, mp_size_t);      printf ("  mp_size_t      %d\n", bits);
+    }
+
+  if (error)
+    abort ();
+
+  exit (0);
+}
diff --git a/tests/t-count_zeros.c b/tests/t-count_zeros.c
new file mode 100644
index 0000000..5bb243c
--- /dev/null
+++ b/tests/t-count_zeros.c
@@ -0,0 +1,86 @@
+/* Test count_leading_zeros and count_trailing_zeros.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+void
+check_clz (int want, mp_limb_t n)
+{
+  int  got;
+  count_leading_zeros (got, n);
+  if (got != want)
+    {
+      printf        ("count_leading_zeros wrong\n");
+      mp_limb_trace ("  n    ", n);
+      printf        ("  want %d\n", want);
+      printf        ("  got  %d\n", got);
+      abort ();
+    }
+}
+
+void
+check_ctz (int want, mp_limb_t n)
+{
+  int  got;
+  count_trailing_zeros (got, n);
+  if (got != want)
+    {
+      printf ("count_trailing_zeros wrong\n");
+      mpn_trace ("  n    ", &n, (mp_size_t) 1);
+      printf    ("  want %d\n", want);
+      printf    ("  got  %d\n", got);
+      abort ();
+    }
+}
+
+void
+check_various (void)
+{
+  int        i;
+
+#ifdef COUNT_LEADING_ZEROS_0
+  check_clz (COUNT_LEADING_ZEROS_0, CNST_LIMB(0));
+#endif
+
+  for (i=0; i < GMP_LIMB_BITS; i++)
+    {
+      check_clz (i, CNST_LIMB(1) << (GMP_LIMB_BITS-1-i));
+      check_ctz (i, CNST_LIMB(1) << i);
+
+      check_ctz (i, MP_LIMB_T_MAX << i);
+      check_clz (i, MP_LIMB_T_MAX >> i);
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/t-hightomask.c b/tests/t-hightomask.c
new file mode 100644
index 0000000..3c65d03
--- /dev/null
+++ b/tests/t-hightomask.c
@@ -0,0 +1,42 @@
+/* Test LIMB_HIGHBIT_TO_MASK.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* There's very little to these tests, but it's nice to have them since if
+   something has gone wrong with the arithmetic right shift business in
+   LIMB_HIGHBIT_TO_MASK then the only symptom is likely to be failures in
+   udiv_qrnnd_preinv, which would not be easy to diagnose.  */
+
+int
+main (void)
+{
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (0) == 0);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (GMP_LIMB_HIGHBIT) == MP_LIMB_T_MAX);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (MP_LIMB_T_MAX) == MP_LIMB_T_MAX);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (GMP_LIMB_HIGHBIT >> 1) == 0);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (MP_LIMB_T_MAX >> 1) == 0);
+
+  exit (0);
+}
diff --git a/tests/t-modlinv.c b/tests/t-modlinv.c
new file mode 100644
index 0000000..47f5533
--- /dev/null
+++ b/tests/t-modlinv.c
@@ -0,0 +1,83 @@
+/* Test binvert_limb.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+void
+one (mp_limb_t n)
+{
+  mp_limb_t  inv, prod;
+
+  binvert_limb (inv, n);
+  prod = (inv * n) & GMP_NUMB_MASK;
+  if (prod != 1)
+    {
+      printf ("binvert_limb wrong\n");
+      mp_limb_trace ("  n       ", n);
+      mp_limb_trace ("  got     ", inv);
+      mp_limb_trace ("  product ", prod);
+      abort ();
+    }
+}
+
+void
+some (void)
+{
+  int  i;
+  for (i = 0; i < 10000; i++)
+    one (refmpn_random_limb () | 1);
+}
+
+void
+all (void)
+{
+  mp_limb_t  n;
+
+  n = 1;
+  do {
+    one (n);
+    n += 2;
+  } while (n != 1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  if (argc >= 2 && strcmp (argv[1], "-a") == 0)
+    {
+      /* it's feasible to run all values on a 32-bit limb, but not a 64-bit */
+      all ();
+    }
+  else
+    {
+      some ();
+    }
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/t-parity.c b/tests/t-parity.c
new file mode 100644
index 0000000..b6f2366
--- /dev/null
+++ b/tests/t-parity.c
@@ -0,0 +1,66 @@
+/* Test ULONG_PARITY.
+
+Copyright 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_one (int want, unsigned long n)
+{
+  int  got;
+  ULONG_PARITY (got, n);
+  if (got != want)
+    {
+      printf ("ULONG_PARITY wrong\n");
+      printf ("  n    %lX\n", n);
+      printf ("  want %d\n", want);
+      printf ("  got  %d\n", got);
+      abort ();
+    }
+}
+
+void
+check_various (void)
+{
+  int  i;
+
+  check_one (0, 0L);
+  check_one (BITS_PER_ULONG & 1, ULONG_MAX);
+  check_one (0, 0x11L);
+  check_one (1, 0x111L);
+  check_one (1, 0x3111L);
+
+  for (i = 0; i < BITS_PER_ULONG; i++)
+    check_one (1, 1UL << i);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/t-popc.c b/tests/t-popc.c
new file mode 100644
index 0000000..421d4e2
--- /dev/null
+++ b/tests/t-popc.c
@@ -0,0 +1,79 @@
+/* Test popc_limb.
+
+Copyright 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+int
+main (void)
+{
+  mp_limb_t  src, want, got;
+  int        i;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  for (i = 0; i < GMP_LIMB_BITS; i++)
+    {
+      src = CNST_LIMB(1) << i;
+      want = 1;
+
+      popc_limb (got, src);
+      if (got != want)
+        {
+        error:
+          printf ("popc_limb wrong result\n");
+          mpn_trace ("  src ", &src,  (mp_size_t) 1);
+          mpn_trace ("  want", &want, (mp_size_t) 1);
+          mpn_trace ("  got ", &got,  (mp_size_t) 1);
+          abort ();
+        }
+    }
+
+  src = 0;
+  want = 0;
+  for (i = 0; i < GMP_LIMB_BITS; i++)
+    {
+      src += CNST_LIMB(1) << i;
+      want += 1;
+
+      popc_limb (got, src);
+      if (got != want)
+        {
+	  goto error;
+        }
+    }
+
+  for (i = 0; i < 100; i++)
+    {
+      mpn_random2 (&src, (mp_size_t) 1);
+      want = ref_popc_limb (src);
+
+      popc_limb (got, src);
+      if (got != want)
+        goto error;
+    }
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/t-sub.c b/tests/t-sub.c
new file mode 100644
index 0000000..e916d4f
--- /dev/null
+++ b/tests/t-sub.c
@@ -0,0 +1,114 @@
+/* Test sub_ddmmss.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+#define M  MP_LIMB_T_MAX
+
+  static const struct {
+    mp_limb_t  want_dh,want_dl, mh,ml, sh,sl;
+  } data[] = {
+    { 0,0,  0,0,  0,0 },
+    { 0,0,  0,1,  0,1 },
+    { 0,0,  1,2,  1,2 },
+
+    { 0,1,  0,2,  0,1 },
+    { 0,M,  1,0,  0,1 },
+    { M,M,  0,0,  0,1 },
+
+    { M,M,  0,M-1,  0,M },
+    { 0,0,  0,M-1,  0,M-1 },
+    { 0,1,  0,M-1,  0,M-2 },
+  };
+  int  i;
+  mp_limb_t  got_dh, got_dl;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      sub_ddmmss (got_dh,got_dl, data[i].mh,data[i].ml, data[i].sh,data[i].sl);
+      if (got_dh != data[i].want_dh || got_dl != data[i].want_dl)
+        {
+          printf ("check_data wrong at data[%d]\n", i);
+          mp_limb_trace ("  mh", data[i].mh);
+          mp_limb_trace ("  ml", data[i].ml);
+          mp_limb_trace ("  sh", data[i].sh);
+          mp_limb_trace ("  sl", data[i].sl);
+          mp_limb_trace ("  want dh", data[i].want_dh);
+          mp_limb_trace ("  want dl", data[i].want_dl);
+          mp_limb_trace ("  got dh ", got_dh);
+          mp_limb_trace ("  got dl ", got_dl);
+          abort ();
+        }
+    }
+}
+
+void
+check_random (void)
+{
+  mp_limb_t  want_dh,want_dl, got_dh,got_dl, mh,ml, sh,sl;
+  int  i;
+
+  for (i = 0; i < 20; i++)
+    {
+      mh = urandom ();
+      ml = urandom ();
+      sh = urandom ();
+      sl = urandom ();
+
+      refmpn_sub_ddmmss (&want_dh,&want_dl, mh,ml, sh,sl);
+
+      sub_ddmmss (got_dh,got_dl, mh,ml, sh,sl);
+
+      if (got_dh != want_dh || got_dl != want_dl)
+        {
+          printf ("check_data wrong at data[%d]\n", i);
+          mp_limb_trace ("  mh", mh);
+          mp_limb_trace ("  ml", ml);
+          mp_limb_trace ("  sh", sh);
+          mp_limb_trace ("  sl", sl);
+          mp_limb_trace ("  want dh", want_dh);
+          mp_limb_trace ("  want dl", want_dl);
+          mp_limb_trace ("  got dh ", got_dh);
+          mp_limb_trace ("  got dl ", got_dl);
+          abort ();
+        }
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_data ();
+  check_random ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/tests/tests.h b/tests/tests.h
new file mode 100644
index 0000000..882c634
--- /dev/null
+++ b/tests/tests.h
@@ -0,0 +1,447 @@
+/* Tests support prototypes etc.
+
+Copyright 2000-2004, 2008-2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#ifndef __TESTS_H__
+#define __TESTS_H__
+
+#include "config.h"
+
+#include <setjmp.h>  /* for jmp_buf */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+#define ANYARGS  ...
+#else
+#define ANYARGS
+#endif
+
+
+void tests_start (void);
+void tests_end (void);
+
+void tests_memory_start (void);
+void tests_memory_end (void);
+void *tests_allocate (size_t);
+void *tests_reallocate (void *, size_t, size_t);
+void tests_free (void *, size_t);
+void tests_free_nosize (void *);
+int tests_memory_valid (void *);
+
+void tests_rand_start (void);
+void tests_rand_end (void);
+
+double tests_infinity_d ();
+int tests_hardware_getround (void);
+int tests_hardware_setround (int);
+int tests_isinf (double);
+int tests_dbl_mant_bits (void);
+
+void x86_fldcw (unsigned short);
+unsigned short x86_fstcw (void);
+
+
+/* tests_setjmp_sigfpe is like a setjmp, establishing a trap for SIGFPE.
+   The initial return is 0, if SIGFPE is trapped execution goes back there
+   with return value 1.
+
+   tests_sigfpe_done puts SIGFPE back to SIG_DFL, which should be used once
+   the setjmp point is out of scope, so a later SIGFPE won't try to go back
+   there.  */
+
+#define tests_setjmp_sigfpe()                   \
+  (signal (SIGFPE, tests_sigfpe_handler),       \
+   setjmp (tests_sigfpe_target))
+
+RETSIGTYPE tests_sigfpe_handler (int);
+void tests_sigfpe_done (void);
+extern jmp_buf  tests_sigfpe_target;
+
+
+#if HAVE_CALLING_CONVENTIONS
+extern mp_limb_t (*calling_conventions_function) (ANYARGS);
+mp_limb_t calling_conventions (ANYARGS);
+int calling_conventions_check (void);
+#define CALLING_CONVENTIONS(function) \
+  (calling_conventions_function = (function), calling_conventions)
+#define CALLING_CONVENTIONS_CHECK()    (calling_conventions_check())
+#else
+#define CALLING_CONVENTIONS(function)  (function)
+#define CALLING_CONVENTIONS_CHECK()    1 /* always ok */
+#endif
+
+
+extern int mp_trace_base;
+void mp_limb_trace (const char *, mp_limb_t);
+void mpn_trace (const char *, mp_srcptr, mp_size_t);
+void mpn_tracea (const char *, const mp_ptr *, int, mp_size_t);
+void mpn_tracen (const char *, int, mp_srcptr, mp_size_t);
+void mpn_trace_file (const char *, mp_srcptr, mp_size_t);
+void mpn_tracea_file (const char *, const mp_ptr *, int, mp_size_t);
+void mpf_trace (const char *, mpf_srcptr);
+void mpq_trace (const char *, mpq_srcptr);
+void mpz_trace (const char *, mpz_srcptr);
+void mpz_tracen (const char *, int, mpz_srcptr);
+void byte_trace (const char *, const void *, mp_size_t);
+void byte_tracen (const char *, int, const void *, mp_size_t);
+void d_trace (const char *, double);
+
+
+void spinner (void);
+extern unsigned long  spinner_count;
+extern int  spinner_wanted;
+extern int  spinner_tick;
+
+
+void *align_pointer (void *, size_t);
+void *__gmp_allocate_func_aligned (size_t, size_t);
+void *__gmp_allocate_or_reallocate (void *, size_t, size_t);
+char *__gmp_allocate_strdup (const char *);
+char *strtoupper (char *);
+mp_limb_t urandom (void);
+void call_rand_algs (void (*func) (const char *, gmp_randstate_t));
+
+
+void mpf_set_str_or_abort (mpf_ptr, const char *, int);
+
+
+void mpq_set_str_or_abort (mpq_ptr, const char *, int);
+
+
+void mpz_erandomb (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_erandomb_nonzero (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_errandomb (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_errandomb_nonzero (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_init_set_n (mpz_ptr, mp_srcptr, mp_size_t);
+void mpz_negrandom (mpz_ptr, gmp_randstate_t);
+int mpz_pow2abs_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+void mpz_set_n (mpz_ptr, mp_srcptr, mp_size_t);
+void mpz_set_str_or_abort (mpz_ptr, const char *, int);
+void mpz_clobber(mpz_ptr);
+
+mp_size_t mpn_diff_highest (mp_srcptr, mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+mp_size_t mpn_diff_lowest (mp_srcptr, mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+mp_size_t byte_diff_highest (const void *, const void *, mp_size_t) __GMP_ATTRIBUTE_PURE;
+mp_size_t byte_diff_lowest (const void *, const void *, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+mp_limb_t ref_addc_limb (mp_limb_t *, mp_limb_t, mp_limb_t);
+mp_limb_t ref_bswap_limb (mp_limb_t);
+unsigned long ref_popc_limb (mp_limb_t);
+mp_limb_t ref_subc_limb (mp_limb_t *, mp_limb_t, mp_limb_t);
+
+
+void refmpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+void refmpf_add_ulp (mpf_ptr );
+void refmpf_fill (mpf_ptr, mp_size_t, mp_limb_t);
+void refmpf_normalize (mpf_ptr);
+void refmpf_set_prec_limbs (mpf_ptr, unsigned long);
+unsigned long refmpf_set_overlap (mpf_ptr, mpf_srcptr);
+void refmpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+int refmpf_validate (const char *, mpf_srcptr, mpf_srcptr);
+int refmpf_validate_division (const char *, mpf_srcptr, mpf_srcptr, mpf_srcptr);
+
+
+mp_limb_t refmpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_add_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addlsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_addlsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_addlsh1_n_ip2 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh2_n_ip2 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh_n_ip2 (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_addlsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addlsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addlsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned, mp_limb_t);
+mp_limb_t refmpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addmul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_addmul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_7 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_8 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+mp_limb_t refmpn_add_n_sub_n (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_add_n_sub_nc (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+void refmpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_big_base (int);
+
+int refmpn_chars_per_limb (int);
+void refmpn_clrbit (mp_ptr, unsigned long);
+int refmpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+int refmpn_cmp_allowzero (mp_srcptr, mp_srcptr, mp_size_t);
+int refmpn_cmp_twosizes (mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+void refmpn_com (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copy (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copy_extend (mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+unsigned refmpn_count_leading_zeros (mp_limb_t);
+unsigned refmpn_count_trailing_zeros (mp_limb_t);
+
+mp_limb_t refmpn_divexact_by3 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t refmpn_divmod_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_divmod_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_divrem_1c (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+int refmpn_equal_anynail (mp_srcptr, mp_srcptr, mp_size_t);
+
+void refmpn_fill (mp_ptr, mp_size_t, mp_limb_t);
+
+mp_limb_t refmpn_gcd_11 (mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t);
+mp_double_limb_t refmpn_gcd_22 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+size_t refmpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+unsigned long refmpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_invert_limb (mp_limb_t);
+void refmpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_lshift_or_copy (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_lshift_or_copy_any (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_lshiftc (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+void refmpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+mp_ptr refmpn_malloc_limbs (mp_size_t);
+mp_ptr refmpn_malloc_limbs_aligned (mp_size_t, size_t);
+void refmpn_free_limbs (mp_ptr);
+mp_limb_t refmpn_msbone (mp_limb_t);
+mp_limb_t refmpn_msbone_mask (mp_limb_t);
+mp_ptr refmpn_memdup_limbs (mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_mod_1c (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_mod_34lsub1 (mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_mul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_mul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+void refmpn_mul_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_mulmid_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_toom42_mulmid (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+void refmpn_mulmid_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_mulmid (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_mullo_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_mul_any (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+void refmpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+mp_size_t refmpn_normalize (mp_srcptr, mp_size_t);
+
+unsigned long refmpn_popcount (mp_srcptr, mp_size_t);
+mp_limb_t refmpn_preinv_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, unsigned);
+mp_limb_t refmpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+void refmpn_random (mp_ptr, mp_size_t);
+void refmpn_random2 (mp_ptr, mp_size_t);
+mp_limb_t refmpn_random_limb (void);
+
+mp_limb_t refmpn_rsh1add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_rsh1sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_rshift_or_copy (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_rshift_or_copy_any (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+
+mp_limb_t refmpn_sb_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+unsigned long refmpn_scan0 (mp_srcptr, unsigned long);
+unsigned long refmpn_scan1 (mp_srcptr, unsigned long);
+void refmpn_setbit (mp_ptr, unsigned long);
+void refmpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_sqrlo (mp_ptr, mp_srcptr, mp_size_t);
+mp_size_t refmpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+void refmpn_sub_ddmmss (mp_limb_t *, mp_limb_t *, mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sub_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sublsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t refmpn_sublsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t refmpn_sublsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sublsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sublsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+mp_limb_t refmpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_submul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+mp_limb_signed_t refmpn_rsblsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_signed_t refmpn_rsblsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_signed_t refmpn_rsblsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_signed_t refmpn_rsblsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_signed_t);
+mp_limb_signed_t refmpn_rsblsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_signed_t);
+mp_limb_signed_t refmpn_rsblsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_signed_t);
+
+void refmpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+int refmpn_tstbit (mp_srcptr, unsigned long);
+
+mp_limb_t refmpn_udiv_qrnnd (mp_limb_t *, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_udiv_qrnnd_r (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t *);
+mp_limb_t refmpn_umul_ppmm (mp_limb_t *, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_umul_ppmm_r (mp_limb_t, mp_limb_t, mp_limb_t *);
+
+void refmpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+void refmpn_zero (mp_ptr, mp_size_t);
+void refmpn_zero_extend (mp_ptr, mp_size_t, mp_size_t);
+int refmpn_zero_p (mp_srcptr, mp_size_t);
+
+void refmpn_binvert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+void refmpn_invert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+
+void refmpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+void refmpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+
+void refmpz_combit (mpz_ptr, unsigned long);
+unsigned long refmpz_hamdist (mpz_srcptr, mpz_srcptr);
+void refmpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+int refmpz_kronecker (mpz_srcptr, mpz_srcptr);
+int refmpz_jacobi (mpz_srcptr, mpz_srcptr);
+int refmpz_legendre (mpz_srcptr, mpz_srcptr);
+int refmpz_kronecker_si (mpz_srcptr, long);
+int refmpz_kronecker_ui (mpz_srcptr, unsigned long);
+int refmpz_si_kronecker (long, mpz_srcptr);
+int refmpz_ui_kronecker (unsigned long, mpz_srcptr);
+
+void refmpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Establish ostringstream and istringstream.  Do this here so as to hide
+   the conditionals, rather than putting stuff in each test program.
+
+   Oldish versions of g++, like 2.95.2, don't have <sstream>, only
+   <strstream>.  Fake up ostringstream and istringstream classes, but not a
+   full implementation, just enough for our purposes.  */
+
+#ifdef __cplusplus
+#if 1 || HAVE_SSTREAM
+#include <sstream>
+#else /* ! HAVE_SSTREAM */
+#include <string>
+#include <strstream>
+class
+ostringstream : public std::ostrstream {
+ public:
+  string str() {
+    int  pcount = ostrstream::pcount ();
+    char *s = (char *) (*__gmp_allocate_func) (pcount + 1);
+    memcpy (s, ostrstream::str(), pcount);
+    s[pcount] = '\0';
+    string ret = string(s);
+    (*__gmp_free_func) (s, pcount + 1);
+    return ret; }
+};
+class
+istringstream : public std::istrstream {
+ public:
+  istringstream (const char *s) : istrstream (s) { };
+};
+#endif /* ! HAVE_SSTREAM */
+#endif /* __cplusplus */
+
+
+#define TESTS_REPS(count, argv, argc)					\
+  do {									\
+  char *envval, *end;							\
+  double repfactor;							\
+  int reps_nondefault = 0;						\
+  if (argc > 1)								\
+    {									\
+      count = strtol (argv[1], &end, 0);				\
+      if (*end || count <= 0)						\
+	{								\
+	  fprintf (stderr, "Invalid test count: %s.\n", argv[1]);	\
+	  exit (1);							\
+	}								\
+      argv++;								\
+      argc--;								\
+      reps_nondefault = 1;						\
+    }									\
+  envval = getenv ("GMP_CHECK_REPFACTOR");				\
+  if (envval != NULL)							\
+    {									\
+      repfactor = strtod (envval, &end);				\
+      if (*end || repfactor <= 0)					\
+	{								\
+	  fprintf (stderr, "Invalid repfactor: %f.\n", repfactor);	\
+	  exit (1);							\
+	}								\
+      count *= repfactor;						\
+      count = MAX (count, 1);						\
+      reps_nondefault = 1;						\
+    }									\
+  if (reps_nondefault)							\
+    printf ("Running test with %ld repetitions (include this in bug reports)\n",\
+	    (long) count);						\
+  } while (0)
+
+
+#endif /* __TESTS_H__ */
diff --git a/tests/trace.c b/tests/trace.c
new file mode 100644
index 0000000..de397f5
--- /dev/null
+++ b/tests/trace.c
@@ -0,0 +1,317 @@
+/* Support for diagnostic traces.
+
+Copyright 1999-2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Future: Would like commas printed between limbs in hex or binary, but
+   perhaps not always since it might upset cutting and pasting into bc or
+   whatever.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strlen */
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+/* Number base for the various trace printing routines.
+   Set this in main() or with the debugger.
+   If hexadecimal is going to be fed into GNU bc, remember to use -16
+   because bc requires upper case.  */
+
+int  mp_trace_base = 10;
+
+
+void
+mp_trace_start (const char *name)
+{
+  if (name != NULL && name[0] != '\0')
+    printf ("%s=", name);
+
+  switch (ABS (mp_trace_base)) {
+  case  2: printf ("bin:");                         break;
+  case  8: printf ("oct:");                         break;
+  case 10:                                          break;
+  case 16: printf ("0x");                           break;
+  default: printf ("base%d:", ABS (mp_trace_base)); break;
+  }
+}
+
+/* Print "name=value\n" to stdout for an mpq_t value.  */
+void
+mpq_trace (const char *name, mpq_srcptr q)
+{
+  mp_trace_start (name);
+  if (q == NULL)
+    {
+      printf ("NULL\n");
+      return;
+    }
+
+  mpq_out_str (stdout, mp_trace_base, q);
+  printf ("\n");
+}
+
+
+/* Print "name=value\n" to stdout for an mpz_t value.  */
+void
+mpz_trace (const char *name, mpz_srcptr z)
+{
+  mpq_t      q;
+  mp_limb_t  one;
+
+  if (z == NULL)
+    {
+      mpq_trace (name, NULL);
+      return;
+    }
+
+  q->_mp_num._mp_alloc = ALLOC(z);
+  q->_mp_num._mp_size = SIZ(z);
+  q->_mp_num._mp_d = PTR(z);
+
+  one = 1;
+  q->_mp_den._mp_alloc = 1;
+  q->_mp_den._mp_size = 1;
+  q->_mp_den._mp_d = &one;
+
+  mpq_trace(name, q);
+}
+
+
+/* Print "name=value\n" to stdout for an mpf_t value. */
+void
+mpf_trace (const char *name, mpf_srcptr f)
+{
+  mp_trace_start (name);
+  if (f == NULL)
+    {
+      printf ("NULL\n");
+      return;
+    }
+
+  mpf_out_str (stdout, ABS (mp_trace_base), 0, f);
+  printf ("\n");
+}
+
+
+/* Print "namenum=value\n" to stdout for an mpz_t value.
+   "name" should have a "%d" to get the number. */
+void
+mpz_tracen (const char *name, int num, mpz_srcptr z)
+{
+  if (name != NULL && name[0] != '\0')
+    {
+      printf (name, num);
+      putchar ('=');
+    }
+  mpz_trace (NULL, z);
+}
+
+
+/* Print "name=value\n" to stdout for an mpn style ptr,size. */
+void
+mpn_trace (const char *name, mp_srcptr ptr, mp_size_t size)
+{
+  mpz_t  z;
+  if (ptr == NULL)
+    {
+      mpz_trace (name, NULL);
+      return;
+    }
+  MPN_NORMALIZE (ptr, size);
+  PTR(z) = (mp_ptr) ptr;
+  SIZ(z) = size;
+  ALLOC(z) = size;
+  mpz_trace (name, z);
+}
+
+/* Print "name=value\n" to stdout for a limb, nail doesn't have to be zero. */
+void
+mp_limb_trace (const char *name, mp_limb_t n)
+{
+#if GMP_NAIL_BITS != 0
+  mp_limb_t  a[2];
+  a[0] = n & GMP_NUMB_MASK;
+  a[1] = n >> GMP_NUMB_BITS;
+  mpn_trace (name, a, (mp_size_t) 2);
+#else
+  mpn_trace (name, &n, (mp_size_t) 1);
+#endif
+}
+
+
+/* Print "namenum=value\n" to stdout for an mpn style ptr,size.
+   "name" should have a "%d" to get the number.  */
+void
+mpn_tracen (const char *name, int num, mp_srcptr ptr, mp_size_t size)
+{
+  if (name != NULL && name[0] != '\0')
+    {
+      printf (name, num);
+      putchar ('=');
+    }
+  mpn_trace (NULL, ptr, size);
+}
+
+
+/* Print "namenum=value\n" to stdout for an array of mpn style ptr,size.
+
+   "a" is an array of pointers, each a[i] is a pointer to "size" many limbs.
+   The formal parameter isn't mp_srcptr because that causes compiler
+   warnings, but the values aren't modified.
+
+   "name" should have a printf style "%d" to get the array index.  */
+
+void
+mpn_tracea (const char *name, const mp_ptr *a, int count, mp_size_t size)
+{
+  int i;
+  for (i = 0; i < count; i++)
+    mpn_tracen (name, i, a[i], size);
+}
+
+
+/* Print "value\n" to a file for an mpz_t value.  Any previous contents of
+   the file are overwritten, so you need different file names each time this
+   is called.
+
+   Overwriting the file is a feature, it means you get old data replaced
+   when you run a test program repeatedly.  */
+
+void
+mpn_trace_file (const char *filename, mp_srcptr ptr, mp_size_t size)
+{
+  FILE   *fp;
+  mpz_t  z;
+
+  fp = fopen (filename, "w");
+  if (fp == NULL)
+    {
+      perror ("fopen");
+      abort();
+    }
+
+  MPN_NORMALIZE (ptr, size);
+  PTR(z) = (mp_ptr) ptr;
+  SIZ(z) = (int) size;
+
+  mpz_out_str (fp, mp_trace_base, z);
+  fprintf (fp, "\n");
+
+  if (ferror (fp) || fclose (fp) != 0)
+    {
+      printf ("error writing %s\n", filename);
+      abort();
+    }
+}
+
+
+/* Print "value\n" to a set of files, one file for each element of the given
+   array of mpn style ptr,size.  Any previous contents of the files are
+   overwritten, so you need different file names each time this is called.
+   Each file is "filenameN" where N is 0 to count-1.
+
+   "a" is an array of pointers, each a[i] is a pointer to "size" many limbs.
+   The formal parameter isn't mp_srcptr because that causes compiler
+   warnings, but the values aren't modified.
+
+   Overwriting the files is a feature, it means you get old data replaced
+   when you run a test program repeatedly.  The output style isn't
+   particularly pretty, but at least it gets something out, and you can cat
+   the files into bc, or whatever. */
+
+void
+mpn_tracea_file (const char *filename,
+                 const mp_ptr *a, int count, mp_size_t size)
+{
+  char  *s;
+  int   i;
+  TMP_DECL;
+
+  TMP_MARK;
+  s = (char *) TMP_ALLOC (strlen (filename) + 50);
+
+  for (i = 0; i < count; i++)
+    {
+      sprintf (s, "%s%d", filename, i);
+      mpn_trace_file (s, a[i], size);
+    }
+
+  TMP_FREE;
+}
+
+
+void
+byte_trace (const char *name, const void *ptr, mp_size_t size)
+{
+  const char *fmt;
+  mp_size_t  i;
+
+  mp_trace_start (name);
+
+  switch (mp_trace_base) {
+  case   8: fmt = " %o"; break;
+  case  10: fmt = " %d"; break;
+  case  16: fmt = " %x"; break;
+  case -16: fmt = " %X"; break;
+  default: printf ("Oops, unsupported base in byte_trace\n"); abort (); break;
+  }
+
+  for (i = 0; i < size; i++)
+    printf (fmt, (int) ((unsigned char *) ptr)[i]);
+  printf ("\n");
+}
+
+void
+byte_tracen (const char *name, int num, const void *ptr, mp_size_t size)
+{
+  if (name != NULL && name[0] != '\0')
+    {
+      printf (name, num);
+      putchar ('=');
+    }
+  byte_trace (NULL, ptr, size);
+}
+
+
+void
+d_trace (const char *name, double d)
+{
+  union {
+    double         d;
+    unsigned char  b[sizeof(double)];
+  } u;
+  int  i;
+
+  if (name != NULL && name[0] != '\0')
+    printf ("%s=", name);
+
+  u.d = d;
+  printf ("[");
+  for (i = 0; i < sizeof (u.b); i++)
+    {
+      if (i != 0)
+        printf (" ");
+      printf ("%02X", (int) u.b[i]);
+    }
+  printf ("] %.20g\n", d);
+}
diff --git a/tests/x86call.asm b/tests/x86call.asm
new file mode 100644
index 0000000..439f781
--- /dev/null
+++ b/tests/x86call.asm
@@ -0,0 +1,154 @@
+dnl  x86 calling conventions checking.
+
+dnl  Copyright 2000, 2003, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library test suite.
+
+dnl  The GNU MP Library test suite is free software; you can redistribute it
+dnl  and/or modify it under the terms of the GNU General Public License as
+dnl  published by the Free Software Foundation; either version 3 of the
+dnl  License, or (at your option) any later version.
+
+dnl  The GNU MP Library test suite is distributed in the hope that it will be
+dnl  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+dnl  Public License for more details.
+
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with the GNU MP Library test suite.  If not, see
+dnl  https://www.gnu.org/licenses/.
+
+
+dnl  The current version of the code attempts to keep the call/return
+dnl  prediction stack valid, but matching calls and returns.
+
+include(`config.m4')
+
+
+C void x86_fldcw (unsigned short cw);
+C
+C Execute an fldcw, setting the x87 control word to cw.
+
+PROLOGUE(x86_fldcw)
+	fldcw	4(%esp)
+	ret
+EPILOGUE()
+
+
+C unsigned short x86_fstcw (void);
+C
+C Execute an fstcw, returning the current x87 control word.
+
+PROLOGUE(x86_fstcw)
+	xor	%eax, %eax
+	push	%eax
+	fstcw	(%esp)
+	pop	%eax
+	ret
+EPILOGUE()
+
+
+dnl  Instrumented profiling doesn't come out quite right below, since we don't
+dnl  do an actual "ret".  There's only a few instructions here, so there's no
+dnl  great need to get them separately accounted, just let them get attributed
+dnl  to the caller.  FIXME this comment might no longer be true.
+
+ifelse(WANT_PROFILING,instrument,
+`define(`WANT_PROFILING',no)')
+
+
+C int calling_conventions (...);
+C
+C The global variable "calling_conventions_function" is the function to
+C call, with the arguments as passed here.
+C
+C Perhaps the finit should be done only if the tags word isn't clear, but
+C nothing uses the rounding mode or anything at the moment.
+
+define(`WANT_EBX', eval(4*0)($1))
+define(`WANT_EBP', eval(4*1)($1))
+define(`WANT_ESI', eval(4*2)($1))
+define(`WANT_EDI', eval(4*3)($1))
+
+define(`JUNK_EAX', eval(4*4)($1))
+define(`JUNK_ECX', eval(4*5)($1))
+define(`JUNK_EDX', eval(4*6)($1))
+
+define(`SAVE_EBX', eval(4*7)($1))
+define(`SAVE_EBP', eval(4*8)($1))
+define(`SAVE_ESI', eval(4*9)($1))
+define(`SAVE_EDI', eval(4*10)($1))
+
+define(`RETADDR',  eval(4*11)($1))
+
+define(`EBX',	   eval(4*12)($1))
+define(`EBP',	   eval(4*13)($1))
+define(`ESI',	   eval(4*14)($1))
+define(`EDI',	   eval(4*15)($1))
+define(`EFLAGS',   eval(4*16)($1))
+
+
+define(G,
+m4_assert_numargs(1)
+`GSYM_PREFIX`'$1')
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(calling_conventions)
+	LEA(	G(calling_conventions_values), %ecx)
+	pop	RETADDR(%ecx)
+
+	mov	%ebx, SAVE_EBX(%ecx)
+	mov	%ebp, SAVE_EBP(%ecx)
+	mov	%esi, SAVE_ESI(%ecx)
+	mov	%edi, SAVE_EDI(%ecx)
+
+	C Values we expect to see unchanged, as per amd64check.c
+	mov	WANT_EBX(%ecx), %ebx
+	mov	WANT_EBP(%ecx), %ebp
+	mov	WANT_ESI(%ecx), %esi
+	mov	WANT_EDI(%ecx), %edi
+
+	C Try to provoke a problem by starting with junk in the caller-saves
+	C registers, especially in %eax and %edx which will be return values
+	mov	JUNK_EAX(%ecx), %eax
+	mov	JUNK_EDX(%ecx), %edx
+C	mov	JUNK_ECX(%ecx), %ecx
+
+ifdef(`PIC',`
+	LEA(	G(calling_conventions_function), %ecx)
+	call	*(%ecx)
+',`
+	call	*G(calling_conventions_function)
+')
+
+	LEA(	G(calling_conventions_values), %ecx)
+
+	mov	%ebx, EBX(%ecx)
+	mov	%ebp, EBP(%ecx)
+	mov	%esi, ESI(%ecx)
+	mov	%edi, EDI(%ecx)
+
+	pushf
+	pop	%ebx
+	mov	%ebx, EFLAGS(%ecx)
+
+	mov	SAVE_EBX(%ecx), %ebx
+	mov	SAVE_ESI(%ecx), %esi
+	mov	SAVE_EDI(%ecx), %edi
+	mov	SAVE_EBP(%ecx), %ebp
+
+	push	RETADDR(%ecx)
+
+ifdef(`PIC',`
+	LEA(	G(calling_conventions_fenv), %ecx)
+	fstenv	(%ecx)
+',`
+	fstenv	G(calling_conventions_fenv)
+')
+	finit
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/tests/x86check.c b/tests/x86check.c
new file mode 100644
index 0000000..12ea5b7
--- /dev/null
+++ b/tests/x86check.c
@@ -0,0 +1,117 @@
+/* x86 calling conventions checking. */
+
+/*
+Copyright 2000, 2001, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Vector if constants and register values.  We use one vector to allow access
+   via a base pointer, very beneficial for the PIC-enabled amd64call.asm.  */
+mp_limb_t calling_conventions_values[17] =
+{
+  CNST_LIMB(0x12345678),	/* want_ebx */
+  CNST_LIMB(0x89ABCDEF),	/* want_ebp */
+  CNST_LIMB(0xDEADBEEF),	/* want_esi */
+  CNST_LIMB(0xFFEEDDCC),	/* want_edi */
+
+  CNST_LIMB(0xFEEDABBA),	/* JUNK_EAX */
+  CNST_LIMB(0xAB78DE89),	/* JUNK_ECX */
+  CNST_LIMB(0x12389018)		/* JUNK_EDX */
+
+  /* rest of array used for dynamic values.  */
+};
+
+/* Index starts for various regions in above vector.  */
+#define WANT	0
+#define JUNK	4
+#define SAVE	7
+#define RETADDR	11
+#define VAL	12
+#define EFLAGS	16
+
+
+/* values to check */
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct {
+  unsigned  control;
+  unsigned  status;
+  unsigned  tag;
+  unsigned  other[4];
+} calling_conventions_fenv;
+#ifdef __cplusplus
+}
+#endif
+
+/* expected values, as per x86call.asm */
+#define VALUE_EBX   0x01234567
+#define VALUE_ESI   0x89ABCDEF
+#define VALUE_EDI   0xFEDCBA98
+#define VALUE_EBP   0x76543210
+
+
+const char *regname[] = {"ebx", "ebp", "esi", "edi"};
+
+#define DIR_BIT(eflags)   (((eflags) & (1<<10)) != 0)
+
+
+/* Return 1 if ok, 0 if not */
+
+int
+calling_conventions_check (void)
+{
+  const char  *header = "Violated calling conventions:\n";
+  int  ret = 1;
+  int i;
+
+#define CHECK(callreg, regstr, value)                   \
+  if (callreg != value)                                 \
+    {                                                   \
+      printf ("%s   %s  got 0x%08X want 0x%08X\n",      \
+              header, regstr, callreg, value);          \
+      header = "";                                      \
+      ret = 0;                                          \
+    }
+
+  for (i = 0; i < 4; i++)
+    {
+      CHECK (calling_conventions_values[VAL+i], regname[i], calling_conventions_values[WANT+i]);
+    }
+
+  if (DIR_BIT (calling_conventions_values[EFLAGS]) != 0)
+    {
+      printf ("%s   eflags dir bit  got %d want 0\n",
+              header, DIR_BIT (calling_conventions_values[EFLAGS]));
+      header = "";
+      ret = 0;
+    }
+
+  if ((calling_conventions_fenv.tag & 0xFFFF) != 0xFFFF)
+    {
+      printf ("%s   fpu tags  got 0x%X want 0xFFFF\n",
+              header, calling_conventions_fenv.tag & 0xFFFF);
+      header = "";
+      ret = 0;
+    }
+
+  return ret;
+}
diff --git a/version.c b/version.c
new file mode 100644
index 0000000..ee7c32a
--- /dev/null
+++ b/version.c
@@ -0,0 +1,33 @@
+/* gmp_version -- version number compiled into the library.
+
+Copyright 1996, 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+const char * const gmp_version = VERSION;