summaryrefslogtreecommitdiff
path: root/rts/gmp/mpz
diff options
context:
space:
mode:
Diffstat (limited to 'rts/gmp/mpz')
-rw-r--r--rts/gmp/mpz/Makefile.am58
-rw-r--r--rts/gmp/mpz/Makefile.in457
-rw-r--r--rts/gmp/mpz/README23
-rw-r--r--rts/gmp/mpz/abs.c51
-rw-r--r--rts/gmp/mpz/add.c123
-rw-r--r--rts/gmp/mpz/add_ui.c84
-rw-r--r--rts/gmp/mpz/addmul_ui.c214
-rw-r--r--rts/gmp/mpz/and.c278
-rw-r--r--rts/gmp/mpz/array_init.c48
-rw-r--r--rts/gmp/mpz/bin_ui.c141
-rw-r--r--rts/gmp/mpz/bin_uiui.c120
-rw-r--r--rts/gmp/mpz/cdiv_q.c51
-rw-r--r--rts/gmp/mpz/cdiv_q_ui.c67
-rw-r--r--rts/gmp/mpz/cdiv_qr.c64
-rw-r--r--rts/gmp/mpz/cdiv_qr_ui.c71
-rw-r--r--rts/gmp/mpz/cdiv_r.c59
-rw-r--r--rts/gmp/mpz/cdiv_r_ui.c57
-rw-r--r--rts/gmp/mpz/cdiv_ui.c50
-rw-r--r--rts/gmp/mpz/clear.c35
-rw-r--r--rts/gmp/mpz/clrbit.c114
-rw-r--r--rts/gmp/mpz/cmp.c75
-rw-r--r--rts/gmp/mpz/cmp_si.c64
-rw-r--r--rts/gmp/mpz/cmp_ui.c53
-rw-r--r--rts/gmp/mpz/cmpabs.c57
-rw-r--r--rts/gmp/mpz/cmpabs_ui.c56
-rw-r--r--rts/gmp/mpz/com.c93
-rw-r--r--rts/gmp/mpz/divexact.c125
-rw-r--r--rts/gmp/mpz/dump.c44
-rw-r--r--rts/gmp/mpz/fac_ui.c157
-rw-r--r--rts/gmp/mpz/fdiv_q.c51
-rw-r--r--rts/gmp/mpz/fdiv_q_2exp.c104
-rw-r--r--rts/gmp/mpz/fdiv_q_ui.c65
-rw-r--r--rts/gmp/mpz/fdiv_qr.c64
-rw-r--r--rts/gmp/mpz/fdiv_qr_ui.c69
-rw-r--r--rts/gmp/mpz/fdiv_r.c58
-rw-r--r--rts/gmp/mpz/fdiv_r_2exp.c156
-rw-r--r--rts/gmp/mpz/fdiv_r_ui.c55
-rw-r--r--rts/gmp/mpz/fdiv_ui.c48
-rw-r--r--rts/gmp/mpz/fib_ui.c165
-rw-r--r--rts/gmp/mpz/fits_sint_p.c50
-rw-r--r--rts/gmp/mpz/fits_slong_p.c50
-rw-r--r--rts/gmp/mpz/fits_sshort_p.c50
-rw-r--r--rts/gmp/mpz/fits_uint_p.c41
-rw-r--r--rts/gmp/mpz/fits_ulong_p.c41
-rw-r--r--rts/gmp/mpz/fits_ushort_p.c41
-rw-r--r--rts/gmp/mpz/gcd.c180
-rw-r--r--rts/gmp/mpz/gcd_ui.c65
-rw-r--r--rts/gmp/mpz/gcdext.c137
-rw-r--r--rts/gmp/mpz/get_d.c128
-rw-r--r--rts/gmp/mpz/get_si.c43
-rw-r--r--rts/gmp/mpz/get_str.c118
-rw-r--r--rts/gmp/mpz/get_ui.c37
-rw-r--r--rts/gmp/mpz/getlimbn.c38
-rw-r--r--rts/gmp/mpz/hamdist.c62
-rw-r--r--rts/gmp/mpz/init.c36
-rw-r--r--rts/gmp/mpz/inp_raw.c101
-rw-r--r--rts/gmp/mpz/inp_str.c167
-rw-r--r--rts/gmp/mpz/invert.c77
-rw-r--r--rts/gmp/mpz/ior.c244
-rw-r--r--rts/gmp/mpz/iset.c49
-rw-r--r--rts/gmp/mpz/iset_d.c39
-rw-r--r--rts/gmp/mpz/iset_si.c49
-rw-r--r--rts/gmp/mpz/iset_str.c47
-rw-r--r--rts/gmp/mpz/iset_ui.c39
-rw-r--r--rts/gmp/mpz/jacobi.c53
-rw-r--r--rts/gmp/mpz/kronsz.c126
-rw-r--r--rts/gmp/mpz/kronuz.c115
-rw-r--r--rts/gmp/mpz/kronzs.c74
-rw-r--r--rts/gmp/mpz/kronzu.c66
-rw-r--r--rts/gmp/mpz/lcm.c61
-rw-r--r--rts/gmp/mpz/legendre.c184
-rw-r--r--rts/gmp/mpz/mod.c63
-rw-r--r--rts/gmp/mpz/mul.c131
-rw-r--r--rts/gmp/mpz/mul_2exp.c76
-rw-r--r--rts/gmp/mpz/mul_siui.c81
-rw-r--r--rts/gmp/mpz/neg.c53
-rw-r--r--rts/gmp/mpz/nextprime.c120
-rw-r--r--rts/gmp/mpz/out_raw.c89
-rw-r--r--rts/gmp/mpz/out_str.c108
-rw-r--r--rts/gmp/mpz/perfpow.c272
-rw-r--r--rts/gmp/mpz/perfsqr.c45
-rw-r--r--rts/gmp/mpz/popcount.c42
-rw-r--r--rts/gmp/mpz/pow_ui.c129
-rw-r--r--rts/gmp/mpz/powm.c364
-rw-r--r--rts/gmp/mpz/powm_ui.c248
-rw-r--r--rts/gmp/mpz/pprime_p.c242
-rw-r--r--rts/gmp/mpz/random.c56
-rw-r--r--rts/gmp/mpz/random2.c48
-rw-r--r--rts/gmp/mpz/realloc.c52
-rw-r--r--rts/gmp/mpz/remove.c93
-rw-r--r--rts/gmp/mpz/root.c183
-rw-r--r--rts/gmp/mpz/rrandomb.c117
-rw-r--r--rts/gmp/mpz/scan0.c35
-rw-r--r--rts/gmp/mpz/scan1.c35
-rw-r--r--rts/gmp/mpz/set.c48
-rw-r--r--rts/gmp/mpz/set_d.c96
-rw-r--r--rts/gmp/mpz/set_f.c64
-rw-r--r--rts/gmp/mpz/set_q.c36
-rw-r--r--rts/gmp/mpz/set_si.c48
-rw-r--r--rts/gmp/mpz/set_str.c157
-rw-r--r--rts/gmp/mpz/set_ui.c43
-rw-r--r--rts/gmp/mpz/setbit.c119
-rw-r--r--rts/gmp/mpz/size.c35
-rw-r--r--rts/gmp/mpz/sizeinbase.c60
-rw-r--r--rts/gmp/mpz/sqrt.c86
-rw-r--r--rts/gmp/mpz/sqrtrem.c111
-rw-r--r--rts/gmp/mpz/sub.c123
-rw-r--r--rts/gmp/mpz/sub_ui.c84
-rw-r--r--rts/gmp/mpz/swap.c52
-rw-r--r--rts/gmp/mpz/tdiv_q.c91
-rw-r--r--rts/gmp/mpz/tdiv_q_2exp.c68
-rw-r--r--rts/gmp/mpz/tdiv_q_ui.c64
-rw-r--r--rts/gmp/mpz/tdiv_qr.c130
-rw-r--r--rts/gmp/mpz/tdiv_qr_ui.c76
-rw-r--r--rts/gmp/mpz/tdiv_r.c98
-rw-r--r--rts/gmp/mpz/tdiv_r_2exp.c79
-rw-r--r--rts/gmp/mpz/tdiv_r_ui.c63
-rw-r--r--rts/gmp/mpz/tdiv_ui.c53
-rw-r--r--rts/gmp/mpz/tstbit.c70
-rw-r--r--rts/gmp/mpz/ui_pow_ui.c139
-rw-r--r--rts/gmp/mpz/urandomb.c49
-rw-r--r--rts/gmp/mpz/urandomm.c78
-rw-r--r--rts/gmp/mpz/xor.c217
123 files changed, 11451 insertions, 0 deletions
diff --git a/rts/gmp/mpz/Makefile.am b/rts/gmp/mpz/Makefile.am
new file mode 100644
index 0000000000..cd6fec4e21
--- /dev/null
+++ b/rts/gmp/mpz/Makefile.am
@@ -0,0 +1,58 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library.
+#
+# The GNU MP Library is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or (at your
+# option) any later version.
+#
+# The GNU MP Library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA.
+
+
+AUTOMAKE_OPTIONS = gnu no-dependencies
+
+SUBDIRS = tests
+
+INCLUDES = -I$(top_srcdir) -DOPERATION_$*
+
+noinst_LTLIBRARIES = libmpz.la
+libmpz_la_SOURCES = \
+ abs.c add.c add_ui.c addmul_ui.c and.c array_init.c \
+ bin_ui.c bin_uiui.c cdiv_q.c \
+ cdiv_q_ui.c cdiv_qr.c cdiv_qr_ui.c cdiv_r.c cdiv_r_ui.c cdiv_ui.c \
+ clear.c clrbit.c cmp.c cmp_si.c cmp_ui.c cmpabs.c cmpabs_ui.c com.c \
+ divexact.c dump.c fac_ui.c fdiv_q.c fdiv_q_2exp.c fdiv_q_ui.c \
+ fdiv_qr.c fdiv_qr_ui.c fdiv_r.c fdiv_r_2exp.c fdiv_r_ui.c fdiv_ui.c \
+ fib_ui.c fits_sint_p.c fits_slong_p.c fits_sshort_p.c fits_uint_p.c \
+ fits_ulong_p.c fits_ushort_p.c gcd.c gcd_ui.c gcdext.c get_d.c get_si.c \
+ get_str.c get_ui.c getlimbn.c hamdist.c init.c inp_raw.c inp_str.c \
+ invert.c ior.c iset.c iset_d.c iset_si.c iset_str.c iset_ui.c \
+ jacobi.c kronsz.c kronuz.c kronzs.c kronzu.c \
+ lcm.c legendre.c mod.c mul.c mul_2exp.c neg.c nextprime.c \
+ out_raw.c out_str.c perfpow.c perfsqr.c popcount.c pow_ui.c powm.c \
+ powm_ui.c pprime_p.c random.c random2.c realloc.c remove.c root.c rrandomb.c \
+ scan0.c scan1.c set.c set_d.c set_f.c set_q.c set_si.c set_str.c \
+ set_ui.c setbit.c size.c sizeinbase.c sqrt.c sqrtrem.c sub.c \
+ sub_ui.c swap.c tdiv_ui.c tdiv_q.c tdiv_q_2exp.c tdiv_q_ui.c tdiv_qr.c \
+ tdiv_qr_ui.c tdiv_r.c tdiv_r_2exp.c tdiv_r_ui.c tstbit.c ui_pow_ui.c \
+ urandomb.c urandomm.c xor.c
+
+EXTRA_DIST = mul_siui.c
+nodist_libmpz_la_SOURCES = mul_si.c mul_ui.c
+CLEANFILES = $(nodist_libmpz_la_SOURCES)
+
+mul_si.c: $(srcdir)/mul_siui.c
+ cp $(srcdir)/mul_siui.c mul_si.c
+mul_ui.c: $(srcdir)/mul_siui.c
+ cp $(srcdir)/mul_siui.c mul_ui.c
diff --git a/rts/gmp/mpz/Makefile.in b/rts/gmp/mpz/Makefile.in
new file mode 100644
index 0000000000..e0f2cdc133
--- /dev/null
+++ b/rts/gmp/mpz/Makefile.in
@@ -0,0 +1,457 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 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.
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+
+@SET_MAKE@
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+AMDEP = @AMDEP@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CPP = @CPP@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+EXEEXT = @EXEEXT@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SPEED_CYCLECOUNTER_OBJS = @SPEED_CYCLECOUNTER_OBJS@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+gmp_srclinks = @gmp_srclinks@
+install_sh = @install_sh@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+
+# Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library.
+#
+# The GNU MP Library is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or (at your
+# option) any later version.
+#
+# The GNU MP Library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA.
+
+
+AUTOMAKE_OPTIONS = gnu no-dependencies
+
+SUBDIRS =
+
+INCLUDES = -I$(top_srcdir) -DOPERATION_$*
+
+noinst_LTLIBRARIES = libmpz.la
+libmpz_la_SOURCES = \
+ abs.c add.c add_ui.c addmul_ui.c and.c array_init.c \
+ bin_ui.c bin_uiui.c cdiv_q.c \
+ cdiv_q_ui.c cdiv_qr.c cdiv_qr_ui.c cdiv_r.c cdiv_r_ui.c cdiv_ui.c \
+ clear.c clrbit.c cmp.c cmp_si.c cmp_ui.c cmpabs.c cmpabs_ui.c com.c \
+ divexact.c dump.c fac_ui.c fdiv_q.c fdiv_q_2exp.c fdiv_q_ui.c \
+ fdiv_qr.c fdiv_qr_ui.c fdiv_r.c fdiv_r_2exp.c fdiv_r_ui.c fdiv_ui.c \
+ fib_ui.c fits_sint_p.c fits_slong_p.c fits_sshort_p.c fits_uint_p.c \
+ fits_ulong_p.c fits_ushort_p.c gcd.c gcd_ui.c gcdext.c get_d.c get_si.c \
+ get_str.c get_ui.c getlimbn.c hamdist.c init.c inp_raw.c inp_str.c \
+ invert.c ior.c iset.c iset_d.c iset_si.c iset_str.c iset_ui.c \
+ jacobi.c kronsz.c kronuz.c kronzs.c kronzu.c \
+ lcm.c legendre.c mod.c mul.c mul_2exp.c neg.c nextprime.c \
+ out_raw.c out_str.c perfpow.c perfsqr.c popcount.c pow_ui.c powm.c \
+ powm_ui.c pprime_p.c random.c random2.c realloc.c remove.c root.c rrandomb.c \
+ scan0.c scan1.c set.c set_d.c set_f.c set_q.c set_si.c set_str.c \
+ set_ui.c setbit.c size.c sizeinbase.c sqrt.c sqrtrem.c sub.c \
+ sub_ui.c swap.c tdiv_ui.c tdiv_q.c tdiv_q_2exp.c tdiv_q_ui.c tdiv_qr.c \
+ tdiv_qr_ui.c tdiv_r.c tdiv_r_2exp.c tdiv_r_ui.c tstbit.c ui_pow_ui.c \
+ urandomb.c urandomm.c xor.c
+
+
+EXTRA_DIST = mul_siui.c
+nodist_libmpz_la_SOURCES = mul_si.c mul_ui.c
+CLEANFILES = $(nodist_libmpz_la_SOURCES)
+subdir = mpz
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libmpz_la_LDFLAGS =
+libmpz_la_LIBADD =
+am_libmpz_la_OBJECTS = abs.lo add.lo add_ui.lo addmul_ui.lo and.lo \
+array_init.lo bin_ui.lo bin_uiui.lo cdiv_q.lo cdiv_q_ui.lo cdiv_qr.lo \
+cdiv_qr_ui.lo cdiv_r.lo cdiv_r_ui.lo cdiv_ui.lo clear.lo clrbit.lo \
+cmp.lo cmp_si.lo cmp_ui.lo cmpabs.lo cmpabs_ui.lo com.lo divexact.lo \
+dump.lo fac_ui.lo fdiv_q.lo fdiv_q_2exp.lo fdiv_q_ui.lo fdiv_qr.lo \
+fdiv_qr_ui.lo fdiv_r.lo fdiv_r_2exp.lo fdiv_r_ui.lo fdiv_ui.lo \
+fib_ui.lo fits_sint_p.lo fits_slong_p.lo fits_sshort_p.lo \
+fits_uint_p.lo fits_ulong_p.lo fits_ushort_p.lo gcd.lo gcd_ui.lo \
+gcdext.lo get_d.lo get_si.lo get_str.lo get_ui.lo getlimbn.lo \
+hamdist.lo init.lo inp_raw.lo inp_str.lo invert.lo ior.lo iset.lo \
+iset_d.lo iset_si.lo iset_str.lo iset_ui.lo jacobi.lo kronsz.lo \
+kronuz.lo kronzs.lo kronzu.lo lcm.lo legendre.lo mod.lo mul.lo \
+mul_2exp.lo neg.lo nextprime.lo out_raw.lo out_str.lo perfpow.lo \
+perfsqr.lo popcount.lo pow_ui.lo powm.lo powm_ui.lo pprime_p.lo \
+random.lo random2.lo realloc.lo remove.lo root.lo rrandomb.lo scan0.lo \
+scan1.lo set.lo set_d.lo set_f.lo set_q.lo set_si.lo set_str.lo \
+set_ui.lo setbit.lo size.lo sizeinbase.lo sqrt.lo sqrtrem.lo sub.lo \
+sub_ui.lo swap.lo tdiv_ui.lo tdiv_q.lo tdiv_q_2exp.lo tdiv_q_ui.lo \
+tdiv_qr.lo tdiv_qr_ui.lo tdiv_r.lo tdiv_r_2exp.lo tdiv_r_ui.lo \
+tstbit.lo ui_pow_ui.lo urandomb.lo urandomm.lo xor.lo
+nodist_libmpz_la_OBJECTS = mul_si.lo mul_ui.lo
+libmpz_la_OBJECTS = $(am_libmpz_la_OBJECTS) $(nodist_libmpz_la_OBJECTS)
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CFLAGS = @CFLAGS@
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libmpz_la_SOURCES)
+DIST_COMMON = README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+depcomp =
+SOURCES = $(libmpz_la_SOURCES) $(nodist_libmpz_la_SOURCES)
+OBJECTS = $(am_libmpz_la_OBJECTS) $(nodist_libmpz_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu mpz/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libmpz.la: $(libmpz_la_OBJECTS) $(libmpz_la_DEPENDENCIES)
+ $(LINK) $(libmpz_la_LDFLAGS) $(libmpz_la_OBJECTS) $(libmpz_la_LIBADD) $(LIBS)
+.c.o:
+ $(COMPILE) -c $<
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+.c.lo:
+ $(LTCOMPILE) -c -o $@ $<
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ if test "$$subdir" = "."; then dot_seen=yes; else :; fi; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir); \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ -rm -f Makefile.in
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-generic \
+ clean-am
+ -rm -f libtool
+
+distclean: distclean-recursive
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool install-recursive \
+uninstall-recursive install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all install-strip \
+installdirs-am installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+mul_si.c: $(srcdir)/mul_siui.c
+ cp $(srcdir)/mul_siui.c mul_si.c
+mul_ui.c: $(srcdir)/mul_siui.c
+ cp $(srcdir)/mul_siui.c mul_ui.c
+
+# 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/rts/gmp/mpz/README b/rts/gmp/mpz/README
new file mode 100644
index 0000000000..06b481d770
--- /dev/null
+++ b/rts/gmp/mpz/README
@@ -0,0 +1,23 @@
+This directory contains functions for GMP's integer function layer.
+
+In this version of GMP, integers are represented like in the figure below.
+(Please note that the format might change between every version, and that
+depending on the internal format in any way is a bad idea.)
+
+ most least
+significant significant
+ limb limb
+
+ _mp_d
+ /
+ /
+ \/
+ ____ ____ ____ ____ ____
+ |____|____|____|____|____|
+
+ <------- _mp_size ------->
+
+
+The most significant limb will be non-zero. The _mp_size field's sign
+reflects the sign of the number. Its absolute value is the count of limbs
+in the number.
diff --git a/rts/gmp/mpz/abs.c b/rts/gmp/mpz/abs.c
new file mode 100644
index 0000000000..0b5eab1ce6
--- /dev/null
+++ b/rts/gmp/mpz/abs.c
@@ -0,0 +1,51 @@
+/* mpz_abs(dst, src) -- Assign the absolute value of SRC to DST.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_abs (mpz_ptr w, mpz_srcptr u)
+#else
+mpz_abs (w, u)
+ mpz_ptr w;
+ mpz_srcptr u;
+#endif
+{
+ mp_ptr wp, up;
+ mp_size_t size;
+
+ size = ABS (u->_mp_size);
+
+ if (u != w)
+ {
+ if (w->_mp_alloc < size)
+ _mpz_realloc (w, size);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ MPN_COPY (wp, up, size);
+ }
+
+ w->_mp_size = size;
+}
diff --git a/rts/gmp/mpz/add.c b/rts/gmp/mpz/add.c
new file mode 100644
index 0000000000..a22c3778fb
--- /dev/null
+++ b/rts/gmp/mpz/add.c
@@ -0,0 +1,123 @@
+/* mpz_add -- Add two integers.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_add (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_add (w, u, v)
+ mpz_ptr w;
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+madd (mpz_srcptr u, mpz_srcptr v, mpz_ptr w)
+#else
+madd (u, v, w)
+ mpz_srcptr u;
+ mpz_srcptr v;
+ mpz_ptr w;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_srcptr up, vp;
+ mp_ptr wp;
+ mp_size_t usize, vsize, wsize;
+ mp_size_t abs_usize;
+ mp_size_t abs_vsize;
+
+ usize = u->_mp_size;
+ vsize = v->_mp_size;
+ abs_usize = ABS (usize);
+ abs_vsize = ABS (vsize);
+
+ if (abs_usize < abs_vsize)
+ {
+ /* Swap U and V. */
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (usize, vsize);
+ MP_SIZE_T_SWAP (abs_usize, abs_vsize);
+ }
+
+ /* True: ABS_USIZE >= ABS_VSIZE. */
+
+ /* If not space for w (and possible carry), increase space. */
+ wsize = abs_usize + 1;
+ if (w->_mp_alloc < wsize)
+ _mpz_realloc (w, wsize);
+
+ /* These must be after realloc (u or v may be the same as w). */
+ up = u->_mp_d;
+ vp = v->_mp_d;
+ wp = w->_mp_d;
+
+ if ((usize ^ vsize) < 0)
+ {
+ /* U and V have different sign. Need to compare them to determine
+ which operand to subtract from which. */
+
+ /* This test is right since ABS_USIZE >= ABS_VSIZE. */
+ if (abs_usize != abs_vsize)
+ {
+ mpn_sub (wp, up, abs_usize, vp, abs_vsize);
+ wsize = abs_usize;
+ MPN_NORMALIZE (wp, wsize);
+ if (usize < 0)
+ wsize = -wsize;
+ }
+ else if (mpn_cmp (up, vp, abs_usize) < 0)
+ {
+ mpn_sub_n (wp, vp, up, abs_usize);
+ wsize = abs_usize;
+ MPN_NORMALIZE (wp, wsize);
+ if (usize >= 0)
+ wsize = -wsize;
+ }
+ else
+ {
+ mpn_sub_n (wp, up, vp, abs_usize);
+ wsize = abs_usize;
+ MPN_NORMALIZE (wp, wsize);
+ if (usize < 0)
+ wsize = -wsize;
+ }
+ }
+ else
+ {
+ /* U and V have same sign. Add them. */
+ mp_limb_t cy_limb = mpn_add (wp, up, abs_usize, vp, abs_vsize);
+ wp[abs_usize] = cy_limb;
+ wsize = abs_usize + cy_limb;
+ if (usize < 0)
+ wsize = -wsize;
+ }
+
+ w->_mp_size = wsize;
+}
diff --git a/rts/gmp/mpz/add_ui.c b/rts/gmp/mpz/add_ui.c
new file mode 100644
index 0000000000..28dbd71f45
--- /dev/null
+++ b/rts/gmp/mpz/add_ui.c
@@ -0,0 +1,84 @@
+/* mpz_add_ui -- Add an mpz_t and an unsigned one-word integer.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_add_ui (mpz_ptr w, mpz_srcptr u, unsigned long int v)
+#else
+mpz_add_ui (w, u, v)
+ mpz_ptr w;
+ mpz_srcptr u;
+ unsigned long int v;
+#endif
+{
+ mp_srcptr up;
+ mp_ptr wp;
+ mp_size_t usize, wsize;
+ mp_size_t abs_usize;
+
+ usize = u->_mp_size;
+ abs_usize = ABS (usize);
+
+ /* If not space for W (and possible carry), increase space. */
+ wsize = abs_usize + 1;
+ if (w->_mp_alloc < wsize)
+ _mpz_realloc (w, wsize);
+
+ /* These must be after realloc (U may be the same as W). */
+ up = u->_mp_d;
+ wp = w->_mp_d;
+
+ if (abs_usize == 0)
+ {
+ wp[0] = v;
+ w->_mp_size = v != 0;
+ return;
+ }
+
+ if (usize >= 0)
+ {
+ mp_limb_t cy;
+ cy = mpn_add_1 (wp, up, abs_usize, (mp_limb_t) v);
+ wp[abs_usize] = cy;
+ wsize = abs_usize + cy;
+ }
+ else
+ {
+ /* The signs are different. Need exact comparison to determine
+ which operand to subtract from which. */
+ if (abs_usize == 1 && up[0] < v)
+ {
+ wp[0] = v - up[0];
+ wsize = 1;
+ }
+ else
+ {
+ mpn_sub_1 (wp, up, abs_usize, (mp_limb_t) v);
+ /* Size can decrease with at most one limb. */
+ wsize = -(abs_usize - (wp[abs_usize - 1] == 0));
+ }
+ }
+
+ w->_mp_size = wsize;
+}
diff --git a/rts/gmp/mpz/addmul_ui.c b/rts/gmp/mpz/addmul_ui.c
new file mode 100644
index 0000000000..7b38d3624d
--- /dev/null
+++ b/rts/gmp/mpz/addmul_ui.c
@@ -0,0 +1,214 @@
+/* mpz_addmul_ui(prodsum, multiplier, small_multiplicand) --
+ Add MULTIPLICATOR times SMALL_MULTIPLICAND to PRODSUM.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+static mp_limb_t mpn_neg1 _PROTO ((mp_ptr, mp_size_t));
+
+#if 0
+#undef MPN_NORMALIZE
+#define MPN_NORMALIZE(DST, NLIMBS) \
+ do { \
+ while (--(NLIMBS) >= 0 && (DST)[NLIMBS] == 0) \
+ ; \
+ (NLIMBS)++; \
+ } while (0)
+#undef MPN_NORMALIZE_NOT_ZERO
+#define MPN_NORMALIZE_NOT_ZERO(DST, NLIMBS) \
+ do { \
+ while ((DST)[--(NLIMBS)] == 0) \
+ ; \
+ (NLIMBS)++; \
+ } while (0)
+#endif
+
+void
+#if __STDC__
+mpz_addmul_ui (mpz_ptr rz, mpz_srcptr az, unsigned long int bu)
+#else
+mpz_addmul_ui (rz, az, bu)
+ mpz_ptr rz;
+ mpz_srcptr az;
+ unsigned long int bu;
+#endif
+{
+ mp_size_t rn, an;
+ mp_ptr rp, ap;
+
+ an = SIZ (az);
+
+ /* If either multiplier is zero, result is unaffected. */
+ if (bu == 0 || an == 0)
+ return;
+
+ rn = SIZ (rz);
+
+ if (rn == 0)
+ {
+ mp_limb_t cy;
+
+ an = ABS (an);
+ if (ALLOC (rz) <= an)
+ _mpz_realloc (rz, an + 1);
+ rp = PTR (rz);
+ ap = PTR (az);
+ cy = mpn_mul_1 (rp, ap, an, (mp_limb_t) bu);
+ rp[an] = cy;
+ an += cy != 0;
+ SIZ (rz) = SIZ (az) >= 0 ? an : -an;
+ return;
+ }
+
+ if ((an ^ rn) >= 0)
+ {
+ /* Sign of operands are the same--really add. */
+ an = ABS (an);
+ rn = ABS (rn);
+ if (rn > an)
+ {
+ mp_limb_t cy;
+ if (ALLOC (rz) <= rn)
+ _mpz_realloc (rz, rn + 1);
+ rp = PTR (rz);
+ ap = PTR (az);
+ cy = mpn_addmul_1 (rp, ap, an, (mp_limb_t) bu);
+ cy = mpn_add_1 (rp + an, rp + an, rn - an, cy);
+ rp[rn] = cy;
+ rn += cy != 0;
+ SIZ (rz) = SIZ (rz) >= 0 ? rn : -rn;
+ return;
+ }
+ else
+ {
+ mp_limb_t cy;
+ if (ALLOC (rz) <= an)
+ _mpz_realloc (rz, an + 1);
+ rp = PTR (rz);
+ ap = PTR (az);
+ cy = mpn_addmul_1 (rp, ap, rn, (mp_limb_t) bu);
+ if (an != rn)
+ {
+ mp_limb_t cy2;
+ cy2 = mpn_mul_1 (rp + rn, ap + rn, an - rn, (mp_limb_t) bu);
+ cy = cy2 + mpn_add_1 (rp + rn, rp + rn, an - rn, cy);
+ }
+ rn = an;
+ rp[rn] = cy;
+ rn += cy != 0;
+ SIZ (rz) = SIZ (rz) >= 0 ? rn : -rn;
+ return;
+ }
+ }
+ else
+ {
+ /* Sign of operands are different--actually subtract. */
+ an = ABS (an);
+ rn = ABS (rn);
+ if (rn > an)
+ {
+ mp_limb_t cy;
+ rp = PTR (rz);
+ ap = PTR (az);
+ cy = mpn_submul_1 (rp, ap, an, (mp_limb_t) bu);
+ cy = mpn_sub_1 (rp + an, rp + an, rn - an, cy);
+ if (cy != 0)
+ {
+ mpn_neg1 (rp, rn);
+ MPN_NORMALIZE_NOT_ZERO (rp, rn);
+ }
+ else
+ {
+ MPN_NORMALIZE (rp, rn);
+ rn = -rn;
+ }
+
+ SIZ (rz) = SIZ (rz) >= 0 ? -rn : rn;
+ return;
+ }
+ else
+ {
+ /* Tricky case. We need to subtract an operand that might be larger
+ than the minuend. To avoid allocating temporary space, we compute
+ a*b-r instead of r-a*b and then negate. */
+ mp_limb_t cy;
+ if (ALLOC (rz) <= an)
+ _mpz_realloc (rz, an + 1);
+ rp = PTR (rz);
+ ap = PTR (az);
+ cy = mpn_submul_1 (rp, ap, rn, (mp_limb_t) bu);
+ if (an != rn)
+ {
+ mp_limb_t cy2;
+ cy -= mpn_neg1 (rp, rn);
+ cy2 = mpn_mul_1 (rp + rn, ap + rn, an - rn, (mp_limb_t) bu);
+ if (cy == ~(mp_limb_t) 0)
+ cy = cy2 - mpn_sub_1 (rp + rn, rp + rn, an - rn, (mp_limb_t) 1);
+ else
+ cy = cy2 + mpn_add_1 (rp + rn, rp + rn, an - rn, cy);
+ rp[an] = cy;
+ rn = an + (cy != 0);
+ rn -= rp[rn - 1] == 0;
+ }
+ else if (cy != 0)
+ {
+ cy -= mpn_neg1 (rp, rn);
+ rp[an] = cy;
+ rn = an + 1;
+ MPN_NORMALIZE_NOT_ZERO (rp, rn);
+ }
+ else
+ {
+ rn = an;
+ MPN_NORMALIZE (rp, rn);
+ rn = -rn;
+ }
+
+ SIZ (rz) = SIZ (rz) >= 0 ? -rn : rn;
+ return;
+ }
+ }
+}
+
+static mp_limb_t
+#if __STDC__
+mpn_neg1 (mp_ptr rp, mp_size_t rn)
+#else
+mpn_neg1 (rp, rn)
+ mp_ptr rp;
+ mp_size_t rn;
+#endif
+{
+ mp_size_t i;
+
+ while (rn != 0 && rp[0] == 0)
+ rp++, rn--;
+
+ if (rn != 0)
+ {
+ rp[0] = -rp[0];
+ for (i = 1; i < rn; i++)
+ rp[i] = ~rp[i];
+ return 1;
+ }
+ return 0;
+}
diff --git a/rts/gmp/mpz/and.c b/rts/gmp/mpz/and.c
new file mode 100644
index 0000000000..354e9455bf
--- /dev/null
+++ b/rts/gmp/mpz/and.c
@@ -0,0 +1,278 @@
+/* mpz_and -- Logical and.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_and (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+#else
+mpz_and (res, op1, op2)
+ mpz_ptr res;
+ mpz_srcptr op1;
+ mpz_srcptr op2;
+#endif
+{
+ mp_srcptr op1_ptr, op2_ptr;
+ mp_size_t op1_size, op2_size;
+ mp_ptr res_ptr;
+ mp_size_t res_size;
+ mp_size_t i;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ op1_size = op1->_mp_size;
+ op2_size = op2->_mp_size;
+
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+
+ if (op1_size >= 0)
+ {
+ if (op2_size >= 0)
+ {
+ res_size = MIN (op1_size, op2_size);
+ /* First loop finds the size of the result. */
+ for (i = res_size - 1; i >= 0; i--)
+ if ((op1_ptr[i] & op2_ptr[i]) != 0)
+ break;
+ res_size = i + 1;
+
+ /* Handle allocation, now then we know exactly how much space is
+ needed for the result. */
+ if (res->_mp_alloc < res_size)
+ {
+ _mpz_realloc (res, res_size);
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+ }
+
+ /* Second loop computes the real result. */
+ for (i = res_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] & op2_ptr[i];
+
+ res->_mp_size = res_size;
+ return;
+ }
+ else /* op2_size < 0 */
+ {
+ /* Fall through to the code at the end of the function. */
+ }
+ }
+ else
+ {
+ if (op2_size < 0)
+ {
+ mp_ptr opx;
+ mp_limb_t cy;
+ mp_size_t res_alloc;
+
+ /* Both operands are negative, so will be the result.
+ -((-OP1) & (-OP2)) = -(~(OP1 - 1) & ~(OP2 - 1)) =
+ = ~(~(OP1 - 1) & ~(OP2 - 1)) + 1 =
+ = ((OP1 - 1) | (OP2 - 1)) + 1 */
+
+ /* It might seem as we could end up with an (invalid) result with
+ a leading zero-limb here when one of the operands is of the
+ type 1,,0,,..,,.0. But some analysis shows that we surely
+ would get carry into the zero-limb in this situation... */
+
+ op1_size = -op1_size;
+ op2_size = -op2_size;
+
+ res_alloc = 1 + MAX (op1_size, op2_size);
+
+ opx = (mp_ptr) TMP_ALLOC (op1_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
+ op1_ptr = opx;
+
+ opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+ op2_ptr = opx;
+
+ if (res->_mp_alloc < res_alloc)
+ {
+ _mpz_realloc (res, res_alloc);
+ res_ptr = res->_mp_d;
+ /* Don't re-read OP1_PTR and OP2_PTR. They point to
+ temporary space--never to the space RES->_mp_d used
+ to point to before reallocation. */
+ }
+
+ if (op1_size >= op2_size)
+ {
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+ op1_size - op2_size);
+ for (i = op2_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] | op2_ptr[i];
+ res_size = op1_size;
+ }
+ else
+ {
+ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+ op2_size - op1_size);
+ for (i = op1_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] | op2_ptr[i];
+ res_size = op2_size;
+ }
+
+ cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
+ if (cy)
+ {
+ res_ptr[res_size] = cy;
+ res_size++;
+ }
+
+ res->_mp_size = -res_size;
+ TMP_FREE (marker);
+ return;
+ }
+ else
+ {
+ /* We should compute -OP1 & OP2. Swap OP1 and OP2 and fall
+ through to the code that handles OP1 & -OP2. */
+ MPZ_SRCPTR_SWAP (op1, op2);
+ MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
+ }
+
+ }
+
+ {
+#if ANDNEW
+ mp_size_t op2_lim;
+ mp_size_t count;
+
+ /* OP2 must be negated as with infinite precision.
+
+ Scan from the low end for a non-zero limb. The first non-zero
+ limb is simply negated (two's complement). Any subsequent
+ limbs are one's complemented. Of course, we don't need to
+ handle more limbs than there are limbs in the other, positive
+ operand as the result for those limbs is going to become zero
+ anyway. */
+
+ /* Scan for the least significant non-zero OP2 limb, and zero the
+ result meanwhile for those limb positions. (We will surely
+ find a non-zero limb, so we can write the loop with one
+ termination condition only.) */
+ for (i = 0; op2_ptr[i] == 0; i++)
+ res_ptr[i] = 0;
+ op2_lim = i;
+
+ op2_size = -op2_size;
+
+ if (op1_size <= op2_size)
+ {
+ /* The ones-extended OP2 is >= than the zero-extended OP1.
+ RES_SIZE <= OP1_SIZE. Find the exact size. */
+ for (i = op1_size - 1; i > op2_lim; i--)
+ if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
+ break;
+ res_size = i + 1;
+ for (i = res_size - 1; i > op2_lim; i--)
+ res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+ res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
+ /* Yes, this *can* happen! */
+ MPN_NORMALIZE (res_ptr, res_size);
+ }
+ else
+ {
+ /* The ones-extended OP2 is < than the zero-extended OP1.
+ RES_SIZE == OP1_SIZE, since OP1 is normalized. */
+ res_size = op1_size;
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
+ for (i = op2_size - 1; i > op2_lim; i--)
+ res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+ res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
+ }
+
+ res->_mp_size = res_size;
+#else
+
+ /* OP1 is positive and zero-extended,
+ OP2 is negative and ones-extended.
+ The result will be positive.
+ OP1 & -OP2 = OP1 & ~(OP2 - 1). */
+
+ mp_ptr opx;
+
+ op2_size = -op2_size;
+ opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+ op2_ptr = opx;
+
+ if (op1_size > op2_size)
+ {
+ /* The result has the same size as OP1, since OP1 is normalized
+ and longer than the ones-extended OP2. */
+ res_size = op1_size;
+
+ /* Handle allocation, now then we know exactly how much space is
+ needed for the result. */
+ if (res->_mp_alloc < res_size)
+ {
+ _mpz_realloc (res, res_size);
+ res_ptr = res->_mp_d;
+ op1_ptr = op1->_mp_d;
+ /* Don't re-read OP2_PTR. It points to temporary space--never
+ to the space RES->_mp_d used to point to before reallocation. */
+ }
+
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+ res_size - op2_size);
+ for (i = op2_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+
+ res->_mp_size = res_size;
+ }
+ else
+ {
+ /* Find out the exact result size. Ignore the high limbs of OP2,
+ OP1 is zero-extended and would make the result zero. */
+ for (i = op1_size - 1; i >= 0; i--)
+ if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
+ break;
+ res_size = i + 1;
+
+ /* Handle allocation, now then we know exactly how much space is
+ needed for the result. */
+ if (res->_mp_alloc < res_size)
+ {
+ _mpz_realloc (res, res_size);
+ res_ptr = res->_mp_d;
+ op1_ptr = op1->_mp_d;
+ /* Don't re-read OP2_PTR. It points to temporary space--never
+ to the space RES->_mp_d used to point to before reallocation. */
+ }
+
+ for (i = res_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+
+ res->_mp_size = res_size;
+ }
+#endif
+ }
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/array_init.c b/rts/gmp/mpz/array_init.c
new file mode 100644
index 0000000000..1c22046986
--- /dev/null
+++ b/rts/gmp/mpz/array_init.c
@@ -0,0 +1,48 @@
+/* mpz_array_init (array, array_size, size_per_elem) --
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_array_init (mpz_ptr arr, mp_size_t arr_size, mp_size_t nbits)
+#else
+mpz_array_init (arr, arr_size, nbits)
+ mpz_ptr arr;
+ mp_size_t arr_size;
+ mp_size_t nbits;
+#endif
+{
+ register mp_ptr p;
+ register size_t i;
+ mp_size_t nlimbs;
+
+ nlimbs = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
+ p = (mp_ptr) (*_mp_allocate_func) (arr_size * nlimbs * BYTES_PER_MP_LIMB);
+
+ for (i = 0; i < arr_size; i++)
+ {
+ arr[i]._mp_alloc = nlimbs + 1; /* Yes, lie a little... */
+ arr[i]._mp_size = 0;
+ arr[i]._mp_d = p + i * nlimbs;
+ }
+}
diff --git a/rts/gmp/mpz/bin_ui.c b/rts/gmp/mpz/bin_ui.c
new file mode 100644
index 0000000000..a7a6c98218
--- /dev/null
+++ b/rts/gmp/mpz/bin_ui.c
@@ -0,0 +1,141 @@
+/* mpz_bin_uiui - compute n over k.
+
+Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This is a poor implementation. Look at bin_uiui.c for improvement ideas.
+ In fact consider calling mpz_bin_uiui() when the arguments fit, leaving
+ the code here only for big n.
+
+ The identity bin(n,k) = (-1)^k * bin(-n+k-1,k) can be found in Knuth vol
+ 1 section 1.2.6 part G. */
+
+
+/* Enhancement: use mpn_divexact_1 when it exists */
+#define DIVIDE() \
+ ASSERT (SIZ(r) > 0); \
+ ASSERT_NOCARRY (mpn_divrem_1 (PTR(r), (mp_size_t) 0, \
+ PTR(r), SIZ(r), kacc)); \
+ SIZ(r) -= (PTR(r)[SIZ(r)-1] == 0);
+
+void
+#if __STDC__
+mpz_bin_ui (mpz_ptr r, mpz_srcptr n, unsigned long int k)
+#else
+mpz_bin_ui (r, n, k)
+ mpz_ptr r;
+ mpz_srcptr n;
+ unsigned long int k;
+#endif
+{
+ mpz_t ni;
+ mp_limb_t i;
+ mpz_t nacc;
+ mp_limb_t kacc;
+ mp_size_t negate;
+
+ if (mpz_sgn (n) < 0)
+ {
+ /* bin(n,k) = (-1)^k * bin(-n+k-1,k), and set ni = -n+k-1 - k = -n-1 */
+ mpz_init (ni);
+ mpz_neg (ni, n);
+ mpz_sub_ui (ni, ni, 1L);
+ negate = (k & 1); /* (-1)^k */
+ }
+ else
+ {
+ /* bin(n,k) == 0 if k>n
+ (no test for this under the n<0 case, since -n+k-1 >= k there) */
+ if (mpz_cmp_ui (n, k) < 0)
+ {
+ mpz_set_ui (r, 0L);
+ return;
+ }
+
+ /* set ni = n-k */
+ mpz_init (ni);
+ mpz_sub_ui (ni, n, k);
+ negate = 0;
+ }
+
+ /* Now wanting bin(ni+k,k), with ni positive, and "negate" is the sign (0
+ for positive, 1 for negative). */
+ mpz_set_ui (r, 1L);
+
+ /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller. In this case it's
+ whether ni+k-k < k meaning ni<k, and if so change to denominator ni+k-k
+ = ni, and new ni of ni+k-ni = k. */
+ if (mpz_cmp_ui (ni, k) < 0)
+ {
+ unsigned long tmp;
+ tmp = k;
+ k = mpz_get_ui (ni);
+ mpz_set_ui (ni, tmp);
+ }
+
+ kacc = 1;
+ mpz_init_set_ui (nacc, 1);
+
+ for (i = 1; i <= k; i++)
+ {
+ mp_limb_t k1, k0;
+
+#if 0
+ mp_limb_t nacclow;
+ int c;
+
+ nacclow = PTR(nacc)[0];
+ for (c = 0; (((kacc | nacclow) & 1) == 0); c++)
+ {
+ kacc >>= 1;
+ nacclow >>= 1;
+ }
+ mpz_div_2exp (nacc, nacc, c);
+#endif
+
+ mpz_add_ui (ni, ni, 1);
+ mpz_mul (nacc, nacc, ni);
+ umul_ppmm (k1, k0, kacc, i);
+ if (k1 != 0)
+ {
+ /* Accumulator overflow. Perform bignum step. */
+ mpz_mul (r, r, nacc);
+ mpz_set_ui (nacc, 1);
+ DIVIDE ();
+ kacc = i;
+ }
+ else
+ {
+ /* Save new products in accumulators to keep accumulating. */
+ kacc = k0;
+ }
+ }
+
+ mpz_mul (r, r, nacc);
+ DIVIDE ();
+ SIZ(r) = (SIZ(r) ^ -negate) + negate;
+
+ mpz_clear (nacc);
+ mpz_clear (ni);
+}
diff --git a/rts/gmp/mpz/bin_uiui.c b/rts/gmp/mpz/bin_uiui.c
new file mode 100644
index 0000000000..b37541ba54
--- /dev/null
+++ b/rts/gmp/mpz/bin_uiui.c
@@ -0,0 +1,120 @@
+/* mpz_bin_uiui - compute n over k.
+
+Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Avoid reallocs by rounding up any new size */
+#define ROUNDUP_MASK 15
+
+/* Enhancement: use mpn_divexact_1 when it exists */
+#define MULDIV() \
+ MPZ_REALLOC (r, (SIZ(r)+1)|ROUNDUP_MASK); \
+ PTR(r)[SIZ(r)] = mpn_mul_1 (PTR(r), PTR(r), SIZ(r), nacc); \
+ ASSERT_NOCARRY (mpn_divrem_1 (PTR(r), (mp_size_t) 0, \
+ PTR(r), SIZ(r)+1, kacc)); \
+ SIZ(r) += (PTR(r)[SIZ(r)] != 0);
+
+void
+#if __STDC__
+mpz_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+#else
+mpz_bin_uiui (r, n, k)
+ mpz_ptr r;
+ unsigned long int n;
+ unsigned long int k;
+#endif
+{
+ unsigned long int i, j;
+ mp_limb_t nacc, kacc;
+ unsigned long int cnt;
+
+ /* bin(n,k) = 0 if k>n. */
+ if (n < k)
+ {
+ mpz_set_ui (r, 0);
+ return;
+ }
+
+ /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller. */
+ k = MIN (k, n-k);
+
+ /* bin(n,0) = 1 */
+ if (k == 0)
+ {
+ mpz_set_ui (r, 1);
+ return;
+ }
+
+ j = n - k + 1;
+ mpz_set_ui (r, j);
+
+ /* Initialize accumulators. */
+ nacc = 1;
+ kacc = 1;
+
+ cnt = 0;
+ for (i = 2; i <= k; i++)
+ {
+ mp_limb_t n1, n0, k1, k0;
+
+ j++;
+#if 0
+ /* Remove common multiples of 2. This will allow us to accumulate
+ more in nacc and kacc before we need a bignum step. It would make
+ sense to cancel factors of 3, 5, etc too, but this would be best
+ handled by sieving out factors. Alternatively, we could perform a
+ gcd of the accumulators just as they have overflown, and keep
+ accumulating until the gcd doesn't remove a significant factor. */
+ while (((nacc | kacc) & 1) == 0)
+ {
+ nacc >>= 1;
+ kacc >>= 1;
+ }
+#else
+ cnt = ((nacc | kacc) & 1) ^ 1;
+ nacc >>= cnt;
+ kacc >>= cnt;
+#endif
+ /* Accumulate next multiples. */
+ umul_ppmm (n1, n0, nacc, j);
+ umul_ppmm (k1, k0, kacc, i);
+ if (n1 != 0)
+ {
+ /* Accumulator overflow. Perform bignum step. */
+ MULDIV ();
+ nacc = j;
+ kacc = i;
+ }
+ else
+ {
+ if (k1 != 0) abort ();
+ /* Save new products in accumulators to keep accumulating. */
+ nacc = n0;
+ kacc = k0;
+ }
+ }
+
+ /* Take care of whatever is left in accumulators. */
+ MULDIV ();
+}
diff --git a/rts/gmp/mpz/cdiv_q.c b/rts/gmp/mpz/cdiv_q.c
new file mode 100644
index 0000000000..b15ba8aaa9
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_q.c
@@ -0,0 +1,51 @@
+/* mpz_cdiv_q -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_cdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_cdiv_q (quot, dividend, divisor)
+ mpz_ptr quot;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t dividend_size = dividend->_mp_size;
+ mp_size_t divisor_size = divisor->_mp_size;
+ mpz_t rem;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ MPZ_TMP_INIT (rem, ABS (divisor_size));
+
+ mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+ if ((divisor_size ^ dividend_size) >= 0 && rem->_mp_size != 0)
+ mpz_add_ui (quot, quot, 1L);
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/cdiv_q_ui.c b/rts/gmp/mpz/cdiv_q_ui.c
new file mode 100644
index 0000000000..74f3a90b83
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_q_ui.c
@@ -0,0 +1,67 @@
+/* mpz_cdiv_q_ui -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator. In order to make it
+ always fit into the return type, the negative of the true remainder is
+ returned.
+
+Copyright (C) 1994, 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_cdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_cdiv_q_ui (quot, dividend, divisor)
+ mpz_ptr quot;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_ptr quot_ptr;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ if (quot->_mp_alloc < size)
+ _mpz_realloc (quot, size);
+
+ quot_ptr = quot->_mp_d;
+
+ remainder_limb = mpn_divmod_1 (quot_ptr, dividend->_mp_d, size,
+ (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size >= 0)
+ {
+ mpn_incr_u (quot_ptr, (mp_limb_t) 1);
+ remainder_limb = divisor - remainder_limb;
+ }
+
+ size -= size != 0 && quot_ptr[size - 1] == 0;
+ quot->_mp_size = dividend_size >= 0 ? size : -size;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/cdiv_qr.c b/rts/gmp/mpz/cdiv_qr.c
new file mode 100644
index 0000000000..29c7c41a4e
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_qr.c
@@ -0,0 +1,64 @@
+/* mpz_cdiv_qr -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_cdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_cdiv_qr (quot, rem, dividend, divisor)
+ mpz_ptr quot;
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t divisor_size = divisor->_mp_size;
+ mp_size_t xsize;
+ mpz_t temp_divisor; /* N.B.: lives until function returns! */
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* We need the original value of the divisor after the quotient and
+ remainder have been preliminary calculated. We have to copy it to
+ temporary space if it's the same variable as either QUOT or REM. */
+ if (quot == divisor || rem == divisor)
+ {
+ MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+ mpz_set (temp_divisor, divisor);
+ divisor = temp_divisor;
+ }
+
+ xsize = dividend->_mp_size ^ divisor_size;;
+ mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+ if (xsize >= 0 && rem->_mp_size != 0)
+ {
+ mpz_add_ui (quot, quot, 1L);
+ mpz_sub (rem, rem, divisor);
+ }
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/cdiv_qr_ui.c b/rts/gmp/mpz/cdiv_qr_ui.c
new file mode 100644
index 0000000000..a7873c6e20
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_qr_ui.c
@@ -0,0 +1,71 @@
+/* mpz_cdiv_qr_ui -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator. In order to make it
+ always fit into the return type, the negative of the true remainder is
+ returned.
+
+Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_cdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_cdiv_qr_ui (quot, rem, dividend, divisor)
+ mpz_ptr quot;
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_ptr quot_ptr;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ if (quot->_mp_alloc < size)
+ _mpz_realloc (quot, size);
+
+ quot_ptr = quot->_mp_d;
+
+ remainder_limb = mpn_divmod_1 (quot_ptr, dividend->_mp_d, size,
+ (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size >= 0)
+ {
+ mpn_incr_u (quot_ptr, (mp_limb_t) 1);
+ remainder_limb = divisor - remainder_limb;
+ }
+
+ size -= size != 0 && quot_ptr[size - 1] == 0;
+ quot->_mp_size = dividend_size >= 0 ? size : -size;
+
+ rem->_mp_d[0] = remainder_limb;
+ rem->_mp_size = -(remainder_limb != 0);
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/cdiv_r.c b/rts/gmp/mpz/cdiv_r.c
new file mode 100644
index 0000000000..e96ce7e677
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_r.c
@@ -0,0 +1,59 @@
+/* mpz_cdiv_r -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_cdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_cdiv_r (rem, dividend, divisor)
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t divisor_size = divisor->_mp_size;
+ mpz_t temp_divisor; /* N.B.: lives until function returns! */
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* We need the original value of the divisor after the remainder has been
+ preliminary calculated. We have to copy it to temporary space if it's
+ the same variable as REM. */
+ if (rem == divisor)
+ {
+
+ MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+ mpz_set (temp_divisor, divisor);
+ divisor = temp_divisor;
+ }
+
+ mpz_tdiv_r (rem, dividend, divisor);
+
+ if ((divisor_size ^ dividend->_mp_size) >= 0 && rem->_mp_size != 0)
+ mpz_sub (rem, rem, divisor);
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/cdiv_r_ui.c b/rts/gmp/mpz/cdiv_r_ui.c
new file mode 100644
index 0000000000..e17e2381c0
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_r_ui.c
@@ -0,0 +1,57 @@
+/* mpz_cdiv_r_ui -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator. In order to make it
+ always fit into the return type, the negative of the true remainder is
+ returned.
+
+Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_cdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_cdiv_r_ui (rem, dividend, divisor)
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ remainder_limb = mpn_mod_1 (dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size >= 0)
+ remainder_limb = divisor - remainder_limb;
+
+ rem->_mp_d[0] = remainder_limb;
+ rem->_mp_size = -(remainder_limb != 0);
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/cdiv_ui.c b/rts/gmp/mpz/cdiv_ui.c
new file mode 100644
index 0000000000..63547a78c0
--- /dev/null
+++ b/rts/gmp/mpz/cdiv_ui.c
@@ -0,0 +1,50 @@
+/* mpz_cdiv_ui -- Division rounding the quotient towards +infinity. The
+ remainder gets the opposite sign as the denominator. In order to make it
+ always fit into the return type, the negative of the true remainder is
+ returned.
+
+Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_cdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_cdiv_ui (dividend, divisor)
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_limb_t remainder_limb;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ remainder_limb = mpn_mod_1 (dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size >= 0)
+ remainder_limb = divisor - remainder_limb;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/clear.c b/rts/gmp/mpz/clear.c
new file mode 100644
index 0000000000..5224553f9e
--- /dev/null
+++ b/rts/gmp/mpz/clear.c
@@ -0,0 +1,35 @@
+/* mpz_clear -- de-allocate the space occupied by the dynamic digit space of
+ an integer.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_clear (mpz_ptr m)
+#else
+mpz_clear (m)
+ mpz_ptr m;
+#endif
+{
+ (*_mp_free_func) (m->_mp_d, m->_mp_alloc * BYTES_PER_MP_LIMB);
+}
diff --git a/rts/gmp/mpz/clrbit.c b/rts/gmp/mpz/clrbit.c
new file mode 100644
index 0000000000..865d84902f
--- /dev/null
+++ b/rts/gmp/mpz/clrbit.c
@@ -0,0 +1,114 @@
+/* mpz_clrbit -- clear a specified bit.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_clrbit (mpz_ptr d, unsigned long int bit_index)
+#else
+mpz_clrbit (d, bit_index)
+ mpz_ptr d;
+ unsigned long int bit_index;
+#endif
+{
+ mp_size_t dsize = d->_mp_size;
+ mp_ptr dp = d->_mp_d;
+ mp_size_t limb_index;
+
+ limb_index = bit_index / BITS_PER_MP_LIMB;
+ if (dsize >= 0)
+ {
+ if (limb_index < dsize)
+ {
+ dp[limb_index] &= ~((mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB));
+ MPN_NORMALIZE (dp, dsize);
+ d->_mp_size = dsize;
+ }
+ else
+ ;
+ }
+ else
+ {
+ mp_size_t zero_bound;
+
+ /* Simulate two's complement arithmetic, i.e. simulate
+ 1. Set OP = ~(OP - 1) [with infinitely many leading ones].
+ 2. clear the bit.
+ 3. Set OP = ~OP + 1. */
+
+ dsize = -dsize;
+
+ /* No upper bound on this loop, we're sure there's a non-zero limb
+ sooner ot later. */
+ for (zero_bound = 0; ; zero_bound++)
+ if (dp[zero_bound] != 0)
+ break;
+
+ if (limb_index > zero_bound)
+ {
+ if (limb_index < dsize)
+ dp[limb_index] |= (mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB);
+ else
+ {
+ /* Ugh. The bit should be cleared outside of the end of the
+ number. We have to increase the size of the number. */
+ if (d->_mp_alloc < limb_index + 1)
+ {
+ _mpz_realloc (d, limb_index + 1);
+ dp = d->_mp_d;
+ }
+ MPN_ZERO (dp + dsize, limb_index - dsize);
+ dp[limb_index] = (mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB);
+ d->_mp_size = -(limb_index + 1);
+ }
+ }
+ else if (limb_index == zero_bound)
+ {
+ dp[limb_index] = ((dp[limb_index] - 1)
+ | ((mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB))) + 1;
+ if (dp[limb_index] == 0)
+ {
+ mp_size_t i;
+ for (i = limb_index + 1; i < dsize; i++)
+ {
+ dp[i] += 1;
+ if (dp[i] != 0)
+ goto fin;
+ }
+ /* We got carry all way out beyond the end of D. Increase
+ its size (and allocation if necessary). */
+ dsize++;
+ if (d->_mp_alloc < dsize)
+ {
+ _mpz_realloc (d, dsize);
+ dp = d->_mp_d;
+ }
+ dp[i] = 1;
+ d->_mp_size = -dsize;
+ fin:;
+ }
+ }
+ else
+ ;
+ }
+}
diff --git a/rts/gmp/mpz/cmp.c b/rts/gmp/mpz/cmp.c
new file mode 100644
index 0000000000..60628348e5
--- /dev/null
+++ b/rts/gmp/mpz/cmp.c
@@ -0,0 +1,75 @@
+/* mpz_cmp(u,v) -- Compare U, V. Return postive, zero, or negative
+ based on if U > V, U == V, or U < V.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+#include "gmp.h"
+#include "gmp-impl.h"
+
+#ifndef BERKELEY_MP
+int
+#if __STDC__
+mpz_cmp (mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_cmp (u, v)
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#else /* BERKELEY_MP */
+int
+#if __STDC__
+mcmp (mpz_srcptr u, mpz_srcptr v)
+#else
+mcmp (u, v)
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_size_t usize = u->_mp_size;
+ mp_size_t vsize = v->_mp_size;
+ mp_size_t size;
+ mp_srcptr up, vp;
+ int cmp;
+
+ if (usize != vsize)
+ return usize - vsize;
+
+ if (usize == 0)
+ return 0;
+
+ size = ABS (usize);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ cmp = mpn_cmp (up, vp, size);
+
+ if (cmp == 0)
+ return 0;
+
+ if ((cmp < 0) == (usize < 0))
+ return 1;
+ else
+ return -1;
+}
diff --git a/rts/gmp/mpz/cmp_si.c b/rts/gmp/mpz/cmp_si.c
new file mode 100644
index 0000000000..0c2212fbe9
--- /dev/null
+++ b/rts/gmp/mpz/cmp_si.c
@@ -0,0 +1,64 @@
+/* mpz_cmp_si(u,v) -- Compare an integer U with a single-word int V.
+ Return positive, zero, or negative based on if U > V, U == V, or U < V.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1996, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+_mpz_cmp_si (mpz_srcptr u, signed long int v_digit)
+#else
+_mpz_cmp_si (u, v_digit)
+ mpz_srcptr u;
+ signed long int v_digit;
+#endif
+{
+ mp_size_t usize = u->_mp_size;
+ mp_size_t vsize;
+ mp_limb_t u_digit;
+
+ vsize = 0;
+ if (v_digit > 0)
+ vsize = 1;
+ else if (v_digit < 0)
+ {
+ vsize = -1;
+ v_digit = -v_digit;
+ }
+
+ if (usize != vsize)
+ return usize - vsize;
+
+ if (usize == 0)
+ return 0;
+
+ u_digit = u->_mp_d[0];
+
+ if (u_digit == (mp_limb_t) (unsigned long) v_digit)
+ return 0;
+
+ if (u_digit > (mp_limb_t) (unsigned long) v_digit)
+ return usize;
+ else
+ return -usize;
+}
diff --git a/rts/gmp/mpz/cmp_ui.c b/rts/gmp/mpz/cmp_ui.c
new file mode 100644
index 0000000000..fd84f301c1
--- /dev/null
+++ b/rts/gmp/mpz/cmp_ui.c
@@ -0,0 +1,53 @@
+/* mpz_cmp_ui.c -- Compare a mpz_t a with an mp_limb_t b. Return positive,
+ zero, or negative based on if a > b, a == b, or a < b.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+_mpz_cmp_ui (mpz_srcptr u, unsigned long int v_digit)
+#else
+_mpz_cmp_ui (u, v_digit)
+ mpz_srcptr u;
+ unsigned long int v_digit;
+#endif
+{
+ mp_size_t usize = u->_mp_size;
+
+ if (usize == 0)
+ return -(v_digit != 0);
+
+ if (usize == 1)
+ {
+ mp_limb_t u_digit;
+
+ u_digit = u->_mp_d[0];
+ if (u_digit > v_digit)
+ return 1;
+ if (u_digit < v_digit)
+ return -1;
+ return 0;
+ }
+
+ return (usize > 0) ? 1 : -1;
+}
diff --git a/rts/gmp/mpz/cmpabs.c b/rts/gmp/mpz/cmpabs.c
new file mode 100644
index 0000000000..037d7a9145
--- /dev/null
+++ b/rts/gmp/mpz/cmpabs.c
@@ -0,0 +1,57 @@
+/* mpz_cmpabs(u,v) -- Compare U, V. Return postive, zero, or negative
+ based on if U > V, U == V, or U < V.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_cmpabs (mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_cmpabs (u, v)
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+{
+ mp_size_t usize = u->_mp_size;
+ mp_size_t vsize = v->_mp_size;
+ mp_size_t size;
+ mp_srcptr up, vp;
+ int cmp;
+
+ usize = ABS (usize);
+ vsize = ABS (vsize);
+
+ if (usize != vsize)
+ return usize - vsize;
+
+ if (usize == 0)
+ return 0;
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ cmp = mpn_cmp (up, vp, usize);
+
+ return cmp;
+}
diff --git a/rts/gmp/mpz/cmpabs_ui.c b/rts/gmp/mpz/cmpabs_ui.c
new file mode 100644
index 0000000000..db816b5820
--- /dev/null
+++ b/rts/gmp/mpz/cmpabs_ui.c
@@ -0,0 +1,56 @@
+/* mpz_cmpabs_ui.c -- Compare a mpz_t a with an mp_limb_t b. Return positive,
+ zero, or negative based on if a > b, a == b, or a < b.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_cmpabs_ui (mpz_srcptr u, unsigned long int v_digit)
+#else
+mpz_cmpabs_ui (u, v_digit)
+ mpz_srcptr u;
+ unsigned long int v_digit;
+#endif
+{
+ mp_size_t usize = u->_mp_size;
+
+ if (usize == 0)
+ return -(v_digit != 0);
+
+ usize = ABS (usize);
+
+ if (usize == 1)
+ {
+ mp_limb_t u_digit;
+
+ u_digit = u->_mp_d[0];
+ if (u_digit > v_digit)
+ return 1;
+ if (u_digit < v_digit)
+ return -1;
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/rts/gmp/mpz/com.c b/rts/gmp/mpz/com.c
new file mode 100644
index 0000000000..18d6427779
--- /dev/null
+++ b/rts/gmp/mpz/com.c
@@ -0,0 +1,93 @@
+/* mpz_com(mpz_ptr dst, mpz_ptr src) -- Assign the bit-complemented value of
+ SRC to DST.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_com (mpz_ptr dst, mpz_srcptr src)
+#else
+mpz_com (dst, src)
+ mpz_ptr dst;
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size = src->_mp_size;
+ mp_srcptr src_ptr;
+ mp_ptr dst_ptr;
+
+ if (size >= 0)
+ {
+ /* As with infinite precision: one's complement, two's complement.
+ But this can be simplified using the identity -x = ~x + 1.
+ So we're going to compute (~~x) + 1 = x + 1! */
+
+ if (dst->_mp_alloc < size + 1)
+ _mpz_realloc (dst, size + 1);
+
+ src_ptr = src->_mp_d;
+ dst_ptr = dst->_mp_d;
+
+ if (size == 0)
+ {
+ /* Special case, as mpn_add wants the first arg's size >= the
+ second arg's size. */
+ dst_ptr[0] = 1;
+ dst->_mp_size = -1;
+ return;
+ }
+
+ {
+ mp_limb_t cy;
+
+ cy = mpn_add_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
+ if (cy)
+ {
+ dst_ptr[size] = cy;
+ size++;
+ }
+ }
+
+ /* Store a negative size, to indicate ones-extension. */
+ dst->_mp_size = -size;
+ }
+ else
+ {
+ /* As with infinite precision: two's complement, then one's complement.
+ But that can be simplified using the identity -x = ~(x - 1).
+ So we're going to compute ~~(x - 1) = x - 1! */
+ size = -size;
+
+ if (dst->_mp_alloc < size)
+ _mpz_realloc (dst, size);
+
+ src_ptr = src->_mp_d;
+ dst_ptr = dst->_mp_d;
+
+ mpn_sub_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
+ size -= dst_ptr[size - 1] == 0;
+
+ /* Store a positive size, to indicate zero-extension. */
+ dst->_mp_size = size;
+ }
+}
diff --git a/rts/gmp/mpz/divexact.c b/rts/gmp/mpz/divexact.c
new file mode 100644
index 0000000000..c2970454fd
--- /dev/null
+++ b/rts/gmp/mpz/divexact.c
@@ -0,0 +1,125 @@
+/* mpz_divexact -- finds quotient when known that quot * den == num && den != 0.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 2000 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+/* Ken Weber (kweber@mat.ufrgs.br, kweber@mcs.kent.edu)
+
+ Funding for this work has been partially provided by Conselho Nacional
+ de Desenvolvimento Cienti'fico e Tecnolo'gico (CNPq) do Brazil, Grant
+ 301314194-2, and was done while I was a visiting reseacher in the Instituto
+ de Matema'tica at Universidade Federal do Rio Grande do Sul (UFRGS).
+
+ References:
+ T. Jebelean, An algorithm for exact division, Journal of Symbolic
+ Computation, v. 15, 1993, pp. 169-180. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+#if __STDC__
+mpz_divexact (mpz_ptr quot, mpz_srcptr num, mpz_srcptr den)
+#else
+mpz_divexact (quot, num, den)
+ mpz_ptr quot;
+ mpz_srcptr num;
+ mpz_srcptr den;
+#endif
+{
+ mp_ptr qp, tp;
+ mp_size_t qsize, tsize;
+ mp_srcptr np, dp;
+ mp_size_t nsize, dsize;
+ TMP_DECL (marker);
+
+ nsize = ABS (num->_mp_size);
+ dsize = ABS (den->_mp_size);
+
+ qsize = nsize - dsize + 1;
+ if (quot->_mp_alloc < qsize)
+ _mpz_realloc (quot, qsize);
+
+ np = num->_mp_d;
+ dp = den->_mp_d;
+ qp = quot->_mp_d;
+
+ if (nsize == 0)
+ {
+ if (dsize == 0)
+ DIVIDE_BY_ZERO;
+ quot->_mp_size = 0;
+ return;
+ }
+
+ if (dsize <= 1)
+ {
+ if (dsize == 1)
+ {
+ mpn_divmod_1 (qp, np, nsize, dp[0]);
+ qsize -= qp[qsize - 1] == 0;
+ quot->_mp_size = (num->_mp_size ^ den->_mp_size) >= 0 ? qsize : -qsize;
+ return;
+ }
+
+ /* Generate divide-by-zero error since dsize == 0. */
+ DIVIDE_BY_ZERO;
+ }
+
+ TMP_MARK (marker);
+
+ /* QUOT <-- NUM/2^r, T <-- DEN/2^r where = r number of twos in DEN. */
+ while (dp[0] == 0)
+ np += 1, nsize -= 1, dp += 1, dsize -= 1;
+ tsize = MIN (qsize, dsize);
+ if ((dp[0] & 1) != 0)
+ {
+ if (quot == den) /* QUOT and DEN overlap. */
+ {
+ tp = (mp_ptr) TMP_ALLOC (tsize * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, dp, tsize);
+ }
+ else
+ tp = (mp_ptr) dp;
+ if (qp != np)
+ MPN_COPY_INCR (qp, np, qsize);
+ }
+ else
+ {
+ unsigned int r;
+ tp = (mp_ptr) TMP_ALLOC (tsize * BYTES_PER_MP_LIMB);
+ count_trailing_zeros (r, dp[0]);
+ mpn_rshift (tp, dp, tsize, r);
+ if (dsize > tsize)
+ tp[tsize - 1] |= dp[tsize] << (BITS_PER_MP_LIMB - r);
+ mpn_rshift (qp, np, qsize, r);
+ if (nsize > qsize)
+ qp[qsize - 1] |= np[qsize] << (BITS_PER_MP_LIMB - r);
+ }
+
+ /* Now QUOT <-- QUOT/T. */
+ mpn_bdivmod (qp, qp, qsize, tp, tsize, qsize * BITS_PER_MP_LIMB);
+ MPN_NORMALIZE (qp, qsize);
+
+ quot->_mp_size = (num->_mp_size ^ den->_mp_size) >= 0 ? qsize : -qsize;
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/dump.c b/rts/gmp/mpz/dump.c
new file mode 100644
index 0000000000..dc318ac8cf
--- /dev/null
+++ b/rts/gmp/mpz/dump.c
@@ -0,0 +1,44 @@
+/* mpz_dump - Dump an integer to stdout.
+
+ THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE. IT IS NOT SAFE TO
+ CALL THIS FUNCTION DIRECTLY. IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+ FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_dump (mpz_srcptr u)
+#else
+mpz_dump (u)
+ mpz_srcptr u;
+#endif
+{
+ char *str;
+
+ str = mpz_get_str (0, 10, u);
+ printf ("%s\n", str);
+ (*_mp_free_func) (str, 0);/* ??? broken alloc interface, pass what size ??? */
+}
diff --git a/rts/gmp/mpz/fac_ui.c b/rts/gmp/mpz/fac_ui.c
new file mode 100644
index 0000000000..85f40f271c
--- /dev/null
+++ b/rts/gmp/mpz/fac_ui.c
@@ -0,0 +1,157 @@
+/* mpz_fac_ui(result, n) -- Set RESULT to N!.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#ifdef DBG
+#include <stdio.h>
+#endif
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+#if __STDC__
+mpz_fac_ui (mpz_ptr result, unsigned long int n)
+#else
+mpz_fac_ui (result, n)
+ mpz_ptr result;
+ unsigned long int n;
+#endif
+{
+#if SIMPLE_FAC
+
+ /* Be silly. Just multiply the numbers in ascending order. O(n**2). */
+
+ unsigned long int k;
+
+ mpz_set_ui (result, 1L);
+
+ for (k = 2; k <= n; k++)
+ mpz_mul_ui (result, result, k);
+#else
+
+ /* Be smarter. Multiply groups of numbers in ascending order until the
+ product doesn't fit in a limb. Multiply these partial product in a
+ balanced binary tree fashion, to make the operand have as equal sizes
+ as possible. When the operands have about the same size, mpn_mul
+ becomes faster. */
+
+ unsigned long int p, k;
+ mp_limb_t p1, p0;
+
+ /* Stack of partial products, used to make the computation balanced
+ (i.e. make the sizes of the multiplication operands equal). The
+ topmost position of MP_STACK will contain a one-limb partial product,
+ the second topmost will contain a two-limb partial product, and so
+ on. MP_STACK[0] will contain a partial product with 2**t limbs.
+ To compute n! MP_STACK needs to be less than
+ log(n)**2/log(BITS_PER_MP_LIMB), so 30 is surely enough. */
+#define MP_STACK_SIZE 30
+ mpz_t mp_stack[MP_STACK_SIZE];
+
+ /* TOP is an index into MP_STACK, giving the topmost element.
+ TOP_LIMIT_SO_FAR is the largets value it has taken so far. */
+ int top, top_limit_so_far;
+
+ /* Count of the total number of limbs put on MP_STACK so far. This
+ variable plays an essential role in making the compututation balanced.
+ See below. */
+ unsigned int tree_cnt;
+
+ top = top_limit_so_far = -1;
+ tree_cnt = 0;
+ p = 1;
+ for (k = 2; k <= n; k++)
+ {
+ /* Multiply the partial product in P with K. */
+ umul_ppmm (p1, p0, (mp_limb_t) p, (mp_limb_t) k);
+
+ /* Did we get overflow into the high limb, i.e. is the partial
+ product now more than one limb? */
+ if (p1 != 0)
+ {
+ tree_cnt++;
+
+ if (tree_cnt % 2 == 0)
+ {
+ mp_size_t i;
+
+ /* TREE_CNT is even (i.e. we have generated an even number of
+ one-limb partial products), which means that we have a
+ single-limb product on the top of MP_STACK. */
+
+ mpz_mul_ui (mp_stack[top], mp_stack[top], p);
+
+ /* If TREE_CNT is divisable by 4, 8,..., we have two
+ similar-sized partial products with 2, 4,... limbs at
+ the topmost two positions of MP_STACK. Multiply them
+ to form a new partial product with 4, 8,... limbs. */
+ for (i = 4; (tree_cnt & (i - 1)) == 0; i <<= 1)
+ {
+ mpz_mul (mp_stack[top - 1],
+ mp_stack[top], mp_stack[top - 1]);
+ top--;
+ }
+ }
+ else
+ {
+ /* Put the single-limb partial product in P on the stack.
+ (The next time we get a single-limb product, we will
+ multiply the two together.) */
+ top++;
+ if (top > top_limit_so_far)
+ {
+ if (top > MP_STACK_SIZE)
+ abort();
+ /* The stack is now bigger than ever, initialize the top
+ element. */
+ mpz_init_set_ui (mp_stack[top], p);
+ top_limit_so_far++;
+ }
+ else
+ mpz_set_ui (mp_stack[top], p);
+ }
+
+ /* We ignored the last result from umul_ppmm. Put K in P as the
+ first component of the next single-limb partial product. */
+ p = k;
+ }
+ else
+ /* We didn't get overflow in umul_ppmm. Put p0 in P and try
+ with one more value of K. */
+ p = p0; /* bogus if long != mp_limb_t */
+ }
+
+ /* We have partial products in mp_stack[0..top], in descending order.
+ We also have a small partial product in p.
+ Their product is the final result. */
+ if (top < 0)
+ mpz_set_ui (result, p);
+ else
+ mpz_mul_ui (result, mp_stack[top--], p);
+ while (top >= 0)
+ mpz_mul (result, result, mp_stack[top--]);
+
+ /* Free the storage allocated for MP_STACK. */
+ for (top = top_limit_so_far; top >= 0; top--)
+ mpz_clear (mp_stack[top]);
+#endif
+}
diff --git a/rts/gmp/mpz/fdiv_q.c b/rts/gmp/mpz/fdiv_q.c
new file mode 100644
index 0000000000..9d75ca33d2
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_q.c
@@ -0,0 +1,51 @@
+/* mpz_fdiv_q -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_fdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_fdiv_q (quot, dividend, divisor)
+ mpz_ptr quot;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t dividend_size = dividend->_mp_size;
+ mp_size_t divisor_size = divisor->_mp_size;
+ mpz_t rem;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ MPZ_TMP_INIT (rem, ABS (divisor_size));
+
+ mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+ if ((divisor_size ^ dividend_size) < 0 && rem->_mp_size != 0)
+ mpz_sub_ui (quot, quot, 1L);
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/fdiv_q_2exp.c b/rts/gmp/mpz/fdiv_q_2exp.c
new file mode 100644
index 0000000000..8e02180ecc
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_q_2exp.c
@@ -0,0 +1,104 @@
+/* mpz_fdiv_q_2exp -- Divide an integer by 2**CNT. Round the quotient
+ towards -infinity.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1998, 1999 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_fdiv_q_2exp (mpz_ptr w, mpz_srcptr u, unsigned long int cnt)
+#else
+mpz_fdiv_q_2exp (w, u, cnt)
+ mpz_ptr w;
+ mpz_srcptr u;
+ unsigned long int cnt;
+#endif
+{
+ mp_size_t usize = u->_mp_size;
+ mp_size_t wsize;
+ mp_size_t abs_usize = ABS (usize);
+ mp_size_t limb_cnt;
+ mp_ptr wp;
+ mp_limb_t round = 0;
+
+ limb_cnt = cnt / BITS_PER_MP_LIMB;
+ wsize = abs_usize - limb_cnt;
+ if (wsize <= 0)
+ {
+ wp = w->_mp_d;
+ wsize = 0;
+ /* Set ROUND since we know we skip some non-zero words in this case.
+ Well, if U is zero, we don't, but then this will be taken care of
+ below, since rounding only really takes place for negative U. */
+ round = 1;
+ wp[0] = 1;
+ w->_mp_size = -(usize < 0);
+ return;
+ }
+ else
+ {
+ mp_size_t i;
+ mp_ptr up;
+
+ /* Make sure there is enough space. We make an extra limb
+ here to account for possible rounding at the end. */
+ if (w->_mp_alloc < wsize + 1)
+ _mpz_realloc (w, wsize + 1);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ /* Set ROUND if we are about skip some non-zero limbs. */
+ for (i = 0; i < limb_cnt && round == 0; i++)
+ round = up[i];
+
+ cnt %= BITS_PER_MP_LIMB;
+ if (cnt != 0)
+ {
+ round |= mpn_rshift (wp, up + limb_cnt, wsize, cnt);
+ wsize -= wp[wsize - 1] == 0;
+ }
+ else
+ {
+ MPN_COPY_INCR (wp, up + limb_cnt, wsize);
+ }
+ }
+
+ if (usize < 0 && round != 0)
+ {
+ mp_limb_t cy;
+ if (wsize != 0)
+ {
+ cy = mpn_add_1 (wp, wp, wsize, (mp_limb_t) 1);
+ wp[wsize] = cy;
+ wsize += cy;
+ }
+ else
+ {
+ /* We shifted something negative to zero. The result is -1. */
+ wp[0] = 1;
+ wsize = 1;
+ }
+ }
+ w->_mp_size = usize >= 0 ? wsize : -wsize;
+}
diff --git a/rts/gmp/mpz/fdiv_q_ui.c b/rts/gmp/mpz/fdiv_q_ui.c
new file mode 100644
index 0000000000..55d2498693
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_q_ui.c
@@ -0,0 +1,65 @@
+/* mpz_fdiv_q_ui -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_fdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_fdiv_q_ui (quot, dividend, divisor)
+ mpz_ptr quot;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_ptr quot_ptr;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ if (quot->_mp_alloc < size)
+ _mpz_realloc (quot, size);
+
+ quot_ptr = quot->_mp_d;
+
+ remainder_limb = mpn_divmod_1 (quot_ptr, dividend->_mp_d, size,
+ (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size < 0)
+ {
+ mpn_incr_u (quot_ptr, (mp_limb_t) 1);
+ remainder_limb = divisor - remainder_limb;
+ }
+
+ size -= size != 0 && quot_ptr[size - 1] == 0;
+ quot->_mp_size = dividend_size >= 0 ? size : -size;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/fdiv_qr.c b/rts/gmp/mpz/fdiv_qr.c
new file mode 100644
index 0000000000..06ce50607b
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_qr.c
@@ -0,0 +1,64 @@
+/* mpz_fdiv_qr -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_fdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_fdiv_qr (quot, rem, dividend, divisor)
+ mpz_ptr quot;
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t divisor_size = divisor->_mp_size;
+ mp_size_t xsize;
+ mpz_t temp_divisor; /* N.B.: lives until function returns! */
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* We need the original value of the divisor after the quotient and
+ remainder have been preliminary calculated. We have to copy it to
+ temporary space if it's the same variable as either QUOT or REM. */
+ if (quot == divisor || rem == divisor)
+ {
+ MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+ mpz_set (temp_divisor, divisor);
+ divisor = temp_divisor;
+ }
+
+ xsize = dividend->_mp_size ^ divisor_size;;
+ mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+ if (xsize < 0 && rem->_mp_size != 0)
+ {
+ mpz_sub_ui (quot, quot, 1L);
+ mpz_add (rem, rem, divisor);
+ }
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/fdiv_qr_ui.c b/rts/gmp/mpz/fdiv_qr_ui.c
new file mode 100644
index 0000000000..600c0dacfc
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_qr_ui.c
@@ -0,0 +1,69 @@
+/* mpz_fdiv_qr_ui -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_fdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_fdiv_qr_ui (quot, rem, dividend, divisor)
+ mpz_ptr quot;
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_ptr quot_ptr;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ if (quot->_mp_alloc < size)
+ _mpz_realloc (quot, size);
+
+ quot_ptr = quot->_mp_d;
+
+ remainder_limb = mpn_divmod_1 (quot_ptr, dividend->_mp_d, size,
+ (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size < 0)
+ {
+ mpn_incr_u (quot_ptr, (mp_limb_t) 1);
+ remainder_limb = divisor - remainder_limb;
+ }
+
+ size -= size != 0 && quot_ptr[size - 1] == 0;
+ quot->_mp_size = dividend_size >= 0 ? size : -size;
+
+ rem->_mp_d[0] = remainder_limb;
+ rem->_mp_size = remainder_limb != 0;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/fdiv_r.c b/rts/gmp/mpz/fdiv_r.c
new file mode 100644
index 0000000000..a3652838d2
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_r.c
@@ -0,0 +1,58 @@
+/* mpz_fdiv_r -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_fdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_fdiv_r (rem, dividend, divisor)
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t divisor_size = divisor->_mp_size;
+ mpz_t temp_divisor; /* N.B.: lives until function returns! */
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* We need the original value of the divisor after the remainder has been
+ preliminary calculated. We have to copy it to temporary space if it's
+ the same variable as REM. */
+ if (rem == divisor)
+ {
+ MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+ mpz_set (temp_divisor, divisor);
+ divisor = temp_divisor;
+ }
+
+ mpz_tdiv_r (rem, dividend, divisor);
+
+ if ((divisor_size ^ dividend->_mp_size) < 0 && rem->_mp_size != 0)
+ mpz_add (rem, rem, divisor);
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/fdiv_r_2exp.c b/rts/gmp/mpz/fdiv_r_2exp.c
new file mode 100644
index 0000000000..081ce19203
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_r_2exp.c
@@ -0,0 +1,156 @@
+/* mpz_fdiv_r_2exp -- Divide a integer by 2**CNT and produce a remainder.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1998, 1999, 2000 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_fdiv_r_2exp (mpz_ptr res, mpz_srcptr in, unsigned long int cnt)
+#else
+mpz_fdiv_r_2exp (res, in, cnt)
+ mpz_ptr res;
+ mpz_srcptr in;
+ unsigned long int cnt;
+#endif
+{
+ mp_size_t in_size = ABS (in->_mp_size);
+ mp_size_t res_size;
+ mp_size_t limb_cnt = cnt / BITS_PER_MP_LIMB;
+ mp_srcptr in_ptr = in->_mp_d;
+
+ if (in_size > limb_cnt)
+ {
+ /* The input operand is (probably) greater than 2**CNT. */
+ mp_limb_t x;
+
+ x = in_ptr[limb_cnt] & (((mp_limb_t) 1 << cnt % BITS_PER_MP_LIMB) - 1);
+ if (x != 0)
+ {
+ res_size = limb_cnt + 1;
+ if (res->_mp_alloc < res_size)
+ _mpz_realloc (res, res_size);
+
+ res->_mp_d[limb_cnt] = x;
+ }
+ else
+ {
+ res_size = limb_cnt;
+ MPN_NORMALIZE (in_ptr, res_size);
+
+ if (res->_mp_alloc < res_size)
+ _mpz_realloc (res, res_size);
+
+ limb_cnt = res_size;
+ }
+ }
+ else
+ {
+ /* The input operand is smaller than 2**CNT. We perform a no-op,
+ apart from that we might need to copy IN to RES, and may need
+ to round the result. */
+ res_size = in_size;
+ if (res->_mp_alloc < res_size)
+ _mpz_realloc (res, res_size);
+
+ limb_cnt = res_size;
+ }
+
+ if (res != in)
+ MPN_COPY (res->_mp_d, in->_mp_d, limb_cnt);
+ in_size = in->_mp_size;
+ res->_mp_size = res_size;
+ if (in_size < 0 && res_size != 0)
+ {
+ /* Result should be 2^CNT - RES */
+ mpz_t tmp;
+ TMP_DECL (marker);
+ TMP_MARK (marker);
+ MPZ_TMP_INIT (tmp, cnt/BITS_PER_MP_LIMB + 2);
+ mpz_set_ui (tmp, 1L);
+ mpz_mul_2exp (tmp, tmp, cnt);
+ mpz_sub (res, tmp, res);
+ TMP_FREE (marker);
+ }
+}
+
+/* This is an alternative ending of the above function using just low-level
+ functions. Tested, but perhaps excessive? */
+#if 0
+ if (in->_mp_size < 0 && res_size != 0)
+ {
+ /* Result should be 2^CNT - RES */
+
+ mp_ptr rp;
+
+ limb_cnt = cnt / BITS_PER_MP_LIMB;
+
+ if (res->_mp_alloc <= limb_cnt)
+ _mpz_realloc (res, limb_cnt + 1);
+ rp = PTR(res);
+ if (res_size > limb_cnt)
+ {
+ mpn_nz_neg (rp, rp, res_size);
+ rp[limb_cnt] &= ~(~(mp_limb_t) 0 << cnt % BITS_PER_MP_LIMB);
+ MPN_NORMALIZE_NOT_ZERO (rp, res_size);
+ }
+ else
+ {
+ mp_size_t i;
+ mpn_nz_neg (rp, rp, res_size);
+ for (i = res_size; i < limb_cnt; i++)
+ rp[i] = ~ (mp_limb_t) 0;
+ res_size = limb_cnt;
+ if (cnt % BITS_PER_MP_LIMB != 0)
+ {
+ rp[res_size] = ((mp_limb_t) 1 << (cnt % BITS_PER_MP_LIMB)) - 1;
+ res_size++;
+ }
+ else
+ MPN_NORMALIZE_NOT_ZERO (rp, res_size);
+ }
+ }
+ SIZ(res) = res_size;
+}
+
+static void
+mpn_nz_neg (rp, sp, n)
+ mp_ptr rp, sp;
+ mp_size_t n;
+{
+ mp_size_t i;
+ mp_limb_t x;
+
+ x = sp[0];
+ rp[0] = -x;
+ for (i = 1; x == 0; i++)
+ {
+ x = sp[i];
+ rp[i] = -x;
+ }
+
+ for (; i < n; i++)
+ {
+ rp[i] = ~sp[i];
+ }
+}
+#endif
diff --git a/rts/gmp/mpz/fdiv_r_ui.c b/rts/gmp/mpz/fdiv_r_ui.c
new file mode 100644
index 0000000000..dd5c743d27
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_r_ui.c
@@ -0,0 +1,55 @@
+/* mpz_fdiv_r_ui -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_fdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_fdiv_r_ui (rem, dividend, divisor)
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ remainder_limb = mpn_mod_1 (dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size < 0)
+ remainder_limb = divisor - remainder_limb;
+
+ rem->_mp_d[0] = remainder_limb;
+ rem->_mp_size = remainder_limb != 0;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/fdiv_ui.c b/rts/gmp/mpz/fdiv_ui.c
new file mode 100644
index 0000000000..f937b5f6d0
--- /dev/null
+++ b/rts/gmp/mpz/fdiv_ui.c
@@ -0,0 +1,48 @@
+/* mpz_fdiv_ui -- Division rounding the quotient towards -infinity.
+ The remainder gets the same sign as the denominator.
+
+Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_fdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_fdiv_ui (dividend, divisor)
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_limb_t remainder_limb;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ remainder_limb = mpn_mod_1 (dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ if (remainder_limb != 0 && dividend_size < 0)
+ remainder_limb = divisor - remainder_limb;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/fib_ui.c b/rts/gmp/mpz/fib_ui.c
new file mode 100644
index 0000000000..4bebb80d94
--- /dev/null
+++ b/rts/gmp/mpz/fib_ui.c
@@ -0,0 +1,165 @@
+/* mpz_fib_ui(result, n) -- Set RESULT to the Nth Fibonacci number.
+
+Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+/* This is fast, but could be made somewhat faster and neater.
+ The timing is somewhat fluctuating for even/odd sizes because
+ of the extra hair used to save variables and operations. Here
+ are a few things one might want to address:
+ 1. Avoid using 4 intermediate variables in mpz_fib_bigcase.
+ 2. Call mpn functions directly. Straightforward for these functions.
+ 3. Merge the three functions into one.
+
+Said by Kevin:
+ Consider using the Lucas numbers L[n] as an auxiliary sequence, making
+ it possible to do the "doubling" operation in mpz_fib_bigcase with two
+ squares rather than two multiplies. The formulas are a little more
+ complicated, something like the following (untested).
+
+ F[2n] = ((F[n]+L[n])^2 - 6*F[n]^2 - 4*(-1)^n) / 2
+ L[2n] = 5*F[n]^2 + 2*(-1)^n
+
+ F[2n+1] = (F[2n] + L[2n]) / 2
+ L[2n+1] = (5*F[2n] + L[2n]) / 2
+
+ The Lucas number that comes for free here could even be returned.
+
+ Maybe there's formulas with two squares using just F[n], but I don't
+ know of any.
+*/
+
+/* Determine the needed storage for Fib(n). */
+#define FIB_SIZE(n) (((mp_size_t) ((n)*0.695)) / BITS_PER_MP_LIMB + 2)
+
+static void mpz_fib_bigcase _PROTO ((mpz_t, mpz_t, unsigned long int));
+static void mpz_fib_basecase _PROTO ((mpz_t, mpz_t, unsigned long int));
+
+
+#ifndef FIB_THRESHOLD
+#define FIB_THRESHOLD 60
+#endif
+
+void
+#if __STDC__
+mpz_fib_ui (mpz_t r, unsigned long int n)
+#else
+mpz_fib_ui (r, n)
+ mpz_t r;
+ unsigned long int n;
+#endif
+{
+ if (n == 0)
+ mpz_set_ui (r, 0);
+ else
+ {
+ mpz_t t1;
+ mpz_init (t1);
+ if (n < FIB_THRESHOLD)
+ mpz_fib_basecase (t1, r, n);
+ else
+ mpz_fib_bigcase (t1, r, n);
+ mpz_clear (t1);
+ }
+}
+
+static void
+#if __STDC__
+mpz_fib_basecase (mpz_t t1, mpz_t t2, unsigned long int n)
+#else
+mpz_fib_basecase (t1, t2, n)
+ mpz_t t1;
+ mpz_t t2;
+ unsigned long int n;
+#endif
+{
+ unsigned long int m, i;
+
+ mpz_set_ui (t1, 0);
+ mpz_set_ui (t2, 1);
+ m = n/2;
+ for (i = 0; i < m; i++)
+ {
+ mpz_add (t1, t1, t2);
+ mpz_add (t2, t1, t2);
+ }
+ if ((n & 1) == 0)
+ {
+ mpz_sub (t1, t2, t1);
+ mpz_sub (t2, t2, t1); /* trick: recover t1 value just overwritten */
+ }
+}
+
+static void
+#if __STDC__
+mpz_fib_bigcase (mpz_t t1, mpz_t t2, unsigned long int n)
+#else
+mpz_fib_bigcase (t1, t2, n)
+ mpz_t t1;
+ mpz_t t2;
+ unsigned long int n;
+#endif
+{
+ unsigned long int n2;
+ int ni, i;
+ mpz_t x1, x2, u1, u2;
+
+ ni = 0;
+ for (n2 = n; n2 >= FIB_THRESHOLD; n2 /= 2)
+ ni++;
+
+ mpz_fib_basecase (t1, t2, n2);
+
+ mpz_init (x1);
+ mpz_init (x2);
+ mpz_init (u1);
+ mpz_init (u2);
+
+ for (i = ni - 1; i >= 0; i--)
+ {
+ mpz_mul_2exp (x1, t1, 1);
+ mpz_mul_2exp (x2, t2, 1);
+
+ mpz_add (x1, x1, t2);
+ mpz_sub (x2, x2, t1);
+
+ mpz_mul (u1, t2, x1);
+ mpz_mul (u2, t1, x2);
+
+ if (((n >> i) & 1) == 0)
+ {
+ mpz_sub (t1, u1, u2);
+ mpz_set (t2, u1);
+ }
+ else
+ {
+ mpz_set (t1, u1);
+ mpz_mul_2exp (t2, u1, 1);
+ mpz_sub (t2, t2, u2);
+ }
+ }
+
+ mpz_clear (x1);
+ mpz_clear (x2);
+ mpz_clear (u1);
+ mpz_clear (u2);
+}
diff --git a/rts/gmp/mpz/fits_sint_p.c b/rts/gmp/mpz/fits_sint_p.c
new file mode 100644
index 0000000000..82e32a24d5
--- /dev/null
+++ b/rts/gmp/mpz/fits_sint_p.c
@@ -0,0 +1,50 @@
+/* int mpz_fits_X_p (mpz_t src) -- Return whether src fits the C type X.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_fits_sint_p (mpz_srcptr src)
+#else
+mpz_fits_sint_p (src)
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t mpl;
+
+ mpl = PTR(src)[0];
+ size = SIZ(src);
+ if (size > 0)
+ {
+ if (size > 1)
+ return 0;
+ return mpl < ~((~(unsigned int) 0) >> 1);
+ }
+ else
+ {
+ if (size < -1)
+ return 0;
+ return mpl <= ~((~(unsigned int) 0) >> 1);
+ }
+}
diff --git a/rts/gmp/mpz/fits_slong_p.c b/rts/gmp/mpz/fits_slong_p.c
new file mode 100644
index 0000000000..e0669b5aaa
--- /dev/null
+++ b/rts/gmp/mpz/fits_slong_p.c
@@ -0,0 +1,50 @@
+/* int mpz_fits_X_p (mpz_t src) -- Return whether src fits the C type X.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_fits_slong_p (mpz_srcptr src)
+#else
+mpz_fits_slong_p (src)
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t mpl;
+
+ mpl = PTR(src)[0];
+ size = SIZ(src);
+ if (size > 0)
+ {
+ if (size > 1)
+ return 0;
+ return mpl < ~((~(unsigned long int) 0) >> 1);
+ }
+ else
+ {
+ if (size < -1)
+ return 0;
+ return mpl <= ~((~(unsigned long int) 0) >> 1);
+ }
+}
diff --git a/rts/gmp/mpz/fits_sshort_p.c b/rts/gmp/mpz/fits_sshort_p.c
new file mode 100644
index 0000000000..5b8e31afae
--- /dev/null
+++ b/rts/gmp/mpz/fits_sshort_p.c
@@ -0,0 +1,50 @@
+/* int mpz_fits_X_p (mpz_t src) -- Return whether src fits the C type X.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_fits_sshort_p (mpz_srcptr src)
+#else
+mpz_fits_sshort_p (src)
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t mpl;
+
+ mpl = PTR(src)[0];
+ size = SIZ(src);
+ if (size > 0)
+ {
+ if (size > 1)
+ return 0;
+ return mpl <= (((unsigned short int) ~(unsigned int) 0) >> 1);
+ }
+ else
+ {
+ if (size < -1)
+ return 0;
+ return mpl <= (((unsigned short int) ~(unsigned int) 0) >> 1) + 1;
+ }
+}
diff --git a/rts/gmp/mpz/fits_uint_p.c b/rts/gmp/mpz/fits_uint_p.c
new file mode 100644
index 0000000000..72f62fa723
--- /dev/null
+++ b/rts/gmp/mpz/fits_uint_p.c
@@ -0,0 +1,41 @@
+/* int mpz_fits_X_p (mpz_t src) -- Return whether src fits the C type X.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_fits_uint_p (mpz_srcptr src)
+#else
+mpz_fits_uint_p (src)
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t mpl;
+
+ mpl = PTR(src)[0];
+ size = SIZ(src);
+ if (size < 0 || size > 1)
+ return 0;
+ return mpl <= (~(unsigned int) 0);
+}
diff --git a/rts/gmp/mpz/fits_ulong_p.c b/rts/gmp/mpz/fits_ulong_p.c
new file mode 100644
index 0000000000..92eb42e86e
--- /dev/null
+++ b/rts/gmp/mpz/fits_ulong_p.c
@@ -0,0 +1,41 @@
+/* int mpz_fits_X_p (mpz_t src) -- Return whether src fits the C type X.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_fits_ulong_p (mpz_srcptr src)
+#else
+mpz_fits_ulong_p (src)
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t mpl;
+
+ mpl = PTR(src)[0];
+ size = SIZ(src);
+ if (size < 0 || size > 1)
+ return 0;
+ return mpl <= (~(unsigned long int) 0);
+}
diff --git a/rts/gmp/mpz/fits_ushort_p.c b/rts/gmp/mpz/fits_ushort_p.c
new file mode 100644
index 0000000000..bde0edae6e
--- /dev/null
+++ b/rts/gmp/mpz/fits_ushort_p.c
@@ -0,0 +1,41 @@
+/* int mpz_fits_X_p (mpz_t src) -- Return whether src fits the C type X.
+
+Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_fits_ushort_p (mpz_srcptr src)
+#else
+mpz_fits_ushort_p (src)
+ mpz_srcptr src;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t mpl;
+
+ mpl = PTR(src)[0];
+ size = SIZ(src);
+ if (size < 0 || size > 1)
+ return 0;
+ return mpl <= ((unsigned short int) ~(unsigned int) 0);
+}
diff --git a/rts/gmp/mpz/gcd.c b/rts/gmp/mpz/gcd.c
new file mode 100644
index 0000000000..0d950dd609
--- /dev/null
+++ b/rts/gmp/mpz/gcd.c
@@ -0,0 +1,180 @@
+/* mpz/gcd.c: Calculate the greatest common divisor of two integers.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_gcd (mpz_ptr g, mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_gcd (g, u, v)
+ mpz_ptr g;
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+gcd (mpz_srcptr u, mpz_srcptr v, mpz_ptr g)
+#else
+gcd (u, v, g)
+ mpz_ptr g;
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#endif /* BERKELEY_MP */
+
+{
+ unsigned long int g_zero_bits, u_zero_bits, v_zero_bits;
+ mp_size_t g_zero_limbs, u_zero_limbs, v_zero_limbs;
+ mp_ptr tp;
+ mp_ptr up = u->_mp_d;
+ mp_size_t usize = ABS (u->_mp_size);
+ mp_ptr vp = v->_mp_d;
+ mp_size_t vsize = ABS (v->_mp_size);
+ mp_size_t gsize;
+ TMP_DECL (marker);
+
+ /* GCD(0, V) == V. */
+ if (usize == 0)
+ {
+ g->_mp_size = vsize;
+ if (g == v)
+ return;
+ if (g->_mp_alloc < vsize)
+ _mpz_realloc (g, vsize);
+ MPN_COPY (g->_mp_d, vp, vsize);
+ return;
+ }
+
+ /* GCD(U, 0) == U. */
+ if (vsize == 0)
+ {
+ g->_mp_size = usize;
+ if (g == u)
+ return;
+ if (g->_mp_alloc < usize)
+ _mpz_realloc (g, usize);
+ MPN_COPY (g->_mp_d, up, usize);
+ return;
+ }
+
+ if (usize == 1)
+ {
+ g->_mp_size = 1;
+ g->_mp_d[0] = mpn_gcd_1 (vp, vsize, up[0]);
+ return;
+ }
+
+ if (vsize == 1)
+ {
+ g->_mp_size = 1;
+ g->_mp_d[0] = mpn_gcd_1 (up, usize, vp[0]);
+ return;
+ }
+
+ TMP_MARK (marker);
+
+ /* Eliminate low zero bits from U and V and move to temporary storage. */
+ while (*up == 0)
+ up++;
+ u_zero_limbs = up - u->_mp_d;
+ usize -= u_zero_limbs;
+ count_trailing_zeros (u_zero_bits, *up);
+ tp = up;
+ up = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB);
+ if (u_zero_bits != 0)
+ {
+ mpn_rshift (up, tp, usize, u_zero_bits);
+ usize -= up[usize - 1] == 0;
+ }
+ else
+ MPN_COPY (up, tp, usize);
+
+ while (*vp == 0)
+ vp++;
+ v_zero_limbs = vp - v->_mp_d;
+ vsize -= v_zero_limbs;
+ count_trailing_zeros (v_zero_bits, *vp);
+ tp = vp;
+ vp = (mp_ptr) TMP_ALLOC (vsize * BYTES_PER_MP_LIMB);
+ if (v_zero_bits != 0)
+ {
+ mpn_rshift (vp, tp, vsize, v_zero_bits);
+ vsize -= vp[vsize - 1] == 0;
+ }
+ else
+ MPN_COPY (vp, tp, vsize);
+
+ if (u_zero_limbs > v_zero_limbs)
+ {
+ g_zero_limbs = v_zero_limbs;
+ g_zero_bits = v_zero_bits;
+ }
+ else if (u_zero_limbs < v_zero_limbs)
+ {
+ g_zero_limbs = u_zero_limbs;
+ g_zero_bits = u_zero_bits;
+ }
+ else /* Equal. */
+ {
+ g_zero_limbs = u_zero_limbs;
+ g_zero_bits = MIN (u_zero_bits, v_zero_bits);
+ }
+
+ /* Call mpn_gcd. The 2nd argument must not have more bits than the 1st. */
+ vsize = (usize < vsize || (usize == vsize && up[usize-1] < vp[vsize-1]))
+ ? mpn_gcd (vp, vp, vsize, up, usize)
+ : mpn_gcd (vp, up, usize, vp, vsize);
+
+ /* Here G <-- V << (g_zero_limbs*BITS_PER_MP_LIMB + g_zero_bits). */
+ gsize = vsize + g_zero_limbs;
+ if (g_zero_bits != 0)
+ {
+ mp_limb_t cy_limb;
+ gsize += (vp[vsize - 1] >> (BITS_PER_MP_LIMB - g_zero_bits)) != 0;
+ if (g->_mp_alloc < gsize)
+ _mpz_realloc (g, gsize);
+ MPN_ZERO (g->_mp_d, g_zero_limbs);
+
+ tp = g->_mp_d + g_zero_limbs;
+ cy_limb = mpn_lshift (tp, vp, vsize, g_zero_bits);
+ if (cy_limb != 0)
+ tp[vsize] = cy_limb;
+ }
+ else
+ {
+ if (g->_mp_alloc < gsize)
+ _mpz_realloc (g, gsize);
+ MPN_ZERO (g->_mp_d, g_zero_limbs);
+ MPN_COPY (g->_mp_d + g_zero_limbs, vp, vsize);
+ }
+
+ g->_mp_size = gsize;
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/gcd_ui.c b/rts/gmp/mpz/gcd_ui.c
new file mode 100644
index 0000000000..f3bec58829
--- /dev/null
+++ b/rts/gmp/mpz/gcd_ui.c
@@ -0,0 +1,65 @@
+/* mpz_gcd_ui -- Calculate the greatest common divisior of two integers.
+
+Copyright (C) 1994, 1996, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_gcd_ui (mpz_ptr w, mpz_srcptr u, unsigned long int v)
+#else
+mpz_gcd_ui (w, u, v)
+ mpz_ptr w;
+ mpz_srcptr u;
+ unsigned long int v;
+#endif
+{
+ mp_size_t size;
+ mp_limb_t res;
+
+ size = ABS (u->_mp_size);
+
+ if (size == 0)
+ res = v;
+ else if (v == 0)
+ {
+ if (w != NULL && u != w)
+ {
+ if (w->_mp_alloc < size)
+ _mpz_realloc (w, size);
+
+ MPN_COPY (w->_mp_d, u->_mp_d, size);
+ }
+ w->_mp_size = size;
+ /* We can't return any useful result for gcd(big,0). */
+ return size > 1 ? 0 : w->_mp_d[0];
+ }
+ else
+ res = mpn_gcd_1 (u->_mp_d, size, (mp_limb_t) v);
+
+ if (w != NULL)
+ {
+ w->_mp_d[0] = res;
+ w->_mp_size = 1;
+ }
+ return res;
+}
diff --git a/rts/gmp/mpz/gcdext.c b/rts/gmp/mpz/gcdext.c
new file mode 100644
index 0000000000..3ba04c84ff
--- /dev/null
+++ b/rts/gmp/mpz/gcdext.c
@@ -0,0 +1,137 @@
+/* mpz_gcdext(g, s, t, a, b) -- Set G to gcd(a, b), and S and T such that
+ g = as + bt.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 2000 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b)
+#else
+mpz_gcdext (g, s, t, a, b)
+ mpz_ptr g;
+ mpz_ptr s;
+ mpz_ptr t;
+ mpz_srcptr a;
+ mpz_srcptr b;
+#endif
+{
+ mp_size_t asize, bsize, usize, vsize;
+ mp_srcptr ap, bp;
+ mp_ptr up, vp;
+ mp_size_t gsize, ssize, tmp_ssize;
+ mp_ptr gp, sp, tmp_gp, tmp_sp;
+ mpz_srcptr u, v;
+ mpz_ptr ss, tt;
+ __mpz_struct stmp, gtmp;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* mpn_gcdext requires that U >= V. Therefore, we often have to swap U and
+ V. This in turn leads to a lot of complications. The computed cofactor
+ will be the wrong one, so we have to fix that up at the end. */
+
+ asize = ABS (SIZ (a));
+ bsize = ABS (SIZ (b));
+ ap = PTR (a);
+ bp = PTR (b);
+ if (asize > bsize || (asize == bsize && mpn_cmp (ap, bp, asize) > 0))
+ {
+ usize = asize;
+ vsize = bsize;
+ up = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
+ vp = (mp_ptr) TMP_ALLOC ((vsize + 1) * BYTES_PER_MP_LIMB);
+ MPN_COPY (up, ap, usize);
+ MPN_COPY (vp, bp, vsize);
+ u = a;
+ v = b;
+ ss = s;
+ tt = t;
+ }
+ else
+ {
+ usize = bsize;
+ vsize = asize;
+ up = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
+ vp = (mp_ptr) TMP_ALLOC ((vsize + 1) * BYTES_PER_MP_LIMB);
+ MPN_COPY (up, bp, usize);
+ MPN_COPY (vp, ap, vsize);
+ u = b;
+ v = a;
+ ss = t;
+ tt = s;
+ }
+
+ tmp_gp = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
+ tmp_sp = (mp_ptr) TMP_ALLOC ((usize + 1) * BYTES_PER_MP_LIMB);
+
+ if (vsize == 0)
+ {
+ tmp_sp[0] = 1;
+ tmp_ssize = 1;
+ MPN_COPY (tmp_gp, up, usize);
+ gsize = usize;
+ }
+ else
+ gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, up, usize, vp, vsize);
+ ssize = ABS (tmp_ssize);
+
+ PTR (&gtmp) = tmp_gp;
+ SIZ (&gtmp) = gsize;
+
+ PTR (&stmp) = tmp_sp;
+ SIZ (&stmp) = (tmp_ssize ^ SIZ (u)) >= 0 ? ssize : -ssize;
+
+ if (tt != NULL)
+ {
+ if (SIZ (v) == 0)
+ SIZ (tt) = 0;
+ else
+ {
+ mpz_t x;
+ MPZ_TMP_INIT (x, ssize + usize + 1);
+ mpz_mul (x, &stmp, u);
+ mpz_sub (x, &gtmp, x);
+ mpz_tdiv_q (tt, x, v);
+ }
+ }
+
+ if (ss != NULL)
+ {
+ if (ALLOC (ss) < ssize)
+ _mpz_realloc (ss, ssize);
+ sp = PTR (ss);
+ MPN_COPY (sp, tmp_sp, ssize);
+ SIZ (ss) = SIZ (&stmp);
+ }
+
+ if (ALLOC (g) < gsize)
+ _mpz_realloc (g, gsize);
+ gp = PTR (g);
+ MPN_COPY (gp, tmp_gp, gsize);
+ SIZ (g) = gsize;
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/get_d.c b/rts/gmp/mpz/get_d.c
new file mode 100644
index 0000000000..6a7c5856bb
--- /dev/null
+++ b/rts/gmp/mpz/get_d.c
@@ -0,0 +1,128 @@
+/* double mpz_get_d (mpz_t src) -- Return the double approximation to SRC.
+
+Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+static int
+#if __STDC__
+mpn_zero_p (mp_ptr p, mp_size_t n)
+#else
+mpn_zero_p (p, n)
+ mp_ptr p;
+ mp_size_t n;
+#endif
+{
+ mp_size_t i;
+
+ for (i = 0; i < n; i++)
+ {
+ if (p[i] != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+double
+#if __STDC__
+mpz_get_d (mpz_srcptr src)
+#else
+mpz_get_d (src)
+ mpz_srcptr src;
+#endif
+{
+ double res;
+ mp_size_t size;
+ int negative;
+ mp_ptr qp;
+ mp_limb_t hz, lz;
+ int cnt;
+
+ size = SIZ(src);
+ if (size == 0)
+ return 0.0;
+
+ negative = size < 0;
+ size = ABS (size);
+ qp = PTR(src);
+
+ if (size == 1)
+ {
+ res = qp[size - 1];
+ }
+ else if (size == 2)
+ {
+ res = MP_BASE_AS_DOUBLE * qp[size - 1] + qp[size - 2];
+ }
+ else
+ {
+ count_leading_zeros (cnt, qp[size - 1]);
+
+#if BITS_PER_MP_LIMB == 32
+ if (cnt == 0)
+ {
+ hz = qp[size - 1];
+ lz = qp[size - 2];
+ }
+ else
+ {
+ hz = (qp[size - 1] << cnt) | (qp[size - 2] >> BITS_PER_MP_LIMB - cnt);
+ lz = (qp[size - 2] << cnt) | (qp[size - 3] >> BITS_PER_MP_LIMB - cnt);
+ }
+#if _GMP_IEEE_FLOATS
+ /* Take bits from less significant limbs, but only if they may affect
+ the result. */
+ if ((lz & 0x7ff) == 0x400)
+ {
+ if (cnt != 0)
+ lz += ((qp[size - 3] << cnt) != 0 || ! mpn_zero_p (qp, size - 3));
+ else
+ lz += (! mpn_zero_p (qp, size - 2));
+ }
+#endif
+ res = MP_BASE_AS_DOUBLE * hz + lz;
+ res = __gmp_scale2 (res, (size - 2) * BITS_PER_MP_LIMB - cnt);
+#endif
+#if BITS_PER_MP_LIMB == 64
+ if (cnt == 0)
+ hz = qp[size - 1];
+ else
+ hz = (qp[size - 1] << cnt) | (qp[size - 2] >> BITS_PER_MP_LIMB - cnt);
+#if _GMP_IEEE_FLOATS
+ if ((hz & 0x7ff) == 0x400)
+ {
+ if (cnt != 0)
+ hz += ((qp[size - 2] << cnt) != 0 || ! mpn_zero_p (qp, size - 2));
+ else
+ hz += (! mpn_zero_p (qp, size - 1));
+ }
+#endif
+ res = hz;
+ res = __gmp_scale2 (res, (size - 1) * BITS_PER_MP_LIMB - cnt);
+#endif
+ }
+
+ return negative ? -res : res;
+}
diff --git a/rts/gmp/mpz/get_si.c b/rts/gmp/mpz/get_si.c
new file mode 100644
index 0000000000..8a5d0e4803
--- /dev/null
+++ b/rts/gmp/mpz/get_si.c
@@ -0,0 +1,43 @@
+/* mpz_get_si(integer) -- Return the least significant digit from INTEGER.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+signed long int
+#if __STDC__
+mpz_get_si (mpz_srcptr op)
+#else
+mpz_get_si (op)
+ mpz_srcptr op;
+#endif
+{
+ mp_size_t size = op->_mp_size;
+ mp_limb_t low_limb = op->_mp_d[0];
+
+ if (size > 0)
+ return low_limb % ((mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1));
+ else if (size < 0)
+ /* This convoluted expression is necessary to properly handle 0x80000000 */
+ return ~((low_limb - 1) % ((mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1)));
+ else
+ return 0;
+}
diff --git a/rts/gmp/mpz/get_str.c b/rts/gmp/mpz/get_str.c
new file mode 100644
index 0000000000..c7278afb52
--- /dev/null
+++ b/rts/gmp/mpz/get_str.c
@@ -0,0 +1,118 @@
+/* mpz_get_str (string, base, mp_src) -- Convert the multiple precision
+ number MP_SRC to a string STRING of base BASE. If STRING is NULL
+ allocate space for the result. In any case, return a pointer to the
+ result. If STRING is not NULL, the caller must ensure enough space is
+ available to store the result.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+char *
+#if __STDC__
+mpz_get_str (char *res_str, int base, mpz_srcptr x)
+#else
+mpz_get_str (res_str, base, x)
+ char *res_str;
+ int base;
+ mpz_srcptr x;
+#endif
+{
+ mp_ptr xp;
+ mp_size_t x_size = x->_mp_size;
+ unsigned char *str;
+ char *return_str;
+ size_t str_size;
+ char *num_to_text;
+ int i;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ if (base >= 0)
+ {
+ if (base == 0)
+ base = 10;
+ num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+ }
+ else
+ {
+ base = -base;
+ num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ }
+
+ /* We allways allocate space for the string. If the caller passed a
+ NULL pointer for RES_STR, we allocate permanent space and return
+ a pointer to that to the caller. */
+ str_size = ((size_t) (ABS (x_size) * BITS_PER_MP_LIMB
+ * __mp_bases[base].chars_per_bit_exactly)) + 3;
+ if (res_str == 0)
+ {
+ /* We didn't get a string from the user. Allocate one (and return
+ a pointer to it). */
+ res_str = (char *) (*_mp_allocate_func) (str_size);
+ /* Make str, the variable used for raw result from mpn_get_str,
+ point to the same string, but just after a possible minus sign. */
+ str = (unsigned char *) res_str + 1;
+ }
+ else
+ {
+ /* Use TMP_ALLOC to get temporary space, since we need a few extra bytes
+ that we can't expect to caller to supply us with. */
+ str = (unsigned char *) TMP_ALLOC (str_size);
+ }
+
+ return_str = res_str;
+
+ if (x_size == 0)
+ {
+ res_str[0] = '0';
+ res_str[1] = 0;
+ TMP_FREE (marker);
+ return res_str;
+ }
+ if (x_size < 0)
+ {
+ *res_str++ = '-';
+ x_size = -x_size;
+ }
+
+ /* Move the number to convert into temporary space, since mpn_get_str
+ clobbers its argument + needs one extra high limb.... */
+ xp = (mp_ptr) TMP_ALLOC ((x_size + 1) * BYTES_PER_MP_LIMB);
+ MPN_COPY (xp, x->_mp_d, x_size);
+
+ str_size = mpn_get_str (str, base, xp, x_size);
+
+ /* mpn_get_str might make some leading zeros. Skip them. */
+ while (*str == 0)
+ {
+ str_size--;
+ str++;
+ }
+
+ /* Translate result to printable chars and move result to RES_STR. */
+ for (i = 0; i < str_size; i++)
+ res_str[i] = num_to_text[str[i]];
+ res_str[str_size] = 0;
+
+ TMP_FREE (marker);
+ return return_str;
+}
diff --git a/rts/gmp/mpz/get_ui.c b/rts/gmp/mpz/get_ui.c
new file mode 100644
index 0000000000..a8ec9e01a4
--- /dev/null
+++ b/rts/gmp/mpz/get_ui.c
@@ -0,0 +1,37 @@
+/* mpz_get_ui(integer) -- Return the least significant digit from INTEGER.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_get_ui (mpz_srcptr integer)
+#else
+mpz_get_ui (integer)
+ mpz_srcptr integer;
+#endif
+{
+ if (integer->_mp_size == 0)
+ return 0;
+ else
+ return integer->_mp_d[0];
+}
diff --git a/rts/gmp/mpz/getlimbn.c b/rts/gmp/mpz/getlimbn.c
new file mode 100644
index 0000000000..b772ed05c4
--- /dev/null
+++ b/rts/gmp/mpz/getlimbn.c
@@ -0,0 +1,38 @@
+/* mpz_getlimbn(integer,n) -- Return the N:th limb from INTEGER.
+
+Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+mp_limb_t
+#if __STDC__
+mpz_getlimbn (mpz_srcptr integer, mp_size_t n)
+#else
+mpz_getlimbn (integer, n)
+ mpz_srcptr integer;
+ mp_size_t n;
+#endif
+{
+ if (ABS (integer->_mp_size) <= n || n < 0)
+ return 0;
+ else
+ return integer->_mp_d[n];
+}
diff --git a/rts/gmp/mpz/hamdist.c b/rts/gmp/mpz/hamdist.c
new file mode 100644
index 0000000000..b039a653d2
--- /dev/null
+++ b/rts/gmp/mpz/hamdist.c
@@ -0,0 +1,62 @@
+/* mpz_hamdist(mpz_ptr op1, mpz_ptr op2) -- Compute the hamming distance
+ between OP1 and OP2. If one of the operands is negative, return ~0. (We
+ could make the function well-defined when both operands are negative, but
+ that would probably not be worth the trouble.
+
+Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_hamdist (mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_hamdist (u, v)
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+{
+ mp_srcptr up, vp;
+ mp_size_t usize, vsize, size;
+ unsigned long int count;
+
+ usize = u->_mp_size;
+ vsize = v->_mp_size;
+
+ if ((usize | vsize) < 0)
+ return ~ (unsigned long int) 0;
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ if (usize > vsize)
+ {
+ count = mpn_popcount (up + vsize, usize - vsize);
+ size = vsize;
+ }
+ else
+ {
+ count = mpn_popcount (vp + usize, vsize - usize);
+ size = usize;
+ }
+
+ return count + mpn_hamdist (up, vp, size);
+}
diff --git a/rts/gmp/mpz/init.c b/rts/gmp/mpz/init.c
new file mode 100644
index 0000000000..2e8e4d2cbd
--- /dev/null
+++ b/rts/gmp/mpz/init.c
@@ -0,0 +1,36 @@
+/* mpz_init() -- Make a new multiple precision number with value 0.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_init (mpz_ptr x)
+#else
+mpz_init (x)
+ mpz_ptr x;
+#endif
+{
+ x->_mp_alloc = 1;
+ x->_mp_d = (mp_ptr) (*_mp_allocate_func) (BYTES_PER_MP_LIMB);
+ x->_mp_size = 0;
+}
diff --git a/rts/gmp/mpz/inp_raw.c b/rts/gmp/mpz/inp_raw.c
new file mode 100644
index 0000000000..15e601229d
--- /dev/null
+++ b/rts/gmp/mpz/inp_raw.c
@@ -0,0 +1,101 @@
+/* mpz_inp_raw -- Input a mpz_t in raw, but endianess, and wordsize
+ independent format (as output by mpz_out_raw).
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h>
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+size_t
+#if __STDC__
+mpz_inp_raw (mpz_ptr x, FILE *stream)
+#else
+mpz_inp_raw (x, stream)
+ mpz_ptr x;
+ FILE *stream;
+#endif
+{
+ int i;
+ mp_size_t s;
+ mp_size_t xsize;
+ mp_ptr xp;
+ unsigned int c;
+ mp_limb_t x_limb;
+ mp_size_t in_bytesize;
+ int neg_flag;
+
+ if (stream == 0)
+ stream = stdin;
+
+ /* Read 4-byte size */
+ in_bytesize = 0;
+ for (i = 4 - 1; i >= 0; i--)
+ {
+ c = fgetc (stream);
+ in_bytesize = (in_bytesize << BITS_PER_CHAR) | c;
+ }
+
+ /* Size is stored as a 32 bit word; sign extend in_bytesize for non-32 bit
+ machines. */
+ if (sizeof (mp_size_t) > 4)
+ in_bytesize |= (-(in_bytesize < 0)) << 31;
+
+ neg_flag = in_bytesize < 0;
+ in_bytesize = ABS (in_bytesize);
+ xsize = (in_bytesize + BYTES_PER_MP_LIMB - 1) / BYTES_PER_MP_LIMB;
+
+ if (xsize == 0)
+ {
+ x->_mp_size = 0;
+ return 4; /* we've read 4 bytes */
+ }
+
+ if (x->_mp_alloc < xsize)
+ _mpz_realloc (x, xsize);
+ xp = x->_mp_d;
+
+ x_limb = 0;
+ for (i = (in_bytesize - 1) % BYTES_PER_MP_LIMB; i >= 0; i--)
+ {
+ c = fgetc (stream);
+ x_limb = (x_limb << BITS_PER_CHAR) | c;
+ }
+ xp[xsize - 1] = x_limb;
+
+ for (s = xsize - 2; s >= 0; s--)
+ {
+ x_limb = 0;
+ for (i = BYTES_PER_MP_LIMB - 1; i >= 0; i--)
+ {
+ c = fgetc (stream);
+ x_limb = (x_limb << BITS_PER_CHAR) | c;
+ }
+ xp[s] = x_limb;
+ }
+
+ if (c == EOF)
+ return 0; /* error */
+
+ MPN_NORMALIZE (xp, xsize);
+ x->_mp_size = neg_flag ? -xsize : xsize;
+ return in_bytesize + 4;
+}
diff --git a/rts/gmp/mpz/inp_str.c b/rts/gmp/mpz/inp_str.c
new file mode 100644
index 0000000000..7aa5e1fc30
--- /dev/null
+++ b/rts/gmp/mpz/inp_str.c
@@ -0,0 +1,167 @@
+/* mpz_inp_str(dest_integer, stream, base) -- Input a number in base
+ BASE from stdio stream STREAM and store the result in DEST_INTEGER.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1998, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp.h"
+#include "gmp-impl.h"
+
+static int
+#if __STDC__
+digit_value_in_base (int c, int base)
+#else
+digit_value_in_base (c, base)
+ int c;
+ int base;
+#endif
+{
+ int digit;
+
+ if (isdigit (c))
+ digit = c - '0';
+ else if (islower (c))
+ digit = c - 'a' + 10;
+ else if (isupper (c))
+ digit = c - 'A' + 10;
+ else
+ return -1;
+
+ if (digit < base)
+ return digit;
+ return -1;
+}
+
+size_t
+#if __STDC__
+mpz_inp_str (mpz_ptr x, FILE *stream, int base)
+#else
+mpz_inp_str (x, stream, base)
+ mpz_ptr x;
+ FILE *stream;
+ int base;
+#endif
+{
+ char *str;
+ size_t alloc_size, str_size;
+ int c;
+ int negative;
+ mp_size_t xsize;
+ size_t nread;
+
+ if (stream == 0)
+ stream = stdin;
+
+ nread = 0;
+
+ /* Skip whitespace. */
+ do
+ {
+ c = getc (stream);
+ nread++;
+ }
+ while (isspace (c));
+
+ negative = 0;
+ if (c == '-')
+ {
+ negative = 1;
+ c = getc (stream);
+ nread++;
+ }
+
+ if (digit_value_in_base (c, base == 0 ? 10 : base) < 0)
+ return 0; /* error if no digits */
+
+ /* If BASE is 0, try to find out the base by looking at the initial
+ characters. */
+ if (base == 0)
+ {
+ base = 10;
+ if (c == '0')
+ {
+ base = 8;
+ c = getc (stream);
+ nread++;
+ if (c == 'x' || c == 'X')
+ {
+ base = 16;
+ c = getc (stream);
+ nread++;
+ }
+ else if (c == 'b' || c == 'B')
+ {
+ base = 2;
+ c = getc (stream);
+ nread++;
+ }
+ }
+ }
+
+ /* Skip leading zeros. */
+ while (c == '0')
+ {
+ c = getc (stream);
+ nread++;
+ }
+
+ alloc_size = 100;
+ str = (char *) (*_mp_allocate_func) (alloc_size);
+ str_size = 0;
+
+ for (;;)
+ {
+ int dig;
+ if (str_size >= alloc_size)
+ {
+ size_t old_alloc_size = alloc_size;
+ alloc_size = alloc_size * 3 / 2;
+ str = (char *) (*_mp_reallocate_func) (str, old_alloc_size, alloc_size);
+ }
+ dig = digit_value_in_base (c, base);
+ if (dig < 0)
+ break;
+ str[str_size++] = dig;
+ c = getc (stream);
+ }
+
+ ungetc (c, stream);
+
+ /* Make sure the string is not empty, mpn_set_str would fail. */
+ if (str_size == 0)
+ {
+ x->_mp_size = 0;
+ (*_mp_free_func) (str, alloc_size);
+ return nread;
+ }
+
+ xsize = (((mp_size_t) (str_size / __mp_bases[base].chars_per_bit_exactly))
+ / BITS_PER_MP_LIMB + 2);
+ if (x->_mp_alloc < xsize)
+ _mpz_realloc (x, xsize);
+
+ /* Convert the byte array in base BASE to our bignum format. */
+ xsize = mpn_set_str (x->_mp_d, (unsigned char *) str, str_size, base);
+ x->_mp_size = negative ? -xsize : xsize;
+
+ (*_mp_free_func) (str, alloc_size);
+ return str_size + nread;
+}
diff --git a/rts/gmp/mpz/invert.c b/rts/gmp/mpz/invert.c
new file mode 100644
index 0000000000..749a0969fc
--- /dev/null
+++ b/rts/gmp/mpz/invert.c
@@ -0,0 +1,77 @@
+/* mpz_invert (inv, x, n). Find multiplicative inverse of X in Z(N).
+ If X has an inverse, return non-zero and store inverse in INVERSE,
+ otherwise, return 0 and put garbage in INVERSE.
+
+Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_invert (mpz_ptr inverse, mpz_srcptr x, mpz_srcptr n)
+#else
+mpz_invert (inverse, x, n)
+ mpz_ptr inverse;
+ mpz_srcptr x, n;
+#endif
+{
+ mpz_t gcd, tmp;
+ mp_size_t xsize, nsize, size;
+ TMP_DECL (marker);
+
+ xsize = SIZ (x);
+ nsize = SIZ (n);
+ xsize = ABS (xsize);
+ nsize = ABS (nsize);
+ size = MAX (xsize, nsize) + 1;
+
+ /* No inverse exists if the leftside operand is 0. Likewise, no
+ inverse exists if the mod operand is 1. */
+ if (xsize == 0 || (nsize == 1 && (PTR (n))[0] == 1))
+ return 0;
+
+ TMP_MARK (marker);
+
+ MPZ_TMP_INIT (gcd, size);
+ MPZ_TMP_INIT (tmp, size);
+ mpz_gcdext (gcd, tmp, (mpz_ptr) 0, x, n);
+
+ /* If no inverse existed, return with an indication of that. */
+ if (gcd->_mp_size != 1 || (gcd->_mp_d)[0] != 1)
+ {
+ TMP_FREE (marker);
+ return 0;
+ }
+
+ /* Make sure we return a positive inverse. */
+ if (SIZ (tmp) < 0)
+ {
+ if (SIZ (n) < 0)
+ mpz_sub (inverse, tmp, n);
+ else
+ mpz_add (inverse, tmp, n);
+ }
+ else
+ mpz_set (inverse, tmp);
+
+ TMP_FREE (marker);
+ return 1;
+}
diff --git a/rts/gmp/mpz/ior.c b/rts/gmp/mpz/ior.c
new file mode 100644
index 0000000000..0bb5a806dc
--- /dev/null
+++ b/rts/gmp/mpz/ior.c
@@ -0,0 +1,244 @@
+/* mpz_ior -- Logical inclusive or.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+#else
+mpz_ior (res, op1, op2)
+ mpz_ptr res;
+ mpz_srcptr op1;
+ mpz_srcptr op2;
+#endif
+{
+ mp_srcptr op1_ptr, op2_ptr;
+ mp_size_t op1_size, op2_size;
+ mp_ptr res_ptr;
+ mp_size_t res_size;
+ mp_size_t i;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ op1_size = op1->_mp_size;
+ op2_size = op2->_mp_size;
+
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+
+ if (op1_size >= 0)
+ {
+ if (op2_size >= 0)
+ {
+ if (op1_size >= op2_size)
+ {
+ if (res->_mp_alloc < op1_size)
+ {
+ _mpz_realloc (res, op1_size);
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+ }
+
+ if (res_ptr != op1_ptr)
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+ op1_size - op2_size);
+ for (i = op2_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] | op2_ptr[i];
+ res_size = op1_size;
+ }
+ else
+ {
+ if (res->_mp_alloc < op2_size)
+ {
+ _mpz_realloc (res, op2_size);
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+ }
+
+ if (res_ptr != op2_ptr)
+ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+ op2_size - op1_size);
+ for (i = op1_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] | op2_ptr[i];
+ res_size = op2_size;
+ }
+
+ res->_mp_size = res_size;
+ return;
+ }
+ else /* op2_size < 0 */
+ {
+ /* Fall through to the code at the end of the function. */
+ }
+ }
+ else
+ {
+ if (op2_size < 0)
+ {
+ mp_ptr opx;
+ mp_limb_t cy;
+
+ /* Both operands are negative, so will be the result.
+ -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
+ = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
+ = ((OP1 - 1) & (OP2 - 1)) + 1 */
+
+ op1_size = -op1_size;
+ op2_size = -op2_size;
+
+ res_size = MIN (op1_size, op2_size);
+
+ /* Possible optimization: Decrease mpn_sub precision,
+ as we won't use the entire res of both. */
+ opx = (mp_ptr) TMP_ALLOC (res_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
+ op1_ptr = opx;
+
+ opx = (mp_ptr) TMP_ALLOC (res_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op2_ptr, res_size, (mp_limb_t) 1);
+ op2_ptr = opx;
+
+ if (res->_mp_alloc < res_size)
+ {
+ _mpz_realloc (res, res_size);
+ res_ptr = res->_mp_d;
+ /* Don't re-read OP1_PTR and OP2_PTR. They point to
+ temporary space--never to the space RES->_mp_d used
+ to point to before reallocation. */
+ }
+
+ /* First loop finds the size of the result. */
+ for (i = res_size - 1; i >= 0; i--)
+ if ((op1_ptr[i] & op2_ptr[i]) != 0)
+ break;
+ res_size = i + 1;
+
+ if (res_size != 0)
+ {
+ /* Second loop computes the real result. */
+ for (i = res_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] & op2_ptr[i];
+
+ cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
+ if (cy)
+ {
+ res_ptr[res_size] = cy;
+ res_size++;
+ }
+ }
+ else
+ {
+ res_ptr[0] = 1;
+ res_size = 1;
+ }
+
+ res->_mp_size = -res_size;
+ TMP_FREE (marker);
+ return;
+ }
+ else
+ {
+ /* We should compute -OP1 | OP2. Swap OP1 and OP2 and fall
+ through to the code that handles OP1 | -OP2. */
+ MPZ_SRCPTR_SWAP (op1, op2);
+ MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
+ }
+ }
+
+ {
+ mp_ptr opx;
+ mp_limb_t cy;
+ mp_size_t res_alloc;
+ mp_size_t count;
+
+ /* Operand 2 negative, so will be the result.
+ -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
+ = ~(OP1 | ~(OP2 - 1)) + 1 =
+ = (~OP1 & (OP2 - 1)) + 1 */
+
+ op2_size = -op2_size;
+
+ res_alloc = op2_size;
+
+ opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+ op2_ptr = opx;
+ op2_size -= op2_ptr[op2_size - 1] == 0;
+
+ if (res->_mp_alloc < res_alloc)
+ {
+ _mpz_realloc (res, res_alloc);
+ op1_ptr = op1->_mp_d;
+ res_ptr = res->_mp_d;
+ /* Don't re-read OP2_PTR. It points to temporary space--never
+ to the space RES->_mp_d used to point to before reallocation. */
+ }
+
+ if (op1_size >= op2_size)
+ {
+ /* We can just ignore the part of OP1 that stretches above OP2,
+ because the result limbs are zero there. */
+
+ /* First loop finds the size of the result. */
+ for (i = op2_size - 1; i >= 0; i--)
+ if ((~op1_ptr[i] & op2_ptr[i]) != 0)
+ break;
+ res_size = i + 1;
+ count = res_size;
+ }
+ else
+ {
+ res_size = op2_size;
+
+ /* Copy the part of OP2 that stretches above OP1, to RES. */
+ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
+ count = op1_size;
+ }
+
+ if (res_size != 0)
+ {
+ /* Second loop computes the real result. */
+ for (i = count - 1; i >= 0; i--)
+ res_ptr[i] = ~op1_ptr[i] & op2_ptr[i];
+
+ cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
+ if (cy)
+ {
+ res_ptr[res_size] = cy;
+ res_size++;
+ }
+ }
+ else
+ {
+ res_ptr[0] = 1;
+ res_size = 1;
+ }
+
+ res->_mp_size = -res_size;
+ }
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/iset.c b/rts/gmp/mpz/iset.c
new file mode 100644
index 0000000000..114bc2d542
--- /dev/null
+++ b/rts/gmp/mpz/iset.c
@@ -0,0 +1,49 @@
+/* mpz_init_set (src_integer) -- Make a new multiple precision number with
+ a value copied from SRC_INTEGER.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_init_set (mpz_ptr w, mpz_srcptr u)
+#else
+mpz_init_set (w, u)
+ mpz_ptr w;
+ mpz_srcptr u;
+#endif
+{
+ mp_ptr wp, up;
+ mp_size_t usize, size;
+
+ usize = u->_mp_size;
+ size = ABS (usize);
+
+ w->_mp_alloc = MAX (size, 1);
+ w->_mp_d = (mp_ptr) (*_mp_allocate_func) (w->_mp_alloc * BYTES_PER_MP_LIMB);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ MPN_COPY (wp, up, size);
+ w->_mp_size = usize;
+}
diff --git a/rts/gmp/mpz/iset_d.c b/rts/gmp/mpz/iset_d.c
new file mode 100644
index 0000000000..502a8933e2
--- /dev/null
+++ b/rts/gmp/mpz/iset_d.c
@@ -0,0 +1,39 @@
+/* mpz_init_set_d(integer, val) -- Initialize and assign INTEGER with a double
+ value VAL.
+
+Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_init_set_d (mpz_ptr dest, double val)
+#else
+mpz_init_set_d (dest, val)
+ mpz_ptr dest;
+ double val;
+#endif
+{
+ dest->_mp_alloc = 1;
+ dest->_mp_d = (mp_ptr) (*_mp_allocate_func) (BYTES_PER_MP_LIMB);
+ dest->_mp_size = 0;
+ mpz_set_d (dest, val);
+}
diff --git a/rts/gmp/mpz/iset_si.c b/rts/gmp/mpz/iset_si.c
new file mode 100644
index 0000000000..842db140ef
--- /dev/null
+++ b/rts/gmp/mpz/iset_si.c
@@ -0,0 +1,49 @@
+/* mpz_init_set_si(val) -- Make a new multiple precision number with
+ value val.
+
+Copyright (C) 1991, 1993, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_init_set_si (mpz_ptr x, signed long int val)
+#else
+mpz_init_set_si (x, val)
+ mpz_ptr x;
+ signed long int val;
+#endif
+{
+ x->_mp_alloc = 1;
+ x->_mp_d = (mp_ptr) (*_mp_allocate_func) (BYTES_PER_MP_LIMB);
+ if (val > 0)
+ {
+ x->_mp_d[0] = val;
+ x->_mp_size = 1;
+ }
+ else if (val < 0)
+ {
+ x->_mp_d[0] = (unsigned long) -val;
+ x->_mp_size = -1;
+ }
+ else
+ x->_mp_size = 0;
+}
diff --git a/rts/gmp/mpz/iset_str.c b/rts/gmp/mpz/iset_str.c
new file mode 100644
index 0000000000..dfb8c6b230
--- /dev/null
+++ b/rts/gmp/mpz/iset_str.c
@@ -0,0 +1,47 @@
+/* mpz_init_set_str(string, base) -- Convert the \0-terminated string
+ STRING in base BASE to a multiple precision integer. Return a MP_INT
+ structure representing the integer. Allow white space in the
+ string. If BASE == 0 determine the base in the C standard way,
+ i.e. 0xhh...h means base 16, 0oo...o means base 8, otherwise
+ assume base 10.
+
+Copyright (C) 1991, 1993, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_init_set_str (mpz_ptr x, const char *str, int base)
+#else
+mpz_init_set_str (x, str, base)
+ mpz_ptr x;
+ const char *str;
+ int base;
+#endif
+{
+ x->_mp_alloc = 1;
+ x->_mp_d = (mp_ptr) (*_mp_allocate_func) (BYTES_PER_MP_LIMB);
+
+ /* if str has no digits mpz_set_str leaves x->_mp_size unset */
+ x->_mp_size = 0;
+
+ return mpz_set_str (x, str, base);
+}
diff --git a/rts/gmp/mpz/iset_ui.c b/rts/gmp/mpz/iset_ui.c
new file mode 100644
index 0000000000..759182c556
--- /dev/null
+++ b/rts/gmp/mpz/iset_ui.c
@@ -0,0 +1,39 @@
+/* mpz_init_set_ui(val) -- Make a new multiple precision number with
+ value val.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_init_set_ui (mpz_ptr x, unsigned long int val)
+#else
+mpz_init_set_ui (x, val)
+ mpz_ptr x;
+ unsigned long int val;
+#endif
+{
+ x->_mp_alloc = 1;
+ x->_mp_d = (mp_ptr) (*_mp_allocate_func) (BYTES_PER_MP_LIMB);
+ x->_mp_d[0] = val;
+ x->_mp_size = val != 0;
+}
diff --git a/rts/gmp/mpz/jacobi.c b/rts/gmp/mpz/jacobi.c
new file mode 100644
index 0000000000..9d49e1d0c6
--- /dev/null
+++ b/rts/gmp/mpz/jacobi.c
@@ -0,0 +1,53 @@
+/* mpz_jacobi (op1, op2).
+ Contributed by Bennet Yee (bsy) at Carnegie-Mellon University
+
+Copyright (C) 1991, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+
+/* Precondition: both p and q are positive */
+
+int
+#if __STDC__
+mpz_jacobi (mpz_srcptr pi, mpz_srcptr qi)
+#else
+mpz_jacobi (pi, qi)
+ mpz_srcptr pi, qi;
+#endif
+{
+#if GCDCHECK
+ int retval;
+ mpz_t gcdval;
+
+ mpz_init (gcdval);
+ mpz_gcd (gcdval, pi, qi);
+ if (!mpz_cmp_ui (gcdval, 1L))
+ {
+ /* J(ab,cb) = J(ab,c)J(ab,b) = J(ab,c)J(0,b) = J(ab,c)*0 */
+ retval = 0;
+ }
+ else
+ retval = mpz_legendre (pi, qi);
+ mpz_clear (gcdval);
+ return retval;
+#else
+ return mpz_legendre (pi, qi);
+#endif
+}
diff --git a/rts/gmp/mpz/kronsz.c b/rts/gmp/mpz/kronsz.c
new file mode 100644
index 0000000000..c8c6752224
--- /dev/null
+++ b/rts/gmp/mpz/kronsz.c
@@ -0,0 +1,126 @@
+/* mpz_si_kronecker -- Kronecker/Jacobi symbol. */
+
+/*
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA.
+*/
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+#if __STDC__
+mpz_si_kronecker (long a, mpz_srcptr b)
+#else
+mpz_si_kronecker (a, b)
+ long a;
+ mpz_srcptr b;
+#endif
+{
+ int b_abs_size;
+ mp_srcptr b_ptr;
+ mp_limb_t b_low;
+ int twos;
+ int result_bit1;
+
+ b_abs_size = ABSIZ (b);
+ if (b_abs_size == 0)
+ return JACOBI_S0 (a); /* (a/0) */
+
+ b_ptr = PTR(b);
+ b_low = b_ptr[0];
+
+ /* (0/b) = 1 if b=+/-1, 0 otherwise */
+ if (a == 0)
+ return (b_abs_size == 1) & (b_low == 1);
+
+ /* account for the effect of the sign of b, so can then ignore it */
+ result_bit1 = JACOBI_BSGN_SZ_BIT1 (a, b);
+
+ if ((b_low & 1) == 0)
+ {
+ /* b even */
+
+ if ((a & 1) == 0)
+ return 0; /* (a/b)=0 if both a,b even */
+
+ /* Require MP_BITS_PER_LIMB even, so that (a/2)^MP_BITS_PER_LIMB = 1,
+ and so that therefore there's no need to account for how many zero
+ limbs are stripped. */
+ ASSERT ((BITS_PER_MP_LIMB & 1) == 0);
+
+ MPN_STRIP_LOW_ZEROS_NOT_ZERO (b_ptr, b_abs_size);
+ b_low = b_ptr[0];
+
+ if ((b_low & 1) == 0)
+ {
+ /* odd a, even b */
+
+ mp_limb_t b_shl_bit1;
+
+ count_trailing_zeros (twos, b_low);
+
+ /* b_shl_bit1 is b>>twos, but with only bit 1 guaranteed */
+ if (twos == BITS_PER_MP_LIMB-1)
+ b_shl_bit1 = (b_abs_size == 1) ? 0 : (b_ptr[1] << 1);
+ else
+ b_shl_bit1 = (b_low >> twos);
+
+ result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a, b_shl_bit1);
+ a = ABS(a);
+
+ if (a == 1)
+ return JACOBI_BIT1_TO_PN (result_bit1); /* (1/b)=1 */
+
+ /* twos (a/2), reciprocity to (b/a), and (b/a) = (b mod a / b) */
+ return mpn_jacobi_base (mpn_mod_1_rshift (b_ptr, b_abs_size,
+ twos, a),
+ a,
+ result_bit1
+ ^ JACOBI_TWOS_U_BIT1 (twos, a)
+ ^ JACOBI_RECIP_UU_BIT1 (a, b_shl_bit1));
+ }
+ }
+
+ /* b odd */
+
+ result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a, b_low);
+ a = ABS(a);
+
+ /* (a/1) = 1 for any a */
+ if (b_abs_size == 1 && b_low == 1)
+ return JACOBI_BIT1_TO_PN (result_bit1);
+
+ /* Note a is cast to unsigned because 0x80..00 doesn't fit in a signed. */
+ if ((a & 1) == 0)
+ {
+ count_trailing_zeros (twos, a);
+ a = ((unsigned long) a) >> twos;
+ result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b_low);
+ }
+
+ if (a == 1)
+ return JACOBI_BIT1_TO_PN (result_bit1); /* (1/b)=1 */
+
+ /* reciprocity to (b/a), and (b/a) == (b mod a / a) */
+ return mpn_jacobi_base (mpn_mod_1 (b_ptr, b_abs_size, a), a,
+ result_bit1 ^ JACOBI_RECIP_UU_BIT1 (a, b_low));
+}
diff --git a/rts/gmp/mpz/kronuz.c b/rts/gmp/mpz/kronuz.c
new file mode 100644
index 0000000000..b877e6f64c
--- /dev/null
+++ b/rts/gmp/mpz/kronuz.c
@@ -0,0 +1,115 @@
+/* mpz_ui_kronecker -- Kronecker/Jacobi symbol. */
+
+/*
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA.
+*/
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+#if __STDC__
+mpz_ui_kronecker (unsigned long a, mpz_srcptr b)
+#else
+mpz_ui_kronecker (a, b)
+ unsigned long a;
+ mpz_srcptr b;
+#endif
+{
+ int b_abs_size;
+ mp_srcptr b_ptr;
+ mp_limb_t b_low;
+ int twos;
+ int result_bit1;
+
+ /* (a/0) */
+ b_abs_size = ABSIZ (b);
+ if (b_abs_size == 0)
+ return JACOBI_U0 (a);
+
+ /* (a/-1)=1 when a>=0, so the sign of b is ignored */
+ b_ptr = PTR(b);
+ b_low = b_ptr[0];
+
+ /* (0/1)=1; (0/-1)=1; (0/b)=0 for b!=+/-1
+ (1/b)=1, for any b */
+ if (a <= 1)
+ return (a == 1) | ((b_abs_size == 1) & (b_low == 1));
+
+ if (b_low & 1)
+ {
+ /* (a/1) = 1 for any a */
+ if (b_abs_size == 1 && b_low == 1)
+ return 1;
+
+ count_trailing_zeros (twos, a);
+ a >>= twos;
+ if (a == 1)
+ return JACOBI_TWOS_U (twos, b_low); /* powers of (2/b) only */
+
+ /* powers of (2/b); reciprocity to (b/a); (b/a) == (b mod a / a) */
+ return mpn_jacobi_base (mpn_mod_1 (b_ptr, b_abs_size, a),
+ a,
+ JACOBI_TWOS_U_BIT1 (twos, b_low)
+ ^ JACOBI_RECIP_UU_BIT1 (b_low, a));
+ }
+
+ /* b is even; (a/2)=0 if a is even */
+ if ((a & 1) == 0)
+ return 0;
+
+ /* Require MP_BITS_PER_LIMB even, so (a/2)^MP_BITS_PER_LIMB = 1, and so we
+ don't have to pay attention to how many trailing zero limbs are
+ stripped. */
+ ASSERT ((BITS_PER_MP_LIMB & 1) == 0);
+
+ MPN_STRIP_LOW_ZEROS_NOT_ZERO (b_ptr, b_abs_size);
+ b_low = b_ptr[0];
+
+ if (b_low & 1)
+ /* reciprocity to (b/a); (b/a) == (b mod a / a) */
+ return mpn_jacobi_base (mpn_mod_1 (b_ptr, b_abs_size, a),
+ a,
+ JACOBI_RECIP_UU_BIT1 (b_low, a));
+
+ count_trailing_zeros (twos, b_low);
+
+ /* reciprocity to get (b/a) */
+ if (twos == BITS_PER_MP_LIMB-1)
+ {
+ if (b_abs_size == 1)
+ {
+ /* b==0x800...00, one limb high bit only, so (a/2)^(BPML-1) */
+ return JACOBI_TWOS_U (BITS_PER_MP_LIMB-1, a);
+ }
+
+ /* b_abs_size > 1 */
+ result_bit1 = JACOBI_RECIP_UU_BIT1 (a, b_ptr[1] << 1);
+ }
+ else
+ result_bit1 = JACOBI_RECIP_UU_BIT1 (a, b_low >> twos);
+
+ /* powers of (a/2); reciprocity to (b/a); (b/a) == (b mod a / a) */
+ return mpn_jacobi_base (mpn_mod_1_rshift (b_ptr, b_abs_size, twos, a),
+ a,
+ JACOBI_TWOS_U_BIT1 (twos, a) ^ result_bit1);
+}
diff --git a/rts/gmp/mpz/kronzs.c b/rts/gmp/mpz/kronzs.c
new file mode 100644
index 0000000000..edfb465976
--- /dev/null
+++ b/rts/gmp/mpz/kronzs.c
@@ -0,0 +1,74 @@
+/* mpz_kronecker_si -- Kronecker/Jacobi symbol. */
+
+/*
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA.
+*/
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This function is expected to be often used with b odd, so there's a test
+ for this before invoking count_trailing_zeros().
+
+ After the absolute value of b is established it's treated as an unsigned
+ long, because 0x80..00 doesn't fit in a signed long. */
+
+int
+#if __STDC__
+mpz_kronecker_si (mpz_srcptr a, long b)
+#else
+mpz_kronecker_si (a, b)
+ mpz_srcptr a;
+ long b;
+#endif
+{
+ int result_bit1;
+ int twos;
+
+ if (b == 0)
+ return JACOBI_Z0 (a);
+
+ result_bit1 = JACOBI_BSGN_ZS_BIT1(a, b);
+ b = ABS (b);
+
+ if (b == 1)
+ return JACOBI_BIT1_TO_PN (result_bit1); /* (a/1) = 1 for any a */
+
+ if (b & 1)
+ return mpn_jacobi_base (mpz_fdiv_ui (a, b), b, result_bit1);
+
+ /* result 0 if both a,b even */
+ if (mpz_even_p (a))
+ return 0;
+
+ /* (a/2)=(2/a) when a odd */
+ count_trailing_zeros (twos, b);
+ result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(a)[0]);
+
+ b = ((unsigned long) b) >> twos;
+ if (b == 1)
+ return JACOBI_BIT1_TO_PN (result_bit1);
+ else
+ return mpn_jacobi_base (mpz_fdiv_ui (a, b), b, result_bit1);
+}
+
+
diff --git a/rts/gmp/mpz/kronzu.c b/rts/gmp/mpz/kronzu.c
new file mode 100644
index 0000000000..749be5df07
--- /dev/null
+++ b/rts/gmp/mpz/kronzu.c
@@ -0,0 +1,66 @@
+/* mpz_kronecker_ui -- Kronecker/Jacobi symbol. */
+
+/*
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA.
+*/
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This function is expected to be often used with b an odd prime, so the
+ code for odd b is nice and short. */
+
+int
+#if __STDC__
+mpz_kronecker_ui (mpz_srcptr a, unsigned long b)
+#else
+mpz_kronecker_ui (a, b)
+ mpz_srcptr a;
+ unsigned long b;
+#endif
+{
+ int twos;
+
+ if (b & 1)
+ {
+ if (b != 1)
+ return mpn_jacobi_base (mpz_fdiv_ui (a, b), b, 0);
+ else
+ return 1; /* (a/1)=1 for any a */
+ }
+
+ if (b == 0)
+ return JACOBI_Z0 (a);
+
+ /* (a/2)=0 if a even */
+ if (mpz_even_p (a))
+ return 0;
+
+ /* (a/2)=(2/a) when a odd */
+ count_trailing_zeros (twos, b);
+ b >>= twos;
+ if (b == 1)
+ return JACOBI_TWOS_U (twos, PTR(a)[0]);
+
+ return mpn_jacobi_base (mpz_fdiv_ui (a, b), b,
+ JACOBI_TWOS_U_BIT1(twos, PTR(a)[0]));
+}
diff --git a/rts/gmp/mpz/lcm.c b/rts/gmp/mpz/lcm.c
new file mode 100644
index 0000000000..7495882ae5
--- /dev/null
+++ b/rts/gmp/mpz/lcm.c
@@ -0,0 +1,61 @@
+/* mpz/lcm.c: Calculate the least common multiple of two integers.
+
+Copyright (C) 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void *_mpz_realloc ();
+
+void
+#if __STDC__
+mpz_lcm (mpz_ptr r, mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_lcm (r, u, v)
+ mpz_ptr r;
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+{
+ mpz_t g;
+ mp_size_t usize, vsize, size;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ usize = ABS (SIZ (u));
+ vsize = ABS (SIZ (v));
+
+ if (usize == 0 || vsize == 0)
+ {
+ SIZ (r) = 0;
+ return;
+ }
+
+ size = MAX (usize, vsize);
+ MPZ_TMP_INIT (g, size);
+
+ mpz_gcd (g, u, v);
+ mpz_divexact (g, u, g);
+ mpz_mul (r, g, v);
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/legendre.c b/rts/gmp/mpz/legendre.c
new file mode 100644
index 0000000000..ab665f70d0
--- /dev/null
+++ b/rts/gmp/mpz/legendre.c
@@ -0,0 +1,184 @@
+/* mpz_legendre (op1, op2).
+ Contributed by Bennet Yee (bsy) at Carnegie-Mellon University
+
+Copyright (C) 1992, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+
+#if defined (DEBUG)
+#include <stdio.h>
+#endif
+
+/* Precondition: both p and q are positive */
+
+int
+#if __STDC__
+mpz_legendre (mpz_srcptr pi, mpz_srcptr qi)
+#else
+mpz_legendre (pi, qi)
+mpz_srcptr pi, qi;
+#endif
+{
+ mpz_t p, q, qdiv2;
+#ifdef Q_MINUS_1
+ mpz_t q_minus_1;
+#endif
+ mpz_ptr mtmp;
+ register mpz_ptr pptr, qptr;
+ register int retval = 1;
+ register unsigned long int s;
+
+ pptr = p;
+ mpz_init_set (pptr, pi);
+ qptr = q;
+ mpz_init_set (qptr, qi);
+
+#ifdef Q_MINUS_1
+ mpz_init (q_minus_1);
+#endif
+ mpz_init (qdiv2);
+
+tail_recurse2:
+#ifdef DEBUG
+ printf ("tail_recurse2: p=");
+ mpz_out_str (stdout, 10, pptr);
+ printf ("\nq=");
+ mpz_out_str (stdout, 10, qptr);
+ putchar ('\n');
+#endif
+ s = mpz_scan1 (qptr, 0);
+ if (s) mpz_tdiv_q_2exp (qptr, qptr, s); /* J(a,2) = 1 */
+#ifdef DEBUG
+ printf ("2 factor decomposition: p=");
+ mpz_out_str (stdout, 10, pptr);
+ printf ("\nq=");
+ mpz_out_str (stdout, 10, qptr);
+ putchar ('\n');
+#endif
+ /* postcondition q odd */
+ if (!mpz_cmp_ui (qptr, 1L)) /* J(a,1) = 1 */
+ goto done;
+ mpz_mod (pptr, pptr, qptr); /* J(a,q) = J(b,q) when a == b mod q */
+#ifdef DEBUG
+ printf ("mod out by q: p=");
+ mpz_out_str (stdout, 10, pptr);
+ printf ("\nq=");
+ mpz_out_str (stdout, 10, qptr);
+ putchar ('\n');
+#endif
+ /* quick calculation to get approximate size first */
+ /* precondition: p < q */
+ if ((mpz_sizeinbase (pptr, 2) + 1 >= mpz_sizeinbase (qptr,2))
+ && (mpz_tdiv_q_2exp (qdiv2, qptr, 1L), mpz_cmp (pptr, qdiv2) > 0))
+ {
+ /* p > q/2 */
+ mpz_sub (pptr, qptr, pptr);
+ /* J(-1,q) = (-1)^((q-1)/2), q odd */
+ if (mpz_get_ui (qptr) & 2)
+ retval = -retval;
+ }
+ /* p < q/2 */
+#ifdef Q_MINUS_1
+ mpz_sub_ui (q_minus_q, qptr, 1L);
+#endif
+tail_recurse: /* we use tail_recurse only if q has not changed */
+#ifdef DEBUG
+ printf ("tail_recurse1: p=");
+ mpz_out_str (stdout, 10, pptr);
+ printf ("\nq=");
+ mpz_out_str (stdout, 10, qptr);
+ putchar ('\n');
+#endif
+ /*
+ * J(0,q) = 0
+ * this occurs only if gcd(p,q) != 1 which is never true for
+ * Legendre function.
+ */
+ if (!mpz_cmp_ui (pptr, 0L))
+ {
+ retval = 0;
+ goto done;
+ }
+
+ if (!mpz_cmp_ui (pptr, 1L))
+ {
+ /* J(1,q) = 1 */
+ /* retval *= 1; */
+ goto done;
+ }
+#ifdef Q_MINUS_1
+ if (!mpz_cmp (pptr, q_minus_1))
+ {
+ /* J(-1,q) = (-1)^((q-1)/2) */
+ if (mpz_get_ui (qptr) & 2)
+ retval = -retval;
+ /* else retval *= 1; */
+ goto done;
+ }
+#endif
+ /*
+ * we do not handle J(xy,q) except for x==2
+ * since we do not want to factor
+ */
+ if ((s = mpz_scan1 (pptr, 0)) != 0)
+ {
+ /*
+ * J(2,q) = (-1)^((q^2-1)/8)
+ *
+ * Note that q odd guarantees that q^2-1 is divisible by 8:
+ * Let a: q=2a+1. q^2 = 4a^2+4a+1, (q^2-1)/8 = a(a+1)/2, qed
+ *
+ * Now, note that this means that the low two bits of _a_
+ * (or the low bits of q shifted over by 1 determines
+ * the factor).
+ */
+ mpz_tdiv_q_2exp (pptr, pptr, s);
+
+ /* even powers of 2 gives J(2,q)^{2n} = 1 */
+ if (s & 1)
+ {
+ s = mpz_get_ui (qptr) >> 1;
+ s = s * (s + 1);
+ if (s & 2)
+ retval = -retval;
+ }
+ goto tail_recurse;
+ }
+ /*
+ * we know p is odd since we have cast out 2s
+ * precondition that q is odd guarantees both odd.
+ *
+ * quadratic reciprocity
+ * J(p,q) = (-1)^((p-1)(q-1)/4) * J(q,p)
+ */
+ if ((s = mpz_scan1 (pptr, 1)) <= 2 && (s + mpz_scan1 (qptr, 1)) <= 2)
+ retval = -retval;
+
+ mtmp = pptr; pptr = qptr; qptr = mtmp;
+ goto tail_recurse2;
+done:
+ mpz_clear (p);
+ mpz_clear (q);
+ mpz_clear (qdiv2);
+#ifdef Q_MINUS_1
+ mpz_clear (q_minus_1);
+#endif
+ return retval;
+}
diff --git a/rts/gmp/mpz/mod.c b/rts/gmp/mpz/mod.c
new file mode 100644
index 0000000000..87033b333b
--- /dev/null
+++ b/rts/gmp/mpz/mod.c
@@ -0,0 +1,63 @@
+/* mpz_mod -- The mathematical mod function.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_mod (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+#else
+mpz_mod (rem, dividend, divisor)
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ mpz_srcptr divisor;
+#endif
+{
+ mp_size_t divisor_size = divisor->_mp_size;
+ mpz_t temp_divisor; /* N.B.: lives until function returns! */
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* We need the original value of the divisor after the remainder has been
+ preliminary calculated. We have to copy it to temporary space if it's
+ the same variable as REM. */
+ if (rem == divisor)
+ {
+ MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+ mpz_set (temp_divisor, divisor);
+ divisor = temp_divisor;
+ }
+
+ mpz_tdiv_r (rem, dividend, divisor);
+
+ if (rem->_mp_size != 0)
+ {
+ if (dividend->_mp_size < 0)
+ if (divisor->_mp_size < 0)
+ mpz_sub (rem, rem, divisor);
+ else
+ mpz_add (rem, rem, divisor);
+ }
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/mul.c b/rts/gmp/mpz/mul.c
new file mode 100644
index 0000000000..7854788e50
--- /dev/null
+++ b/rts/gmp/mpz/mul.c
@@ -0,0 +1,131 @@
+/* mpz_mul -- Multiply two integers.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_mul (w, u, v)
+ mpz_ptr w;
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+mult (mpz_srcptr u, mpz_srcptr v, mpz_ptr w)
+#else
+mult (u, v, w)
+ mpz_srcptr u;
+ mpz_srcptr v;
+ mpz_ptr w;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_size_t usize = u->_mp_size;
+ mp_size_t vsize = v->_mp_size;
+ mp_size_t wsize;
+ mp_size_t sign_product;
+ mp_ptr up, vp;
+ mp_ptr wp;
+ mp_ptr free_me = NULL;
+ size_t free_me_size;
+ mp_limb_t cy_limb;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ sign_product = usize ^ vsize;
+ usize = ABS (usize);
+ vsize = ABS (vsize);
+
+ if (usize < vsize)
+ {
+ /* Swap U and V. */
+ {const __mpz_struct *t = u; u = v; v = t;}
+ {mp_size_t t = usize; usize = vsize; vsize = t;}
+ }
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+ wp = w->_mp_d;
+
+ /* Ensure W has space enough to store the result. */
+ wsize = usize + vsize;
+ if (w->_mp_alloc < wsize)
+ {
+ if (wp == up || wp == vp)
+ {
+ free_me = wp;
+ free_me_size = w->_mp_alloc;
+ }
+ else
+ (*_mp_free_func) (wp, w->_mp_alloc * BYTES_PER_MP_LIMB);
+
+ w->_mp_alloc = wsize;
+ wp = (mp_ptr) (*_mp_allocate_func) (wsize * BYTES_PER_MP_LIMB);
+ w->_mp_d = wp;
+ }
+ else
+ {
+ /* Make U and V not overlap with W. */
+ if (wp == up)
+ {
+ /* W and U are identical. Allocate temporary space for U. */
+ up = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB);
+ /* Is V identical too? Keep it identical with U. */
+ if (wp == vp)
+ vp = up;
+ /* Copy to the temporary space. */
+ MPN_COPY (up, wp, usize);
+ }
+ else if (wp == vp)
+ {
+ /* W and V are identical. Allocate temporary space for V. */
+ vp = (mp_ptr) TMP_ALLOC (vsize * BYTES_PER_MP_LIMB);
+ /* Copy to the temporary space. */
+ MPN_COPY (vp, wp, vsize);
+ }
+ }
+
+ if (vsize == 0)
+ {
+ wsize = 0;
+ }
+ else
+ {
+ cy_limb = mpn_mul (wp, up, usize, vp, vsize);
+ wsize = usize + vsize;
+ wsize -= cy_limb == 0;
+ }
+
+ w->_mp_size = sign_product < 0 ? -wsize : wsize;
+ if (free_me != NULL)
+ (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/mul_2exp.c b/rts/gmp/mpz/mul_2exp.c
new file mode 100644
index 0000000000..abea5fed2c
--- /dev/null
+++ b/rts/gmp/mpz/mul_2exp.c
@@ -0,0 +1,76 @@
+/* mpz_mul_2exp -- Multiply a bignum by 2**CNT
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_mul_2exp (mpz_ptr w, mpz_srcptr u, unsigned long int cnt)
+#else
+mpz_mul_2exp (w, u, cnt)
+ mpz_ptr w;
+ mpz_srcptr u;
+ unsigned long int cnt;
+#endif
+{
+ mp_size_t usize = u->_mp_size;
+ mp_size_t abs_usize = ABS (usize);
+ mp_size_t wsize;
+ mp_size_t limb_cnt;
+ mp_ptr wp;
+ mp_limb_t wlimb;
+
+ if (usize == 0)
+ {
+ w->_mp_size = 0;
+ return;
+ }
+
+ limb_cnt = cnt / BITS_PER_MP_LIMB;
+ wsize = abs_usize + limb_cnt + 1;
+ if (w->_mp_alloc < wsize)
+ _mpz_realloc (w, wsize);
+
+ wp = w->_mp_d;
+ wsize = abs_usize + limb_cnt;
+
+ cnt %= BITS_PER_MP_LIMB;
+ if (cnt != 0)
+ {
+ wlimb = mpn_lshift (wp + limb_cnt, u->_mp_d, abs_usize, cnt);
+ if (wlimb != 0)
+ {
+ wp[wsize] = wlimb;
+ wsize++;
+ }
+ }
+ else
+ {
+ MPN_COPY_DECR (wp + limb_cnt, u->_mp_d, abs_usize);
+ }
+
+ /* Zero all whole limbs at low end. Do it here and not before calling
+ mpn_lshift, not to lose for U == W. */
+ MPN_ZERO (wp, limb_cnt);
+
+ w->_mp_size = usize >= 0 ? wsize : -wsize;
+}
diff --git a/rts/gmp/mpz/mul_siui.c b/rts/gmp/mpz/mul_siui.c
new file mode 100644
index 0000000000..9849cd41b0
--- /dev/null
+++ b/rts/gmp/mpz/mul_siui.c
@@ -0,0 +1,81 @@
+/* mpz_mul_ui/si (product, multiplier, small_multiplicand) -- Set PRODUCT to
+ MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_mul_ui
+#define FUNCTION mpz_mul_ui
+#define MULTIPLICAND_UNSIGNED unsigned
+#define MULTIPLICAND_ABS(x) x
+#else
+#ifdef OPERATION_mul_si
+#define FUNCTION mpz_mul_si
+#define MULTIPLICAND_UNSIGNED
+#define MULTIPLICAND_ABS(x) ABS(x)
+#else
+Error, error, unrecognised OPERATION
+#endif
+#endif
+
+
+void
+#if __STDC__
+FUNCTION (mpz_ptr prod, mpz_srcptr mult,
+ MULTIPLICAND_UNSIGNED long int small_mult)
+#else
+FUNCTION (prod, mult, small_mult)
+ mpz_ptr prod;
+ mpz_srcptr mult;
+ MULTIPLICAND_UNSIGNED long int small_mult;
+#endif
+{
+ mp_size_t size = mult->_mp_size;
+ mp_size_t sign_product = size;
+ mp_limb_t cy;
+ mp_size_t prod_size;
+ mp_ptr prod_ptr;
+
+ if (size == 0 || small_mult == 0)
+ {
+ prod->_mp_size = 0;
+ return;
+ }
+ size = ABS (size);
+
+ prod_size = size + 1;
+ if (prod->_mp_alloc < prod_size)
+ _mpz_realloc (prod, prod_size);
+
+ prod_ptr = prod->_mp_d;
+
+ cy = mpn_mul_1 (prod_ptr, mult->_mp_d, size,
+ (mp_limb_t) MULTIPLICAND_ABS (small_mult));
+ if (cy != 0)
+ {
+ prod_ptr[size] = cy;
+ size++;
+ }
+
+ prod->_mp_size = ((sign_product < 0) ^ (small_mult < 0)) ? -size : size;
+}
diff --git a/rts/gmp/mpz/neg.c b/rts/gmp/mpz/neg.c
new file mode 100644
index 0000000000..566c3a95aa
--- /dev/null
+++ b/rts/gmp/mpz/neg.c
@@ -0,0 +1,53 @@
+/* mpz_neg(mpz_ptr dst, mpz_ptr src) -- Assign the negated value of SRC to DST.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_neg (mpz_ptr w, mpz_srcptr u)
+#else
+mpz_neg (w, u)
+ mpz_ptr w;
+ mpz_srcptr u;
+#endif
+{
+ mp_ptr wp, up;
+ mp_size_t usize, size;
+
+ usize = u->_mp_size;
+
+ if (u != w)
+ {
+ size = ABS (usize);
+
+ if (w->_mp_alloc < size)
+ _mpz_realloc (w, size);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ MPN_COPY (wp, up, size);
+ }
+
+ w->_mp_size = -usize;
+}
diff --git a/rts/gmp/mpz/nextprime.c b/rts/gmp/mpz/nextprime.c
new file mode 100644
index 0000000000..f024dd1206
--- /dev/null
+++ b/rts/gmp/mpz/nextprime.c
@@ -0,0 +1,120 @@
+/* mpz_nextprime(p,t) - compute the next prime > t and store that in p.
+
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_nextprime (mpz_ptr p, mpz_srcptr t)
+#else
+mpz_nextprime (p, t)
+ mpz_ptr p;
+ mpz_srcptr t;
+#endif
+{
+ mpz_add_ui (p, t, 1L);
+ while (! mpz_probab_prime_p (p, 5))
+ mpz_add_ui (p, p, 1L);
+}
+
+#if 0
+/* This code is not yet tested. Will be enabled in 3.1. */
+
+status unsigned short primes[] =
+{
+3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
+101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,
+191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,
+281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,
+389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,
+491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,
+607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,
+719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,
+829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,
+953,967,971,977,983,991,997
+};
+
+#define NUMBER_OF_PRIMES 167
+
+void
+#if __STDC__
+mpz_nextprime (mpz_ptr p, mpz_srcptr n)
+#else
+mpz_nextprime (p, n)
+ mpz_ptr p;
+ mpz_srcptr n;
+#endif
+{
+ mpz_t tmp;
+ unsigned short *moduli;
+ unsigned long difference;
+ int i;
+ int composite;
+
+ /* First handle tiny numbers */
+ if (mpz_cmp_ui (n, 2) < 0)
+ {
+ mpz_set_ui (p, 2);
+ return;
+ }
+ mpz_add_ui (p, n, 1);
+ mpz_setbit (p, 0);
+
+ if (mpz_cmp_ui (p, 7) <= 0)
+ return;
+
+ prime_limit = NUMBER_OF_PRIMES - 1;
+ if (mpz_cmp_ui (p, primes[prime_limit]) <= 0)
+ /* Just use first three entries (3,5,7) of table for small numbers */
+ prime_limit = 3;
+ if (prime_limit)
+ {
+ /* Compute residues modulo small odd primes */
+ moduli = (unsigned short *) TMP_ALLOC (prime_limit * sizeof moduli[0]);
+ for (i = 0; i < prime_limit; i++)
+ moduli[i] = mpz_fdiv_ui (p, primes[i]);
+ }
+ for (difference = 0; ; difference += 2)
+ {
+ composite = 0;
+
+ /* First check residues */
+ for (i = 0; i < prime_limit; i++)
+ {
+ int acc, pr;
+ composite |= (moduli[i] == 0);
+ acc = moduli[i] + 2;
+ pr = primes[i];
+ moduli[i] = acc >= pr ? acc - pr : acc;
+ }
+ if (composite)
+ continue;
+
+ mpz_add_ui (p, p, difference);
+ difference = 0;
+
+ /* Miller-Rabin test */
+ if (mpz_millerrabin (p, 2))
+ break;
+ }
+}
+#endif
diff --git a/rts/gmp/mpz/out_raw.c b/rts/gmp/mpz/out_raw.c
new file mode 100644
index 0000000000..62709479c5
--- /dev/null
+++ b/rts/gmp/mpz/out_raw.c
@@ -0,0 +1,89 @@
+/* mpz_out_raw -- Output a mpz_t in binary. Use an endianess and word size
+ independent format.
+
+Copyright (C) 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h>
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+size_t
+#if __STDC__
+mpz_out_raw (FILE *stream, mpz_srcptr x)
+#else
+mpz_out_raw (stream, x)
+ FILE *stream;
+ mpz_srcptr x;
+#endif
+{
+ int i;
+ mp_size_t s;
+ mp_size_t xsize = ABS (x->_mp_size);
+ mp_srcptr xp = x->_mp_d;
+ mp_size_t out_bytesize;
+ mp_limb_t hi_limb;
+ int n_bytes_in_hi_limb;
+
+ if (stream == 0)
+ stream = stdout;
+
+ if (xsize == 0)
+ {
+ for (i = 4 - 1; i >= 0; i--)
+ fputc (0, stream);
+ return ferror (stream) ? 0 : 4;
+ }
+
+ hi_limb = xp[xsize - 1];
+ for (i = BYTES_PER_MP_LIMB - 1; i > 0; i--)
+ {
+ if ((hi_limb >> i * BITS_PER_CHAR) != 0)
+ break;
+ }
+ n_bytes_in_hi_limb = i + 1;
+ out_bytesize = BYTES_PER_MP_LIMB * (xsize - 1) + n_bytes_in_hi_limb;
+ if (x->_mp_size < 0)
+ out_bytesize = -out_bytesize;
+
+ /* Make the size 4 bytes on all machines, to make the format portable. */
+ for (i = 4 - 1; i >= 0; i--)
+ fputc ((out_bytesize >> (i * BITS_PER_CHAR)) % (1 << BITS_PER_CHAR),
+ stream);
+
+ /* Output from the most significant limb to the least significant limb,
+ with each limb also output in decreasing significance order. */
+
+ /* Output the most significant limb separately, since we will only
+ output some of its bytes. */
+ for (i = n_bytes_in_hi_limb - 1; i >= 0; i--)
+ fputc ((hi_limb >> (i * BITS_PER_CHAR)) % (1 << BITS_PER_CHAR), stream);
+
+ /* Output the remaining limbs. */
+ for (s = xsize - 2; s >= 0; s--)
+ {
+ mp_limb_t x_limb;
+
+ x_limb = xp[s];
+ for (i = BYTES_PER_MP_LIMB - 1; i >= 0; i--)
+ fputc ((x_limb >> (i * BITS_PER_CHAR)) % (1 << BITS_PER_CHAR), stream);
+ }
+ return ferror (stream) ? 0 : ABS (out_bytesize) + 4;
+}
diff --git a/rts/gmp/mpz/out_str.c b/rts/gmp/mpz/out_str.c
new file mode 100644
index 0000000000..bf971b0057
--- /dev/null
+++ b/rts/gmp/mpz/out_str.c
@@ -0,0 +1,108 @@
+/* mpz_out_str(stream, base, integer) -- Output to STREAM the multi prec.
+ integer INTEGER in base BASE.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include "gmp.h"
+#include "gmp-impl.h"
+
+size_t
+#if __STDC__
+mpz_out_str (FILE *stream, int base, mpz_srcptr x)
+#else
+mpz_out_str (stream, base, x)
+ FILE *stream;
+ int base;
+ mpz_srcptr x;
+#endif
+{
+ mp_ptr xp;
+ mp_size_t x_size = x->_mp_size;
+ unsigned char *str;
+ size_t str_size;
+ size_t i;
+ size_t written;
+ char *num_to_text;
+ TMP_DECL (marker);
+
+ if (stream == 0)
+ stream = stdout;
+
+ if (base >= 0)
+ {
+ if (base == 0)
+ base = 10;
+ num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+ }
+ else
+ {
+ base = -base;
+ num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ }
+
+ if (x_size == 0)
+ {
+ fputc ('0', stream);
+ return ferror (stream) ? 0 : 1;
+ }
+
+ written = 0;
+
+ if (x_size < 0)
+ {
+ fputc ('-', stream);
+ x_size = -x_size;
+ written = 1;
+ }
+
+ TMP_MARK (marker);
+ str_size = ((size_t) (x_size * BITS_PER_MP_LIMB
+ * __mp_bases[base].chars_per_bit_exactly)) + 3;
+ str = (unsigned char *) TMP_ALLOC (str_size);
+
+ /* Move the number to convert into temporary space, since mpn_get_str
+ clobbers its argument + needs one extra high limb.... */
+ xp = (mp_ptr) TMP_ALLOC ((x_size + 1) * BYTES_PER_MP_LIMB);
+ MPN_COPY (xp, x->_mp_d, x_size);
+
+ str_size = mpn_get_str (str, base, xp, x_size);
+
+ /* mpn_get_str might make some leading zeros. Skip them. */
+ while (*str == 0)
+ {
+ str_size--;
+ str++;
+ }
+
+ /* Translate to printable chars. */
+ for (i = 0; i < str_size; i++)
+ str[i] = num_to_text[str[i]];
+ str[str_size] = 0;
+
+ {
+ size_t fwret;
+ fwret = fwrite ((char *) str, 1, str_size, stream);
+ written += fwret;
+ }
+
+ TMP_FREE (marker);
+ return ferror (stream) ? 0 : written;
+}
diff --git a/rts/gmp/mpz/perfpow.c b/rts/gmp/mpz/perfpow.c
new file mode 100644
index 0000000000..e71670a0be
--- /dev/null
+++ b/rts/gmp/mpz/perfpow.c
@@ -0,0 +1,272 @@
+/* mpz_perfect_power_p(arg) -- Return non-zero if ARG is a perfect power,
+ zero otherwise.
+
+Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+/*
+ We are to determine if c is a perfect power, c = a ^ b.
+ Assume c is divisible by 2^n and that codd = c/2^n is odd.
+ Assume a is divisible by 2^m and that aodd = a/2^m is odd.
+ It is always true that m divides n.
+
+ * If n is prime, either 1) a is 2*aodd and b = n
+ or 2) a = c and b = 1.
+ So for n prime, we readily have a solution.
+ * If n is factorable into the non-trivial factors p1,p2,...
+ Since m divides n, m has a subset of n's factors and b = n / m.
+
+ BUG: Should handle negative numbers, since they can be odd perfect powers.
+*/
+
+/* This is a naive approach to recognizing perfect powers.
+ Many things can be improved. In particular, we should use p-adic
+ arithmetic for computing possible roots. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static unsigned long int gcd _PROTO ((unsigned long int a, unsigned long int b));
+static int isprime _PROTO ((unsigned long int t));
+
+static const unsigned short primes[] =
+{ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
+ 59, 61, 67, 71, 73, 79, 83, 89, 97,101,103,107,109,113,127,131,
+ 137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,
+ 227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,
+ 313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,
+ 419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,
+ 509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,
+ 617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,
+ 727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,
+ 829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,
+ 947,953,967,971,977,983,991,997,0
+};
+#define SMALLEST_OMITTED_PRIME 1009
+
+
+int
+#if __STDC__
+mpz_perfect_power_p (mpz_srcptr u)
+#else
+mpz_perfect_power_p (u)
+ mpz_srcptr u;
+#endif
+{
+ unsigned long int prime;
+ unsigned long int n, n2;
+ int i;
+ unsigned long int rem;
+ mpz_t u2, q;
+ int exact;
+ mp_size_t uns;
+ TMP_DECL (marker);
+
+ if (mpz_cmp_ui (u, 1) <= 0)
+ return 0;
+
+ n2 = mpz_scan1 (u, 0);
+ if (n2 == 1)
+ return 0;
+
+ TMP_MARK (marker);
+
+ uns = ABSIZ (u) - n2 / BITS_PER_MP_LIMB;
+ MPZ_TMP_INIT (q, uns);
+ MPZ_TMP_INIT (u2, uns);
+
+ mpz_tdiv_q_2exp (u2, u, n2);
+
+ if (isprime (n2))
+ goto n2prime;
+
+ for (i = 1; primes[i] != 0; i++)
+ {
+ prime = primes[i];
+ rem = mpz_tdiv_ui (u2, prime);
+ if (rem == 0) /* divisable? */
+ {
+ rem = mpz_tdiv_q_ui (q, u2, prime * prime);
+ if (rem != 0)
+ {
+ TMP_FREE (marker);
+ return 0;
+ }
+ mpz_swap (q, u2);
+ for (n = 2;;)
+ {
+ rem = mpz_tdiv_q_ui (q, u2, prime);
+ if (rem != 0)
+ break;
+ mpz_swap (q, u2);
+ n++;
+ }
+
+ n2 = gcd (n2, n);
+ if (n2 == 1)
+ {
+ TMP_FREE (marker);
+ return 0;
+ }
+
+ /* As soon as n2 becomes a prime number, stop factoring.
+ Either we have u=x^n2 or u is not a perfect power. */
+ if (isprime (n2))
+ goto n2prime;
+ }
+ }
+
+ if (mpz_cmp_ui (u2, 1) == 0)
+ {
+ TMP_FREE (marker);
+ return 1;
+ }
+
+ if (n2 == 0)
+ {
+ unsigned long int nth;
+ /* We did not find any factors above. We have to consider all values
+ of n. */
+ for (nth = 2;; nth++)
+ {
+ if (! isprime (nth))
+ continue;
+#if 0
+ exact = mpz_padic_root (q, u2, nth, PTH);
+ if (exact)
+#endif
+ exact = mpz_root (q, u2, nth);
+ if (exact)
+ {
+ TMP_FREE (marker);
+ return 1;
+ }
+ if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0)
+ {
+ TMP_FREE (marker);
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ unsigned long int nth;
+ /* We found some factors above. We just need to consider values of n
+ that divides n2. */
+ for (nth = 2; nth <= n2; nth++)
+ {
+ if (! isprime (nth))
+ continue;
+ if (n2 % nth != 0)
+ continue;
+#if 0
+ exact = mpz_padic_root (q, u2, nth, PTH);
+ if (exact)
+#endif
+ exact = mpz_root (q, u2, nth);
+ if (exact)
+ {
+ TMP_FREE (marker);
+ return 1;
+ }
+ if (mpz_cmp_ui (q, SMALLEST_OMITTED_PRIME) < 0)
+ {
+ TMP_FREE (marker);
+ return 0;
+ }
+ }
+
+ TMP_FREE (marker);
+ return 0;
+ }
+
+n2prime:
+ exact = mpz_root (NULL, u2, n2);
+ TMP_FREE (marker);
+ return exact;
+}
+
+static unsigned long int
+#if __STDC__
+gcd (unsigned long int a, unsigned long int b)
+#else
+gcd (a, b)
+ unsigned long int a, b;
+#endif
+{
+ int an2, bn2, n2;
+
+ if (a == 0)
+ return b;
+ if (b == 0)
+ return a;
+
+ count_trailing_zeros (an2, a);
+ a >>= an2;
+
+ count_trailing_zeros (bn2, b);
+ b >>= bn2;
+
+ n2 = MIN (an2, bn2);
+
+ while (a != b)
+ {
+ if (a > b)
+ {
+ a -= b;
+ do
+ a >>= 1;
+ while ((a & 1) == 0);
+ }
+ else /* b > a. */
+ {
+ b -= a;
+ do
+ b >>= 1;
+ while ((b & 1) == 0);
+ }
+ }
+
+ return a << n2;
+}
+
+static int
+#if __STDC__
+isprime (unsigned long int t)
+#else
+isprime (t)
+ unsigned long int t;
+#endif
+{
+ unsigned long int q, r, d;
+
+ if (t < 3 || (t & 1) == 0)
+ return t == 2;
+
+ for (d = 3, r = 1; r != 0; d += 2)
+ {
+ q = t / d;
+ r = t - q * d;
+ if (q < d)
+ return 1;
+ }
+ return 0;
+}
diff --git a/rts/gmp/mpz/perfsqr.c b/rts/gmp/mpz/perfsqr.c
new file mode 100644
index 0000000000..92e8d08ea9
--- /dev/null
+++ b/rts/gmp/mpz/perfsqr.c
@@ -0,0 +1,45 @@
+/* mpz_perfect_square_p(arg) -- Return non-zero if ARG is a perfect square,
+ zero otherwise.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_perfect_square_p (mpz_srcptr a)
+#else
+mpz_perfect_square_p (a)
+ mpz_srcptr a;
+#endif
+{
+ mp_size_t asize = a->_mp_size;
+
+ /* No negative numbers are perfect squares. */
+ if (asize < 0)
+ return 0;
+
+ /* Zero is a perfect square. */
+ if (asize == 0)
+ return 1;
+
+ return mpn_perfect_square_p (a->_mp_d, asize);
+}
diff --git a/rts/gmp/mpz/popcount.c b/rts/gmp/mpz/popcount.c
new file mode 100644
index 0000000000..3105258e26
--- /dev/null
+++ b/rts/gmp/mpz/popcount.c
@@ -0,0 +1,42 @@
+/* mpz_popcount(mpz_ptr op) -- Population count of OP. If the operand is
+ negative, return ~0 (a novel representation of infinity).
+
+Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_popcount (mpz_srcptr u)
+#else
+mpz_popcount (u)
+ mpz_srcptr u;
+#endif
+{
+ mp_size_t usize;
+
+ usize = u->_mp_size;
+
+ if ((usize) < 0)
+ return ~ (unsigned long int) 0;
+
+ return mpn_popcount (u->_mp_d, usize);
+}
diff --git a/rts/gmp/mpz/pow_ui.c b/rts/gmp/mpz/pow_ui.c
new file mode 100644
index 0000000000..96ca114e4d
--- /dev/null
+++ b/rts/gmp/mpz/pow_ui.c
@@ -0,0 +1,129 @@
+/* mpz_pow_ui(res, base, exp) -- Set RES to BASE**EXP.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_pow_ui (mpz_ptr r, mpz_srcptr b, unsigned long int e)
+#else
+mpz_pow_ui (r, b, e)
+ mpz_ptr r;
+ mpz_srcptr b;
+ unsigned long int e;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+rpow (const MINT *b, signed short int e, MINT *r)
+#else
+rpow (b, e, r)
+ const MINT *b;
+ signed short int e;
+ MINT *r;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_ptr rp, bp, tp, xp;
+ mp_size_t ralloc, rsize, bsize;
+ int cnt, i;
+ mp_limb_t blimb;
+ TMP_DECL (marker);
+
+ bsize = ABS (b->_mp_size);
+
+ /* Single out cases that give result == 0 or 1. These tests are here
+ to simplify the general code below, not to optimize. */
+ if (e == 0)
+ {
+ r->_mp_d[0] = 1;
+ r->_mp_size = 1;
+ return;
+ }
+ if (bsize == 0
+#ifdef BERKELEY_MP
+ || e < 0
+#endif
+ )
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ bp = b->_mp_d;
+
+ blimb = bp[bsize - 1];
+ if (bsize == 1 && blimb < 0x100)
+ {
+ /* Estimate space requirements accurately. Using the code from the
+ `else' path would over-estimate space requirements wildly. */
+ float lb = __mp_bases[blimb].chars_per_bit_exactly;
+ ralloc = 3 + ((mp_size_t) (e / lb) / BITS_PER_MP_LIMB);
+ }
+ else
+ {
+ /* Over-estimate space requirements somewhat. */
+ count_leading_zeros (cnt, blimb);
+ ralloc = bsize * e - cnt * e / BITS_PER_MP_LIMB + 2;
+ }
+
+ TMP_MARK (marker);
+
+ /* The two areas are used to alternatingly hold the input and recieve the
+ product for mpn_mul. (This scheme is used to fulfill the requirements
+ of mpn_mul; that the product space may not be the same as any of the
+ input operands.) */
+ rp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
+ tp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
+
+ MPN_COPY (rp, bp, bsize);
+ rsize = bsize;
+ count_leading_zeros (cnt, e);
+
+ for (i = BITS_PER_MP_LIMB - cnt - 2; i >= 0; i--)
+ {
+ mpn_mul_n (tp, rp, rp, rsize);
+ rsize = 2 * rsize;
+ rsize -= tp[rsize - 1] == 0;
+ xp = tp; tp = rp; rp = xp;
+
+ if ((e & ((mp_limb_t) 1 << i)) != 0)
+ {
+ rsize = rsize + bsize - (mpn_mul (tp, rp, rsize, bp, bsize) == 0);
+ xp = tp; tp = rp; rp = xp;
+ }
+ }
+
+ /* Now then we know the exact space requirements, reallocate if
+ necessary. */
+ if (r->_mp_alloc < rsize)
+ _mpz_realloc (r, rsize);
+
+ MPN_COPY (r->_mp_d, rp, rsize);
+ r->_mp_size = (e & 1) == 0 || b->_mp_size >= 0 ? rsize : -rsize;
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/powm.c b/rts/gmp/mpz/powm.c
new file mode 100644
index 0000000000..e6af855a71
--- /dev/null
+++ b/rts/gmp/mpz/powm.c
@@ -0,0 +1,364 @@
+/* mpz_powm(res,base,exp,mod) -- Set RES to (base**exp) mod MOD.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation, Inc.
+Contributed by Paul Zimmermann.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+
+/* set c <- (a*b)/R^n mod m c has to have at least (2n) allocated limbs */
+static void
+#if __STDC__
+mpz_redc (mpz_ptr c, mpz_srcptr a, mpz_srcptr b, mpz_srcptr m, mp_limb_t Nprim)
+#else
+mpz_redc (c, a, b, m, Nprim)
+ mpz_ptr c;
+ mpz_srcptr a;
+ mpz_srcptr b;
+ mpz_srcptr m;
+ mp_limb_t Nprim;
+#endif
+{
+ mp_ptr cp, mp = PTR (m);
+ mp_limb_t cy, cout = 0;
+ mp_limb_t q;
+ size_t j, n = ABSIZ (m);
+
+ ASSERT (ALLOC (c) >= 2 * n);
+
+ mpz_mul (c, a, b);
+ cp = PTR (c);
+ j = ABSIZ (c);
+ MPN_ZERO (cp + j, 2 * n - j);
+ for (j = 0; j < n; j++)
+ {
+ q = cp[0] * Nprim;
+ cy = mpn_addmul_1 (cp, mp, n, q);
+ cout += mpn_add_1 (cp + n, cp + n, n - j, cy);
+ cp++;
+ }
+ cp -= n;
+ if (cout)
+ {
+ cy = cout - mpn_sub_n (cp, cp + n, mp, n);
+ while (cy)
+ cy -= mpn_sub_n (cp, cp, mp, n);
+ }
+ else
+ MPN_COPY (cp, cp + n, n);
+ MPN_NORMALIZE (cp, n);
+ SIZ (c) = SIZ (c) < 0 ? -n : n;
+}
+
+/* average number of calls to redc for an exponent of n bits
+ with the sliding window algorithm of base 2^k: the optimal is
+ obtained for the value of k which minimizes 2^(k-1)+n/(k+1):
+
+ n\k 4 5 6 7 8
+ 128 156* 159 171 200 261
+ 256 309 307* 316 343 403
+ 512 617 607* 610 632 688
+ 1024 1231 1204 1195* 1207 1256
+ 2048 2461 2399 2366 2360* 2396
+ 4096 4918 4787 4707 4665* 4670
+*/
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_powm (mpz_ptr res, mpz_srcptr base, mpz_srcptr e, mpz_srcptr mod)
+#else
+mpz_powm (res, base, e, mod)
+ mpz_ptr res;
+ mpz_srcptr base;
+ mpz_srcptr e;
+ mpz_srcptr mod;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+pow (mpz_srcptr base, mpz_srcptr e, mpz_srcptr mod, mpz_ptr res)
+#else
+pow (base, e, mod, res)
+ mpz_srcptr base;
+ mpz_srcptr e;
+ mpz_srcptr mod;
+ mpz_ptr res;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_limb_t invm, *ep, c, mask;
+ mpz_t xx, *g;
+ mp_size_t n, i, K, j, l, k;
+ int sh;
+ int use_redc;
+
+#ifdef POWM_DEBUG
+ mpz_t exp;
+ mpz_init (exp);
+#endif
+
+ n = ABSIZ (mod);
+
+ if (n == 0)
+ DIVIDE_BY_ZERO;
+
+ if (SIZ (e) == 0)
+ {
+ /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
+ depending on if MOD equals 1. */
+ SIZ(res) = (ABSIZ (mod) == 1 && (PTR(mod))[0] == 1) ? 0 : 1;
+ PTR(res)[0] = 1;
+ return;
+ }
+
+ /* Use REDC instead of usual reduction for sizes < POWM_THRESHOLD.
+ In REDC each modular multiplication costs about 2*n^2 limbs operations,
+ whereas using usual reduction it costs 3*K(n), where K(n) is the cost of a
+ multiplication using Karatsuba, and a division is assumed to cost 2*K(n),
+ for example using Burnikel-Ziegler's algorithm. This gives a theoretical
+ threshold of a*KARATSUBA_SQR_THRESHOLD, with a=(3/2)^(1/(2-ln(3)/ln(2))) ~
+ 2.66. */
+ /* For now, also disable REDC when MOD is even, as the inverse can't
+ handle that. */
+
+#ifndef POWM_THRESHOLD
+#define POWM_THRESHOLD ((8 * KARATSUBA_SQR_THRESHOLD) / 3)
+#endif
+
+ use_redc = (n < POWM_THRESHOLD && PTR(mod)[0] % 2 != 0);
+ if (use_redc)
+ {
+ /* invm = -1/m mod 2^BITS_PER_MP_LIMB, must have m odd */
+ modlimb_invert (invm, PTR(mod)[0]);
+ invm = -invm;
+ }
+
+ /* determines optimal value of k */
+ l = ABSIZ (e) * BITS_PER_MP_LIMB; /* number of bits of exponent */
+ k = 1;
+ K = 2;
+ while (2 * l > K * (2 + k * (3 + k)))
+ {
+ k++;
+ K *= 2;
+ }
+
+ g = (mpz_t *) (*_mp_allocate_func) (K / 2 * sizeof (mpz_t));
+ /* compute x*R^n where R=2^BITS_PER_MP_LIMB */
+ mpz_init (g[0]);
+ if (use_redc)
+ {
+ mpz_mul_2exp (g[0], base, n * BITS_PER_MP_LIMB);
+ mpz_mod (g[0], g[0], mod);
+ }
+ else
+ mpz_mod (g[0], base, mod);
+
+ /* compute xx^g for odd g < 2^k */
+ mpz_init (xx);
+ if (use_redc)
+ {
+ _mpz_realloc (xx, 2 * n);
+ mpz_redc (xx, g[0], g[0], mod, invm); /* xx = x^2*R^n */
+ }
+ else
+ {
+ mpz_mul (xx, g[0], g[0]);
+ mpz_mod (xx, xx, mod);
+ }
+ for (i = 1; i < K / 2; i++)
+ {
+ mpz_init (g[i]);
+ if (use_redc)
+ {
+ _mpz_realloc (g[i], 2 * n);
+ mpz_redc (g[i], g[i - 1], xx, mod, invm); /* g[i] = x^(2i+1)*R^n */
+ }
+ else
+ {
+ mpz_mul (g[i], g[i - 1], xx);
+ mpz_mod (g[i], g[i], mod);
+ }
+ }
+
+ /* now starts the real stuff */
+ mask = (mp_limb_t) ((1<<k) - 1);
+ ep = PTR (e);
+ i = ABSIZ (e) - 1; /* current index */
+ c = ep[i]; /* current limb */
+ count_leading_zeros (sh, c);
+ sh = BITS_PER_MP_LIMB - sh; /* significant bits in ep[i] */
+ sh -= k; /* index of lower bit of ep[i] to take into account */
+ if (sh < 0)
+ { /* k-sh extra bits are needed */
+ if (i > 0)
+ {
+ i--;
+ c = (c << (-sh)) | (ep[i] >> (BITS_PER_MP_LIMB + sh));
+ sh += BITS_PER_MP_LIMB;
+ }
+ }
+ else
+ c = c >> sh;
+#ifdef POWM_DEBUG
+ printf ("-1/m mod 2^%u = %lu\n", BITS_PER_MP_LIMB, invm);
+ mpz_set_ui (exp, c);
+#endif
+ j=0;
+ while (c % 2 == 0)
+ {
+ j++;
+ c = (c >> 1);
+ }
+ mpz_set (xx, g[c >> 1]);
+ while (j--)
+ {
+ if (use_redc)
+ mpz_redc (xx, xx, xx, mod, invm);
+ else
+ {
+ mpz_mul (xx, xx, xx);
+ mpz_mod (xx, xx, mod);
+ }
+ }
+
+#ifdef POWM_DEBUG
+ printf ("x^"); mpz_out_str (0, 10, exp);
+ printf ("*2^%u mod m = ", n * BITS_PER_MP_LIMB); mpz_out_str (0, 10, xx);
+ putchar ('\n');
+#endif
+
+ while (i > 0 || sh > 0)
+ {
+ c = ep[i];
+ sh -= k;
+ l = k; /* number of bits treated */
+ if (sh < 0)
+ {
+ if (i > 0)
+ {
+ i--;
+ c = (c << (-sh)) | (ep[i] >> (BITS_PER_MP_LIMB + sh));
+ sh += BITS_PER_MP_LIMB;
+ }
+ else
+ {
+ l += sh; /* may be less bits than k here */
+ c = c & ((1<<l) - 1);
+ }
+ }
+ else
+ c = c >> sh;
+ c = c & mask;
+
+ /* this while loop implements the sliding window improvement */
+ while ((c & (1 << (k - 1))) == 0 && (i > 0 || sh > 0))
+ {
+ if (use_redc) mpz_redc (xx, xx, xx, mod, invm);
+ else
+ {
+ mpz_mul (xx, xx, xx);
+ mpz_mod (xx, xx, mod);
+ }
+ if (sh)
+ {
+ sh--;
+ c = (c<<1) + ((ep[i]>>sh) & 1);
+ }
+ else
+ {
+ i--;
+ sh = BITS_PER_MP_LIMB - 1;
+ c = (c<<1) + (ep[i]>>sh);
+ }
+ }
+
+#ifdef POWM_DEBUG
+ printf ("l=%u c=%lu\n", l, c);
+ mpz_mul_2exp (exp, exp, k);
+ mpz_add_ui (exp, exp, c);
+#endif
+
+ /* now replace xx by xx^(2^k)*x^c */
+ if (c != 0)
+ {
+ j = 0;
+ while (c % 2 == 0)
+ {
+ j++;
+ c = c >> 1;
+ }
+ /* c0 = c * 2^j, i.e. xx^(2^k)*x^c = (A^(2^(k - j))*c)^(2^j) */
+ l -= j;
+ while (l--)
+ if (use_redc) mpz_redc (xx, xx, xx, mod, invm);
+ else
+ {
+ mpz_mul (xx, xx, xx);
+ mpz_mod (xx, xx, mod);
+ }
+ if (use_redc)
+ mpz_redc (xx, xx, g[c >> 1], mod, invm);
+ else
+ {
+ mpz_mul (xx, xx, g[c >> 1]);
+ mpz_mod (xx, xx, mod);
+ }
+ }
+ else
+ j = l; /* case c=0 */
+ while (j--)
+ {
+ if (use_redc)
+ mpz_redc (xx, xx, xx, mod, invm);
+ else
+ {
+ mpz_mul (xx, xx, xx);
+ mpz_mod (xx, xx, mod);
+ }
+ }
+#ifdef POWM_DEBUG
+ printf ("x^"); mpz_out_str (0, 10, exp);
+ printf ("*2^%u mod m = ", n * BITS_PER_MP_LIMB); mpz_out_str (0, 10, xx);
+ putchar ('\n');
+#endif
+ }
+
+ /* now convert back xx to xx/R^n */
+ if (use_redc)
+ {
+ mpz_set_ui (g[0], 1);
+ mpz_redc (xx, xx, g[0], mod, invm);
+ if (mpz_cmp (xx, mod) >= 0)
+ mpz_sub (xx, xx, mod);
+ }
+ mpz_set (res, xx);
+
+ mpz_clear (xx);
+ for (i = 0; i < K / 2; i++)
+ mpz_clear (g[i]);
+ (*_mp_free_func) (g, K / 2 * sizeof (mpz_t));
+}
diff --git a/rts/gmp/mpz/powm_ui.c b/rts/gmp/mpz/powm_ui.c
new file mode 100644
index 0000000000..00f70bd563
--- /dev/null
+++ b/rts/gmp/mpz/powm_ui.c
@@ -0,0 +1,248 @@
+/* mpz_powm_ui(res,base,exp,mod) -- Set RES to (base**exp) mod MOD.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+#if __STDC__
+mpz_powm_ui (mpz_ptr res, mpz_srcptr base, unsigned long int exp, mpz_srcptr mod)
+#else
+mpz_powm_ui (res, base, exp, mod)
+ mpz_ptr res;
+ mpz_srcptr base;
+ unsigned long int exp;
+ mpz_srcptr mod;
+#endif
+{
+ mp_ptr rp, mp, bp;
+ mp_size_t msize, bsize, rsize;
+ mp_size_t size;
+ int mod_shift_cnt;
+ int negative_result;
+ mp_limb_t *free_me = NULL;
+ size_t free_me_size;
+ TMP_DECL (marker);
+
+ msize = ABS (mod->_mp_size);
+ size = 2 * msize;
+
+ rp = res->_mp_d;
+
+ if (msize == 0)
+ DIVIDE_BY_ZERO;
+
+ if (exp == 0)
+ {
+ /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
+ depending on if MOD equals 1. */
+ res->_mp_size = (msize == 1 && (mod->_mp_d)[0] == 1) ? 0 : 1;
+ rp[0] = 1;
+ return;
+ }
+
+ TMP_MARK (marker);
+
+ /* Normalize MOD (i.e. make its most significant bit set) as required by
+ mpn_divmod. This will make the intermediate values in the calculation
+ slightly larger, but the correct result is obtained after a final
+ reduction using the original MOD value. */
+
+ mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
+ count_leading_zeros (mod_shift_cnt, mod->_mp_d[msize - 1]);
+ if (mod_shift_cnt != 0)
+ mpn_lshift (mp, mod->_mp_d, msize, mod_shift_cnt);
+ else
+ MPN_COPY (mp, mod->_mp_d, msize);
+
+ bsize = ABS (base->_mp_size);
+ if (bsize > msize)
+ {
+ /* The base is larger than the module. Reduce it. */
+
+ /* Allocate (BSIZE + 1) with space for remainder and quotient.
+ (The quotient is (bsize - msize + 1) limbs.) */
+ bp = (mp_ptr) TMP_ALLOC ((bsize + 1) * BYTES_PER_MP_LIMB);
+ MPN_COPY (bp, base->_mp_d, bsize);
+ /* We don't care about the quotient, store it above the remainder,
+ at BP + MSIZE. */
+ mpn_divmod (bp + msize, bp, bsize, mp, msize);
+ bsize = msize;
+ /* Canonicalize the base, since we are going to multiply with it
+ quite a few times. */
+ MPN_NORMALIZE (bp, bsize);
+ }
+ else
+ bp = base->_mp_d;
+
+ if (bsize == 0)
+ {
+ res->_mp_size = 0;
+ TMP_FREE (marker);
+ return;
+ }
+
+ if (res->_mp_alloc < size)
+ {
+ /* We have to allocate more space for RES. If any of the input
+ parameters are identical to RES, defer deallocation of the old
+ space. */
+
+ if (rp == mp || rp == bp)
+ {
+ free_me = rp;
+ free_me_size = res->_mp_alloc;
+ }
+ else
+ (*_mp_free_func) (rp, res->_mp_alloc * BYTES_PER_MP_LIMB);
+
+ rp = (mp_ptr) (*_mp_allocate_func) (size * BYTES_PER_MP_LIMB);
+ res->_mp_alloc = size;
+ res->_mp_d = rp;
+ }
+ else
+ {
+ /* Make BASE, EXP and MOD not overlap with RES. */
+ if (rp == bp)
+ {
+ /* RES and BASE are identical. Allocate temp. space for BASE. */
+ bp = (mp_ptr) TMP_ALLOC (bsize * BYTES_PER_MP_LIMB);
+ MPN_COPY (bp, rp, bsize);
+ }
+ if (rp == mp)
+ {
+ /* RES and MOD are identical. Allocate temporary space for MOD. */
+ mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
+ MPN_COPY (mp, rp, msize);
+ }
+ }
+
+ MPN_COPY (rp, bp, bsize);
+ rsize = bsize;
+
+ {
+ mp_ptr xp = (mp_ptr) TMP_ALLOC (2 * (msize + 1) * BYTES_PER_MP_LIMB);
+ int c;
+ mp_limb_t e;
+ mp_limb_t carry_limb;
+
+ negative_result = (exp & 1) && base->_mp_size < 0;
+
+ e = exp;
+ count_leading_zeros (c, e);
+ e = (e << c) << 1; /* shift the exp bits to the left, lose msb */
+ c = BITS_PER_MP_LIMB - 1 - c;
+
+ /* Main loop.
+
+ Make the result be pointed to alternately by XP and RP. This
+ helps us avoid block copying, which would otherwise be necessary
+ with the overlap restrictions of mpn_divmod. With 50% probability
+ the result after this loop will be in the area originally pointed
+ by RP (==RES->_mp_d), and with 50% probability in the area originally
+ pointed to by XP. */
+
+ while (c != 0)
+ {
+ mp_ptr tp;
+ mp_size_t xsize;
+
+ mpn_mul_n (xp, rp, rp, rsize);
+ xsize = 2 * rsize;
+ xsize -= xp[xsize - 1] == 0;
+ if (xsize > msize)
+ {
+ mpn_divmod (xp + msize, xp, xsize, mp, msize);
+ xsize = msize;
+ }
+
+ tp = rp; rp = xp; xp = tp;
+ rsize = xsize;
+
+ if ((mp_limb_signed_t) e < 0)
+ {
+ mpn_mul (xp, rp, rsize, bp, bsize);
+ xsize = rsize + bsize;
+ xsize -= xp[xsize - 1] == 0;
+ if (xsize > msize)
+ {
+ mpn_divmod (xp + msize, xp, xsize, mp, msize);
+ xsize = msize;
+ }
+
+ tp = rp; rp = xp; xp = tp;
+ rsize = xsize;
+ }
+ e <<= 1;
+ c--;
+ }
+
+ /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
+ steps. Adjust the result by reducing it with the original MOD.
+
+ Also make sure the result is put in RES->_mp_d (where it already
+ might be, see above). */
+
+ if (mod_shift_cnt != 0)
+ {
+ carry_limb = mpn_lshift (res->_mp_d, rp, rsize, mod_shift_cnt);
+ rp = res->_mp_d;
+ if (carry_limb != 0)
+ {
+ rp[rsize] = carry_limb;
+ rsize++;
+ }
+ }
+ else
+ {
+ MPN_COPY (res->_mp_d, rp, rsize);
+ rp = res->_mp_d;
+ }
+
+ if (rsize >= msize)
+ {
+ mpn_divmod (rp + msize, rp, rsize, mp, msize);
+ rsize = msize;
+ }
+
+ /* Remove any leading zero words from the result. */
+ if (mod_shift_cnt != 0)
+ mpn_rshift (rp, rp, rsize, mod_shift_cnt);
+ MPN_NORMALIZE (rp, rsize);
+ }
+
+ if (negative_result && rsize != 0)
+ {
+ if (mod_shift_cnt != 0)
+ mpn_rshift (mp, mp, msize, mod_shift_cnt);
+ mpn_sub (rp, mp, msize, rp, rsize);
+ rsize = msize;
+ MPN_NORMALIZE (rp, rsize);
+ }
+ res->_mp_size = rsize;
+
+ if (free_me != NULL)
+ (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/pprime_p.c b/rts/gmp/mpz/pprime_p.c
new file mode 100644
index 0000000000..82eb678238
--- /dev/null
+++ b/rts/gmp/mpz/pprime_p.c
@@ -0,0 +1,242 @@
+/* mpz_probab_prime_p --
+ An implementation of the probabilistic primality test found in Knuth's
+ Seminumerical Algorithms book. If the function mpz_probab_prime_p()
+ returns 0 then n is not prime. If it returns 1, then n is 'probably'
+ prime. If it returns 2, n is surely prime. The probability of a false
+ positive is (1/4)**reps, where reps is the number of internal passes of the
+ probabilistic algorithm. Knuth indicates that 25 passes are reasonable.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 1998, 1999, 2000 Free Software
+Foundation, Inc. Miller-Rabin code contributed by John Amanatides.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static int isprime _PROTO ((unsigned long int t));
+static int mpz_millerrabin _PROTO ((mpz_srcptr n, int reps));
+
+int
+#if __STDC__
+mpz_probab_prime_p (mpz_srcptr n, int reps)
+#else
+mpz_probab_prime_p (n, reps)
+ mpz_srcptr n;
+ int reps;
+#endif
+{
+ mp_limb_t r;
+
+ /* Handle small and negative n. */
+ if (mpz_cmp_ui (n, 1000000L) <= 0)
+ {
+ int is_prime;
+ if (mpz_sgn (n) < 0)
+ {
+ /* Negative number. Negate and call ourselves. */
+ mpz_t n2;
+ mpz_init (n2);
+ mpz_neg (n2, n);
+ is_prime = mpz_probab_prime_p (n2, reps);
+ mpz_clear (n2);
+ return is_prime;
+ }
+ is_prime = isprime (mpz_get_ui (n));
+ return is_prime ? 2 : 0;
+ }
+
+ /* If n is now even, it is not a prime. */
+ if ((mpz_get_ui (n) & 1) == 0)
+ return 0;
+
+ /* Check if n has small factors. */
+ if (UDIV_TIME > (2 * UMUL_TIME + 6))
+ r = mpn_preinv_mod_1 (PTR(n), SIZ(n), (mp_limb_t) PP, (mp_limb_t) PP_INVERTED);
+ else
+ r = mpn_mod_1 (PTR(n), SIZ(n), (mp_limb_t) PP);
+ if (r % 3 == 0 || r % 5 == 0 || r % 7 == 0 || r % 11 == 0 || r % 13 == 0
+ || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0
+#if BITS_PER_MP_LIMB == 64
+ || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0
+ || r % 47 == 0 || r % 53 == 0
+#endif
+ )
+ {
+ return 0;
+ }
+
+ /* Do more dividing. We collect small primes, using umul_ppmm, until we
+ overflow a single limb. We divide our number by the small primes product,
+ and look for factors in the remainder. */
+ {
+ unsigned long int ln2;
+ unsigned long int q;
+ mp_limb_t p1, p0, p;
+ unsigned int primes[15];
+ int nprimes;
+
+ nprimes = 0;
+ p = 1;
+ ln2 = mpz_sizeinbase (n, 2) / 30; ln2 = ln2 * ln2;
+ for (q = BITS_PER_MP_LIMB == 64 ? 59 : 31; q < ln2; q += 2)
+ {
+ if (isprime (q))
+ {
+ umul_ppmm (p1, p0, p, q);
+ if (p1 != 0)
+ {
+ r = mpn_mod_1 (PTR(n), SIZ(n), p);
+ while (--nprimes >= 0)
+ if (r % primes[nprimes] == 0)
+ {
+ if (mpn_mod_1 (PTR(n), SIZ(n), (mp_limb_t) primes[nprimes]) != 0)
+ abort ();
+ return 0;
+ }
+ p = q;
+ nprimes = 0;
+ }
+ else
+ {
+ p = p0;
+ }
+ primes[nprimes++] = q;
+ }
+ }
+ }
+
+ /* Perform a number of Miller-Rabin tests. */
+ return mpz_millerrabin (n, reps);
+}
+
+static int
+#if __STDC__
+isprime (unsigned long int t)
+#else
+isprime (t)
+ unsigned long int t;
+#endif
+{
+ unsigned long int q, r, d;
+
+ if (t < 3 || (t & 1) == 0)
+ return t == 2;
+
+ for (d = 3, r = 1; r != 0; d += 2)
+ {
+ q = t / d;
+ r = t - q * d;
+ if (q < d)
+ return 1;
+ }
+ return 0;
+}
+
+static int millerrabin _PROTO ((mpz_srcptr n, mpz_srcptr nm1,
+ mpz_ptr x, mpz_ptr y,
+ mpz_srcptr q, unsigned long int k));
+
+static int
+#if __STDC__
+mpz_millerrabin (mpz_srcptr n, int reps)
+#else
+mpz_millerrabin (n, reps)
+ mpz_srcptr n;
+ int reps;
+#endif
+{
+ int r;
+ mpz_t nm1, x, y, q;
+ unsigned long int k;
+ gmp_randstate_t rstate;
+ int is_prime;
+ TMP_DECL (marker);
+ TMP_MARK (marker);
+
+ MPZ_TMP_INIT (nm1, SIZ (n) + 1);
+ mpz_sub_ui (nm1, n, 1L);
+
+ MPZ_TMP_INIT (x, SIZ (n));
+ MPZ_TMP_INIT (y, 2 * SIZ (n)); /* mpz_powm_ui needs excessive memory!!! */
+
+ /* Perform a Fermat test. */
+ mpz_set_ui (x, 210L);
+ mpz_powm (y, x, nm1, n);
+ if (mpz_cmp_ui (y, 1L) != 0)
+ {
+ TMP_FREE (marker);
+ return 0;
+ }
+
+ MPZ_TMP_INIT (q, SIZ (n));
+
+ /* Find q and k, where q is odd and n = 1 + 2**k * q. */
+ k = mpz_scan1 (nm1, 0L);
+ mpz_tdiv_q_2exp (q, nm1, k);
+
+ gmp_randinit (rstate, GMP_RAND_ALG_DEFAULT, 32L);
+
+ is_prime = 1;
+ for (r = 0; r < reps && is_prime; r++)
+ {
+ do
+ mpz_urandomb (x, rstate, mpz_sizeinbase (n, 2) - 1);
+ while (mpz_cmp_ui (x, 1L) <= 0);
+
+ is_prime = millerrabin (n, nm1, x, y, q, k);
+ }
+
+ gmp_randclear (rstate);
+
+ TMP_FREE (marker);
+ return is_prime;
+}
+
+static int
+#if __STDC__
+millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,
+ mpz_srcptr q, unsigned long int k)
+#else
+millerrabin (n, nm1, x, y, q, k)
+ mpz_srcptr n;
+ mpz_srcptr nm1;
+ mpz_ptr x;
+ mpz_ptr y;
+ mpz_srcptr q;
+ unsigned long int k;
+#endif
+{
+ unsigned long int i;
+
+ mpz_powm (y, x, q, n);
+
+ if (mpz_cmp_ui (y, 1L) == 0 || mpz_cmp (y, nm1) == 0)
+ return 1;
+
+ for (i = 1; i < k; i++)
+ {
+ mpz_powm_ui (y, y, 2L, n);
+ if (mpz_cmp (y, nm1) == 0)
+ return 1;
+ if (mpz_cmp_ui (y, 1L) == 0)
+ return 0;
+ }
+ return 0;
+}
diff --git a/rts/gmp/mpz/random.c b/rts/gmp/mpz/random.c
new file mode 100644
index 0000000000..60d9113991
--- /dev/null
+++ b/rts/gmp/mpz/random.c
@@ -0,0 +1,56 @@
+/* mpz_random -- Generate a random mpz_t of specified size.
+ This function is non-portable and generates poor random numbers.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "urandom.h"
+
+void
+#if __STDC__
+mpz_random (mpz_ptr x, mp_size_t size)
+#else
+mpz_random (x, size)
+ mpz_ptr x;
+ mp_size_t size;
+#endif
+{
+ mp_size_t i;
+ mp_limb_t ran;
+ mp_ptr xp;
+ mp_size_t abs_size;
+
+ abs_size = ABS (size);
+
+ if (x->_mp_alloc < abs_size)
+ _mpz_realloc (x, abs_size);
+
+ xp = x->_mp_d;
+
+ for (i = 0; i < abs_size; i++)
+ {
+ ran = urandom ();
+ xp[i] = ran;
+ }
+
+ MPN_NORMALIZE (xp, abs_size);
+ x->_mp_size = size < 0 ? -abs_size : abs_size;
+}
diff --git a/rts/gmp/mpz/random2.c b/rts/gmp/mpz/random2.c
new file mode 100644
index 0000000000..a90af115e9
--- /dev/null
+++ b/rts/gmp/mpz/random2.c
@@ -0,0 +1,48 @@
+/* mpz_random2 -- Generate a positive random mpz_t of specified size, with
+ long runs of consecutive ones and zeros in the binary representation.
+ Meant for testing of other MP routines.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_random2 (mpz_ptr x, mp_size_t size)
+#else
+mpz_random2 (x, size)
+ mpz_ptr x;
+ mp_size_t size;
+#endif
+{
+ mp_size_t abs_size;
+
+ abs_size = ABS (size);
+ if (abs_size != 0)
+ {
+ if (x->_mp_alloc < abs_size)
+ _mpz_realloc (x, abs_size);
+
+ mpn_random2 (x->_mp_d, abs_size);
+ }
+
+ x->_mp_size = size;
+}
diff --git a/rts/gmp/mpz/realloc.c b/rts/gmp/mpz/realloc.c
new file mode 100644
index 0000000000..0b9e447ec3
--- /dev/null
+++ b/rts/gmp/mpz/realloc.c
@@ -0,0 +1,52 @@
+/* _mpz_realloc -- make the mpz_t have NEW_SIZE digits allocated.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void *
+#if __STDC__
+_mpz_realloc (mpz_ptr m, mp_size_t new_size)
+#else
+_mpz_realloc (m, new_size)
+ mpz_ptr m;
+ mp_size_t new_size;
+#endif
+{
+ /* Never allocate zero space. */
+ if (new_size == 0)
+ new_size = 1;
+
+ m->_mp_d = (mp_ptr) (*_mp_reallocate_func) (m->_mp_d,
+ m->_mp_alloc * BYTES_PER_MP_LIMB,
+ new_size * BYTES_PER_MP_LIMB);
+ m->_mp_alloc = new_size;
+
+#if 0
+ /* This might break some code that reads the size field after
+ reallocation, in the case the reallocated destination and a
+ source argument are identical. */
+ if (ABS (m->_mp_size) > new_size)
+ m->_mp_size = 0;
+#endif
+
+ return (void *) m->_mp_d;
+}
diff --git a/rts/gmp/mpz/remove.c b/rts/gmp/mpz/remove.c
new file mode 100644
index 0000000000..bc6675f972
--- /dev/null
+++ b/rts/gmp/mpz/remove.c
@@ -0,0 +1,93 @@
+/* mpz_remove -- divide out a factor and return its multiplicity.
+
+Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_remove (mpz_ptr dest, mpz_srcptr src, mpz_srcptr f)
+#else
+mpz_remove (dest, src, f)
+ mpz_ptr dest;
+ mpz_srcptr src;
+ mpz_srcptr f;
+#endif
+{
+ mpz_t fpow[40]; /* inexhaustible...until year 2020 or so */
+ mpz_t x, rem;
+ unsigned long int pwr;
+ int p;
+
+ if (mpz_cmp_ui (f, 1) <= 0 || mpz_sgn (src) == 0)
+ DIVIDE_BY_ZERO;
+ if (mpz_cmp_ui (f, 2) == 0)
+ {
+ unsigned long int s0;
+ s0 = mpz_scan1 (src, 0);
+ mpz_div_2exp (dest, src, s0);
+ return s0;
+ }
+
+ /* We could perhaps compute mpz_scan1(src,0)/mpz_scan1(f,0). It is an
+ upper bound of the result we're seeking. We could also shift down the
+ operands so that they become odd, to make intermediate values smaller. */
+
+ mpz_init (rem);
+ mpz_init (x);
+
+ pwr = 0;
+ mpz_init (fpow[0]);
+ mpz_set (fpow[0], f);
+ mpz_set (dest, src);
+
+ /* Divide by f, f^2, ..., f^(2^k) until we get a remainder for f^(2^k). */
+ for (p = 0;; p++)
+ {
+ mpz_tdiv_qr (x, rem, dest, fpow[p]);
+ if (SIZ (rem) != 0)
+ break;
+ mpz_init (fpow[p + 1]);
+ mpz_mul (fpow[p + 1], fpow[p], fpow[p]);
+ mpz_set (dest, x);
+ }
+
+ pwr = (1 << p) - 1;
+
+ mpz_clear (fpow[p]);
+
+ /* Divide by f^(2^(k-1)), f^(2^(k-2)), ..., f for all divisors that give a
+ zero remainder. */
+ while (--p >= 0)
+ {
+ mpz_tdiv_qr (x, rem, dest, fpow[p]);
+ if (SIZ (rem) == 0)
+ {
+ pwr += 1 << p;
+ mpz_set (dest, x);
+ }
+ mpz_clear (fpow[p]);
+ }
+
+ mpz_clear (x);
+ mpz_clear (rem);
+ return pwr;
+}
diff --git a/rts/gmp/mpz/root.c b/rts/gmp/mpz/root.c
new file mode 100644
index 0000000000..0920bf22d3
--- /dev/null
+++ b/rts/gmp/mpz/root.c
@@ -0,0 +1,183 @@
+/* mpz_root(root, u, nth) -- Set ROOT to floor(U^(1/nth)).
+ Return an indication if the result is exact.
+
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+/* Naive implementation of nth root extraction. It would probably be a
+ better idea to use a division-free Newton iteration. It is insane
+ to use full precision from iteration 1. The mpz_scan1 trick compensates
+ to some extent. It would be natural to avoid representing the low zero
+ bits mpz_scan1 is counting, and at the same time call mpn directly. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+int
+#if __STDC__
+mpz_root (mpz_ptr r, mpz_srcptr c, unsigned long int nth)
+#else
+mpz_root (r, c, nth)
+ mpz_ptr r;
+ mpz_srcptr c;
+ unsigned long int nth;
+#endif
+{
+ mpz_t x, t0, t1, t2;
+ __mpz_struct ccs, *cc = &ccs;
+ unsigned long int nbits;
+ int bit;
+ int exact;
+ int i;
+ unsigned long int lowz;
+ unsigned long int rl;
+
+ /* even roots of negatives provoke an exception */
+ if (mpz_sgn (c) < 0 && (nth & 1) == 0)
+ SQRT_OF_NEGATIVE;
+
+ /* root extraction interpreted as c^(1/nth) means a zeroth root should
+ provoke a divide by zero, do this even if c==0 */
+ if (nth == 0)
+ DIVIDE_BY_ZERO;
+
+ if (mpz_sgn (c) == 0)
+ {
+ if (r != NULL)
+ mpz_set_ui (r, 0);
+ return 1; /* exact result */
+ }
+
+ PTR(cc) = PTR(c);
+ SIZ(cc) = ABSIZ(c);
+
+ nbits = (mpz_sizeinbase (cc, 2) - 1) / nth;
+ if (nbits == 0)
+ {
+ if (r != NULL)
+ mpz_set_ui (r, 1);
+ if (mpz_sgn (c) < 0)
+ {
+ if (r != NULL)
+ SIZ(r) = -SIZ(r);
+ return mpz_cmp_si (c, -1L) == 0;
+ }
+ return mpz_cmp_ui (c, 1L) == 0;
+ }
+
+ mpz_init (x);
+ mpz_init (t0);
+ mpz_init (t1);
+ mpz_init (t2);
+
+ /* Create a one-bit approximation. */
+ mpz_set_ui (x, 0);
+ mpz_setbit (x, nbits);
+
+ /* Make the approximation better, one bit at a time. This odd-looking
+ termination criteria makes large nth get better initial approximation,
+ which avoids slow convergence for such values. */
+ bit = nbits - 1;
+ for (i = 1; (nth >> i) != 0; i++)
+ {
+ mpz_setbit (x, bit);
+ mpz_tdiv_q_2exp (t0, x, bit);
+ mpz_pow_ui (t1, t0, nth);
+ mpz_mul_2exp (t1, t1, bit * nth);
+ if (mpz_cmp (cc, t1) < 0)
+ mpz_clrbit (x, bit);
+
+ bit--; /* check/set next bit */
+ if (bit < 0)
+ {
+ /* We're done. */
+ mpz_pow_ui (t1, x, nth);
+ goto done;
+ }
+ }
+ mpz_setbit (x, bit);
+ mpz_set_ui (t2, 0); mpz_setbit (t2, bit); mpz_add (x, x, t2);
+
+#if DEBUG
+ /* Check that the starting approximation is >= than the root. */
+ mpz_pow_ui (t1, x, nth);
+ if (mpz_cmp (cc, t1) >= 0)
+ abort ();
+#endif
+
+ mpz_add_ui (x, x, 1);
+
+ /* Main loop */
+ do
+ {
+ lowz = mpz_scan1 (x, 0);
+ mpz_tdiv_q_2exp (t0, x, lowz);
+ mpz_pow_ui (t1, t0, nth - 1);
+ mpz_mul_2exp (t1, t1, lowz * (nth - 1));
+ mpz_tdiv_q (t2, cc, t1);
+ mpz_sub (t2, x, t2);
+ rl = mpz_tdiv_q_ui (t2, t2, nth);
+ mpz_sub (x, x, t2);
+ }
+ while (mpz_sgn (t2) != 0);
+
+ /* If we got a non-zero remainder in the last division, we know our root
+ is too large. */
+ mpz_sub_ui (x, x, (mp_limb_t) (rl != 0));
+
+ /* Adjustment loop. If we spend more care on rounding in the loop above,
+ we could probably get rid of this, or greatly simplify it. */
+ {
+ int bad = 0;
+ lowz = mpz_scan1 (x, 0);
+ mpz_tdiv_q_2exp (t0, x, lowz);
+ mpz_pow_ui (t1, t0, nth);
+ mpz_mul_2exp (t1, t1, lowz * nth);
+ while (mpz_cmp (cc, t1) < 0)
+ {
+ bad++;
+ if (bad > 2)
+ abort (); /* abort if our root is far off */
+ mpz_sub_ui (x, x, 1);
+ lowz = mpz_scan1 (x, 0);
+ mpz_tdiv_q_2exp (t0, x, lowz);
+ mpz_pow_ui (t1, t0, nth);
+ mpz_mul_2exp (t1, t1, lowz * nth);
+ }
+ }
+
+ done:
+ exact = mpz_cmp (t1, cc) == 0;
+
+ if (r != NULL)
+ {
+ mpz_set (r, x);
+ if (mpz_sgn (c) < 0)
+ SIZ(r) = -SIZ(r);
+ }
+
+ mpz_clear (t2);
+ mpz_clear (t1);
+ mpz_clear (t0);
+ mpz_clear (x);
+
+ return exact;
+}
diff --git a/rts/gmp/mpz/rrandomb.c b/rts/gmp/mpz/rrandomb.c
new file mode 100644
index 0000000000..7d78243674
--- /dev/null
+++ b/rts/gmp/mpz/rrandomb.c
@@ -0,0 +1,117 @@
+/* mpz_rrandomb -- Generate a positive random mpz_t of specified bit size, with
+ long runs of consecutive ones and zeros in the binary representation.
+ Meant for testing of other MP routines.
+
+Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+static void gmp_rrandomb _PROTO ((mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits));
+
+void
+#if __STDC__
+mpz_rrandomb (mpz_ptr x, gmp_randstate_t rstate, unsigned long int nbits)
+#else
+mpz_rrandomb (x, rstate, nbits)
+ mpz_ptr x;
+ gmp_randstate_t rstate;
+ unsigned long int nbits;
+#endif
+{
+ mp_size_t nl = 0;
+
+ if (nbits != 0)
+ {
+ mp_ptr xp;
+ nl = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
+ if (x->_mp_alloc < nl)
+ _mpz_realloc (x, nl);
+
+ xp = PTR(x);
+ gmp_rrandomb (xp, rstate, nbits);
+ MPN_NORMALIZE (xp, nl);
+ }
+
+ SIZ(x) = nl;
+}
+
+#define BITS_PER_CHUNK 4
+
+static void
+#if __STDC__
+gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, unsigned long int nbits)
+#else
+gmp_rrandomb (rp, rstate, nbits)
+ mp_ptr rp;
+ gmp_randstate_t rstate;
+ unsigned long int nbits;
+#endif
+{
+ int nb;
+ int bit_pos;
+ mp_size_t limb_pos;
+ mp_limb_t ran, ranm;
+ mp_limb_t acc;
+ mp_size_t n;
+
+ bit_pos = nbits % BITS_PER_MP_LIMB;
+ limb_pos = nbits / BITS_PER_MP_LIMB;
+ if (bit_pos == 0)
+ {
+ bit_pos = BITS_PER_MP_LIMB;
+ limb_pos--;
+ }
+
+ acc = 0;
+ while (limb_pos >= 0)
+ {
+ _gmp_rand (&ranm, rstate, BITS_PER_CHUNK + 1);
+ ran = ranm;
+ nb = (ran >> 1) + 1;
+ if ((ran & 1) != 0)
+ {
+ /* Generate a string of ones. */
+ if (nb > bit_pos)
+ {
+ rp[limb_pos--] = acc | ((((mp_limb_t) 1) << bit_pos) - 1);
+ bit_pos += BITS_PER_MP_LIMB;
+ bit_pos -= nb;
+ acc = (~(mp_limb_t) 0) << bit_pos;
+ }
+ else
+ {
+ bit_pos -= nb;
+ acc |= ((((mp_limb_t) 1) << nb) - 1) << bit_pos;
+ }
+ }
+ else
+ {
+ /* Generate a string of zeroes. */
+ if (nb > bit_pos)
+ {
+ rp[limb_pos--] = acc;
+ acc = 0;
+ bit_pos += BITS_PER_MP_LIMB;
+ }
+ bit_pos -= nb;
+ }
+ }
+}
diff --git a/rts/gmp/mpz/scan0.c b/rts/gmp/mpz/scan0.c
new file mode 100644
index 0000000000..6c59cf8939
--- /dev/null
+++ b/rts/gmp/mpz/scan0.c
@@ -0,0 +1,35 @@
+/* mpz_scan0(op, startbit) -- Scan for the next set bit, starting at startbit.
+
+Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_scan0 (mpz_srcptr u, unsigned long int starting_bit)
+#else
+mpz_scan0 (u, starting_bit)
+ mpz_srcptr u;
+ unsigned long int starting_bit;
+#endif
+{
+ return mpn_scan0 (u->_mp_d, starting_bit);
+}
diff --git a/rts/gmp/mpz/scan1.c b/rts/gmp/mpz/scan1.c
new file mode 100644
index 0000000000..3b84e3420c
--- /dev/null
+++ b/rts/gmp/mpz/scan1.c
@@ -0,0 +1,35 @@
+/* mpz_scan1(op, startbit) -- Scan for the next set bit, starting at startbit.
+
+Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_scan1 (mpz_srcptr u, unsigned long int starting_bit)
+#else
+mpz_scan1 (u, starting_bit)
+ mpz_srcptr u;
+ unsigned long int starting_bit;
+#endif
+{
+ return mpn_scan1 (u->_mp_d, starting_bit);
+}
diff --git a/rts/gmp/mpz/set.c b/rts/gmp/mpz/set.c
new file mode 100644
index 0000000000..06b2eef511
--- /dev/null
+++ b/rts/gmp/mpz/set.c
@@ -0,0 +1,48 @@
+/* mpz_set (dest_integer, src_integer) -- Assign DEST_INTEGER from SRC_INTEGER.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_set (mpz_ptr w, mpz_srcptr u)
+#else
+mpz_set (w, u)
+ mpz_ptr w;
+ mpz_srcptr u;
+#endif
+{
+ mp_ptr wp, up;
+ mp_size_t usize, size;
+
+ usize = u->_mp_size;
+ size = ABS (usize);
+
+ if (w->_mp_alloc < size)
+ _mpz_realloc (w, size);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ MPN_COPY (wp, up, size);
+ w->_mp_size = usize;
+}
diff --git a/rts/gmp/mpz/set_d.c b/rts/gmp/mpz/set_d.c
new file mode 100644
index 0000000000..e90ed9bc2f
--- /dev/null
+++ b/rts/gmp/mpz/set_d.c
@@ -0,0 +1,96 @@
+/* mpz_set_d(integer, val) -- Assign INTEGER with a double value VAL.
+
+Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_set_d (mpz_ptr r, double d)
+#else
+mpz_set_d (r, d)
+ mpz_ptr r;
+ double d;
+#endif
+{
+ int negative;
+ mp_limb_t tp[3];
+ mp_ptr rp;
+ mp_size_t rn;
+
+ negative = d < 0;
+ d = ABS (d);
+
+ /* Handle small arguments quickly. */
+ if (d < MP_BASE_AS_DOUBLE)
+ {
+ mp_limb_t tmp;
+ tmp = d;
+ PTR(r)[0] = tmp;
+ SIZ(r) = negative ? -(tmp != 0) : (tmp != 0);
+ return;
+ }
+
+ rn = __gmp_extract_double (tp, d);
+
+ if (ALLOC(r) < rn)
+ _mpz_realloc (r, rn);
+
+ rp = PTR (r);
+
+#if BITS_PER_MP_LIMB == 32
+ switch (rn)
+ {
+ default:
+ MPN_ZERO (rp, rn - 3);
+ rp += rn - 3;
+ /* fall through */
+ case 3:
+ rp[2] = tp[2];
+ rp[1] = tp[1];
+ rp[0] = tp[0];
+ break;
+ case 2:
+ rp[1] = tp[2];
+ rp[0] = tp[1];
+ break;
+ case 1:
+ /* handled in "small aguments" case above */
+ abort ();
+ }
+#else
+ switch (rn)
+ {
+ default:
+ MPN_ZERO (rp, rn - 2);
+ rp += rn - 2;
+ /* fall through */
+ case 2:
+ rp[1] = tp[1], rp[0] = tp[0];
+ break;
+ case 1:
+ /* handled in "small aguments" case above */
+ abort ();
+ }
+#endif
+
+ SIZ(r) = negative ? -rn : rn;
+}
diff --git a/rts/gmp/mpz/set_f.c b/rts/gmp/mpz/set_f.c
new file mode 100644
index 0000000000..2273953dfd
--- /dev/null
+++ b/rts/gmp/mpz/set_f.c
@@ -0,0 +1,64 @@
+/* mpz_set_f (dest_integer, src_float) -- Assign DEST_INTEGER from SRC_FLOAT.
+
+Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_set_f (mpz_ptr w, mpf_srcptr u)
+#else
+mpz_set_f (w, u)
+ mpz_ptr w;
+ mpf_srcptr u;
+#endif
+{
+ mp_ptr wp, up;
+ mp_size_t usize, size;
+ mp_exp_t exp;
+
+ usize = SIZ (u);
+ size = ABS (usize);
+ exp = EXP (u);
+
+ if (w->_mp_alloc < exp)
+ _mpz_realloc (w, exp);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ if (exp <= 0)
+ {
+ SIZ (w) = 0;
+ return;
+ }
+ if (exp < size)
+ {
+ MPN_COPY (wp, up + size - exp, exp);
+ }
+ else
+ {
+ MPN_ZERO (wp, exp - size);
+ MPN_COPY (wp + exp - size, up, size);
+ }
+
+ w->_mp_size = usize >= 0 ? exp : -exp;
+}
diff --git a/rts/gmp/mpz/set_q.c b/rts/gmp/mpz/set_q.c
new file mode 100644
index 0000000000..72d3222a80
--- /dev/null
+++ b/rts/gmp/mpz/set_q.c
@@ -0,0 +1,36 @@
+/* mpz_set_q (dest_integer, src_rational) -- Assign DEST_INTEGER from
+ SRC_rational.
+
+Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_set_q (mpz_ptr w, mpq_srcptr u)
+#else
+mpz_set_q (w, u)
+ mpz_ptr w;
+ mpq_srcptr u;
+#endif
+{
+ mpz_tdiv_q (w, mpq_numref (u), mpq_denref (u));
+}
diff --git a/rts/gmp/mpz/set_si.c b/rts/gmp/mpz/set_si.c
new file mode 100644
index 0000000000..9ba2fbaf30
--- /dev/null
+++ b/rts/gmp/mpz/set_si.c
@@ -0,0 +1,48 @@
+/* mpz_set_si(integer, val) -- Assign INTEGER with a small value VAL.
+
+Copyright (C) 1991, 1993, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_set_si (mpz_ptr dest, signed long int val)
+#else
+mpz_set_si (dest, val)
+ mpz_ptr dest;
+ signed long int val;
+#endif
+{
+ /* We don't check if the allocation is enough, since the rest of the
+ package ensures it's at least 1, which is what we need here. */
+ if (val > 0)
+ {
+ dest->_mp_d[0] = val;
+ dest->_mp_size = 1;
+ }
+ else if (val < 0)
+ {
+ dest->_mp_d[0] = (unsigned long) -val;
+ dest->_mp_size = -1;
+ }
+ else
+ dest->_mp_size = 0;
+}
diff --git a/rts/gmp/mpz/set_str.c b/rts/gmp/mpz/set_str.c
new file mode 100644
index 0000000000..3ab79c0e89
--- /dev/null
+++ b/rts/gmp/mpz/set_str.c
@@ -0,0 +1,157 @@
+/* mpz_set_str(mp_dest, string, base) -- Convert the \0-terminated
+ string STRING in base BASE to multiple precision integer in
+ MP_DEST. Allow white space in the string. If BASE == 0 determine
+ the base in the C standard way, i.e. 0xhh...h means base 16,
+ 0oo...o means base 8, otherwise assume base 10.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 1998, 2000 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <string.h>
+#include <ctype.h>
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static int
+#if __STDC__
+digit_value_in_base (int c, int base)
+#else
+digit_value_in_base (c, base)
+ int c;
+ int base;
+#endif
+{
+ int digit;
+
+ if (isdigit (c))
+ digit = c - '0';
+ else if (islower (c))
+ digit = c - 'a' + 10;
+ else if (isupper (c))
+ digit = c - 'A' + 10;
+ else
+ return -1;
+
+ if (digit < base)
+ return digit;
+ return -1;
+}
+
+int
+#if __STDC__
+mpz_set_str (mpz_ptr x, const char *str, int base)
+#else
+mpz_set_str (x, str, base)
+ mpz_ptr x;
+ const char *str;
+ int base;
+#endif
+{
+ size_t str_size;
+ char *s, *begs;
+ size_t i;
+ mp_size_t xsize;
+ int c;
+ int negative;
+ TMP_DECL (marker);
+
+ /* Skip whitespace. */
+ do
+ c = *str++;
+ while (isspace (c));
+
+ negative = 0;
+ if (c == '-')
+ {
+ negative = 1;
+ c = *str++;
+ }
+
+ if (digit_value_in_base (c, base == 0 ? 10 : base) < 0)
+ return -1; /* error if no digits */
+
+ /* If BASE is 0, try to find out the base by looking at the initial
+ characters. */
+ if (base == 0)
+ {
+ base = 10;
+ if (c == '0')
+ {
+ base = 8;
+ c = *str++;
+ if (c == 'x' || c == 'X')
+ {
+ base = 16;
+ c = *str++;
+ }
+ else if (c == 'b' || c == 'B')
+ {
+ base = 2;
+ c = *str++;
+ }
+ }
+ }
+
+ /* Skip leading zeros. */
+ while (c == '0')
+ c = *str++;
+ /* Make sure the string does not become empty, mpn_set_str would fail. */
+ if (c == 0)
+ {
+ x->_mp_size = 0;
+ return 0;
+ }
+
+ TMP_MARK (marker);
+ str_size = strlen (str - 1);
+ s = begs = (char *) TMP_ALLOC (str_size + 1);
+
+ /* Remove spaces from the string and convert the result from ASCII to a
+ byte array. */
+ for (i = 0; i < str_size; i++)
+ {
+ if (!isspace (c))
+ {
+ int dig = digit_value_in_base (c, base);
+ if (dig < 0)
+ {
+ TMP_FREE (marker);
+ return -1;
+ }
+ *s++ = dig;
+ }
+ c = *str++;
+ }
+
+ str_size = s - begs;
+
+ xsize = (((mp_size_t) (str_size / __mp_bases[base].chars_per_bit_exactly))
+ / BITS_PER_MP_LIMB + 2);
+ if (x->_mp_alloc < xsize)
+ _mpz_realloc (x, xsize);
+
+ /* Convert the byte array in base BASE to our bignum format. */
+ xsize = mpn_set_str (x->_mp_d, (unsigned char *) begs, str_size, base);
+ x->_mp_size = negative ? -xsize : xsize;
+
+ TMP_FREE (marker);
+ return 0;
+}
diff --git a/rts/gmp/mpz/set_ui.c b/rts/gmp/mpz/set_ui.c
new file mode 100644
index 0000000000..d6097c170a
--- /dev/null
+++ b/rts/gmp/mpz/set_ui.c
@@ -0,0 +1,43 @@
+/* mpz_set_ui(integer, val) -- Assign INTEGER with a small value VAL.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_set_ui (mpz_ptr dest, unsigned long int val)
+#else
+mpz_set_ui (dest, val)
+ mpz_ptr dest;
+ unsigned long int val;
+#endif
+{
+ /* We don't check if the allocation is enough, since the rest of the
+ package ensures it's at least 1, which is what we need here. */
+ if (val > 0)
+ {
+ dest->_mp_d[0] = val;
+ dest->_mp_size = 1;
+ }
+ else
+ dest->_mp_size = 0;
+}
diff --git a/rts/gmp/mpz/setbit.c b/rts/gmp/mpz/setbit.c
new file mode 100644
index 0000000000..d4249a434e
--- /dev/null
+++ b/rts/gmp/mpz/setbit.c
@@ -0,0 +1,119 @@
+/* mpz_setbit -- set a specified bit.
+
+Copyright (C) 1991, 1993, 1994, 1995, 1997, 1999 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_setbit (mpz_ptr d, unsigned long int bit_index)
+#else
+mpz_setbit (d, bit_index)
+ mpz_ptr d;
+ unsigned long int bit_index;
+#endif
+{
+ mp_size_t dsize = d->_mp_size;
+ mp_ptr dp = d->_mp_d;
+ mp_size_t limb_index;
+
+ limb_index = bit_index / BITS_PER_MP_LIMB;
+ if (dsize >= 0)
+ {
+ if (limb_index < dsize)
+ {
+ dp[limb_index] |= (mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB);
+ d->_mp_size = dsize;
+ }
+ else
+ {
+ /* Ugh. The bit should be set outside of the end of the
+ number. We have to increase the size of the number. */
+ if (d->_mp_alloc < limb_index + 1)
+ {
+ _mpz_realloc (d, limb_index + 1);
+ dp = d->_mp_d;
+ }
+ MPN_ZERO (dp + dsize, limb_index - dsize);
+ dp[limb_index] = (mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB);
+ d->_mp_size = limb_index + 1;
+ }
+ }
+ else
+ {
+ mp_size_t zero_bound;
+
+ /* Simulate two's complement arithmetic, i.e. simulate
+ 1. Set OP = ~(OP - 1) [with infinitely many leading ones].
+ 2. Set the bit.
+ 3. Set OP = ~OP + 1. */
+
+ dsize = -dsize;
+
+ /* No upper bound on this loop, we're sure there's a non-zero limb
+ sooner ot later. */
+ for (zero_bound = 0; ; zero_bound++)
+ if (dp[zero_bound] != 0)
+ break;
+
+ if (limb_index > zero_bound)
+ {
+ if (limb_index < dsize)
+ dp[limb_index] &= ~((mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB));
+ else
+ ;
+ }
+ else if (limb_index == zero_bound)
+ {
+ dp[limb_index] = ((dp[limb_index] - 1)
+ & ~((mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB))) + 1;
+ if (dp[limb_index] == 0)
+ {
+ mp_size_t i;
+ for (i = limb_index + 1; i < dsize; i++)
+ {
+ dp[i] += 1;
+ if (dp[i] != 0)
+ goto fin;
+ }
+ /* We got carry all way out beyond the end of D. Increase
+ its size (and allocation if necessary). */
+ dsize++;
+ if (d->_mp_alloc < dsize)
+ {
+ _mpz_realloc (d, dsize);
+ dp = d->_mp_d;
+ }
+ dp[i] = 1;
+ d->_mp_size = -dsize;
+ fin:;
+ }
+ }
+ else
+ {
+ mpn_decr_u (dp + limb_index,
+ (mp_limb_t) 1 << (bit_index % BITS_PER_MP_LIMB));
+ dsize -= dp[dsize - 1] == 0;
+ d->_mp_size = -dsize;
+ }
+ }
+}
diff --git a/rts/gmp/mpz/size.c b/rts/gmp/mpz/size.c
new file mode 100644
index 0000000000..6574756783
--- /dev/null
+++ b/rts/gmp/mpz/size.c
@@ -0,0 +1,35 @@
+/* mpz_size(x) -- return the number of lims currently used by the
+ value of integer X.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+size_t
+#if __STDC__
+mpz_size (mpz_srcptr x)
+#else
+mpz_size (x)
+ mpz_srcptr x;
+#endif
+{
+ return ABS (x->_mp_size);
+}
diff --git a/rts/gmp/mpz/sizeinbase.c b/rts/gmp/mpz/sizeinbase.c
new file mode 100644
index 0000000000..734f9c4532
--- /dev/null
+++ b/rts/gmp/mpz/sizeinbase.c
@@ -0,0 +1,60 @@
+/* mpz_sizeinbase(x, base) -- return an approximation to the number of
+ character the integer X would have printed in base BASE. The
+ approximation is never too small.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+size_t
+#if __STDC__
+mpz_sizeinbase (mpz_srcptr x, int base)
+#else
+mpz_sizeinbase (x, base)
+ mpz_srcptr x;
+ int base;
+#endif
+{
+ mp_size_t size = ABS (x->_mp_size);
+ int lb_base, cnt;
+ size_t totbits;
+
+ /* Special case for X == 0. */
+ if (size == 0)
+ return 1;
+
+ /* Calculate the total number of significant bits of X. */
+ count_leading_zeros (cnt, x->_mp_d[size - 1]);
+ totbits = size * BITS_PER_MP_LIMB - cnt;
+
+ if ((base & (base - 1)) == 0)
+ {
+ /* Special case for powers of 2, giving exact result. */
+
+ count_leading_zeros (lb_base, base);
+ lb_base = BITS_PER_MP_LIMB - lb_base - 1;
+
+ return (totbits + lb_base - 1) / lb_base;
+ }
+ else
+ return (size_t) (totbits * __mp_bases[base].chars_per_bit_exactly) + 1;
+}
diff --git a/rts/gmp/mpz/sqrt.c b/rts/gmp/mpz/sqrt.c
new file mode 100644
index 0000000000..fe82fe407a
--- /dev/null
+++ b/rts/gmp/mpz/sqrt.c
@@ -0,0 +1,86 @@
+/* mpz_sqrt(root, u) -- Set ROOT to floor(sqrt(U)).
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_sqrt (mpz_ptr root, mpz_srcptr op)
+#else
+mpz_sqrt (root, op)
+ mpz_ptr root;
+ mpz_srcptr op;
+#endif
+{
+ mp_size_t op_size, root_size;
+ mp_ptr root_ptr, op_ptr;
+ mp_ptr free_me = NULL;
+ mp_size_t free_me_size;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ op_size = op->_mp_size;
+ if (op_size < 0)
+ SQRT_OF_NEGATIVE;
+
+ /* The size of the root is accurate after this simple calculation. */
+ root_size = (op_size + 1) / 2;
+
+ root_ptr = root->_mp_d;
+ op_ptr = op->_mp_d;
+
+ if (root->_mp_alloc < root_size)
+ {
+ if (root_ptr == op_ptr)
+ {
+ free_me = root_ptr;
+ free_me_size = root->_mp_alloc;
+ }
+ else
+ (*_mp_free_func) (root_ptr, root->_mp_alloc * BYTES_PER_MP_LIMB);
+
+ root->_mp_alloc = root_size;
+ root_ptr = (mp_ptr) (*_mp_allocate_func) (root_size * BYTES_PER_MP_LIMB);
+ root->_mp_d = root_ptr;
+ }
+ else
+ {
+ /* Make OP not overlap with ROOT. */
+ if (root_ptr == op_ptr)
+ {
+ /* ROOT and OP are identical. Allocate temporary space for OP. */
+ op_ptr = (mp_ptr) TMP_ALLOC (op_size * BYTES_PER_MP_LIMB);
+ /* Copy to the temporary space. Hack: Avoid temporary variable
+ by using ROOT_PTR. */
+ MPN_COPY (op_ptr, root_ptr, op_size);
+ }
+ }
+
+ mpn_sqrtrem (root_ptr, NULL, op_ptr, op_size);
+
+ root->_mp_size = root_size;
+
+ if (free_me != NULL)
+ (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/sqrtrem.c b/rts/gmp/mpz/sqrtrem.c
new file mode 100644
index 0000000000..99a6453122
--- /dev/null
+++ b/rts/gmp/mpz/sqrtrem.c
@@ -0,0 +1,111 @@
+/* mpz_sqrtrem(root,rem,x) -- Set ROOT to floor(sqrt(X)) and REM
+ to the remainder, i.e. X - ROOT**2.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include <stdio.h> /* for NULL */
+#include "gmp.h"
+#include "gmp-impl.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_sqrtrem (mpz_ptr root, mpz_ptr rem, mpz_srcptr op)
+#else
+mpz_sqrtrem (root, rem, op)
+ mpz_ptr root;
+ mpz_ptr rem;
+ mpz_srcptr op;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+msqrt (mpz_srcptr op, mpz_ptr root, mpz_ptr rem)
+#else
+msqrt (op, root, rem)
+ mpz_srcptr op;
+ mpz_ptr root;
+ mpz_ptr rem;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_size_t op_size, root_size, rem_size;
+ mp_ptr root_ptr, op_ptr;
+ mp_ptr free_me = NULL;
+ mp_size_t free_me_size;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ op_size = op->_mp_size;
+ if (op_size < 0)
+ SQRT_OF_NEGATIVE;
+
+ if (rem->_mp_alloc < op_size)
+ _mpz_realloc (rem, op_size);
+
+ /* The size of the root is accurate after this simple calculation. */
+ root_size = (op_size + 1) / 2;
+
+ root_ptr = root->_mp_d;
+ op_ptr = op->_mp_d;
+
+ if (root->_mp_alloc < root_size)
+ {
+ if (root_ptr == op_ptr)
+ {
+ free_me = root_ptr;
+ free_me_size = root->_mp_alloc;
+ }
+ else
+ (*_mp_free_func) (root_ptr, root->_mp_alloc * BYTES_PER_MP_LIMB);
+
+ root->_mp_alloc = root_size;
+ root_ptr = (mp_ptr) (*_mp_allocate_func) (root_size * BYTES_PER_MP_LIMB);
+ root->_mp_d = root_ptr;
+ }
+ else
+ {
+ /* Make OP not overlap with ROOT. */
+ if (root_ptr == op_ptr)
+ {
+ /* ROOT and OP are identical. Allocate temporary space for OP. */
+ op_ptr = (mp_ptr) TMP_ALLOC (op_size * BYTES_PER_MP_LIMB);
+ /* Copy to the temporary space. Hack: Avoid temporary variable
+ by using ROOT_PTR. */
+ MPN_COPY (op_ptr, root_ptr, op_size);
+ }
+ }
+
+ rem_size = mpn_sqrtrem (root_ptr, rem->_mp_d, op_ptr, op_size);
+
+ root->_mp_size = root_size;
+
+ /* Write remainder size last, to enable us to define this function to
+ give only the square root remainder, if the user calls if with
+ ROOT == REM. */
+ rem->_mp_size = rem_size;
+
+ if (free_me != NULL)
+ (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/sub.c b/rts/gmp/mpz/sub.c
new file mode 100644
index 0000000000..f3ae7c23a0
--- /dev/null
+++ b/rts/gmp/mpz/sub.c
@@ -0,0 +1,123 @@
+/* mpz_sub -- Subtract two integers.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+#ifndef BERKELEY_MP
+void
+#if __STDC__
+mpz_sub (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+#else
+mpz_sub (w, u, v)
+ mpz_ptr w;
+ mpz_srcptr u;
+ mpz_srcptr v;
+#endif
+#else /* BERKELEY_MP */
+void
+#if __STDC__
+msub (mpz_srcptr u, mpz_srcptr v, mpz_ptr w)
+#else
+msub (u, v, w)
+ mpz_srcptr u;
+ mpz_srcptr v;
+ mpz_ptr w;
+#endif
+#endif /* BERKELEY_MP */
+{
+ mp_srcptr up, vp;
+ mp_ptr wp;
+ mp_size_t usize, vsize, wsize;
+ mp_size_t abs_usize;
+ mp_size_t abs_vsize;
+
+ usize = u->_mp_size;
+ vsize = -v->_mp_size; /* The "-" makes the difference from mpz_add */
+ abs_usize = ABS (usize);
+ abs_vsize = ABS (vsize);
+
+ if (abs_usize < abs_vsize)
+ {
+ /* Swap U and V. */
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (usize, vsize);
+ MP_SIZE_T_SWAP (abs_usize, abs_vsize);
+ }
+
+ /* True: ABS_USIZE >= ABS_VSIZE. */
+
+ /* If not space for w (and possible carry), increase space. */
+ wsize = abs_usize + 1;
+ if (w->_mp_alloc < wsize)
+ _mpz_realloc (w, wsize);
+
+ /* These must be after realloc (u or v may be the same as w). */
+ up = u->_mp_d;
+ vp = v->_mp_d;
+ wp = w->_mp_d;
+
+ if ((usize ^ vsize) < 0)
+ {
+ /* U and V have different sign. Need to compare them to determine
+ which operand to subtract from which. */
+
+ /* This test is right since ABS_USIZE >= ABS_VSIZE. */
+ if (abs_usize != abs_vsize)
+ {
+ mpn_sub (wp, up, abs_usize, vp, abs_vsize);
+ wsize = abs_usize;
+ MPN_NORMALIZE (wp, wsize);
+ if (usize < 0)
+ wsize = -wsize;
+ }
+ else if (mpn_cmp (up, vp, abs_usize) < 0)
+ {
+ mpn_sub_n (wp, vp, up, abs_usize);
+ wsize = abs_usize;
+ MPN_NORMALIZE (wp, wsize);
+ if (usize >= 0)
+ wsize = -wsize;
+ }
+ else
+ {
+ mpn_sub_n (wp, up, vp, abs_usize);
+ wsize = abs_usize;
+ MPN_NORMALIZE (wp, wsize);
+ if (usize < 0)
+ wsize = -wsize;
+ }
+ }
+ else
+ {
+ /* U and V have same sign. Add them. */
+ mp_limb_t cy_limb = mpn_add (wp, up, abs_usize, vp, abs_vsize);
+ wp[abs_usize] = cy_limb;
+ wsize = abs_usize + cy_limb;
+ if (usize < 0)
+ wsize = -wsize;
+ }
+
+ w->_mp_size = wsize;
+}
diff --git a/rts/gmp/mpz/sub_ui.c b/rts/gmp/mpz/sub_ui.c
new file mode 100644
index 0000000000..327add8503
--- /dev/null
+++ b/rts/gmp/mpz/sub_ui.c
@@ -0,0 +1,84 @@
+/* mpz_sub_ui -- Subtract an unsigned one-word integer from an MP_INT.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_sub_ui (mpz_ptr w, mpz_srcptr u, unsigned long int v)
+#else
+mpz_sub_ui (w, u, v)
+ mpz_ptr w;
+ mpz_srcptr u;
+ unsigned long int v;
+#endif
+{
+ mp_srcptr up;
+ mp_ptr wp;
+ mp_size_t usize, wsize;
+ mp_size_t abs_usize;
+
+ usize = u->_mp_size;
+ abs_usize = ABS (usize);
+
+ /* If not space for W (and possible carry), increase space. */
+ wsize = abs_usize + 1;
+ if (w->_mp_alloc < wsize)
+ _mpz_realloc (w, wsize);
+
+ /* These must be after realloc (U may be the same as W). */
+ up = u->_mp_d;
+ wp = w->_mp_d;
+
+ if (abs_usize == 0)
+ {
+ wp[0] = v;
+ w->_mp_size = -(v != 0);
+ return;
+ }
+
+ if (usize < 0)
+ {
+ mp_limb_t cy;
+ cy = mpn_add_1 (wp, up, abs_usize, (mp_limb_t) v);
+ wp[abs_usize] = cy;
+ wsize = -(abs_usize + cy);
+ }
+ else
+ {
+ /* The signs are different. Need exact comparison to determine
+ which operand to subtract from which. */
+ if (abs_usize == 1 && up[0] < v)
+ {
+ wp[0] = v - up[0];
+ wsize = -1;
+ }
+ else
+ {
+ mpn_sub_1 (wp, up, abs_usize, (mp_limb_t) v);
+ /* Size can decrease with at most one limb. */
+ wsize = abs_usize - (wp[abs_usize - 1] == 0);
+ }
+ }
+
+ w->_mp_size = wsize;
+}
diff --git a/rts/gmp/mpz/swap.c b/rts/gmp/mpz/swap.c
new file mode 100644
index 0000000000..0070d6ff24
--- /dev/null
+++ b/rts/gmp/mpz/swap.c
@@ -0,0 +1,52 @@
+/* mpz_swap (dest_integer, src_integer) -- Swap U and V.
+
+Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_swap (mpz_ptr u, mpz_ptr v)
+#else
+mpz_swap (u, v)
+ mpz_ptr u;
+ mpz_ptr v;
+#endif
+{
+ mp_ptr up, vp;
+ mp_size_t usize, vsize;
+ mp_size_t ualloc, valloc;
+
+ ualloc = u->_mp_alloc;
+ valloc = v->_mp_alloc;
+ v->_mp_alloc = ualloc;
+ u->_mp_alloc = valloc;
+
+ usize = u->_mp_size;
+ vsize = v->_mp_size;
+ v->_mp_size = usize;
+ u->_mp_size = vsize;
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+ v->_mp_d = up;
+ u->_mp_d = vp;
+}
diff --git a/rts/gmp/mpz/tdiv_q.c b/rts/gmp/mpz/tdiv_q.c
new file mode 100644
index 0000000000..21db4ab385
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_q.c
@@ -0,0 +1,91 @@
+/* mpz_tdiv_q -- divide two integers and produce a quotient.
+
+Copyright (C) 1991, 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+#if __STDC__
+mpz_tdiv_q (mpz_ptr quot, mpz_srcptr num, mpz_srcptr den)
+#else
+mpz_tdiv_q (quot, num, den)
+ mpz_ptr quot;
+ mpz_srcptr num;
+ mpz_srcptr den;
+#endif
+{
+ mp_size_t ql;
+ mp_size_t ns, ds, nl, dl;
+ mp_ptr np, dp, qp, rp;
+ TMP_DECL (marker);
+
+ ns = SIZ (num);
+ ds = SIZ (den);
+ nl = ABS (ns);
+ dl = ABS (ds);
+ ql = nl - dl + 1;
+
+ if (dl == 0)
+ DIVIDE_BY_ZERO;
+
+ if (ql <= 0)
+ {
+ SIZ (quot) = 0;
+ return;
+ }
+
+ MPZ_REALLOC (quot, ql);
+
+ TMP_MARK (marker);
+ qp = PTR (quot);
+ rp = (mp_ptr) TMP_ALLOC (dl * BYTES_PER_MP_LIMB);
+ np = PTR (num);
+ dp = PTR (den);
+
+ /* FIXME: We should think about how to handle the temporary allocation.
+ Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+ allocate temp space. */
+
+ /* Copy denominator to temporary space if it overlaps with the quotient. */
+ if (dp == qp)
+ {
+ mp_ptr tp;
+ tp = (mp_ptr) TMP_ALLOC (dl * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, dp, dl);
+ dp = tp;
+ }
+ /* Copy numerator to temporary space if it overlaps with the quotient. */
+ if (np == qp)
+ {
+ mp_ptr tp;
+ tp = (mp_ptr) TMP_ALLOC (nl * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, np, nl);
+ np = tp;
+ }
+
+ mpn_tdiv_qr (qp, rp, 0L, np, nl, dp, dl);
+
+ ql -= qp[ql - 1] == 0;
+
+ SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql;
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/tdiv_q_2exp.c b/rts/gmp/mpz/tdiv_q_2exp.c
new file mode 100644
index 0000000000..03d1e01f89
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_q_2exp.c
@@ -0,0 +1,68 @@
+/* mpz_tdiv_q_2exp -- Divide an integer by 2**CNT. Round the quotient
+ towards -infinity.
+
+Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_tdiv_q_2exp (mpz_ptr w, mpz_srcptr u, unsigned long int cnt)
+#else
+mpz_tdiv_q_2exp (w, u, cnt)
+ mpz_ptr w;
+ mpz_srcptr u;
+ unsigned long int cnt;
+#endif
+{
+ mp_size_t usize, wsize;
+ mp_size_t limb_cnt;
+
+ usize = u->_mp_size;
+ limb_cnt = cnt / BITS_PER_MP_LIMB;
+ wsize = ABS (usize) - limb_cnt;
+ if (wsize <= 0)
+ w->_mp_size = 0;
+ else
+ {
+ mp_ptr wp;
+ mp_srcptr up;
+
+ if (w->_mp_alloc < wsize)
+ _mpz_realloc (w, wsize);
+
+ wp = w->_mp_d;
+ up = u->_mp_d;
+
+ cnt %= BITS_PER_MP_LIMB;
+ if (cnt != 0)
+ {
+ mpn_rshift (wp, up + limb_cnt, wsize, cnt);
+ wsize -= wp[wsize - 1] == 0;
+ }
+ else
+ {
+ MPN_COPY_INCR (wp, up + limb_cnt, wsize);
+ }
+
+ w->_mp_size = usize >= 0 ? wsize : -wsize;
+ }
+}
diff --git a/rts/gmp/mpz/tdiv_q_ui.c b/rts/gmp/mpz/tdiv_q_ui.c
new file mode 100644
index 0000000000..a2e3462b76
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_q_ui.c
@@ -0,0 +1,64 @@
+/* mpz_tdiv_q_ui(quot, dividend, divisor_limb)
+ -- Divide DIVIDEND by DIVISOR_LIMB and store the result in QUOT.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1998 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_tdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_tdiv_q_ui (quot, dividend, divisor)
+ mpz_ptr quot;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_ptr quot_ptr;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ /* No need for temporary allocation and copying if QUOT == DIVIDEND as
+ the divisor is just one limb, and thus no intermediate remainders
+ need to be stored. */
+
+ if (quot->_mp_alloc < size)
+ _mpz_realloc (quot, size);
+
+ quot_ptr = quot->_mp_d;
+
+ remainder_limb
+ = mpn_divmod_1 (quot_ptr, dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ /* The quotient is SIZE limbs, but the most significant might be zero. */
+ size -= size != 0 && quot_ptr[size - 1] == 0;
+ quot->_mp_size = dividend_size >= 0 ? size : -size;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/tdiv_qr.c b/rts/gmp/mpz/tdiv_qr.c
new file mode 100644
index 0000000000..d66f57d9e5
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_qr.c
@@ -0,0 +1,130 @@
+/* mpz_tdiv_qr(quot,rem,dividend,divisor) -- Set QUOT to DIVIDEND/DIVISOR,
+ and REM to DIVIDEND mod DIVISOR.
+
+Copyright (C) 1991, 1993, 1994, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+#ifdef BERKELEY_MP
+#include "mp.h"
+#endif
+
+
+#ifndef BERKELEY_MP
+
+void
+#if __STDC__
+mpz_tdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr num, mpz_srcptr den)
+#else
+mpz_tdiv_qr (quot, rem, num, den)
+ mpz_ptr quot;
+ mpz_ptr rem;
+ mpz_srcptr num;
+ mpz_srcptr den;
+#endif
+
+#else /* BERKELEY_MP */
+
+void
+#if __STDC__
+mdiv (mpz_srcptr num, mpz_srcptr den, mpz_ptr quot, mpz_ptr rem)
+#else
+mdiv (num, den, quot, rem)
+ mpz_srcptr num;
+ mpz_srcptr den;
+ mpz_ptr quot;
+ mpz_ptr rem;
+#endif
+
+#endif /* BERKELEY_MP */
+{
+ mp_size_t ql;
+ mp_size_t ns, ds, nl, dl;
+ mp_ptr np, dp, qp, rp;
+ TMP_DECL (marker);
+
+ ns = SIZ (num);
+ ds = SIZ (den);
+ nl = ABS (ns);
+ dl = ABS (ds);
+ ql = nl - dl + 1;
+
+ if (dl == 0)
+ DIVIDE_BY_ZERO;
+
+ MPZ_REALLOC (rem, dl);
+
+ if (ql <= 0)
+ {
+ if (num != rem)
+ {
+ mp_ptr np, rp;
+ np = PTR (num);
+ rp = PTR (rem);
+ MPN_COPY (rp, np, nl);
+ SIZ (rem) = SIZ (num);
+ }
+ /* This needs to follow the assignment to rem, in case the
+ numerator and quotient are the same. */
+ SIZ (quot) = 0;
+ return;
+ }
+
+ MPZ_REALLOC (quot, ql);
+
+ TMP_MARK (marker);
+ qp = PTR (quot);
+ rp = PTR (rem);
+ np = PTR (num);
+ dp = PTR (den);
+
+ /* FIXME: We should think about how to handle the temporary allocation.
+ Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+ allocate temp space. */
+
+ /* Copy denominator to temporary space if it overlaps with the quotient
+ or remainder. */
+ if (dp == rp || dp == qp)
+ {
+ mp_ptr tp;
+ tp = (mp_ptr) TMP_ALLOC (dl * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, dp, dl);
+ dp = tp;
+ }
+ /* Copy numerator to temporary space if it overlaps with the quotient or
+ remainder. */
+ if (np == rp || np == qp)
+ {
+ mp_ptr tp;
+ tp = (mp_ptr) TMP_ALLOC (nl * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, np, nl);
+ np = tp;
+ }
+
+ mpn_tdiv_qr (qp, rp, 0L, np, nl, dp, dl);
+
+ ql -= qp[ql - 1] == 0;
+ MPN_NORMALIZE (rp, dl);
+
+ SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql;
+ SIZ (rem) = ns >= 0 ? dl : -dl;
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/tdiv_qr_ui.c b/rts/gmp/mpz/tdiv_qr_ui.c
new file mode 100644
index 0000000000..10368cd340
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_qr_ui.c
@@ -0,0 +1,76 @@
+/* mpz_tdiv_qr_ui(quot,rem,dividend,short_divisor) --
+ Set QUOT to DIVIDEND / SHORT_DIVISOR
+ and REM to DIVIDEND mod SHORT_DIVISOR.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1998 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_tdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_tdiv_qr_ui (quot, rem, dividend, divisor)
+ mpz_ptr quot;
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_ptr quot_ptr;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ /* No need for temporary allocation and copying if QUOT == DIVIDEND as
+ the divisor is just one limb, and thus no intermediate remainders
+ need to be stored. */
+
+ if (quot->_mp_alloc < size)
+ _mpz_realloc (quot, size);
+
+ quot_ptr = quot->_mp_d;
+
+ remainder_limb = mpn_divmod_1 (quot_ptr, dividend->_mp_d, size,
+ (mp_limb_t) divisor);
+
+ if (remainder_limb == 0)
+ rem->_mp_size = 0;
+ else
+ {
+ /* Store the single-limb remainder. We don't check if there's space
+ for just one limb, since no function ever makes zero space. */
+ rem->_mp_size = dividend_size >= 0 ? 1 : -1;
+ rem->_mp_d[0] = remainder_limb;
+ }
+
+ /* The quotient is SIZE limbs, but the most significant might be zero. */
+ size -= size != 0 && quot_ptr[size - 1] == 0;
+ quot->_mp_size = dividend_size >= 0 ? size : -size;
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/tdiv_r.c b/rts/gmp/mpz/tdiv_r.c
new file mode 100644
index 0000000000..9eb87dfabf
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_r.c
@@ -0,0 +1,98 @@
+/* mpz_tdiv_r(rem, dividend, divisor) -- Set REM to DIVIDEND mod DIVISOR.
+
+Copyright (C) 1991, 1993, 1994, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+#if __STDC__
+mpz_tdiv_r (mpz_ptr rem, mpz_srcptr num, mpz_srcptr den)
+#else
+mpz_tdiv_r (rem, num, den)
+ mpz_ptr rem;
+ mpz_srcptr num;
+ mpz_srcptr den;
+#endif
+{
+ mp_size_t ql;
+ mp_size_t ns, ds, nl, dl;
+ mp_ptr np, dp, qp, rp;
+ TMP_DECL (marker);
+
+ ns = SIZ (num);
+ ds = SIZ (den);
+ nl = ABS (ns);
+ dl = ABS (ds);
+ ql = nl - dl + 1;
+
+ if (dl == 0)
+ DIVIDE_BY_ZERO;
+
+ MPZ_REALLOC (rem, dl);
+
+ if (ql <= 0)
+ {
+ if (num != rem)
+ {
+ mp_ptr np, rp;
+ np = PTR (num);
+ rp = PTR (rem);
+ MPN_COPY (rp, np, nl);
+ SIZ (rem) = SIZ (num);
+ }
+ return;
+ }
+
+ TMP_MARK (marker);
+ qp = (mp_ptr) TMP_ALLOC (ql * BYTES_PER_MP_LIMB);
+ rp = PTR (rem);
+ np = PTR (num);
+ dp = PTR (den);
+
+ /* FIXME: We should think about how to handle the temporary allocation.
+ Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+ allocate temp space. */
+
+ /* Copy denominator to temporary space if it overlaps with the remainder. */
+ if (dp == rp)
+ {
+ mp_ptr tp;
+ tp = (mp_ptr) TMP_ALLOC (dl * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, dp, dl);
+ dp = tp;
+ }
+ /* Copy numerator to temporary space if it overlaps with the remainder. */
+ if (np == rp)
+ {
+ mp_ptr tp;
+ tp = (mp_ptr) TMP_ALLOC (nl * BYTES_PER_MP_LIMB);
+ MPN_COPY (tp, np, nl);
+ np = tp;
+ }
+
+ mpn_tdiv_qr (qp, rp, 0L, np, nl, dp, dl);
+
+ MPN_NORMALIZE (rp, dl);
+
+ SIZ (rem) = ns >= 0 ? dl : -dl;
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/tdiv_r_2exp.c b/rts/gmp/mpz/tdiv_r_2exp.c
new file mode 100644
index 0000000000..91de170f5c
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_r_2exp.c
@@ -0,0 +1,79 @@
+/* mpz_tdiv_r_2exp -- Divide a integer by 2**CNT and produce a remainder.
+
+Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_tdiv_r_2exp (mpz_ptr res, mpz_srcptr in, unsigned long int cnt)
+#else
+mpz_tdiv_r_2exp (res, in, cnt)
+ mpz_ptr res;
+ mpz_srcptr in;
+ unsigned long int cnt;
+#endif
+{
+ mp_size_t in_size = ABS (in->_mp_size);
+ mp_size_t res_size;
+ mp_size_t limb_cnt = cnt / BITS_PER_MP_LIMB;
+ mp_srcptr in_ptr = in->_mp_d;
+
+ if (in_size > limb_cnt)
+ {
+ /* The input operand is (probably) greater than 2**CNT. */
+ mp_limb_t x;
+
+ x = in_ptr[limb_cnt] & (((mp_limb_t) 1 << cnt % BITS_PER_MP_LIMB) - 1);
+ if (x != 0)
+ {
+ res_size = limb_cnt + 1;
+ if (res->_mp_alloc < res_size)
+ _mpz_realloc (res, res_size);
+
+ res->_mp_d[limb_cnt] = x;
+ }
+ else
+ {
+ res_size = limb_cnt;
+ MPN_NORMALIZE (in_ptr, res_size);
+
+ if (res->_mp_alloc < res_size)
+ _mpz_realloc (res, res_size);
+
+ limb_cnt = res_size;
+ }
+ }
+ else
+ {
+ /* The input operand is smaller than 2**CNT. We perform a no-op,
+ apart from that we might need to copy IN to RES. */
+ res_size = in_size;
+ if (res->_mp_alloc < res_size)
+ _mpz_realloc (res, res_size);
+
+ limb_cnt = res_size;
+ }
+
+ if (res != in)
+ MPN_COPY (res->_mp_d, in->_mp_d, limb_cnt);
+ res->_mp_size = in->_mp_size >= 0 ? res_size : -res_size;
+}
diff --git a/rts/gmp/mpz/tdiv_r_ui.c b/rts/gmp/mpz/tdiv_r_ui.c
new file mode 100644
index 0000000000..2ea411fda1
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_r_ui.c
@@ -0,0 +1,63 @@
+/* mpz_tdiv_r_ui(rem, dividend, divisor_limb)
+ -- Set REM to DIVDEND mod DIVISOR_LIMB.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1998 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_tdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_tdiv_r_ui (rem, dividend, divisor)
+ mpz_ptr rem;
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ /* No need for temporary allocation and copying if QUOT == DIVIDEND as
+ the divisor is just one limb, and thus no intermediate remainders
+ need to be stored. */
+
+ remainder_limb = mpn_mod_1 (dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ if (remainder_limb == 0)
+ rem->_mp_size = 0;
+ else
+ {
+ /* Store the single-limb remainder. We don't check if there's space
+ for just one limb, since no function ever makes zero space. */
+ rem->_mp_size = dividend_size >= 0 ? 1 : -1;
+ rem->_mp_d[0] = remainder_limb;
+ }
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/tdiv_ui.c b/rts/gmp/mpz/tdiv_ui.c
new file mode 100644
index 0000000000..7a40a6a7f7
--- /dev/null
+++ b/rts/gmp/mpz/tdiv_ui.c
@@ -0,0 +1,53 @@
+/* mpz_tdiv_ui(dividend, divisor_limb)
+ -- Return DIVDEND mod DIVISOR_LIMB.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 1998 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+unsigned long int
+#if __STDC__
+mpz_tdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+#else
+mpz_tdiv_ui (dividend, divisor)
+ mpz_srcptr dividend;
+ unsigned long int divisor;
+#endif
+{
+ mp_size_t dividend_size;
+ mp_size_t size;
+ mp_limb_t remainder_limb;
+
+ if (divisor == 0)
+ DIVIDE_BY_ZERO;
+
+ dividend_size = dividend->_mp_size;
+ size = ABS (dividend_size);
+
+ /* No need for temporary allocation and copying if QUOT == DIVIDEND as
+ the divisor is just one limb, and thus no intermediate remainders
+ need to be stored. */
+
+ remainder_limb = mpn_mod_1 (dividend->_mp_d, size, (mp_limb_t) divisor);
+
+ return remainder_limb;
+}
diff --git a/rts/gmp/mpz/tstbit.c b/rts/gmp/mpz/tstbit.c
new file mode 100644
index 0000000000..b0a8b0b31a
--- /dev/null
+++ b/rts/gmp/mpz/tstbit.c
@@ -0,0 +1,70 @@
+/* mpz_tstbit -- test a specified bit. Simulate 2's complement representation.
+
+Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+int
+#if __STDC__
+mpz_tstbit (mpz_srcptr d, unsigned long int bit_index)
+#else
+mpz_tstbit (d, bit_index)
+ mpz_srcptr d;
+ unsigned long int bit_index;
+#endif
+{
+ mp_size_t dsize = d->_mp_size;
+ mp_ptr dp = d->_mp_d;
+ mp_size_t limb_index;
+
+ limb_index = bit_index / BITS_PER_MP_LIMB;
+ if (dsize >= 0)
+ {
+ if (limb_index < dsize)
+ return (dp[limb_index] >> (bit_index % BITS_PER_MP_LIMB)) & 1;
+ else
+ /* Testing a bit outside of a positive number. */
+ return 0;
+ }
+ else
+ {
+ mp_size_t zero_bound;
+
+ dsize = -dsize;
+
+ /* Locate the least significant non-zero limb. */
+ for (zero_bound = 0; dp[zero_bound] == 0; zero_bound++)
+ ;
+
+ if (limb_index > zero_bound)
+ {
+ if (limb_index < dsize)
+ return (~dp[limb_index] >> (bit_index % BITS_PER_MP_LIMB)) & 1;
+ else
+ /* Testing a bit outside of a negative number. */
+ return 1;
+ }
+ else if (limb_index == zero_bound)
+ return (-dp[limb_index] >> (bit_index % BITS_PER_MP_LIMB)) & 1;
+ else
+ return 0;
+ }
+}
diff --git a/rts/gmp/mpz/ui_pow_ui.c b/rts/gmp/mpz/ui_pow_ui.c
new file mode 100644
index 0000000000..edd2dee625
--- /dev/null
+++ b/rts/gmp/mpz/ui_pow_ui.c
@@ -0,0 +1,139 @@
+/* mpz_ui_pow_ui(res, base, exp) -- Set RES to BASE**EXP.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+static void mpz_pow2 _PROTO ((mpz_ptr r, mp_limb_t blimb, unsigned long int e, mp_limb_t rl));
+
+void
+#if __STDC__
+mpz_ui_pow_ui (mpz_ptr r, unsigned long int b, unsigned long int e)
+#else
+mpz_ui_pow_ui (r, b, e)
+ mpz_ptr r;
+ unsigned long int b;
+ unsigned long int e;
+#endif
+{
+ mp_limb_t blimb = b;
+ mp_limb_t rl;
+
+ if (e == 0)
+ {
+ /* For x^0 we return 1, even if x is 0. */
+ r->_mp_d[0] = 1;
+ r->_mp_size = 1;
+ return;
+ }
+
+ /* Compute b^e as (b^n)^(e div n) * b^(e mod n), where n is chosen such that
+ the latter factor is the largest number small enough to fit in a limb. */
+
+ rl = 1;
+ while (e != 0 && blimb < ((mp_limb_t) 1 << BITS_PER_MP_LIMB/2))
+ {
+ if ((e & 1) != 0)
+ rl = rl * blimb;
+ blimb = blimb * blimb;
+ e = e >> 1;
+ }
+
+ /* rl is now b^(e mod n). (I.e., the latter factor above.) */
+
+ if (e == 0)
+ {
+ r->_mp_d[0] = rl;
+ r->_mp_size = rl != 0;
+ return;
+ }
+
+ mpz_pow2 (r, blimb, e, rl);
+}
+
+/* Multi-precision part of expontialization code. */
+static void
+#if __STDC__
+mpz_pow2 (mpz_ptr r, mp_limb_t blimb, unsigned long int e, mp_limb_t rl)
+#else
+mpz_pow2 (r, blimb, e, rl)
+ mpz_ptr r;
+ mp_limb_t blimb;
+ unsigned long int e;
+ mp_limb_t rl;
+#endif
+{
+ mp_ptr rp, tp;
+ mp_size_t ralloc, rsize;
+ int cnt, i;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* Over-estimate temporary space requirements somewhat. */
+ count_leading_zeros (cnt, blimb);
+ ralloc = e - cnt * e / BITS_PER_MP_LIMB + 1;
+
+ /* The two areas are used to alternatingly hold the input and receive the
+ product for mpn_mul. (Needed since mpn_mul_n requires that the product
+ is distinct from either input operand.) */
+ rp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
+ tp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
+
+ rp[0] = blimb;
+ rsize = 1;
+
+ count_leading_zeros (cnt, e);
+ for (i = BITS_PER_MP_LIMB - cnt - 2; i >= 0; i--)
+ {
+ mpn_mul_n (tp, rp, rp, rsize);
+ rsize = 2 * rsize;
+ rsize -= tp[rsize - 1] == 0;
+ MP_PTR_SWAP (rp, tp);
+
+ if ((e & ((mp_limb_t) 1 << i)) != 0)
+ {
+ mp_limb_t cy;
+ cy = mpn_mul_1 (rp, rp, rsize, blimb);
+ rp[rsize] = cy;
+ rsize += cy != 0;
+ }
+ }
+
+ /* We will need rsize or rsize+1 limbs for the result. */
+ if (r->_mp_alloc <= rsize)
+ _mpz_realloc (r, rsize + 1);
+
+ /* Multiply the two factors (in rp,rsize and rl) and put the final result
+ in place. */
+ {
+ mp_limb_t cy;
+ cy = mpn_mul_1 (r->_mp_d, rp, rsize, rl);
+ (r->_mp_d)[rsize] = cy;
+ rsize += cy != 0;
+ }
+
+ r->_mp_size = rsize;
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/urandomb.c b/rts/gmp/mpz/urandomb.c
new file mode 100644
index 0000000000..caca086e05
--- /dev/null
+++ b/rts/gmp/mpz/urandomb.c
@@ -0,0 +1,49 @@
+/* mpz_urandomb (rop, state, n) -- Generate a uniform pseudorandom
+ integer in the range 0 to 2^N - 1, inclusive, using STATE as the
+ random state previously initialized by a call to gmp_randinit().
+
+Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_urandomb (mpz_t rop, gmp_randstate_t rstate, unsigned long int nbits)
+#else
+mpz_urandomb (rop, rstate, nbits)
+ mpz_t rop;
+ gmp_randstate_t rstate;
+ unsigned long int nbits;
+#endif
+{
+ mp_ptr rp;
+ mp_size_t size;
+
+ size = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB;
+ if (ALLOC (rop) < size)
+ _mpz_realloc (rop, size);
+
+ rp = PTR (rop);
+
+ _gmp_rand (rp, rstate, nbits);
+ MPN_NORMALIZE (rp, size);
+ SIZ (rop) = size;
+}
diff --git a/rts/gmp/mpz/urandomm.c b/rts/gmp/mpz/urandomm.c
new file mode 100644
index 0000000000..69e1bae78a
--- /dev/null
+++ b/rts/gmp/mpz/urandomm.c
@@ -0,0 +1,78 @@
+/* mpz_urandomm (rop, state, n) -- Generate a uniform pseudorandom
+ integer in the range 0 to N-1, using STATE as the random state
+ previously initialized by a call to gmp_randinit().
+
+Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+#if __STDC__
+mpz_urandomm (mpz_t rop, gmp_randstate_t rstate, mpz_t n)
+#else
+mpz_urandomm (rop, rstate, n)
+ mpz_t rop;
+ gmp_randstate_t rstate;
+ mpz_t n;
+#endif
+{
+ mpz_t t, p, m;
+ mp_ptr tp;
+ mp_size_t nbits, size;
+ int count;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+
+ /* FIXME: Should check for n == 0 and report error */
+
+ size = SIZ (n);
+ count_leading_zeros (count, PTR (n)[size - 1]);
+ nbits = size * BITS_PER_MP_LIMB - count;
+
+ /* Allocate enough for any mpz function called since a realloc of
+ these will fail. */
+ MPZ_TMP_INIT (t, size);
+ MPZ_TMP_INIT (m, size + 1);
+ MPZ_TMP_INIT (p, size + 1);
+
+ /* Let m = highest possible random number plus 1. */
+ mpz_set_ui (m, 0);
+ mpz_setbit (m, nbits);
+
+ /* Let p = floor(m / n) * n. */
+ mpz_fdiv_q (p, m, n);
+ mpz_mul (p, p, n);
+
+ tp = PTR (t);
+ do
+ {
+ _gmp_rand (tp, rstate, nbits);
+ MPN_NORMALIZE (tp, size); /* FIXME: Really necessary? */
+ SIZ (t) = size;
+ }
+ while (mpz_cmp (t, p) >= 0);
+
+ mpz_mod (rop, t, n);
+
+ TMP_FREE (marker);
+}
diff --git a/rts/gmp/mpz/xor.c b/rts/gmp/mpz/xor.c
new file mode 100644
index 0000000000..69898d1791
--- /dev/null
+++ b/rts/gmp/mpz/xor.c
@@ -0,0 +1,217 @@
+/* mpz_xor -- Logical xor.
+
+Copyright (C) 1991, 1993, 1994, 1996, 1997, 2000 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+
+void
+#if __STDC__
+mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+#else
+mpz_xor (res, op1, op2)
+ mpz_ptr res;
+ mpz_srcptr op1;
+ mpz_srcptr op2;
+#endif
+{
+ mp_srcptr op1_ptr, op2_ptr;
+ mp_size_t op1_size, op2_size;
+ mp_ptr res_ptr;
+ mp_size_t res_size, res_alloc;
+ mp_size_t i;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ op1_size = op1->_mp_size;
+ op2_size = op2->_mp_size;
+
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+
+ if (op1_size >= 0)
+ {
+ if (op2_size >= 0)
+ {
+ if (op1_size >= op2_size)
+ {
+ if (res->_mp_alloc < op1_size)
+ {
+ _mpz_realloc (res, op1_size);
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+ }
+
+ if (res_ptr != op1_ptr)
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+ op1_size - op2_size);
+ for (i = op2_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
+ res_size = op1_size;
+ }
+ else
+ {
+ if (res->_mp_alloc < op2_size)
+ {
+ _mpz_realloc (res, op2_size);
+ op1_ptr = op1->_mp_d;
+ op2_ptr = op2->_mp_d;
+ res_ptr = res->_mp_d;
+ }
+
+ if (res_ptr != op2_ptr)
+ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+ op2_size - op1_size);
+ for (i = op1_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
+ res_size = op2_size;
+ }
+
+ MPN_NORMALIZE (res_ptr, res_size);
+ res->_mp_size = res_size;
+ return;
+ }
+ else /* op2_size < 0 */
+ {
+ /* Fall through to the code at the end of the function. */
+ }
+ }
+ else
+ {
+ if (op2_size < 0)
+ {
+ mp_ptr opx;
+ mp_limb_t cy;
+
+ /* Both operands are negative, the result will be positive.
+ (-OP1) ^ (-OP2) =
+ = ~(OP1 - 1) ^ ~(OP2 - 1) =
+ = (OP1 - 1) ^ (OP2 - 1) */
+
+ op1_size = -op1_size;
+ op2_size = -op2_size;
+
+ /* Possible optimization: Decrease mpn_sub precision,
+ as we won't use the entire res of both. */
+ opx = (mp_ptr) TMP_ALLOC (op1_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
+ op1_ptr = opx;
+
+ opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+ op2_ptr = opx;
+
+ res_alloc = MAX (op1_size, op2_size);
+ if (res->_mp_alloc < res_alloc)
+ {
+ _mpz_realloc (res, res_alloc);
+ res_ptr = res->_mp_d;
+ /* Don't re-read OP1_PTR and OP2_PTR. They point to
+ temporary space--never to the space RES->_mp_d used
+ to point to before reallocation. */
+ }
+
+ if (op1_size > op2_size)
+ {
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+ op1_size - op2_size);
+ for (i = op2_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
+ res_size = op1_size;
+ }
+ else
+ {
+ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+ op2_size - op1_size);
+ for (i = op1_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
+ res_size = op2_size;
+ }
+
+ MPN_NORMALIZE (res_ptr, res_size);
+ res->_mp_size = res_size;
+ TMP_FREE (marker);
+ return;
+ }
+ else
+ {
+ /* We should compute -OP1 ^ OP2. Swap OP1 and OP2 and fall
+ through to the code that handles OP1 ^ -OP2. */
+ MPZ_SRCPTR_SWAP (op1, op2);
+ MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
+ }
+ }
+
+ {
+ mp_ptr opx;
+ mp_limb_t cy;
+ mp_size_t count;
+
+ /* Operand 2 negative, so will be the result.
+ -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
+ = ~(OP1 ^ ~(OP2 - 1)) + 1 =
+ = (OP1 ^ (OP2 - 1)) + 1 */
+
+ op2_size = -op2_size;
+
+ opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB);
+ mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+ op2_ptr = opx;
+
+ res_alloc = MAX (op1_size, op2_size) + 1;
+ if (res->_mp_alloc < res_alloc)
+ {
+ _mpz_realloc (res, res_alloc);
+ op1_ptr = op1->_mp_d;
+ res_ptr = res->_mp_d;
+ /* Don't re-read OP2_PTR. It points to temporary space--never
+ to the space RES->_mp_d used to point to before reallocation. */
+ }
+
+ if (op1_size > op2_size)
+ {
+ MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
+ for (i = op2_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
+ res_size = op1_size;
+ }
+ else
+ {
+ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
+ for (i = op1_size - 1; i >= 0; i--)
+ res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
+ res_size = op2_size;
+ }
+
+ cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
+ if (cy)
+ {
+ res_ptr[res_size] = cy;
+ res_size++;
+ }
+
+ MPN_NORMALIZE (res_ptr, res_size);
+ res->_mp_size = -res_size;
+ TMP_FREE (marker);
+ }
+}