shithub: femtolisp

Download patch

ref: c3f004633be7e8a15fe8e1e158dde24c2af2f765
parent: 467826415fe2cc2846097dfd37ec879b9d62cf62
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Nov 16 22:05:28 EST 2024

import the rest of libmp tests from 9front

diff: cannot open b/3rd/mp/test//null: file does not exist: 'b/3rd/mp/test//null'
--- a/3rd/mp/test.c
+++ b/3rd/mp/test.c
@@ -436,7 +436,6 @@
 	if(argc == 3 && strcmp(argv[1], "-n") == 0)
 		loops = atoi(argv[2]);
 
-	memset(str, 0, sizeof(str));
 	D_PNAN = D_NNAN = strtod("+NaN", nil);
 	D_PINF = D_NINF = strtod("+Inf", nil);
 
--- /dev/null
+++ b/3rd/mp/test/convtest.c
@@ -1,0 +1,126 @@
+#include "platform.h"
+#include "mp.h"
+#include "dat.h"
+#include "fns.h"
+
+/* these tests suck but better than nothing... but really should test more values than just 1<<i */
+
+#define MPTOX(_name,_type,_func)  \
+static void \
+_name(void) \
+{ \
+	mpint *m; \
+	int i, sign, mag; \
+	_type v, e; \
+	int fail; \
+	 \
+	fail = 0; \
+	m = mpnew(0); \
+	for(i = 0; i < 256; i++){ \
+		sign = i >= 128 ? -1 : 1; \
+		mag = i % 128; \
+		itomp(sign, m); \
+		mpleft(m, mag, m); \
+		v = _func(m); \
+		e = 0xcafebabe; USED(e);
+#define MPTOX_END(_func,_format)  \
+		if(v != e){ \
+			fprintf(stderr, "FAIL: "#_func"(%s): return value: got "_format", expected "_format"\n", MFMT(m), v, e); \
+			fail=1; \
+		} \
+	} \
+	mpfree(m); \
+	if(!fail) \
+		fprintf(stderr, #_func": passed\n"); \
+}
+
+#define XTOMP(_name,_type,_func)  \
+static void \
+_name(void) \
+{ \
+	mpint *m, *r; \
+	int i, sign, mag; \
+	_type v; \
+	int fail; \
+	 \
+	fail = 0; \
+	m = mpnew(0); \
+	r = mpnew(0); \
+	for(i = 0; i < 256; i++){ \
+		sign = i >= 128 ? -1 : 1; \
+		mag = i % 128; \
+		itomp(sign, r); \
+		mpleft(r, mag, r);
+#define XTOMP_END(_func,_type,_format)  \
+		_func(sign * ((_type)1<<mag), m); \
+		if(mpcmp(r, m) != 0){ \
+			fprintf(stderr, "FAIL: "#_func"("_format"): return value: got %s, expected %s\n", sign * ((_type)1<<mag), MFMT(m), MFMT(r)); \
+			fail=1; \
+		} \
+	} \
+	mpfree(m); \
+	mpfree(r); \
+	if(!fail) \
+		fprintf(stderr, #_func": passed\n"); \
+	USED(v); \
+}
+
+MPTOX(test_mptoi, int, mptoi)
+	if(mag < 31)
+		e = sign*(1<<mag);
+	else
+		e = sign > 0 ? (1U<<31)-1 : 1U<<31;
+MPTOX_END(mptoi, "%#x")
+
+MPTOX(test_mptoui, uint32_t, mptoui)
+	if(mag < 32 && sign > 0)
+		e = 1<<mag;
+	else
+		e = sign > 0 ? -1 : 0;
+MPTOX_END(mptoui, "%#x")
+
+
+MPTOX(test_mptov, int64_t, mptov)
+	if(mag < 63)
+		e = sign*(1LL<<mag);
+	else
+		e = sign > 0 ? (1ULL<<63)-1 : 1ULL<<63;
+MPTOX_END(mptov, "%#"PRIx64)
+
+MPTOX(test_mptouv, uint64_t, mptouv)
+	if(mag < 64 && sign > 0)
+		e = 1LL<<mag;
+	else
+		e = sign > 0 ? -1ULL : 0;
+MPTOX_END(mptouv, "%#"PRIx64)
+
+XTOMP(test_itomp, int, itomp)
+	if(mag >= 31) continue;
+XTOMP_END(vtomp, int64_t, "%"PRId64)
+
+XTOMP(test_uitomp, uint32_t, uitomp)
+	if(mag >= 32 || sign < 0) continue;
+XTOMP_END(uitomp, uint32_t, "%"PRIu32)
+
+XTOMP(test_vtomp, int64_t, vtomp)
+	if(mag >= 63) continue;
+XTOMP_END(vtomp, int64_t, "%"PRId64)
+
+XTOMP(test_uvtomp, uint64_t, uvtomp)
+	if(mag >= 64 || sign < 0) continue;
+XTOMP_END(uvtomp, int64_t, "%"PRId64)
+
+
+void
+convtests(void)
+{
+	test_mptoi();
+	test_mptoui();
+	test_mptov();
+	test_mptouv();
+	test_itomp();
+	test_uitomp();
+	test_vtomp();
+	test_uvtomp();
+}
+
--- /dev/null
+++ b/3rd/mp/test/dat.h
@@ -1,0 +1,8 @@
+typedef struct ldint ldint;
+
+struct ldint {
+	uint32_t n;
+	uint8_t *b;
+};
+
+enum {NTEST = 2 * 257 + 32};
--- /dev/null
+++ b/3rd/mp/test/fns.h
@@ -1,0 +1,28 @@
+ldint* ldnew(int);
+int ldcmp(ldint *, ldint *);
+int ldmagcmp(ldint *, ldint *);
+void ldadd(ldint *, ldint *, ldint *);
+void ldsub(ldint *, ldint *, ldint *);
+void ldmagadd(ldint *, ldint *, ldint *);
+void ldmagsub(ldint *, ldint *, ldint *);
+void ldand(ldint *, ldint *, ldint *);
+void ldbic(ldint *, ldint *, ldint *);
+void ldor(ldint *, ldint *, ldint *);
+void ldxor(ldint *, ldint *, ldint *);
+void ldnot(ldint *, ldint *);
+void ldleft(ldint *, int, ldint *);
+void ldright(ldint *, int, ldint *);
+void ldasr(ldint *, int, ldint *);
+void lddiv_(ldint *, ldint *, ldint *, ldint *);
+void ldfree(ldint *);
+void testgen(int, ldint *);
+int ldmpeq(ldint *, mpint *);
+mpint* ldtomp(ldint *, mpint *);
+void mptarget(mpint *);
+void tests(void);
+void mpdiv_(mpint *, mpint *, mpint *, mpint *);
+void convtests(void);
+
+char *LFMT(ldint *);
+char *MFMT(mpint *);
+void prng(uint8_t *p, int n);
--- /dev/null
+++ b/3rd/mp/test/gen.tab.c
@@ -1,0 +1,1170 @@
+#include "platform.h"
+#include "mp.h"
+#include "dat.h"
+#include "fns.h"
+static void
+testcmp(void)
+{
+	int fail=0;
+	int a, b;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			a=ldcmp(l2, l3);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			b=mpcmp(m2, m3);
+			if(b<0) b=-1;
+			if(b>0) b=1;
+			if(a != b){
+				fprintf(stderr, "FAIL: mpcmp(%s, %s): return value: got %d, expected %d\n", LFMT(l2), LFMT(l3), b, a);
+				fail=1;
+			}
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpcmp(%s, %s): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpcmp(%s, %s): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	if(!fail) fprintf(stderr, "mpcmp: passed\n");
+}
+static void
+testmagcmp(void)
+{
+	int fail=0;
+	int a, b;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			a=ldmagcmp(l2, l3);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			b=mpmagcmp(m2, m3);
+			if(b<0) b=-1;
+			if(b>0) b=1;
+			if(a != b){
+				fprintf(stderr, "FAIL: mpmagcmp(%s, %s): return value: got %d, expected %d\n", LFMT(l2), LFMT(l3), b, a);
+				fail=1;
+			}
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpmagcmp(%s, %s): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpmagcmp(%s, %s): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	if(!fail) fprintf(stderr, "mpmagcmp: passed\n");
+}
+static void
+testadd(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldadd(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpadd(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpadd(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpadd(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpadd(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpadd: passed\n");
+}
+static void
+testsub(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldsub(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpsub(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpsub(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpsub(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpsub(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpsub: passed\n");
+}
+static void
+testmagadd(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldmagadd(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpmagadd(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpmagadd(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpmagadd(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpmagadd(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpmagadd: passed\n");
+}
+static void
+testmagsub(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldmagsub(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpmagsub(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpmagsub(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpmagsub(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpmagsub(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpmagsub: passed\n");
+}
+static void
+testand(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldand(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpand(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpand(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpand(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpand(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpand: passed\n");
+}
+static void
+testbic(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldbic(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpbic(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpbic(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpbic(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpbic(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpbic: passed\n");
+}
+static void
+testor(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldor(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpor(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpor(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpor(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpor(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpor: passed\n");
+}
+static void
+testxor(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			ldxor(l2, l3, l4);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpxor(m2, m3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpxor(m2, m3, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mpxor(m2, m3, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpxor(%s, %s, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpxor: passed\n");
+}
+static void
+testnot(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		ldnot(l2, l3);
+		ldtomp(l2, m2);
+		mptarget(m3);
+		mpnot(m2, m3);
+		if(!ldmpeq(l2, m2)){
+			fprintf(stderr, "FAIL: mpnot(%s, out): arg 1: input corrupted\n", LFMT(l2));
+			fail=1;
+		}
+		if(m3->top == 0 && m3->sign < 0){
+			fprintf(stderr, "FAIL: mpnot(%s, out): arg 2: got -0, shouldn't happen\n", LFMT(l2));
+			fail=1;
+		}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+			fprintf(stderr, "FAIL: mpnot(%s, out): arg 2: got denormalised result\n", LFMT(l2));
+			fail=1;
+		}else if(!ldmpeq(l3, m3)){
+			fprintf(stderr, "FAIL: mpnot(%s, out): arg 2: got %s, expected %s\n", LFMT(l2), MFMT(m3), LFMT(l3));
+			fail=1;
+		}
+		ldtomp(l2, m2);
+		mptarget(m3);
+		mpnot(m2, m2);
+		if(m2->top == 0 && m2->sign < 0){
+			fprintf(stderr, "FAIL: mpnot(%s, out): alias 2 and 1: arg 2: got -0, shouldn't happen\n", LFMT(l2));
+			fail=1;
+		}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+			fprintf(stderr, "FAIL: mpnot(%s, out): alias 2 and 1: arg 2: got denormalised result\n", LFMT(l2));
+			fail=1;
+		}else if(!ldmpeq(l3, m2)){
+			fprintf(stderr, "FAIL: mpnot(%s, out): alias 2 and 1: arg 2: got %s, expected %s\n", LFMT(l2), MFMT(m2), LFMT(l3));
+			fail=1;
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	if(!fail) fprintf(stderr, "mpnot: passed\n");
+}
+static void
+testleft(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=-128;i3<=128;i3++){
+			ldleft(l2, i3, l4);
+			ldtomp(l2, m2);
+			mptarget(m4);
+			mpleft(m2, i3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): arg 1: input corrupted\n", LFMT(l2), i3);
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), i3);
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): arg 3: got denormalised result\n", LFMT(l2), i3);
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): arg 3: got %s, expected %s\n", LFMT(l2), i3, MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			mptarget(m4);
+			mpleft(m2, i3, m2);
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), i3);
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), i3);
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpleft(%s, %d, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), i3, MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpleft: passed\n");
+}
+static void
+testright(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=-128;i3<=128;i3++){
+			ldright(l2, i3, l4);
+			ldtomp(l2, m2);
+			mptarget(m4);
+			mpright(m2, i3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): arg 1: input corrupted\n", LFMT(l2), i3);
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), i3);
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): arg 3: got denormalised result\n", LFMT(l2), i3);
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): arg 3: got %s, expected %s\n", LFMT(l2), i3, MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			mptarget(m4);
+			mpright(m2, i3, m2);
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), i3);
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), i3);
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpright(%s, %d, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), i3, MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpright: passed\n");
+}
+static void
+testasr(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=-128;i3<=128;i3++){
+			ldasr(l2, i3, l4);
+			ldtomp(l2, m2);
+			mptarget(m4);
+			mpasr(m2, i3, m4);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): arg 1: input corrupted\n", LFMT(l2), i3);
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), i3);
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): arg 3: got denormalised result\n", LFMT(l2), i3);
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): arg 3: got %s, expected %s\n", LFMT(l2), i3, MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			mptarget(m4);
+			mpasr(m2, i3, m2);
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), i3);
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), i3);
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpasr(%s, %d, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), i3, MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l4);
+	mpfree(m4);
+	if(!fail) fprintf(stderr, "mpasr: passed\n");
+}
+static void
+testdiv_(void)
+{
+	int fail=0;
+	ldint *l2 = ldnew(0);
+	mpint *m2 = mpnew(0);
+	int i2;
+	ldint *l3 = ldnew(0);
+	mpint *m3 = mpnew(0);
+	int i3;
+	ldint *l4 = ldnew(0);
+	mpint *m4 = mpnew(0);
+	ldint *l5 = ldnew(0);
+	mpint *m5 = mpnew(0);
+	for(i2=0;i2<NTEST;i2++){
+		testgen(i2, l2);
+		for(i3=0;i3<NTEST;i3++){
+			testgen(i3, l3);
+			lddiv_(l2, l3, l4, l5);
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mptarget(m5);
+			mpdiv_(m2, m3, m4, m5);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			if(m5->top == 0 && m5->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 4: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m5->top != 0 && m5->p[m5->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 4: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l5, m5)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): arg 4: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m5), LFMT(l5));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mptarget(m5);
+			mpdiv_(m2, m3, m2, m5);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m5->top == 0 && m5->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 4: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m5->top != 0 && m5->p[m5->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 4: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l5, m5)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 4: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m5), LFMT(l5));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m2)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mptarget(m5);
+			mpdiv_(m2, m3, m3, m5);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m5->top == 0 && m5->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 4: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m5->top != 0 && m5->p[m5->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 4: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l5, m5)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 4: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m5), LFMT(l5));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m3)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 3 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l4));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mptarget(m5);
+			mpdiv_(m2, m3, m4, m2);
+			if(!ldmpeq(l3, m3)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 2: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			if(m2->top == 0 && m2->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 4: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m2->top != 0 && m2->p[m2->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 4: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l5, m2)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 1: arg 4: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m2), LFMT(l5));
+				fail=1;
+			}
+			ldtomp(l2, m2);
+			ldtomp(l3, m3);
+			mptarget(m4);
+			mptarget(m5);
+			mpdiv_(m2, m3, m4, m3);
+			if(!ldmpeq(l2, m2)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 1: input corrupted\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}
+			if(m4->top == 0 && m4->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 3: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m4->top != 0 && m4->p[m4->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 3: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l4, m4)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 3: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m4), LFMT(l4));
+				fail=1;
+			}
+			if(m3->top == 0 && m3->sign < 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 4: got -0, shouldn't happen\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(m3->top != 0 && m3->p[m3->top - 1] == 0){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 4: got denormalised result\n", LFMT(l2), LFMT(l3));
+				fail=1;
+			}else if(!ldmpeq(l5, m3)){
+				fprintf(stderr, "FAIL: mpdiv_(%s, %s, out, out): alias 4 and 2: arg 4: got %s, expected %s\n", LFMT(l2), LFMT(l3), MFMT(m3), LFMT(l5));
+				fail=1;
+			}
+		}
+	}
+	ldfree(l2);
+	mpfree(m2);
+	ldfree(l3);
+	mpfree(m3);
+	ldfree(l4);
+	mpfree(m4);
+	ldfree(l5);
+	mpfree(m5);
+	if(!fail) fprintf(stderr, "mpdiv_: passed\n");
+}
+void
+tests(void)
+{
+	testcmp();
+	testmagcmp();
+	testadd();
+	testsub();
+	testmagadd();
+	testmagsub();
+	testand();
+	testbic();
+	testor();
+	testxor();
+	testnot();
+	testleft();
+	testright();
+	testasr();
+	testdiv_();
+}
--- /dev/null
+++ b/3rd/mp/test/ld.c
@@ -1,0 +1,560 @@
+#include "platform.h"
+#include "mp.h"
+#include "dat.h"
+#include "fns.h"
+
+static int
+ldget(ldint *a, uint32_t n)
+{
+	if(n < 0) return 0;
+	if(n >= a->n) return a->b[a->n - 1]&1;
+	return a->b[n]&1;
+}
+
+static void
+ldbits(ldint *a, int n)
+{
+	a->b = realloc(a->b, n);
+	a->n = n;
+}
+
+static ldint *
+ldnorm(ldint *a)
+{
+	int i;
+
+	if(a->n > 0){
+		for(i = a->n - 2; i >= 0; i--)
+			if(a->b[i] != a->b[a->n-1])
+				break;
+		ldbits(a, i + 2);
+	}else{
+		ldbits(a, 1);
+		a->b[0] = 0;
+	}
+	return a;
+}
+
+static void
+ldneg(ldint *a)
+{
+	int c, s, z;
+	uint32_t i;
+	
+	c = 1;
+	s = a->b[a->n - 1];
+	z = 1;
+	for(i = 0; i < a->n; i++){
+		if(a->b[i]) z = 0;
+		c += 1 ^ a->b[i] & 1;
+		a->b[i] = c & 1;
+		c >>= 1;
+	}
+	if(!z && s == a->b[a->n - 1]){
+		ldbits(a, a->n + 1);
+		a->b[a->n - 1] = !s;
+	}
+}
+
+static int
+max(int a, int b)
+{
+	return a>b? a : b;
+}
+
+ldint *
+ldnew(int n)
+{
+	ldint *a;
+	
+	a = malloc(sizeof(ldint));
+	if(n <= 0) n = 1;
+	a->b = malloc(n);
+	a->n = n;
+	return a;
+}
+
+void
+ldfree(ldint *a)
+{
+	if(a == nil) return;
+	free(a->b);
+	free(a);
+}
+
+mpint *
+ldtomp(ldint *a, mpint *b)
+{
+	int s, c;
+	uint32_t i;
+
+	if(b == nil)
+		b = mpnew(0);
+	mpbits(b, a->n);
+	s = a->b[a->n - 1] & 1;
+	b->sign = 1 - 2 * s;
+	c = s;
+	memset(b->p, 0, (a->n + Dbits - 1) / Dbits * Dbytes);
+	for(i = 0; i < a->n; i++){
+		c += s ^ a->b[i] & 1;
+		b->p[i / Dbits] |= (mpdigit)(c & 1) << (i & Dbits - 1);
+		c >>= 1;
+	}
+	b->top = (a->n + Dbits - 1) / Dbits;
+	mpnorm(b);
+	return b;
+}
+
+static ldint *
+itold(int n, ldint *a)
+{
+	uint32_t i;
+
+	if(a == nil)
+		a = ldnew(sizeof(n)*8);
+	else
+		ldbits(a, sizeof(n)*8);
+	for(i = 0; i < sizeof(n)*8; i++)
+		a->b[i] = n >> i & 1;
+	ldnorm(a);
+	return a;
+}
+
+static ldint *
+pow2told(int n, ldint *a)
+{
+	int k;
+	
+	k = abs(n);
+	if(a == nil)
+		a = ldnew(k+2);
+	else
+		ldbits(a, k+2);
+	memset(a->b, 0, k+2);
+	a->b[k] = 1;
+	if(n < 0) ldneg(a);
+	ldnorm(a);
+	return a;
+}
+
+static char str[16][8192];
+static int istr = -1;
+
+char *
+LFMT(ldint *a)
+{
+	char *b, *p;
+	int s, c;
+	uint32_t i, d;
+
+	istr = (istr+1) % nelem(str);
+	b = str[istr] + 3;
+	d = (a->n + 3) / 4;
+	c = s = a->b[a->n - 1];
+	for(i = 0; i < a->n; i++){
+		c += s^ldget(a, i);
+		b[d - 1 - (i >> 2)] |= (c & 1) << (i & 3);
+		c >>= 1;
+	}
+	for(i = 0; i < d; i++)
+		b[i] = "0123456789ABCDEF"[(int)b[i]];
+	p = b;
+	while(*p == '0' && p[1] != 0) p++;
+	*--p = 'x';
+	*--p = '0';
+	if(a->b[a->n - 1])
+		*--p = '-';
+	return p;
+}
+
+char *
+MFMT(mpint *m)
+{
+	char *b;
+	istr = (istr+1) % nelem(str);
+	b = str[istr];
+	return mptoa(m, 16, b, sizeof(str[istr]));
+}
+
+int
+ldcmp(ldint *a, ldint *b)
+{
+	int x, y;
+	int i, r;
+	
+	r = max(a->n, b->n);
+	if(a->b[a->n-1] != b->b[b->n-1])
+		return b->b[b->n - 1] - a->b[a->n - 1];
+	for(i = r - 1; --i >= 0; ){
+		x = ldget(a, i);
+		y = ldget(b, i);
+		if(x != y)
+			return x - y;
+	}
+	return 0;
+}
+
+int
+ldmagcmp(ldint *a, ldint *b)
+{
+	int s1, s2, r;
+	
+	s1 = a->b[a->n - 1];
+	s2 = b->b[b->n - 1];
+	if(s1) ldneg(a);
+	if(s2) ldneg(b);
+	r = ldcmp(a, b);
+	if(s1) ldneg(a);
+	if(s2) ldneg(b);
+	return r;
+}
+
+int
+ldmpeq(ldint *a, mpint *b)
+{
+	uint32_t i, c;
+
+	if(b->sign > 0){
+		for(i = 0; i < b->top * Dbits; i++)
+			if(ldget(a, i) != (b->p[i / Dbits] >> (i & Dbits - 1) & 1))
+				return 0;
+		for(; i < a->n; i++)
+			if(a->b[i] != 0)
+				return 0;
+		return 1;
+	}else{
+		c = 1;
+		for(i = 0; i < b->top * Dbits; i++){
+			c += !ldget(a, i);
+			if((c & 1) != (b->p[i / Dbits] >> (i & Dbits - 1) & 1))
+				return 0;
+			c >>= 1;
+		}
+		for(; i < a->n; i++)
+			if(a->b[i] != 1)
+				return 0;
+		return 1;
+	}
+}
+
+void
+mptarget(mpint *r)
+{
+	int n;
+
+	n = rand() & 15;
+	mpbits(r, n * Dbits);
+	r->top = n;
+	prng((void *) r->p, n * Dbytes);
+	r->sign = 1 - 2 * (rand() & 1);
+}
+
+void
+ldadd(ldint *a, ldint *b, ldint *q)
+{
+	int r, i, c;
+	
+	r = max(a->n, b->n) + 1;
+	ldbits(q, r);
+	c = 0;
+	for(i = 0; i < r; i++){
+		c += ldget(a, i) + ldget(b, i);
+		q->b[i] = c & 1;
+		c >>= 1;
+	}
+	ldnorm(q);
+}
+
+void
+ldmagadd(ldint *a, ldint *b, ldint *q)
+{
+	int i, r, s1, s2, c1, c2, co;
+	
+	r = max(a->n, b->n) + 2;
+	ldbits(q, r);
+	co = 0;
+	s1 = c1 = a->b[a->n - 1] & 1;
+	s2 = c2 = b->b[b->n - 1] & 1;
+	for(i = 0; i < r; i++){
+		c1 += s1 ^ ldget(a, i) & 1;
+		c2 += s2 ^ ldget(b, i) & 1;
+		co += (c1 & 1) + (c2 & 1);
+		q->b[i] = co & 1;
+		co >>= 1;
+		c1 >>= 1;
+		c2 >>= 1;
+	}
+	ldnorm(q);
+}
+
+void
+ldmagsub(ldint *a, ldint *b, ldint *q)
+{
+	int i, r, s1, s2, c1, c2, co;
+	
+	r = max(a->n, b->n) + 2;
+	ldbits(q, r);
+	co = 0;
+	s1 = c1 = a->b[a->n - 1] & 1;
+	s2 = c2 = 1 ^ b->b[b->n - 1] & 1;
+	for(i = 0; i < r; i++){
+		c1 += s1 ^ ldget(a, i) & 1;
+		c2 += s2 ^ ldget(b, i) & 1;
+		co += (c1 & 1) + (c2 & 1);
+		q->b[i] = co & 1;
+		co >>= 1;
+		c1 >>= 1;
+		c2 >>= 1;
+	}
+	ldnorm(q);
+}
+
+void
+ldsub(ldint *a, ldint *b, ldint *q)
+{
+	int r, i, c;
+	
+	r = max(a->n, b->n) + 1;
+	ldbits(q, r);
+	c = 1;
+	for(i = 0; i < r; i++){
+		c += ldget(a, i) + (1^ldget(b, i));
+		q->b[i] = c & 1;
+		c >>= 1;
+	}
+	ldnorm(q);
+}
+
+static void
+lddiv(ldint *a, ldint *b, ldint *q, ldint *r)
+{
+	int n, i, j, c, s;
+	
+	n = max(a->n, b->n) + 1;
+	ldbits(q, n);
+	ldbits(r, n);
+	memset(r->b, 0, n);
+	c = s = a->b[a->n-1];
+	for(i = 0; i < n; i++){
+		c += s ^ ldget(a, i);
+		q->b[i] = c & 1;
+		c >>= 1;
+	}
+	for(i = 0; i < n; i++){
+		for(j = n-1; --j >= 0; )
+			r->b[j + 1] = r->b[j];
+		r->b[0] = q->b[n - 1];
+		for(j = n-1; --j >= 0; )
+			q->b[j + 1] = q->b[j];
+		q->b[0] = !r->b[n - 1];
+		c = s = r->b[n - 1] == b->b[b->n - 1];
+		for(j = 0; j < n; j++){
+			c += r->b[j] + (s ^ ldget(b, j));
+			r->b[j] = c & 1;
+			c >>= 1;
+		}
+	}
+	for(j = n-1; --j >= 0; )
+		q->b[j + 1] = q->b[j];
+	q->b[0] = 1;
+	if(r->b[r->n - 1]){
+		c = 0;
+		for(j = 0; j < n; j++){
+			c += 1 + q->b[j];
+			q->b[j] = c & 1;
+			c >>= 1;
+		}
+		c = s = b->b[b->n - 1];
+		for(j = 0; j < n; j++){
+			c += r->b[j] + (s ^ ldget(b, j));
+			r->b[j] = c & 1;
+			c >>= 1;
+		}
+	}
+	c = s = a->b[a->n-1] ^ b->b[b->n-1];
+	for(j = 0; j < n; j++){
+		c += s ^ q->b[j];
+		q->b[j] = c & 1;
+		c >>= 1;
+	}
+	c = s = a->b[a->n-1];
+	for(j = 0; j < n; j++){
+		c += s ^ r->b[j];
+		r->b[j] = c & 1;
+		c >>= 1;
+	}
+	ldnorm(q);
+	ldnorm(r);
+}
+
+void
+lddiv_(ldint *a, ldint *b, ldint *q, ldint *r)
+{
+	if(ldmpeq(b, mpzero)){
+		memset(q->b, 0, q->n);
+		memset(r->b, 0, r->n);
+		return;
+	}
+	lddiv(a, b, q, r);
+}
+
+void
+mpdiv_(mpint *a, mpint *b, mpint *q, mpint *r)
+{
+	if(mpcmp(b, mpzero) == 0){
+		mpassign(mpzero, q);
+		mpassign(mpzero, r);
+		return;
+	}
+	mpdiv(a, b, q, r);
+}
+
+void
+ldand(ldint *a, ldint *b, ldint *q)
+{
+	int r, i;
+	
+	r = max(a->n, b->n);
+	ldbits(q, r);
+	for(i = 0; i < r; i++)
+		q->b[i] = ldget(a, i) & ldget(b, i);
+	ldnorm(q);
+}
+
+void
+ldbic(ldint *a, ldint *b, ldint *q)
+{
+	int r, i;
+	
+	r = max(a->n, b->n);
+	ldbits(q, r);
+	for(i = 0; i < r; i++)
+		q->b[i] = ldget(a, i) & ~ldget(b, i);
+	ldnorm(q);
+}
+
+void
+ldor(ldint *a, ldint *b, ldint *q)
+{
+	int r, i;
+	
+	r = max(a->n, b->n);
+	ldbits(q, r);
+	for(i = 0; i < r; i++)
+		q->b[i] = ldget(a, i) | ldget(b, i);
+	ldnorm(q);
+}
+
+void
+ldxor(ldint *a, ldint *b, ldint *q)
+{
+	int r, i;
+	
+	r = max(a->n, b->n);
+	ldbits(q, r);
+	for(i = 0; i < r; i++)
+		q->b[i] = ldget(a, i) ^ ldget(b, i);
+	ldnorm(q);
+}
+
+void
+ldleft(ldint *a, int n, ldint *b)
+{
+	int c;
+	uint32_t i;
+
+	if(n < 0){
+		if(a->n <= (uint32_t)-n){
+			b->n = 0;
+			ldnorm(b);
+			return;
+		}
+		c = 0;
+		if(a->b[a->n - 1])
+			for(i = 0; i < (uint32_t)-n; i++)
+				if(a->b[i]){
+					c = 1;
+					break;
+				}
+		ldbits(b, a->n + n);
+		for(i = 0; i < a->n + n; i++){
+			c += a->b[i - n] & 1;
+			b->b[i] = c & 1;
+			c >>= 1;
+		}
+	}else{
+		ldbits(b, a->n + n);
+		memmove(b->b + n, a->b, a->n);
+		memset(b->b, 0, n);
+	}
+	ldnorm(b);
+}
+
+void
+ldright(ldint *a, int n, ldint *b)
+{
+	ldleft(a, -n, b);
+}
+
+void
+ldasr(ldint *a, int n, ldint *b)
+{
+	if(n < 0){
+		ldleft(a, -n, b);
+		return;
+	}
+	if(a->n <= (uint32_t)n){
+		ldbits(b, 1);
+		b->b[0] = a->b[a->n - 1];
+		return;
+	}
+	ldbits(b, a->n - n);
+	memmove(b->b, a->b + n, a->n - n);
+	ldnorm(b);
+}
+
+void
+ldnot(ldint *a, ldint *b)
+{
+	uint32_t i;
+	
+	ldbits(b, a->n);
+	for(i = 0; i < a->n; i++)
+		b->b[i] = a->b[i] ^ 1;
+}
+
+static uint32_t
+xorshift(uint32_t *state)
+{
+	uint32_t x = *state;
+	x ^= x << 13;
+	x ^= x >> 17;
+	x ^= x << 5;
+	*state = x;
+	return x;
+}
+
+void
+testgen(int i, ldint *a)
+{
+	uint32_t j, state;
+	uint32_t r = 0;
+
+	if(i < 257)
+		itold(i-128, a);
+	else if(i < 514)
+		pow2told(i-385, a);
+	else{
+		state = i;
+		xorshift(&state);
+		xorshift(&state);
+		xorshift(&state);
+		ldbits(a, Dbits * (1 + (xorshift(&state) & 15)));
+		for(j = 0; j < a->n; j++){
+			if((j & 31) == 0)
+				r = xorshift(&state);
+			a->b[j] = r & 1;
+			r >>= 1;
+		}
+	}
+}
--- /dev/null
+++ b/3rd/mp/test/main.c
@@ -1,0 +1,32 @@
+#include "platform.h"
+#include "mp.h"
+#include "dat.h"
+#include "fns.h"
+#include "ieee754.h"
+
+double D_PNAN, D_NNAN, D_PINF, D_NINF;
+float F_PNAN, F_NNAN, F_PINF, F_NINF;
+
+void
+prng(uint8_t *p, int n)
+{
+	while(n-- > 0)
+		*p++ = rand();
+}
+
+int
+main()
+{
+	D_PNAN = D_NNAN = strtod("+NaN", nil);
+	D_PINF = D_NINF = strtod("+Inf", nil);
+
+	union ieee754_double *d;
+	d = (union ieee754_double *)&D_NNAN;
+	d->ieee.negative = 1;
+	d = (union ieee754_double *)&D_NINF;
+	d->ieee.negative = 1;
+
+	convtests();
+	tests();
+	return 0;
+}
--- a/meson.build
+++ b/meson.build
@@ -25,40 +25,6 @@
 	language: 'c',
 )
 
-mp = [
-	'3rd/mp/mpadd.c',
-	'3rd/mp/mpaux.c',
-	'3rd/mp/mpcmp.c',
-	'3rd/mp/mpdigdiv.c',
-	'3rd/mp/mpdiv.c',
-	'3rd/mp/mpextendedgcd.c',
-	'3rd/mp/mpexp.c',
-	'3rd/mp/mpfmt.c',
-	'3rd/mp/mpinvert.c',
-	'3rd/mp/mpleft.c',
-	'3rd/mp/mplogic.c',
-	'3rd/mp/mpmod.c',
-	'3rd/mp/mpmodop.c',
-	'3rd/mp/mpmul.c',
-	'3rd/mp/mprand.c',
-	'3rd/mp/mpright.c',
-	'3rd/mp/mpsub.c',
-	'3rd/mp/mptobe.c',
-	'3rd/mp/mptober.c',
-	'3rd/mp/mptod.c',
-	'3rd/mp/mptoi.c',
-	'3rd/mp/mptoui.c',
-	'3rd/mp/mptouv.c',
-	'3rd/mp/mptov.c',
-	'3rd/mp/mpvecadd.c',
-	'3rd/mp/mpveccmp.c',
-	'3rd/mp/mpvecdigmuladd.c',
-	'3rd/mp/mpvecsub.c',
-	'3rd/mp/mpvectscmp.c',
-	'3rd/mp/strtomp.c',
-	'3rd/mp/u16.c',
-]
-
 utf = [
 	'3rd/utf/rune.c',
 	'3rd/utf/runeistype.c',
@@ -153,11 +119,51 @@
 	],
 )
 
+mp = static_library(
+	'mp',
+	[
+		'3rd/mp/mpadd.c',
+		'3rd/mp/mpaux.c',
+		'3rd/mp/mpcmp.c',
+		'3rd/mp/mpdigdiv.c',
+		'3rd/mp/mpdiv.c',
+		'3rd/mp/mpexp.c',
+		'3rd/mp/mpextendedgcd.c',
+		'3rd/mp/mpfmt.c',
+		'3rd/mp/mpinvert.c',
+		'3rd/mp/mpleft.c',
+		'3rd/mp/mplogic.c',
+		'3rd/mp/mpmod.c',
+		'3rd/mp/mpmodop.c',
+		'3rd/mp/mpmul.c',
+		'3rd/mp/mprand.c',
+		'3rd/mp/mpright.c',
+		'3rd/mp/mpsub.c',
+		'3rd/mp/mptobe.c',
+		'3rd/mp/mptober.c',
+		'3rd/mp/mptod.c',
+		'3rd/mp/mptoi.c',
+		'3rd/mp/mptoui.c',
+		'3rd/mp/mptouv.c',
+		'3rd/mp/mptov.c',
+		'3rd/mp/mpvecadd.c',
+		'3rd/mp/mpveccmp.c',
+		'3rd/mp/mpvecdigmuladd.c',
+		'3rd/mp/mpvecsub.c',
+		'3rd/mp/mpvectscmp.c',
+		'3rd/mp/strtomp.c',
+		'3rd/mp/u16.c',
+	],
+	include_directories: include_directories(
+		'3rd/mp',
+		'posix',
+	),
+)
+
 flisp = executable(
 	'flisp',
 	sources: [
 		src,
-		mp,
 		utf,
 		boot,
 		builtins,
@@ -171,6 +177,9 @@
 		'3rd/utf',
 		'posix',
 	),
+	link_with: [
+		mp,
+	],
 )
 
 mptest = executable(
@@ -177,22 +186,40 @@
 	'mptest',
 	sources: [
 		'3rd/mp/test.c',
-		mp,
 	],
 	include_directories: include_directories(
-		'3rd',
-		'3rd/mp',
 		'posix',
 	),
+	link_with: [
+		mp,
+	],
 )
 test('mp', mptest)
 
+mptest2 = executable(
+	'mptest2',
+	sources: [
+		'3rd/mp/test/convtest.c',
+		'3rd/mp/test/gen.tab.c',
+		'3rd/mp/test/ld.c',
+		'3rd/mp/test/main.c',
+	],
+	include_directories: include_directories(
+		'3rd/mp/test',
+		'posix',
+	),
+	link_with: [
+		mp,
+	],
+)
+test('mp2', mptest2, timeout: -1)
+
 tests_dir = join_paths(meson.current_source_dir(), 'test')
 
 test('argv', flisp, args: ['argv.lsp'], workdir: tests_dir)
 test('hash', flisp, args: ['hashtest.lsp'], workdir: tests_dir)
-test('perf', flisp, args: ['perf.lsp'], workdir: tests_dir, timeout: 60)
+test('perf', flisp, args: ['perf.lsp'], workdir: tests_dir, timeout: -1)
 test('tme', flisp, args: ['tme.lsp'], workdir: tests_dir)
-test('torture', flisp, args: ['torture.scm'], workdir: tests_dir, timeout: 60)
+test('torture', flisp, args: ['torture.scm'], workdir: tests_dir, timeout: -1)
 test('torus', flisp, args: ['torus.lsp'], workdir: tests_dir)
 test('unit', flisp, args: ['unittest.lsp'], workdir: tests_dir)