Add libgmp 6.2.0 to third_party

Don't build it yet.  That will come in the next review.

Change-Id: Idf3266558165e5ab45f4a41c98cc8c838c8244d5
diff --git a/third_party/gmp/tests/devel/Makefile.am b/third_party/gmp/tests/devel/Makefile.am
new file mode 100644
index 0000000..6b384f0
--- /dev/null
+++ b/third_party/gmp/tests/devel/Makefile.am
@@ -0,0 +1,35 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2002, 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/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+# add_n_sub_n add_n_sub_n_2 not yet built since mpn_add_n_sub_n doesn't yet exist
+#
+EXTRA_PROGRAMS = \
+  aors_n anymul_1 copy divmod_1 divrem shift logops_n sqrtrem_1_2 primes tst-addsub try addmul_N mul_N cnd_aors_n
+
+allprogs: $(EXTRA_PROGRAMS)
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/devel/Makefile.in b/third_party/gmp/tests/devel/Makefile.in
new file mode 100644
index 0000000..796371d
--- /dev/null
+++ b/third_party/gmp/tests/devel/Makefile.in
@@ -0,0 +1,748 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2002, 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/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = aors_n$(EXEEXT) anymul_1$(EXEEXT) copy$(EXEEXT) \
+	divmod_1$(EXEEXT) divrem$(EXEEXT) shift$(EXEEXT) \
+	logops_n$(EXEEXT) sqrtrem_1_2$(EXEEXT) primes$(EXEEXT) \
+	tst-addsub$(EXEEXT) try$(EXEEXT) addmul_N$(EXEEXT) \
+	mul_N$(EXEEXT) cnd_aors_n$(EXEEXT)
+subdir = tests/devel
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+addmul_N_SOURCES = addmul_N.c
+addmul_N_OBJECTS = addmul_N.$(OBJEXT)
+addmul_N_LDADD = $(LDADD)
+addmul_N_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+anymul_1_SOURCES = anymul_1.c
+anymul_1_OBJECTS = anymul_1.$(OBJEXT)
+anymul_1_LDADD = $(LDADD)
+anymul_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+aors_n_SOURCES = aors_n.c
+aors_n_OBJECTS = aors_n.$(OBJEXT)
+aors_n_LDADD = $(LDADD)
+aors_n_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+cnd_aors_n_SOURCES = cnd_aors_n.c
+cnd_aors_n_OBJECTS = cnd_aors_n.$(OBJEXT)
+cnd_aors_n_LDADD = $(LDADD)
+cnd_aors_n_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+copy_SOURCES = copy.c
+copy_OBJECTS = copy.$(OBJEXT)
+copy_LDADD = $(LDADD)
+copy_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+divmod_1_SOURCES = divmod_1.c
+divmod_1_OBJECTS = divmod_1.$(OBJEXT)
+divmod_1_LDADD = $(LDADD)
+divmod_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+divrem_SOURCES = divrem.c
+divrem_OBJECTS = divrem.$(OBJEXT)
+divrem_LDADD = $(LDADD)
+divrem_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+logops_n_SOURCES = logops_n.c
+logops_n_OBJECTS = logops_n.$(OBJEXT)
+logops_n_LDADD = $(LDADD)
+logops_n_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+mul_N_SOURCES = mul_N.c
+mul_N_OBJECTS = mul_N.$(OBJEXT)
+mul_N_LDADD = $(LDADD)
+mul_N_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+primes_SOURCES = primes.c
+primes_OBJECTS = primes.$(OBJEXT)
+primes_LDADD = $(LDADD)
+primes_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+shift_SOURCES = shift.c
+shift_OBJECTS = shift.$(OBJEXT)
+shift_LDADD = $(LDADD)
+shift_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+sqrtrem_1_2_SOURCES = sqrtrem_1_2.c
+sqrtrem_1_2_OBJECTS = sqrtrem_1_2.$(OBJEXT)
+sqrtrem_1_2_LDADD = $(LDADD)
+sqrtrem_1_2_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+try_SOURCES = try.c
+try_OBJECTS = try.$(OBJEXT)
+try_LDADD = $(LDADD)
+try_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+tst_addsub_SOURCES = tst-addsub.c
+tst_addsub_OBJECTS = tst-addsub.$(OBJEXT)
+tst_addsub_LDADD = $(LDADD)
+tst_addsub_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = addmul_N.c anymul_1.c aors_n.c cnd_aors_n.c copy.c \
+	divmod_1.c divrem.c logops_n.c mul_N.c primes.c shift.c \
+	sqrtrem_1_2.c try.c tst-addsub.c
+DIST_SOURCES = addmul_N.c anymul_1.c aors_n.c cnd_aors_n.c copy.c \
+	divmod_1.c divrem.c logops_n.c mul_N.c primes.c shift.c \
+	sqrtrem_1_2.c try.c tst-addsub.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/devel/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/devel/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+addmul_N$(EXEEXT): $(addmul_N_OBJECTS) $(addmul_N_DEPENDENCIES) $(EXTRA_addmul_N_DEPENDENCIES) 
+	@rm -f addmul_N$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(addmul_N_OBJECTS) $(addmul_N_LDADD) $(LIBS)
+
+anymul_1$(EXEEXT): $(anymul_1_OBJECTS) $(anymul_1_DEPENDENCIES) $(EXTRA_anymul_1_DEPENDENCIES) 
+	@rm -f anymul_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(anymul_1_OBJECTS) $(anymul_1_LDADD) $(LIBS)
+
+aors_n$(EXEEXT): $(aors_n_OBJECTS) $(aors_n_DEPENDENCIES) $(EXTRA_aors_n_DEPENDENCIES) 
+	@rm -f aors_n$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(aors_n_OBJECTS) $(aors_n_LDADD) $(LIBS)
+
+cnd_aors_n$(EXEEXT): $(cnd_aors_n_OBJECTS) $(cnd_aors_n_DEPENDENCIES) $(EXTRA_cnd_aors_n_DEPENDENCIES) 
+	@rm -f cnd_aors_n$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(cnd_aors_n_OBJECTS) $(cnd_aors_n_LDADD) $(LIBS)
+
+copy$(EXEEXT): $(copy_OBJECTS) $(copy_DEPENDENCIES) $(EXTRA_copy_DEPENDENCIES) 
+	@rm -f copy$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(copy_OBJECTS) $(copy_LDADD) $(LIBS)
+
+divmod_1$(EXEEXT): $(divmod_1_OBJECTS) $(divmod_1_DEPENDENCIES) $(EXTRA_divmod_1_DEPENDENCIES) 
+	@rm -f divmod_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(divmod_1_OBJECTS) $(divmod_1_LDADD) $(LIBS)
+
+divrem$(EXEEXT): $(divrem_OBJECTS) $(divrem_DEPENDENCIES) $(EXTRA_divrem_DEPENDENCIES) 
+	@rm -f divrem$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(divrem_OBJECTS) $(divrem_LDADD) $(LIBS)
+
+logops_n$(EXEEXT): $(logops_n_OBJECTS) $(logops_n_DEPENDENCIES) $(EXTRA_logops_n_DEPENDENCIES) 
+	@rm -f logops_n$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(logops_n_OBJECTS) $(logops_n_LDADD) $(LIBS)
+
+mul_N$(EXEEXT): $(mul_N_OBJECTS) $(mul_N_DEPENDENCIES) $(EXTRA_mul_N_DEPENDENCIES) 
+	@rm -f mul_N$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(mul_N_OBJECTS) $(mul_N_LDADD) $(LIBS)
+
+primes$(EXEEXT): $(primes_OBJECTS) $(primes_DEPENDENCIES) $(EXTRA_primes_DEPENDENCIES) 
+	@rm -f primes$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(primes_OBJECTS) $(primes_LDADD) $(LIBS)
+
+shift$(EXEEXT): $(shift_OBJECTS) $(shift_DEPENDENCIES) $(EXTRA_shift_DEPENDENCIES) 
+	@rm -f shift$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(shift_OBJECTS) $(shift_LDADD) $(LIBS)
+
+sqrtrem_1_2$(EXEEXT): $(sqrtrem_1_2_OBJECTS) $(sqrtrem_1_2_DEPENDENCIES) $(EXTRA_sqrtrem_1_2_DEPENDENCIES) 
+	@rm -f sqrtrem_1_2$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(sqrtrem_1_2_OBJECTS) $(sqrtrem_1_2_LDADD) $(LIBS)
+
+try$(EXEEXT): $(try_OBJECTS) $(try_DEPENDENCIES) $(EXTRA_try_DEPENDENCIES) 
+	@rm -f try$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(try_OBJECTS) $(try_LDADD) $(LIBS)
+
+tst-addsub$(EXEEXT): $(tst_addsub_OBJECTS) $(tst_addsub_DEPENDENCIES) $(EXTRA_tst_addsub_DEPENDENCIES) 
+	@rm -f tst-addsub$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(tst_addsub_OBJECTS) $(tst_addsub_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/devel/README b/third_party/gmp/tests/devel/README
new file mode 100644
index 0000000..77fa65d
--- /dev/null
+++ b/third_party/gmp/tests/devel/README
@@ -0,0 +1,37 @@
+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/.
+
+
+
+
+                       DEVELOPMENT TEST PROGRAMS
+
+
+This directory contains various programs used during development.  Casual
+GMP users are unlikely to find anything of interest.
+
+Nothing here is built or installed, nor even run in a "make check", but
+there's Makefile rules to build each program, or "allprogs" to build
+everything.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/tests/devel/addmul_N.c b/third_party/gmp/tests/devel/addmul_N.c
new file mode 100644
index 0000000..410e291
--- /dev/null
+++ b/third_party/gmp/tests/devel/addmul_N.c
@@ -0,0 +1,272 @@
+/*
+Copyright 1996-2002, 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+#ifndef NOCHECK
+static void print_posneg (mp_limb_t);
+#endif
+#ifdef PRINT
+static void mpn_print (mp_ptr, mp_size_t);
+#endif
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+#if N == 2
+#define mpn_addmul_N mpn_addmul_2
+#elif N == 3
+#define mpn_addmul_N mpn_addmul_3
+#elif N == 4
+#define mpn_addmul_N mpn_addmul_4
+#elif N == 5
+#define mpn_addmul_N mpn_addmul_5
+#elif N == 6
+#define mpn_addmul_N mpn_addmul_6
+#elif N == 7
+#define mpn_addmul_N mpn_addmul_7
+#elif N == 8
+#define mpn_addmul_N mpn_addmul_8
+#endif
+
+mp_limb_t
+refmpn_addmul_N (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_srcptr vp)
+{
+  int i;
+  for (i = 1; i < N; i++)
+    {
+      rp[n] = mpn_addmul_1 (rp, up, n, *vp);
+      rp++;
+      vp++;
+    }
+  return mpn_addmul_1 (rp, up, n, *vp);
+}
+
+int
+main (int argc, char **argv)
+{
+  mp_limb_t up[SIZE];
+  mp_limb_t ref[SIZE + N - 1];
+  mp_limb_t mem[SIZE + N + 1];
+  mp_ptr rp = mem + 1;
+  mp_limb_t vp[N];
+  mp_limb_t cy_ref, cy_try;
+  int i;
+#if TIMES != 1
+  long t0, t;
+  double cyc;
+#endif
+  unsigned test;
+  mp_size_t size;
+  unsigned ntests;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (CLOCK / SIZE / 1000) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % (SIZE - N + 1) + N;
+#else
+      size = SIZE;
+#endif
+
+      rp[size + N - 1] = 0x12345678;
+      rp[-1] = 0x87654321;
+
+      mpn_random (vp, N);
+
+#if TIMES != 1			/* run timing tests unless asked not to */
+      mpn_random (up, size);
+      mpn_random (rp, size + N - 1);
+
+      MPN_COPY (ref, rp, size + N - 1);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_addmul_N (ref, up, size, vp);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0) / N;
+      printf ("mpn_addmul_%d:    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      N, t, cyc, CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef ZEROu
+      MPN_ZERO (up, size);
+#else
+      MPN_RANDOM (up, size);
+#endif
+      MPN_RANDOM (vp, N);
+#ifdef ZERO
+      MPN_ZERO (rp, size + N - 1);
+#else
+      MPN_RANDOM (rp, size + N - 1);
+#endif
+
+#if defined (PRINT) || defined (PRINTV)
+      printf ("vp=");
+      mpn_print (vp, N);
+#endif
+#ifdef PRINT
+      printf ("%*s ", 3 + N * LXW, "");
+      mpn_print (rp, size);
+      printf ("%*s ", 3 + N * LXW, "");
+      mpn_print (up, size);
+#endif
+
+      MPN_COPY (ref, rp, size + N - 1);
+      cy_ref = refmpn_addmul_N (ref, up, size, vp);
+      cy_try = mpn_addmul_N (rp, up, size, vp);
+
+#ifdef PRINT
+      printf ("%*lX ", LXW, cy_ref);
+      mpn_print (ref, size + N - 1);
+      printf ("%*lX ", LXW, cy_try);
+      mpn_print (rp, size + N - 1);
+#endif
+
+#ifndef NOCHECK
+      if (cy_ref != cy_try || mpn_cmp (ref, rp, size + N - 1) != 0
+	  || rp[size + N - 1] != 0x12345678 || rp[-1] != 0x87654321)
+	{
+	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
+	  for (i = 0; i < size + N - 1; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
+	      print_posneg (rp[i] - ref[i]);
+	      printf ("\n");
+	    }
+	  printf ("retval: ");
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
+	  print_posneg (cy_try - cy_ref);
+	  printf ("\n");
+	  if (rp[-1] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (rp[size + N - 1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+#ifndef NOCHECK
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+#endif
+
+#ifdef PRINT
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", LXW, p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
+#endif
diff --git a/third_party/gmp/tests/devel/anymul_1.c b/third_party/gmp/tests/devel/anymul_1.c
new file mode 100644
index 0000000..84f2781
--- /dev/null
+++ b/third_party/gmp/tests/devel/anymul_1.c
@@ -0,0 +1,255 @@
+/*
+Copyright 1996-2002, 2004, 2006-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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#ifdef OPERATION_mul_1
+#define func __gmpn_mul_1
+#define reffunc refmpn_mul_1
+#define funcname "mpn_mul_1"
+#endif
+
+#ifdef OPERATION_addmul_1
+#define func __gmpn_addmul_1
+#define reffunc refmpn_addmul_1
+#define funcname "mpn_addmul_1"
+#endif
+
+#ifdef OPERATION_submul_1
+#define func __gmpn_submul_1
+#define reffunc refmpn_submul_1
+#define funcname "mpn_submul_1"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, ref, rp;
+  mp_limb_t cy_ref, cy_try;
+  int i;
+  long t0, t;
+  unsigned int test;
+  mp_limb_t xlimb;
+  mp_size_t size;
+  double cyc;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  ref = malloc (SIZE * sizeof (mp_limb_t));
+  rp = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  rp++;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (1 + 0x80000 / (SIZE + 20)) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      rp[-1] = 0x87654321;
+      rp[size] = 0x12345678;
+
+#ifdef FIXED_XLIMB
+      xlimb = FIXED_XLIMB;
+#else
+      MPN_RANDOM (&xlimb, 1);
+#endif
+
+#if TIMES != 1
+      mpn_random (s1, size);
+      mpn_random (rp, size);
+
+      MPN_COPY (ref, rp, size);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (ref, s1, size, xlimb);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0);
+      printf (funcname ":    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      t, cyc,
+	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+#ifndef NOCHECK
+      MPN_RANDOM (s1, size);
+#ifdef ZERO
+      memset (rp, 0, size * sizeof *rp);
+#else
+      MPN_RANDOM (rp, size);
+#endif
+#if defined (PRINT) || defined (XPRINT)
+      printf ("xlimb=");
+      mpn_print (&xlimb, 1);
+#endif
+#ifdef PRINT
+#ifndef OPERATION_mul_1
+      printf ("%*s ", (int) (2 * sizeof(mp_limb_t)), "");
+      mpn_print (rp, size);
+#endif
+      printf ("%*s ", (int) (2 * sizeof(mp_limb_t)), "");
+      mpn_print (s1, size);
+#endif
+
+      MPN_COPY (ref, rp, size);
+      cy_ref = reffunc (ref, s1, size, xlimb);
+      cy_try = func (rp, s1, size, xlimb);
+
+#ifdef PRINT
+      mpn_print (&cy_ref, 1);
+      mpn_print (ref, size);
+      mpn_print (&cy_try, 1);
+      mpn_print (rp, size);
+#endif
+
+      if (cy_ref != cy_try || mpn_cmp (ref, rp, size) != 0
+	  || rp[-1] != 0x87654321 || rp[size] != 0x12345678)
+	{
+	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
+	  for (i = 0; i < size; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
+	      print_posneg (rp[i] - ref[i]);
+	      printf ("\n");
+	    }
+	  printf ("retval: ");
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
+	  print_posneg (cy_try - cy_ref);
+	  printf ("\n");
+	  if (rp[-1] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (rp[size] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/aors_n.c b/third_party/gmp/tests/devel/aors_n.c
new file mode 100644
index 0000000..d15cb58
--- /dev/null
+++ b/third_party/gmp/tests/devel/aors_n.c
@@ -0,0 +1,262 @@
+/*
+Copyright 1996-2004, 2009, 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 <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_add_n
+#define func __gmpn_add_n
+#define reffunc refmpn_add_n
+#define funcname "mpn_add_n"
+#endif
+
+#ifdef OPERATION_sub_n
+#define func __gmpn_sub_n
+#define reffunc refmpn_sub_n
+#define funcname "mpn_sub_n"
+#endif
+
+#ifdef OPERATION_addlsh1_n
+#define func __gmpn_addlsh1_n
+#define reffunc refmpn_addlsh1_n
+#define funcname "mpn_addlsh1_n"
+#endif
+
+#ifdef OPERATION_sublsh1_n
+#define func __gmpn_sublsh1_n
+#define reffunc refmpn_sublsh1_n
+#define funcname "mpn_sublsh1_n"
+#endif
+
+#ifdef OPERATION_rsh1add_n
+#define func __gmpn_rsh1add_n
+#define reffunc refmpn_rsh1add_n
+#define funcname "mpn_rsh1add_n"
+#endif
+
+#ifdef OPERATION_rsh1sub_n
+#define func __gmpn_rsh1sub_n
+#define reffunc refmpn_rsh1sub_n
+#define funcname "mpn_rsh1sub_n"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 328
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, s2, dx, dy;
+  mp_limb_t cyx, cyy;
+  int i;
+#if TIMES != 1
+  long t0, t;
+#endif
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  s2 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+      mpn_random (s2, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, s2, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random2 (s1, size);
+      mpn_random2 (s2, size);
+
+#ifdef PRINT
+      mpn_print (s1, size);
+      mpn_print (s2, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      cyx = reffunc (dx+1, s1, s2, size);
+      cyy = func (dy+1, s1, s2, size);
+
+#ifdef PRINT
+      mpn_print (&cyx, 1);
+      mpn_print (dx+1, size);
+      mpn_print (&cyy, 1);
+      mpn_print (dy+1, size);
+#endif
+
+      if (cyx != cyy || mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+	  printf ("%6s: ", "retval");
+	  printf ("%0*llX ", LXW, (unsigned long long) cyx);
+	  printf ("%0*llX ", LXW, (unsigned long long) cyy);
+	  print_posneg (cyx - cyy);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/cnd_aors_n.c b/third_party/gmp/tests/devel/cnd_aors_n.c
new file mode 100644
index 0000000..00d6db1
--- /dev/null
+++ b/third_party/gmp/tests/devel/cnd_aors_n.c
@@ -0,0 +1,257 @@
+/*
+Copyright 1996-2004, 2009, 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 <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests/tests.h"
+
+#ifdef OPERATION_cnd_add_n
+#define func __gmpn_cnd_add_n
+#define reffunc refmpn_cnd_add_n
+#define funcname "mpn_cnd_add_n"
+#endif
+
+#ifdef OPERATION_cnd_sub_n
+#define func __gmpn_cnd_sub_n
+#define reffunc refmpn_cnd_sub_n
+#define funcname "mpn_cnd_sub_n"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 328
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, s2, dx, dy;
+  mp_limb_t cyx, cyy;
+  int i;
+#if TIMES != 1
+  long t0, t;
+#endif
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  s2 = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  s1 += 1;
+  s2 += 1;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1 - 1, size + 2);
+      mpn_random (s2 - 1, size + 2);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (i & 1, dx+1, s1, s2, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+#ifndef ZEROup
+      MPN_RANDOM (s1 - 1, size + 2);
+#else
+      MPN_ZERO (s1, size);
+#endif
+#ifndef ZEROvp
+      MPN_RANDOM (s2 - 1, size + 2);
+#else
+      MPN_ZERO (s2, size);
+#endif
+
+#ifdef PRINT
+      mpn_print (s1, size);
+      mpn_print (s2, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      int cond = random() & 1;
+
+      cyx = reffunc (cond, dx+1, s1, s2, size);
+      cyy = func (cond, dy+1, s1, s2, size);
+
+#ifdef PRINT
+      mpn_print (&cyx, 1);
+      mpn_print (dx+1, size);
+      mpn_print (&cyy, 1);
+      mpn_print (dy+1, size);
+#endif
+
+      if (cyx != cyy || mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+	  printf ("%6s: ", "retval");
+	  printf ("%0*llX ", LXW, (unsigned long long) cyx);
+	  printf ("%0*llX ", LXW, (unsigned long long) cyy);
+	  print_posneg (cyx - cyy);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/copy.c b/third_party/gmp/tests/devel/copy.c
new file mode 100644
index 0000000..65dbd9b
--- /dev/null
+++ b/third_party/gmp/tests/devel/copy.c
@@ -0,0 +1,225 @@
+/*
+Copyright 1999-2001, 2004, 2009, 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 <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_copyi
+#define func MPN_COPY_INCR
+#define reffunc refmpn_copyi
+#define funcname "MPN_COPY_INCR"
+#endif
+
+#ifdef OPERATION_copyd
+#define func MPN_COPY_DECR
+#define reffunc refmpn_copyd
+#define funcname "MPN_COPY_DECR"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, dx, dy;
+  int i;
+  long t0, t;
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random2 (s1, size);
+
+#ifdef PRINT
+      mpn_print (s1, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      reffunc (dx+1, s1, size);
+      func (dy+1, s1, size);
+
+#ifdef PRINT
+      mpn_print (dx+1, size);
+      mpn_print (dy+1, size);
+#endif
+
+      if (mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/divmod_1.c b/third_party/gmp/tests/devel/divmod_1.c
new file mode 100644
index 0000000..2757375
--- /dev/null
+++ b/third_party/gmp/tests/devel/divmod_1.c
@@ -0,0 +1,199 @@
+/*
+Copyright 1996, 1998, 2000, 2001, 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 <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS 20000000
+#endif
+#ifndef SIZE
+#define SIZE 1000
+#endif
+#ifndef TIMES
+#define TIMES OPS/SIZE
+#endif
+
+#ifndef FSIZE
+#define FSIZE SIZE
+#endif
+
+int
+main ()
+{
+  mp_limb_t np[SIZE];
+  mp_limb_t dx[SIZE + FSIZE + 2];
+  mp_limb_t dy[SIZE + FSIZE + 2];
+  mp_limb_t dlimb;
+  mp_size_t nn, fn;
+  mp_limb_t retx, rety;
+  int test;
+#if TIMES != 1
+  int i;
+  long t0, t;
+  double cyc;
+#endif
+
+  for (test = 0; ; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      nn = random () % (SIZE + 1);
+      fn = random () % (FSIZE + 1);
+#else
+      nn = SIZE;
+      fn = FSIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dx[nn + fn + 1] = 0x12345678;
+      dy[0] = 0x87654321;
+      dy[nn + fn + 1] = 0x12345678;
+      mpn_random2 (np, nn);
+
+#ifdef FIXED_DLIMB
+      dlimb = FIXED_DLIMB;
+#else
+      do
+	{
+	  mpn_random2 (&dlimb, 1);
+#ifdef FORCE_NORM
+	  dlimb |= GMP_NUMB_HIGHBIT;
+#endif
+#ifdef FORCE_UNNORM
+	  dlimb &= GMP_NUMB_MAX >> 1;
+#endif
+	}
+      while (dlimb == 0);
+#endif
+
+#if defined (PRINT) || defined (XPRINT)
+      printf ("N=");
+      mpn_print (np, nn);
+      printf ("D=");
+      mpn_print (&dlimb, 1);
+      printf ("nn=%ld\n", (long) nn);
+#endif
+
+#if TIMES != 1
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_divrem_1 (dx + 1, 0L, np, nn, dlimb);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * nn * 1000.0);
+      printf ("mpn_divrem_1 int:    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      t, cyc,
+	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_divrem_1 (dx + 1, fn, np, 0, dlimb);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * fn * 1000.0);
+      printf ("mpn_divrem_1 frac:   %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      t, cyc,
+	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+      retx = refmpn_divrem_1 (dx + 1, fn, np, nn, dlimb);
+      rety = mpn_divrem_1 (dy + 1, fn, np, nn, dlimb);
+
+#ifndef NOCHECK
+      if (retx != rety || mpn_cmp (dx, dy, fn + nn + 2) != 0)
+	{
+	  printf ("ERROR in test %d, nn=%ld, fn=%ld\n", test, nn, fn);
+	  mpn_print (np, nn);
+	  mpn_print (&dlimb, 1);
+	  printf ("rq: ");
+	  mpn_print (dx + 1, nn + fn);
+	  printf ("rr: %*lX\n", (int) (2 * sizeof(mp_limb_t)), retx);
+	  printf (" q: ");
+	  mpn_print (dy + 1, nn + fn);
+	  printf (" r: %*lX\n", (int) (2 * sizeof(mp_limb_t)), rety);
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end %*lX\n", (int) (2 * sizeof(mp_limb_t)), dy[0]);
+	  if (dy[nn + fn + 1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  abort ();
+	}
+#endif
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/divrem.c b/third_party/gmp/tests/devel/divrem.c
new file mode 100644
index 0000000..e6c38c6
--- /dev/null
+++ b/third_party/gmp/tests/devel/divrem.c
@@ -0,0 +1,118 @@
+/*
+Copyright 1996-1998, 2000, 2001, 2007, 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"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS 20000000
+#endif
+#ifndef SIZE
+#define SIZE 100
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main ()
+{
+  mp_limb_t nptr[2 * SIZE];
+  mp_limb_t dptr[2 * SIZE];
+  mp_limb_t qptr[2 * SIZE];
+  mp_limb_t pptr[2 * SIZE + 1];
+  mp_limb_t rptr[2 * SIZE];
+  mp_size_t nsize, dsize, qsize, rsize, psize;
+  int test;
+  mp_limb_t qlimb;
+
+  for (test = 0; ; test++)
+    {
+      printf ("%d\n", test);
+#ifdef RANDOM
+      nsize = random () % (2 * SIZE) + 1;
+      dsize = random () % nsize + 1;
+#else
+      nsize = 2 * SIZE;
+      dsize = SIZE;
+#endif
+
+      mpn_random2 (nptr, nsize);
+      mpn_random2 (dptr, dsize);
+      dptr[dsize - 1] |= (mp_limb_t) 1 << (GMP_LIMB_BITS - 1);
+
+      MPN_COPY (rptr, nptr, nsize);
+      qlimb = mpn_divrem (qptr, (mp_size_t) 0, rptr, nsize, dptr, dsize);
+      rsize = dsize;
+      qsize = nsize - dsize;
+      qptr[qsize] = qlimb;
+      qsize += qlimb;
+      if (qsize == 0 || qsize > 2 * SIZE)
+	{
+	  continue;		/* bogus */
+	}
+      else
+	{
+	  mp_limb_t cy;
+	  if (qsize > dsize)
+	    mpn_mul (pptr, qptr, qsize, dptr, dsize);
+	  else
+	    mpn_mul (pptr, dptr, dsize, qptr, qsize);
+	  psize = qsize + dsize;
+	  psize -= pptr[psize - 1] == 0;
+	  cy = mpn_add (pptr, pptr, psize, rptr, rsize);
+	  pptr[psize] = cy;
+	  psize += cy;
+	}
+
+      if (nsize != psize || mpn_cmp (nptr, pptr, nsize) != 0)
+	abort ();
+    }
+}
diff --git a/third_party/gmp/tests/devel/logops_n.c b/third_party/gmp/tests/devel/logops_n.c
new file mode 100644
index 0000000..349c637
--- /dev/null
+++ b/third_party/gmp/tests/devel/logops_n.c
@@ -0,0 +1,229 @@
+/*
+Copyright 1996-2004, 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"
+
+#ifdef OPERATION_and_n
+#define func __gmpn_and_n
+#define reffunc refmpn_and_n
+#define funcname "mpn_and_n"
+#endif
+
+#ifdef OPERATION_andn_n
+#define func __gmpn_andn_n
+#define reffunc refmpn_andn_n
+#define funcname "mpn_andn_n"
+#endif
+
+#ifdef OPERATION_nand_n
+#define func __gmpn_nand_n
+#define reffunc refmpn_nand_n
+#define funcname "mpn_nand_n"
+#endif
+
+#ifdef OPERATION_ior_n
+#define func __gmpn_ior_n
+#define reffunc refmpn_ior_n
+#define funcname "mpn_ior_n"
+#endif
+
+#ifdef OPERATION_iorn_n
+#define func __gmpn_iorn_n
+#define reffunc refmpn_iorn_n
+#define funcname "mpn_iorn_n"
+#endif
+
+#ifdef OPERATION_nior_n
+#define func __gmpn_nior_n
+#define reffunc refmpn_nior_n
+#define funcname "mpn_nior_n"
+#endif
+
+#ifdef OPERATION_xor_n
+#define func __gmpn_xor_n
+#define reffunc refmpn_xor_n
+#define funcname "mpn_xor_n"
+#endif
+
+#ifdef OPERATION_xnor_n
+#define func __gmpn_xnor_n
+#define reffunc refmpn_xnor_n
+#define funcname "mpn_xnor_n"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 328
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, s2, dx, dy;
+  int i;
+  long t0, t;
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  s2 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%d", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+      mpn_random (s2, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, s2, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random2 (s1, size);
+      mpn_random2 (s2, size);
+
+#ifdef PRINT
+      mpn_print (s1, size);
+      mpn_print (s2, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      reffunc (dx+1, s1, s2, size);
+      func (dy+1, s1, s2, size);
+#ifdef PRINT
+      mpn_print (dx+1, size);
+      mpn_print (dy+1, size);
+#endif
+      if (mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+#ifndef PRINT
+	  mpn_print (dx+1, size);
+	  mpn_print (dy+1, size);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/mul_N.c b/third_party/gmp/tests/devel/mul_N.c
new file mode 100644
index 0000000..c9de5ec
--- /dev/null
+++ b/third_party/gmp/tests/devel/mul_N.c
@@ -0,0 +1,270 @@
+/*
+Copyright 1996-2002, 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+#ifndef NOCHECK
+static void print_posneg (mp_limb_t);
+#endif
+#ifdef PRINT
+static void mpn_print (mp_ptr, mp_size_t);
+#endif
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+#if N == 2
+#define mpn_mul_N mpn_mul_2
+#elif N == 3
+#define mpn_mul_N mpn_mul_3
+#elif N == 4
+#define mpn_mul_N mpn_mul_4
+#elif N == 5
+#define mpn_mul_N mpn_mul_5
+#elif N == 6
+#define mpn_mul_N mpn_mul_6
+#elif N == 7
+#define mpn_mul_N mpn_mul_7
+#elif N == 8
+#define mpn_mul_N mpn_mul_8
+#endif
+
+mp_limb_t
+refmpn_mul_N (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_srcptr vp)
+{
+  int i;
+  rp[n] = mpn_mul_1 (rp, up, n, *vp);
+  rp++;
+  vp++;
+  for (i = 2; i < N; i++)
+    {
+      rp[n] = mpn_addmul_1 (rp, up, n, *vp);
+      rp++;
+      vp++;
+    }
+  return mpn_addmul_1 (rp, up, n, *vp);
+}
+
+int
+main (int argc, char **argv)
+{
+  mp_limb_t up[SIZE];
+  mp_limb_t ref[SIZE + N - 1];
+  mp_limb_t mem[SIZE + N + 1];
+  mp_ptr rp = mem + 1;
+  mp_limb_t vp[N];
+  mp_limb_t cy_ref, cy_try;
+  int i;
+#if TIMES != 1
+  long t0, t;
+  double cyc;
+#endif
+  unsigned test;
+  mp_size_t size;
+  unsigned ntests;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (CLOCK / SIZE / 1000) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % (SIZE - N + 1) + N;
+#else
+      size = SIZE;
+#endif
+
+      rp[size + N - 1] = 0x12345678;
+      rp[-1] = 0x87654321;
+
+      mpn_random (vp, N);
+
+#if TIMES != 1			/* run timing tests unless asked not to */
+      mpn_random (up, size);
+
+      MPN_COPY (ref, rp, size + N - 1);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_mul_N (ref, up, size, vp);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0) / N;
+      printf ("mpn_mul_%d:    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      N, t, cyc, CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef ZEROu
+      MPN_ZERO (up, size);
+#else
+      MPN_RANDOM (up, size);
+#endif
+      MPN_RANDOM (vp, N);
+      /* vp[0] = vp[1] = vp[2] = vp[3] = vp[4] =  vp[5] = 0; */
+      MPN_RANDOM (rp, size + N - 1);
+
+#if defined (PRINT) || defined (PRINTV)
+      printf ("vp=");
+      mpn_print (vp, N);
+#endif
+#ifdef PRINT
+      printf ("%*s ", 3 + N * LXW, "");
+      mpn_print (up, size);
+#endif
+
+      MPN_COPY (ref, rp, size + N - 1);
+      cy_ref = refmpn_mul_N (ref, up, size, vp);
+      cy_try = mpn_mul_N (rp, up, size, vp);
+
+#ifdef PRINT
+      printf ("%*lX ", LXW, cy_ref);
+      mpn_print (ref, size + N - 1);
+      printf ("%*lX ", LXW, cy_try);
+      mpn_print (rp, size + N - 1);
+#endif
+
+#ifndef NOCHECK
+      if (cy_ref != cy_try || mpn_cmp (ref, rp, size + N - 1) != 0
+//      if (cy_ref != cy_try || mpn_cmp (ref + 5, rp + 5, size + N - 1 - 6) != 0
+	  || rp[size + N - 1] != 0x12345678 || rp[-1] != 0x87654321)
+	{
+	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
+	  for (i = 0; i < size + N - 1; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
+	      print_posneg (rp[i] - ref[i]);
+	      printf ("\n");
+	    }
+	  printf ("retval: ");
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
+	  print_posneg (cy_try - cy_ref);
+	  printf ("\n");
+	  if (rp[-1] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (rp[size + N - 1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+#ifndef NOCHECK
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+#endif
+
+#ifdef PRINT
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", LXW, p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
+#endif
diff --git a/third_party/gmp/tests/devel/primes.c b/third_party/gmp/tests/devel/primes.c
new file mode 100644
index 0000000..84b3b51
--- /dev/null
+++ b/third_party/gmp/tests/devel/primes.c
@@ -0,0 +1,341 @@
+/*
+Copyright 2018-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/.  */
+
+/* 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 [n0] <nMax>
+
+     Checks mpz_nextprime() exhaustively, starting from n=n0 up to
+     nMax.
+
+     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_to_bit(n) / GMP_LIMB_BITS + 1; }
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if (((sieve)[__index] & __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, __index, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __index = __i / GMP_LIMB_BITS;				\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __index += __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_to_bit(begin) + (begin % 3 == 0);
+
+	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_to_bit(start) + (start % 3 == 0),
+			     n_to_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;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, 2) != 0)
+	STOP (something_wrong (g, -1));
+      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, -1));
+      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_to_bit(start) + (start % 3 == 0),
+			     n_to_bit (end), 0, sieve);
+
+	mpz_nextprime (g, g);
+	if (mpz_cmp_ui (g, prime) != 0)
+	  STOP (something_wrong (g, -1));
+
+	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;
+    default:
+      begin = end;
+      end = atol (argv[1]);
+    }
+
+  if (begin >= end)
+    {
+      fprintf (stderr, "usage: primes [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;
+  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/third_party/gmp/tests/devel/shift.c b/third_party/gmp/tests/devel/shift.c
new file mode 100644
index 0000000..ad5125b
--- /dev/null
+++ b/third_party/gmp/tests/devel/shift.c
@@ -0,0 +1,244 @@
+/*
+Copyright 1996, 1998-2001, 2004, 2007, 2009, 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 <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_lshift
+#define func __gmpn_lshift
+#define reffunc refmpn_lshift
+#define funcname "mpn_lshift"
+#endif
+
+#ifdef OPERATION_rshift
+#define func __gmpn_rshift
+#define reffunc refmpn_rshift
+#define funcname "mpn_rshift"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+#ifndef CNT
+int CNT = 4;
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, dx, dy;
+  mp_limb_t cyx, cyy;
+  int i;
+  long t0, t;
+  unsigned int test;
+  int cnt = CNT;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#if TIMES == 1
+      cnt = random () % (GMP_NUMB_BITS - 1) + 1;
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, size, cnt);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random (s1, size);
+
+#ifdef PRINT
+      printf ("cnt=%-*d ", (int) (2 * sizeof(mp_limb_t)) - 4, cnt);
+      mpn_print (s1, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      cyx = reffunc (dx+1, s1, size, cnt);
+      cyy = func (dy+1, s1, size, cnt);
+
+#ifdef PRINT
+      mpn_print (&cyx, 1);
+      mpn_print (dx+1, size);
+      mpn_print (&cyy, 1);
+      mpn_print (dy+1, size);
+#endif
+
+      if (cyx != cyy || mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  printf ("cnt=%-*d\n", (int) (2 * sizeof(mp_limb_t)) - 4, cnt);
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+	  printf ("%6s: ", "retval");
+	  printf ("%0*llX ", LXW, (unsigned long long) cyx);
+	  printf ("%0*llX ", LXW, (unsigned long long) cyy);
+	  print_posneg (cyx - cyy);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/sqrtrem_1_2.c b/third_party/gmp/tests/devel/sqrtrem_1_2.c
new file mode 100644
index 0000000..3951191
--- /dev/null
+++ b/third_party/gmp/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/third_party/gmp/tests/devel/try.c b/third_party/gmp/tests/devel/try.c
new file mode 100644
index 0000000..f8f4a1c
--- /dev/null
+++ b/third_party/gmp/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/third_party/gmp/tests/devel/tst-addsub.c b/third_party/gmp/tests/devel/tst-addsub.c
new file mode 100644
index 0000000..4aa827a
--- /dev/null
+++ b/third_party/gmp/tests/devel/tst-addsub.c
@@ -0,0 +1,97 @@
+/* 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 ADD 1
+#define SUB 2
+
+#ifndef METHOD
+#define METHOD ADD
+#endif
+
+#if METHOD == ADD
+#define REFCALL refmpn_add_n
+#define TESTCALL mpn_add_n
+#endif
+
+#if METHOD == SUB
+#define REFCALL refmpn_sub_n
+#define TESTCALL mpn_sub_n
+#endif
+
+#define SIZE 100
+
+int
+main (int argc, char **argv)
+{
+  mp_size_t alloc_size, max_size, size, i, cumul_size;
+  mp_ptr s1, s2, dx, dy;
+  int s1_align, s2_align, d_align;
+  long pass, n_passes;
+  mp_limb_t cx, cy;
+
+  max_size = SIZE;
+  n_passes = 1000000;
+
+  argc--; argv++;
+  if (argc)
+    {
+      max_size = atol (*argv);
+      argc--; argv++;
+    }
+
+  alloc_size = max_size + 32;
+  s1 = malloc (alloc_size * GMP_LIMB_BYTES);
+  s2 = malloc (alloc_size * GMP_LIMB_BYTES);
+  dx = malloc (alloc_size * GMP_LIMB_BYTES);
+  dy = malloc (alloc_size * GMP_LIMB_BYTES);
+
+  cumul_size = 0;
+  for (pass = 0; pass < n_passes; pass++)
+    {
+      size = random () % max_size + 1;
+
+      cumul_size += size;
+      if (cumul_size >= 1000000)
+	{
+	  cumul_size -= 1000000;
+	  printf ("\r%ld", pass); fflush (stdout);
+	}
+      s1_align = random () % 32;
+      s2_align = random () % 32;
+      d_align = random () % 32;
+
+      mpn_random2 (s1 + s1_align, size);
+      mpn_random2 (s2 + s2_align, size);
+
+      for (i = 0; i < alloc_size; i++)
+	dx[i] = dy[i] = i + 0x9876500;
+
+      cx = TESTCALL (dx + d_align, s1 + s1_align, s2 + s2_align, size);
+      cy = REFCALL (dy + d_align, s1 + s1_align, s2 + s2_align, size);
+
+      if (cx != cy || mpn_cmp (dx, dy, alloc_size) != 0)
+	abort ();
+    }
+
+  printf ("%ld passes OK\n", n_passes);
+  exit (0);
+}