shithub: femtolisp

Download patch

ref: 20488fc4915662e0ec50bb8c4ebc2609d6e110b4
parent: 1b00536fd5957d70dfde3a67fece862dbb879492
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Nov 15 19:30:55 EST 2024

refactor (mostly arithmetic)

Make fixnum<->bignum arithmetic correct and more seamless when it
comes to possible overflows of underlying types.
Fixnums will transition to bignums (vice versa) when needed.
C-specific types are no longer considered as preferred numerical
types.

--- a/3rd/mp/mpaux.c
+++ b/3rd/mp/mpaux.c
@@ -75,13 +75,13 @@
 			return;
 	} else {
 		if(b->p == (mpdigit*)&b[1]){
-			b->p = (mpdigit*)LLT_ALLOC(n*Dbytes);
+			b->p = (mpdigit*)MEM_ALLOC(n*Dbytes);
 			if(b->p == nil)
 				sysfatal("mpbits: %r");
 			memmove(b->p, &b[1], Dbytes*b->top);
 			memset(&b[1], 0, Dbytes*b->size);
 		} else {
-			b->p = (mpdigit*)LLT_REALLOC(b->p, n*Dbytes);
+			b->p = (mpdigit*)MEM_REALLOC(b->p, n*Dbytes);
 			if(b->p == nil)
 				sysfatal("mpbits: %r");
 		}
@@ -101,8 +101,8 @@
 		sysfatal("freeing mp constant");
 	memset(b->p, 0, b->size*Dbytes);
 	if(b->p != (mpdigit*)&b[1])
-		LLT_FREE(b->p);
-	LLT_FREE(b);
+		MEM_FREE(b->p);
+	MEM_FREE(b);
 }
 
 mpint*
--- a/3rd/mp/mpfmt.c
+++ b/3rd/mp/mpfmt.c
@@ -143,7 +143,7 @@
 		for(rv=1; (base >> rv) > 1; rv++)
 			;
 		len = 10 + (b->top*Dbits / rv);
-		buf = LLT_ALLOC(len);
+		buf = MEM_ALLOC(len);
 		if(buf == nil)
 			return nil;
 		alloced = 1;
@@ -179,7 +179,7 @@
 	}
 	if(rv < 0){
 		if(alloced)
-			LLT_FREE(buf);
+			MEM_FREE(buf);
 		return nil;
 	}
 	return buf;
--- a/3rd/mp/mpmul.c
+++ b/3rd/mp/mpmul.c
@@ -90,7 +90,7 @@
 		mpvecadd(res+n, reslen-n, diffprod, u0len+v0len, res+n);
 	memmove(p, res, (alen+blen)*Dbytes);
 
-	LLT_FREE(t);
+	MEM_FREE(t);
 }
 
 #define KARATSUBAMIN 32
--- a/3rd/mp/mptobe.c
+++ b/3rd/mp/mptobe.c
@@ -13,7 +13,7 @@
 		m++;
 	if(p == nil){
 		n = m;
-		p = LLT_ALLOC(n);
+		p = MEM_ALLOC(n);
 		if(p == nil)
 			sysfatal("mptobe: %r");
 	} else {
--- a/3rd/spooky.c
+++ b/3rd/spooky.c
@@ -26,7 +26,7 @@
 #include "platform.h"
 #include "spooky.h"
 
-#define ALLOW_UNALIGNED_READS 1
+#define ALLOW_UNALIGNED_READS 0
 
 //
 // SC_CONST: a constant which:
@@ -369,9 +369,18 @@
 	} u;
 	size_t left;
 
-	h[0] = h[3] = h[6] = h[9] = *hash1;
-	h[1] = h[4] = h[7] = h[10] = *hash2;
-	h[2] = h[5] = h[8] = h[11] = SC_CONST;
+	h[0] = *hash1;
+	h[1] = *hash2;
+	h[2] = SC_CONST;
+	h[3] = *hash1;
+	h[4] = *hash2;
+	h[5] = SC_CONST;
+	h[6] = *hash1;
+	h[7] = *hash2;
+	h[8] = SC_CONST;
+	h[9] = *hash1;
+	h[10] = *hash2;
+	h[11] = SC_CONST;
 
 	u.p8 = (const uint8_t *) message;
 	end = u.p64 + (length / SC_BLOCKSIZE) * SC_NUMVARS;
--- a/3rd/wcwidth.c
+++ b/3rd/wcwidth.c
@@ -15,7 +15,7 @@
  * https://github.com/termux/termux-packages/tree/master/packages/libandroid-support
  */
 
-#include "../llt.h"
+#include "flisp.h"
 
 struct width_interval {
 	int start;
--- a/bitvector.c
+++ b/bitvector.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 
 uint32_t *
 bitvector_resize(uint32_t *b, uint64_t oldsz, uint64_t newsz, int initzero)
@@ -5,7 +5,7 @@
 {
 	uint32_t *p;
 	size_t sz = ((newsz+31)>>5) * sizeof(uint32_t);
-	p = LLT_REALLOC(b, sz);
+	p = MEM_REALLOC(b, sz);
 	if(p == nil)
 		return nil;
 	if(initzero && newsz>oldsz){
--- a/builtins.c
+++ b/builtins.c
@@ -2,7 +2,6 @@
   Extra femtoLisp builtin functions
 */
 
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 #include "cvalues.h"
@@ -9,6 +8,9 @@
 #include "timefuncs.h"
 #include "random.h"
 
+#define DBL_MAXINT (1LL<<53)
+#define FLT_MAXINT (1<<24)
+
 size_t
 llength(value_t v)
 {
@@ -131,7 +133,7 @@
 BUILTIN("symbol", symbol)
 {
 	argcount(nargs, 1);
-	if(!fl_isstring(args[0]))
+	if(__unlikely(!fl_isstring(args[0])))
 		type_error("string", args[0]);
 	return symbol(cvalue_data(args[0]));
 }
@@ -245,13 +247,15 @@
 BUILTIN("fixnum", fixnum)
 {
 	argcount(nargs, 1);
-	if(isfixnum(args[0]))
-		return args[0];
-	if(iscprim(args[0])){
-		cprim_t *cp = (cprim_t*)ptr(args[0]);
-		return fixnum(conv_to_long(cp_data(cp), cp_numtype(cp)));
-	}
-	type_error("number", args[0]);
+	value_t v = args[0];
+	if(isfixnum(v))
+		return v;
+	void *p = ptr(v);
+	if(iscprim(v))
+		return fixnum(conv_to_int64(cp_data(p), cp_numtype(p)));
+	if(iscvalue(v) && cp_numtype(p) == T_MPINT)
+		return fixnum(mptov(*(mpint**)cv_data(p)));
+	type_error("number", v);
 }
 
 BUILTIN("truncate", truncate)
@@ -285,11 +289,11 @@
 
 BUILTIN("vector-alloc", vector_alloc)
 {
-	uint32_t i, k, a;
+	size_t i, k, a;
 	value_t f, v;
 	if(nargs < 1)
 		argcount(nargs, 1);
-	i = toulong(args[0]);
+	i = tosize(args[0]);
 	v = alloc_vector(i, 0);
 	a = 1;
 	for(k = 0; k < i; k++){
@@ -394,14 +398,12 @@
 BUILTIN("rand", rand)
 {
 	USED(args); USED(nargs);
-	uint64_t x = genrand_int63();
-	fixnum_t r;
 #ifdef BITS64
-	r = x >> 3;
+	uint64_t x = genrand_uint64();
 #else
-	r = x >> (32+3);
+	uint32_t x = genrand_uint32();
 #endif
-	return fixnum(r);
+	return fixnum(x >> 3);
 }
 
 BUILTIN("rand-uint32", rand_uint32)
--- a/cvalues.c
+++ b/cvalues.c
@@ -1,9 +1,7 @@
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 #include "cvalues.h"
 #include "types.h"
-#include "overflows.h"
 #include "iostream.h"
 
 // trigger unconditional GC after this many bytes are allocated
@@ -16,7 +14,7 @@
 {
 	if(FL(nfinalizers) == FL(maxfinalizers)){
 		size_t nn = FL(maxfinalizers) == 0 ? 256 : FL(maxfinalizers)*2;
-		cvalue_t **temp = LLT_REALLOC(FL(finalizers), nn*sizeof(cvalue_t*));
+		cvalue_t **temp = MEM_REALLOC(FL(finalizers), nn*sizeof(cvalue_t*));
 		if(temp == nil)
 			lerrorf(FL(MemoryError), "out of memory");
 		FL(finalizers) = temp;
@@ -47,7 +45,7 @@
 				t->vtable->finalize(tagptr(tmp, TAG_CVALUE));
 			if(!isinlined(tmp) && owned(tmp) && !FL(exiting)){
 				memset(cv_data(tmp), 0xbb, cv_len(tmp));
-				LLT_FREE(cv_data(tmp));
+				MEM_FREE(cv_data(tmp));
 			}
 			ndel++;
 		}
@@ -54,7 +52,7 @@
 	}while((n < l-ndel) && SWAP_sf(lst[n], lst[n+ndel]));
 
 	FL(nfinalizers) -= ndel;
-#ifdef VERBOSEGC
+#if defined(VERBOSEGC)
 	if(ndel > 0)
 		printf("GC: finalized %d objects\n", ndel);
 #endif
@@ -125,7 +123,7 @@
 			gc(0);
 		pcv = alloc_words(CVALUE_NWORDS);
 		pcv->type = type;
-		pcv->data = LLT_ALLOC(sz);
+		pcv->data = MEM_ALLOC(sz);
 		autorelease(pcv);
 		FL(malloc_pressure) += sz;
 	}
@@ -211,7 +209,7 @@
 	size_t sz = cv_len(cv);
 	if(cv_isstr(cv))
 		sz++;
-	void *data = LLT_ALLOC(sz);
+	void *data = MEM_ALLOC(sz);
 	memcpy(data, cv_data(cv), sz);
 	cv->data = data;
 	autorelease(cv);
@@ -226,9 +224,13 @@
 		if(isfixnum(arg)) \
 			n = (ctype)numval(arg); \
 		else if(iscprim(arg)){ \
-			cprim_t *cp = (cprim_t*)ptr(arg); \
+			cprim_t *cp = ptr(arg); \
 			void *p = cp_data(cp); \
 			n = (ctype)conv_to_##cnvt(p, cp_numtype(cp)); \
+		}else if(iscvalue(arg) && cp_numtype(ptr(arg)) == T_MPINT){ \
+			cvalue_t *cv = ptr(arg); \
+			void *p = cv_data(cv); \
+			n = (ctype)conv_to_##cnvt(p, T_MPINT); \
 		}else \
 			return 1; \
 		*((ctype*)dest) = n; \
@@ -281,20 +283,9 @@
 num_ctor(int64, int64_t, T_INT64)
 num_ctor(uint64, uint64_t, T_UINT64)
 num_ctor_init(byte,  uint8_t, T_UINT8)
-#if defined(ULONG64)
-num_ctor_init(long, int64_t, T_INT64)
-num_ctor(ulong, uint64_t, T_UINT64)
-#else
-num_ctor_init(long, int32_t, T_INT32)
-num_ctor(ulong, uint32_t, T_UINT32)
-#endif
 num_ctor(float, float, T_FLOAT)
 num_ctor(double, double, T_DOUBLE)
-#if defined(__plan9__)
 num_ctor(rune, uint32_t, T_UINT32)
-#else
-num_ctor(rune, int32_t, T_INT32)
-#endif
 
 static int
 cvalue_mpint_init(fltype_t *type, value_t arg, void *dest)
@@ -303,6 +294,10 @@
 	USED(type);
 	if(isfixnum(arg)){
 		n = vtomp(numval(arg), nil);
+	}else if(iscvalue(arg)){
+		cvalue_t *cv = ptr(arg);
+		void *p = cv_data(cv);
+		n = conv_to_mpint(p, cp_numtype(cv));
 	}else if(iscprim(arg)){
 		cprim_t *cp = (cprim_t*)ptr(arg);
 		void *p = cp_data(cp);
@@ -348,20 +343,22 @@
 value_t
 size_wrap(size_t sz)
 {
-	if(fits_fixnum(sz))
-		return fixnum(sz);
-	assert(sizeof(void*) == sizeof(size_t));
-	return mk_ulong(sz);
+	if(sizeof(size_t) == 8)
+		return fits_fixnum(sz) ? fixnum(sz): mk_uint64(sz);
+	else
+		return fits_fixnum(sz) ? fixnum(sz): mk_uint32(sz);
 }
 
 size_t
-toulong(value_t n)
+tosize(value_t n)
 {
 	if(isfixnum(n))
 		return (size_t)numval(n);
 	if(iscprim(n)){
 		cprim_t *cp = (cprim_t*)ptr(n);
-		return conv_to_ulong(cp_data(cp), cp_numtype(cp));
+		if(sizeof(size_t) == 8)
+			return conv_to_uint64(cp_data(cp), cp_numtype(cp));
+		return conv_to_uint32(cp_data(cp), cp_numtype(cp));
 	}
 	type_error("number", n);
 }
@@ -451,7 +448,7 @@
 	cnt = predict_arraylen(arg);
 
 	if(iscons(cdr_(cdr_(type)))){
-		size_t tc = toulong(car_(cdr_(cdr_(type))));
+		size_t tc = tosize(car_(cdr_(cdr_(type))));
 		if(tc != cnt)
 			lerrorf(FL(ArgError), "size mismatch");
 	}
@@ -533,7 +530,7 @@
 
 	if(nargs < 3)
 		argcount(nargs, 3);
-	cnt = toulong(args[1]);
+	cnt = tosize(args[1]);
 	if(cnt < 0)
 		lerrorf(FL(ArgError), "invalid size: %d", cnt);
 
@@ -572,7 +569,7 @@
 	while(iscons(fld)){
 		fsz = ctype_sizeof(car(cdr(car_(fld))), &al);
 
-		ssz = LLT_ALIGN(ssz, al);
+		ssz = ALIGNED(ssz, al);
 		if(al > *palign)
 			*palign = al;
 
@@ -582,7 +579,7 @@
 		ssz += fsz;
 		fld = cdr_(fld);
 	}
-	return LLT_ALIGN(ssz, *palign);
+	return ALIGNED(ssz, *palign);
 }
 
 static size_t
@@ -601,7 +598,7 @@
 			usz = fsz;
 		fld = cdr_(fld);
 	}
-	return LLT_ALIGN(usz, *palign);
+	return ALIGNED(usz, *palign);
 }
 
 // *palign is an output argument giving the alignment required by type
@@ -630,7 +627,7 @@
 			if(!iscons(cdr_(cdr_(type))))
 				lerrorf(FL(ArgError), "incomplete type");
 			value_t n = car_(cdr_(cdr_(type)));
-			size_t sz = toulong(n);
+			size_t sz = tosize(n);
 			return sz * ctype_sizeof(t, palign);
 		}
 		if(hed == FL(enumsym)){
@@ -741,7 +738,7 @@
 		size_t len = cv_len(cv);
 		if(cv_isstr(cv))
 			len++;
-		ncv->data = LLT_ALLOC(len);
+		ncv->data = MEM_ALLOC(len);
 		memcpy(ncv->data, cv_data(cv), len);
 		autorelease(ncv);
 		if(hasparent(cv)){
@@ -801,7 +798,7 @@
 		size_t cnt;
 
 		if(iscons(cdr_(cdr_(type))))
-			cnt = toulong(car_(cdr_(cdr_(type))));
+			cnt = tosize(car_(cdr_(cdr_(type))));
 		else if(nargs == 2)
 			cnt = predict_arraylen(args[1]);
 		else
@@ -845,7 +842,7 @@
 	cvalue_t *cv = ptr(arr);
 	*data = cv_data(cv);
 	numel = cv_len(cv)/cv_class(cv)->elsz;
-	*index = toulong(ind);
+	*index = tosize(ind);
 	if(*index < 0 || *index >= numel)
 		bounds_error(arr, ind);
 }
@@ -967,149 +964,33 @@
 {
 	if(fits_fixnum(Saccum))
 		return fixnum((fixnum_t)Saccum);
-	if(Saccum > (int64_t)UINT32_MAX || Saccum < (int64_t)INT32_MIN)
-		RETURN_NUM_AS(Saccum, int64);
-	if(Saccum > (int64_t)INT32_MAX)
-		RETURN_NUM_AS(Saccum, uint32);
-	RETURN_NUM_AS(Saccum, int32);
+	RETURN_NUM_AS(vtomp(Saccum, nil), mpint);
 }
 
+#define ACCUM_DEFAULT 0
+#define ARITH_OP(a, b) (a)+(b)
+#define MP_OP mpadd
+#define ARITH_OVERFLOW sadd_overflow_64
 value_t
-fl_add_any(value_t *args, uint32_t nargs, fixnum_t carryIn)
+fl_add_any(value_t *args, uint32_t nargs)
 {
-	uint64_t Uaccum = 0;
-	uint64_t Uresult = 0;
-	int64_t Saccum = carryIn;
-	int64_t Sresult;
-	double Faccum = 0;
-	bool inexact = false;
-	uint32_t i;
-	int64_t i64;
-	value_t arg;
-	mpint *Maccum = nil, *x;
-	numerictype_t pt;
-	fixnum_t pi;
-	void *a;
+#include "fl_arith_any.inc"
+}
 
-	FOR_ARGS(i, 0, arg, args){
-		if(isfixnum(arg)){
-			Saccum += numval(arg);
-			continue;
-		}
-		if(num_to_ptr(arg, &pi, &pt, &a)){
-			switch(pt){
-			case T_INT8:   Saccum += *(int8_t*)a; break;
-			case T_UINT8:  Uaccum += *(uint8_t*)a; break;
-			case T_INT16:  Saccum += *(int16_t*)a; break;
-			case T_UINT16: Uaccum += *(uint16_t*)a; break;
-			case T_INT32:  Saccum += *(int32_t*)a; break;
-			case T_UINT32: Uaccum += *(uint32_t*)a; break;
-			case T_INT64:
-				i64 = *(int64_t*)a;
-				if(i64 >= 0){
-					if(addof_uint64(Uresult, Uaccum, (uint64_t)i64)){
-						if(Maccum == nil)
-							Maccum = mpnew(0);
-						x = uvtomp((uint64_t)i64, nil);
-						mpadd(Maccum, x, Maccum);
-						mpfree(x);
-					}else
-						Uaccum = Uresult;
-				}else{
-					if(subof_int64(Sresult, Saccum, i64)){
-						if(Maccum == nil)
-							Maccum = mpnew(0);
-						x = uvtomp(-(uint64_t)i64, nil);
-						x->sign = -1;
-						mpadd(Maccum, x, Maccum);
-						mpfree(x);
-					}else{
-						USED(Sresult);
-						Saccum += i64;
-					}
-				}
-				break;
-			case T_UINT64:
-				if(addof_uint64(Uresult, Uaccum, *(uint64_t*)a)){
-					if(Maccum == nil)
-						Maccum = mpnew(0);
-					x = uvtomp(*(uint64_t*)a, nil);
-					mpadd(Maccum, x, Maccum);
-					mpfree(x);
-				}else
-					Uaccum = Uresult;
-				break;
-			case T_MPINT:
-				if(Maccum == nil)
-					Maccum = mpnew(0);
-				mpadd(Maccum, *(mpint**)a, Maccum);
-				break;
-			case T_FLOAT:  Faccum += *(float*)a; inexact = true; break;
-			case T_DOUBLE: Faccum += *(double*)a; inexact = true; break;
-			default:
-				goto add_type_error;
-			}
-			continue;
-		}
-
-add_type_error:
-		mpfree(Maccum);
-		type_error("number", arg);
-	}
-	if(inexact){
-		Faccum += Uaccum;
-		Faccum += Saccum;
-		if(Maccum != nil){
-			Faccum += mptod(Maccum);
-			mpfree(Maccum);
-		}
-		return mk_double(Faccum);
-	}
-	if(Maccum != nil){
-		/* FIXME - check if it fits into fixnum first, etc */
-		x = vtomp(Saccum, nil);
-		mpadd(Maccum, x, Maccum);
-		x = uvtomp(Uaccum, x);
-		mpadd(Maccum, x, Maccum);
-		mpfree(x);
-		return mk_mpint(Maccum);
-	}
-	if(Saccum < 0){
-		uint64_t negpart = -(uint64_t)Saccum;
-		if(negpart > Uaccum){
-			Saccum += (int64_t)Uaccum;
-			// return value in Saccum
-			if(Saccum >= INT32_MIN){
-				if(fits_fixnum(Saccum)){
-					return fixnum((fixnum_t)Saccum);
-				}
-				RETURN_NUM_AS(Saccum, int32);
-			}
-			RETURN_NUM_AS(Saccum, int64);
-		}
-		Uaccum -= negpart;
-	}else{
-		if(addof_uint64(Uresult, Uaccum, (uint64_t)Saccum)){
-			if(Maccum == nil)
-				Maccum = mpnew(0);
-			x = vtomp(Saccum, nil);
-			mpadd(Maccum, x, Maccum);
-			x = uvtomp(Uaccum, x);
-			mpadd(Maccum, x, Maccum);
-			mpfree(x);
-			return mk_mpint(Maccum);
-		}else
-			Uaccum = Uresult;
-	}
-	return return_from_uint64(Uaccum);
+#define ACCUM_DEFAULT 1
+#define ARITH_OP(a, b) (a)*(b)
+#define MP_OP mpmul
+#define ARITH_OVERFLOW smul_overflow_64
+value_t
+fl_mul_any(value_t *args, uint32_t nargs)
+{
+#include "fl_arith_any.inc"
 }
 
 value_t
 fl_neg(value_t n)
 {
-	int32_t i32;
 	int64_t i64;
-	uint32_t ui32;
 	uint64_t ui64;
 	mpint *mp;
 	numerictype_t pt;
@@ -1117,46 +998,45 @@
 	void *a;
 
 	if(isfixnum(n)){
-		fixnum_t s = fixnum(-numval(n));
-		if(__unlikely((value_t)s == n))
-			return mk_xlong(-numval(n));
-		return s;
+		i64 = -(int64_t)numval(n);
+i64neg:
+		return fits_fixnum(i64) ? fixnum(i64) : mk_mpint(vtomp(i64, nil));
 	}
 
 	if(num_to_ptr(n, &pi, &pt, &a)){
 		switch(pt){
-		case T_INT8:   return fixnum(-(int32_t)*(int8_t*)a);
-		case T_UINT8:  return fixnum(-(int32_t)*(uint8_t*)a);
-		case T_INT16:  return fixnum(-(int32_t)*(int16_t*)a);
-		case T_UINT16: return fixnum(-(int32_t)*(uint16_t*)a);
-		case T_INT32:
-			i32 = *(int32_t*)a;
-			if(i32 == (int32_t)BIT31)
-				return mk_uint32((uint32_t)BIT31);
-			return mk_int32(-i32);
+		case T_DOUBLE: return mk_double(-*(double*)a);
+		case T_FLOAT:  return mk_float(-*(float*)a);
+		case T_INT8:   return fixnum(-(fixnum_t)*(int8_t*)a);
+		case T_UINT8:  return fixnum(-(fixnum_t)*(uint8_t*)a);
+		case T_INT16:  return fixnum(-(fixnum_t)*(int16_t*)a);
+		case T_UINT16: return fixnum(-(fixnum_t)*(uint16_t*)a);
 		case T_UINT32:
-			ui32 = *(uint32_t*)a;
-			if(ui32 <= (uint32_t)INT32_MAX+1)
-				return mk_int32(-(uint32_t)ui32);
-			return mk_int64(-(int64_t)ui32);
+			i64 = -(int64_t)*(uint32_t*)a;
+			if(0){
+		case T_INT32:
+				i64 = -(int64_t)*(int32_t*)a;
+			}
+			goto i64neg;
 		case T_INT64:
 			i64 = *(int64_t*)a;
-			if(i64 == (int64_t)BIT63)
-				return mk_uint64((uint64_t)BIT63);
-			return mk_int64(-i64);
+			if(i64 == INT64_MIN)
+				return mk_mpint(uvtomp((uint64_t)INT64_MAX+1, nil));
+			i64 = -i64;
+			goto i64neg;
 		case T_UINT64:
 			ui64 = *(uint64_t*)a;
-			if(ui64 <= (uint64_t)INT64_MAX+1)
-				return mk_int64(-(uint64_t)ui64);
-			mp = uvtomp(ui64, nil);
-			mp->sign = -1;
-			return mk_mpint(mp);
+			if(ui64 >= (uint64_t)INT64_MAX+1){
+				mp = uvtomp(ui64, nil);
+				mp->sign = -1;
+				return mk_mpint(mp);
+			}
+			i64 = -(int64_t)ui64;
+			goto i64neg;
 		case T_MPINT:
 			mp = mpcopy(*(mpint**)a);
-			mpsub(mpzero, mp, mp);
+			mp->sign = -mp->sign;
 			return mk_mpint(mp);
-		case T_FLOAT:  return mk_float(-*(float*)a);
-		case T_DOUBLE: return mk_double(-*(double*)a);
 		}
 	}
 
@@ -1163,91 +1043,6 @@
 	type_error("number", n);
 }
 
-value_t
-fl_mul_any(value_t *args, uint32_t nargs)
-{
-	int64_t Saccum = 1;
-	uint64_t Uaccum = 1;
-	double Faccum = 1;
-	bool inexact = false;
-	int64_t i64;
-	uint32_t i;
-	value_t arg;
-	mpint *Maccum = nil, *x;
-	numerictype_t pt;
-	fixnum_t pi;
-	void *a;
-
-	FOR_ARGS(i, 0, arg, args){
-		if(isfixnum(arg)){
-			Saccum *= numval(arg);
-			continue;
-		}
-		if(num_to_ptr(arg, &pi, &pt, &a)){
-			switch(pt){
-			case T_INT8:   Saccum *= *(int8_t*)a; break;
-			case T_UINT8:  Uaccum *= *(uint8_t*)a; break;
-			case T_INT16:  Saccum *= *(int16_t*)a; break;
-			case T_UINT16: Uaccum *= *(uint16_t*)a; break;
-			case T_INT32:  Saccum *= *(int32_t*)a; break;
-			case T_UINT32: Uaccum *= *(uint32_t*)a; break;
-			case T_INT64:
-				i64 = *(int64_t*)a;
-				if(i64 > 0)
-					Uaccum *= (uint64_t)i64;
-				else
-					Saccum *= i64;
-				break;
-			case T_UINT64: Uaccum *= *(uint64_t*)a; break;
-			case T_MPINT:
-				if(Maccum == nil)
-					Maccum = mpcopy(mpone);
-				mpmul(Maccum, *(mpint**)a, Maccum);
-				break;
-			case T_FLOAT:  Faccum *= *(float*)a; inexact = true; break;
-			case T_DOUBLE: Faccum *= *(double*)a; inexact = true; break;
-			default:
-				goto mul_type_error;
-			}
-			continue;
-		}
-
-mul_type_error:
-		type_error("number", arg);
-	}
-	if(inexact){
-		Faccum *= Uaccum;
-		Faccum *= Saccum;
-		if(Maccum != nil){
-			Faccum *= mptod(Maccum);
-			mpfree(Maccum);
-		}
-		return mk_double(Faccum);
-	}
-	if(Maccum != nil){
-		/* FIXME might still fit into a fixnum */
-		x = vtomp(Saccum, nil);
-		mpmul(Maccum, x, Maccum);
-		x = uvtomp(Uaccum, x);
-		mpmul(Maccum, x, Maccum);
-		mpfree(x);
-		return mk_mpint(Maccum);
-	}
-	if(Saccum < 0){
-		Saccum *= (int64_t)Uaccum;
-		if(Saccum >= INT32_MIN){
-			if(fits_fixnum(Saccum)){
-				return fixnum((fixnum_t)Saccum);
-			}
-			RETURN_NUM_AS(Saccum, int32);
-		}
-		RETURN_NUM_AS(Saccum, int64);
-	}else{
-		Uaccum *= (uint64_t)Saccum;
-	}
-	return return_from_uint64(Uaccum);
-}
-
 int
 num_to_ptr(value_t a, fixnum_t *pi, numerictype_t *pt, void **pp)
 {
@@ -1283,7 +1078,7 @@
 int
 numeric_compare(value_t a, value_t b, int eq, int eqnans, int typeerr)
 {
-	lltint_t ai, bi;
+	fixnum_t ai, bi;
 	numerictype_t ta, tb;
 	void *aptr, *bptr;
 
@@ -1325,7 +1120,7 @@
 fl_div2(value_t a, value_t b)
 {
 	double da, db;
-	lltint_t ai, bi;
+	fixnum_t ai, bi;
 	numerictype_t ta, tb;
 	void *aptr, *bptr;
 
@@ -1350,7 +1145,7 @@
 value_t
 fl_idiv2(value_t a, value_t b)
 {
-	lltint_t ai, bi;
+	fixnum_t ai, bi;
 	numerictype_t ta, tb;
 	void *aptr, *bptr;
 	int64_t a64, b64;
@@ -1411,7 +1206,7 @@
 static value_t
 fl_bitwise_op(value_t a, value_t b, int opcode)
 {
-	lltint_t ai, bi;
+	fixnum_t ai, bi;
 	numerictype_t ta, tb, itmp;
 	void *aptr = nil, *bptr = nil, *ptmp;
 	mpint *bmp = nil, *resmp = nil;
@@ -1561,6 +1356,16 @@
 		case T_UINT64: return mk_uint64(~*(uint64_t*)aptr);
 		}
 	}
+	if(iscvalue(a)){
+		cvalue_t *cv = ptr(a);
+		ta = cp_numtype(cv);
+		aptr = cv_data(cv);
+		if(ta == T_MPINT){
+			mpint *m = mpnew(0);
+			mpnot(*(mpint**)aptr, m);
+			return mk_mpint(m);
+		}
+	}
 	type_error("integer", a);
 }
 
@@ -1637,13 +1442,6 @@
 	ctor_cv_intern(int64, T_INT64, int64_t);
 	ctor_cv_intern(uint64, T_UINT64, uint64_t);
 	ctor_cv_intern(byte, T_UINT8, uint8_t);
-#if defined(ULONG64)
-	ctor_cv_intern(long, T_INT64, int64_t);
-	ctor_cv_intern(ulong, T_UINT64, uint64_t);
-#else
-	ctor_cv_intern(long, T_INT32, int32_t);
-	ctor_cv_intern(ulong, T_UINT32, uint32_t);
-#endif
 	ctor_cv_intern(rune, T_UINT32, uint32_t);
 	ctor_cv_intern(float, T_FLOAT, float);
 	ctor_cv_intern(double, T_DOUBLE, double);
@@ -1670,13 +1468,6 @@
 	mk_primtype(uint32, uint32_t);
 	mk_primtype(int64, int64_t);
 	mk_primtype(uint64, uint64_t);
-#if defined(ULONG64)
-	mk_primtype(long, int64_t);
-	mk_primtype(ulong, uint64_t);
-#else
-	mk_primtype(long, int32_t);
-	mk_primtype(ulong, uint32_t);
-#endif
 	mk_primtype(byte, uint8_t);
 	mk_primtype(rune, uint32_t);
 	mk_primtype(float, float);
--- a/cvalues.h
+++ b/cvalues.h
@@ -1,11 +1,10 @@
 #pragma once
 
-#ifdef BITS64
+#if defined(BITS64)
 #define NWORDS(sz) (((sz)+7)>>3)
 #else
 #define NWORDS(sz) (((sz)+3)>>2)
 #endif
-
 #define CVALUE_NWORDS 4
 #define MAX_INL_SIZE 384
 #define CV_OWNED_BIT  0x1
@@ -30,7 +29,7 @@
 void cv_pin(cvalue_t *cv);
 value_t mk_mpint(mpint *n);
 value_t size_wrap(size_t sz);
-size_t toulong(value_t n);
+size_t tosize(value_t n);
 off_t tooffset(value_t n);
 int cvalue_enum_init(fltype_t *ft, value_t arg, void *dest);
 int isarray(value_t v);
@@ -46,7 +45,7 @@
 value_t cbuiltin(char *name, builtin_t f);
 value_t return_from_uint64(uint64_t Uaccum);
 value_t return_from_int64(int64_t Saccum);
-value_t fl_add_any(value_t *args, uint32_t nargs, fixnum_t carryIn);
+value_t fl_add_any(value_t *args, uint32_t nargs);
 value_t fl_neg(value_t n);
 value_t fl_mul_any(value_t *args, uint32_t nargs);
 int num_to_ptr(value_t a, fixnum_t *pi, numerictype_t *pt, void **pp);
@@ -63,11 +62,6 @@
 value_t mk_int64(int64_t n);
 value_t mk_uint64(uint64_t n);
 value_t mk_rune(Rune n);
-#if defined(ULONG64)
-value_t mk_ulong(uint64_t n);
-#else
-value_t mk_ulong(uint32_t n);
-#endif
 
 /* builtins.c */
 size_t llength(value_t v);
--- a/equal.c
+++ b/equal.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 #include "opcodes.h"
@@ -9,10 +8,14 @@
 #define BOUNDED_COMPARE_BOUND 128
 #define BOUNDED_HASH_BOUND 16384
 
-#ifdef BITS64
+#if defined(BITS64)
 #define inthash int64hash
+#define MIX(a, b) int64hash((uint64_t)(a) ^ (uint64_t)(b));
+#define doublehash(a) int64hash(a)
 #else
 #define inthash int32hash
+#define MIX(a, b) int64to32hash((uint64_t)(a)<<32 | (uint64_t)(b));
+#define doublehash(a) int64to32hash(a)
 #endif
 
 // comparable tag
@@ -327,14 +330,6 @@
   * less redundant tag checking, 3-bit tags
 */
 
-#ifdef BITS64
-#define MIX(a, b) int64hash((uint64_t)(a) ^ (uint64_t)(b));
-#define doublehash(a) int64hash(a)
-#else
-#define MIX(a, b) int64to32hash(((uint64_t)(a))<<32 | ((uint64_t)(b)))
-#define doublehash(a) int64to32hash(a)
-#endif
-
 // *oob: output argument, means we hit the limit specified by 'bound'
 static uintptr_t
 bounded_hash(value_t a, int bound, int *oob)
@@ -377,7 +372,7 @@
 		if(cv->type == FL(mpinttype)){
 			len = mptobe(*(mpint**)data, nil, 0, (uint8_t**)&data);
 			h = memhash(data, len);
-			LLT_FREE(data);
+			MEM_FREE(data);
 		}else{
 			h = memhash(data, cv_len(cv));
 		}
--- a/equalhash.c
+++ b/equalhash.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "equalhash.h"
 #include "equal.h"
--- /dev/null
+++ b/fl_arith_any.inc
@@ -1,0 +1,164 @@
+//value_t
+//fl_*_any(value_t *args, uint32_t nargs)
+// input: ACCUM_DEFAULT ARITH_OP(a,b)   MP_OP   ARITH_OVERFLOW
+// add:   0             a+b             mpadd   sadd_overflow_64
+// mul:   1             a*b             mpmul   smul_overflow_64
+
+	mpint *Maccum = nil, *m = nil;
+	int64_t Saccum = ACCUM_DEFAULT, x;
+	uint64_t u64;
+	double Faccum = ACCUM_DEFAULT;
+	bool inexact = false;
+	value_t arg;
+	numerictype_t pt;
+	void *a;
+	cprim_t *cp;
+	cvalue_t *cv;
+
+	uint32_t i, j;
+	FOR_ARGS(i, 0, arg, args){
+		if(isfixnum(arg))
+			x = numval(arg);
+		else{
+			if(iscprim(arg)){
+				cp = ptr(arg);
+				a = cp_data(cp);
+				pt = cp_numtype(cp);
+			}else if(iscvalue(arg)){
+				cv = ptr(arg);
+				a = cv_data(cv);
+				pt = cv_class(cv)->numtype;
+			}else{
+typeerr:
+				mpfree(Maccum);
+				mpfree(m);
+				type_error("number", arg);
+			}
+			switch(pt){
+			case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
+			case T_FLOAT:  Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue;
+			case T_INT8:   x = *(int8_t*)a; break;
+			case T_UINT8:  x = *(uint8_t*)a; break;
+			case T_INT16:  x = *(int16_t*)a; break;
+			case T_UINT16: x = *(uint16_t*)a; break;
+			case T_INT32:  x = *(int32_t*)a; break;
+			case T_UINT32: x = *(uint32_t*)a; break;
+			case T_INT64:  x = *(int64_t*)a; break;
+			case T_UINT64:
+				u64 = *(uint64_t*)a;
+				if(u64 > INT64_MAX){
+					x = ACCUM_DEFAULT;
+					goto overflow;
+				}
+				x = u64;
+				break;
+			case T_MPINT:
+				x = ACCUM_DEFAULT;
+				u64 = ACCUM_DEFAULT;
+				m = mpcopy(*(mpint**)a);
+				goto overflow;
+			default:
+				goto typeerr;
+			}
+		}
+
+		int64_t accu;
+		if(ARITH_OVERFLOW(Saccum, x, &accu)){
+			u64 = ACCUM_DEFAULT;
+			goto overflow;
+		}
+		Saccum = accu;
+	}
+
+	if(inexact)
+		return mk_double(ARITH_OP(Faccum, Saccum));
+	if(fits_fixnum(Saccum))
+		return fixnum((fixnum_t)Saccum);
+	u64 = ACCUM_DEFAULT;
+	x = ACCUM_DEFAULT;
+
+overflow:
+	i++;
+	if(Maccum == nil)
+		Maccum = vtomp(Saccum, nil);
+	if(m == nil){
+		if(u64 != ACCUM_DEFAULT)
+			m = uvtomp(u64, nil);
+		else if(x != ACCUM_DEFAULT)
+			m = vtomp(x, nil);
+		else
+			m = mpnew(ACCUM_DEFAULT);
+	}
+
+	MP_OP(Maccum, m, Maccum);
+
+	FOR_ARGS(j, i, arg, args){
+		if(isfixnum(arg)){
+			vtomp(numval(arg), m);
+			MP_OP(Maccum, m, Maccum);
+			continue;
+		}
+
+		if(iscprim(arg)){
+			cp = ptr(arg);
+			a = cp_data(cp);
+			pt = cp_numtype(cp);
+		}else if(iscvalue(arg)){
+			cv = ptr(arg);
+			a = cv_data(cv);
+			pt = cv_class(cv)->numtype;
+		}else{
+			goto typeerr;
+		}
+		switch(pt){
+		case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
+		case T_FLOAT:  Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue;
+		case T_INT8:   x = *(int8_t*)a; break;
+		case T_UINT8:  x = *(uint8_t*)a; break;
+		case T_INT16:  x = *(int16_t*)a; break;
+		case T_UINT16: x = *(uint16_t*)a; break;
+		case T_INT32:  x = *(int32_t*)a; break;
+		case T_UINT32: x = *(uint32_t*)a; break;
+		case T_INT64:  x = *(int64_t*)a; break;
+		case T_UINT64:
+			uvtomp(*(uint64_t*)a, m);
+			MP_OP(Maccum, m, Maccum);
+			continue;
+		case T_MPINT:
+			MP_OP(Maccum, *(mpint**)a, Maccum);
+			continue;
+		default:
+			goto typeerr;
+		}
+		vtomp(x, m);
+		MP_OP(Maccum, m, Maccum);
+	}
+
+	int n = mpsignif(Maccum);
+	if(n >= FIXNUM_BITS){
+		if(inexact){
+			dtomp(Faccum, m);
+			MP_OP(Maccum, m, Maccum);
+			n = mpsignif(Maccum);
+			if(n < FIXNUM_BITS){
+				inexact = false;
+				goto down;
+			}
+		}
+		mpfree(m);
+		return mk_mpint(Maccum);
+	}
+
+down:
+	mpfree(m);
+	Saccum = mptov(Maccum);
+	mpfree(Maccum);
+	if(inexact)
+		return mk_double(ARITH_OP(Faccum, Saccum));
+	assert(fits_fixnum(Saccum));
+	return fixnum((fixnum_t)Saccum);
+
+#undef ACCUM_DEFAULT
+#undef ARITH_OP
+#undef MP_OP
+#undef ARITH_OVERFLOW
--- a/flisp.c
+++ b/flisp.c
@@ -5,7 +5,6 @@
   Distributed under the BSD License
 */
 
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 #include "cvalues.h"
@@ -286,7 +285,7 @@
 	value_t *first;
 
 	assert(n > 0);
-	n = LLT_ALIGN(n, 2);   // only allocate multiples of 2 words
+	n = ALIGNED(n, 2);   // only allocate multiples of 2 words
 	if(__unlikely((value_t*)FL(curheap) > (value_t*)FL(lim)+2-n)){
 		gc(0);
 		while((value_t*)FL(curheap) > ((value_t*)FL(lim))+2-n)
@@ -497,7 +496,7 @@
 
 	sweep_finalizers();
 
-#ifdef VERBOSEGC
+#if defined(VERBOSEGC)
 	printf("GC: found %d/%d live conses\n",
 		   (FL(curheap)-FL(tospace))/sizeof(cons_t), FL(heapsize)/sizeof(cons_t));
 #endif
@@ -509,7 +508,7 @@
 	// more space to fill next time. if we grew tospace last time,
 	// grow the other half of the heap this time to catch up.
 	if(FL(grew) || ((FL(lim)-FL(curheap)) < (int)(FL(heapsize)/5)) || mustgrow){
-		temp = LLT_REALLOC(FL(tospace), FL(heapsize)*2);
+		temp = MEM_REALLOC(FL(tospace), FL(heapsize)*2);
 		if(__unlikely(temp == nil))
 			fl_raise(FL(memory_exception_value));
 		FL(tospace) = temp;
@@ -534,7 +533,7 @@
 grow_stack(void)
 {
 	size_t newsz = FL(nstack) * 2;
-	value_t *ns = LLT_REALLOC(FL(stack), newsz*sizeof(value_t));
+	value_t *ns = MEM_REALLOC(FL(stack), newsz*sizeof(value_t));
 	if(__unlikely(ns == nil))
 		lerrorf(FL(MemoryError), "stack overflow");
 	FL(stack) = ns;
@@ -786,7 +785,7 @@
 		if(__unlikely(i >= nargs))
 			lerrorf(FL(ArgError), "keyword %s requires an argument", symbol_name(v));
 		value_t hv = fixnum(((symbol_t*)ptr(v))->hash);
-		lltint_t lx = numval(hv);
+		fixnum_t lx = numval(hv);
 		uintptr_t x = 2*((lx < 0 ? -lx : lx) % n);
 		if(__likely(vector_elt(kwtable, x) == v)){
 			uintptr_t idx = numval(vector_elt(kwtable, x+1));
@@ -866,7 +865,9 @@
 	int tail, x;
 
 	// temporary variables (not necessary to preserve across calls)
-	uint32_t op, i, ipd;
+	size_t isz;
+	uint8_t op;
+	uint32_t i, ipd;
 	symbol_t *sym;
 	cons_t *c;
 	value_t *pv;
@@ -895,7 +896,7 @@
 	PUSH(0); // captured?
 	FL(curr_frame) = FL(sp);
 
-#ifdef COMPUTED_GOTO
+#if defined(COMPUTED_GOTO)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
 #define OP(x) op_##x:
@@ -1060,9 +1061,9 @@
 					if(isbuiltin(func)){
 						s = builtins[i].nargs;
 						if(s >= 0)
-							argcount(n, s);
+							argcount(n, (unsigned)s);
 						else if(s != ANYARGS && (signed)n < -s)
-							argcount(n, -s);
+							argcount(n, (unsigned)-s);
 						// remove function arg
 						for(s = FL(sp)-n-1; s < (int)FL(sp)-1; s++)
 							FL(stack)[s] = FL(stack)[s+1];
@@ -1077,7 +1078,7 @@
 						case OP_DIV:	goto apply_div;
 						default:
 							op = i;
-#ifdef COMPUTED_GOTO
+#if defined(COMPUTED_GOTO)
 							goto *((uint8_t*)&&op_OP_LOADA0 + ops[i]);
 #else
 							continue;
@@ -1259,10 +1260,10 @@
 			v = FL(stack)[FL(sp)-2];
 			if(isvector(v)){
 				e = FL(stack)[FL(sp)-1];
-				i = isfixnum(e) ? numval(e) : (uint32_t)toulong(e);
-				if(__unlikely(i >= vector_size(v)))
+				isz = tosize(e);
+				if(__unlikely(isz >= vector_size(v)))
 					bounds_error(v, e);
-				v = vector_elt(v, i);
+				v = vector_elt(v, isz);
 			}else if(__likely(isarray(v))){
 				v = cvalue_array_aref(&FL(stack)[FL(sp)-2]);
 			}else{
@@ -1297,13 +1298,24 @@
 			NEXT_OP;
 
 		OP(OP_ADD2)
+		do_add2:
 			FL(stack)[ipd] = (uintptr_t)ip;
-			if(bothfixnums(FL(stack)[FL(sp)-1], FL(stack)[FL(sp)-2])){
-				s = numval(FL(stack)[FL(sp)-1]) + numval(FL(stack)[FL(sp)-2]);
-				v = fits_fixnum(s) ? fixnum(s) : mk_xlong(s);
-			}else{
-				v = fl_add_any(&FL(stack)[FL(sp)-2], 2, 0);
+			if(0){
+		OP(OP_SUB2)
+		do_sub2:
+				FL(stack)[ipd] = (uintptr_t)ip;
+				FL(stack)[FL(sp)-1] = fl_neg(FL(stack)[FL(sp)-1]);
 			}
+			{
+				fixnum_t a, b, c;
+				a = FL(stack)[FL(sp)-2];
+				b = FL(stack)[FL(sp)-1];
+				if(bothfixnums(a, b) && !sadd_overflow(numval(a), numval(b), &c) && fits_fixnum(c)){
+					v = fixnum(c);
+				}else{
+					v = fl_add_any(&FL(stack)[FL(sp)-2], 2);
+				}
+			}
 			POPN(1);
 			FL(stack)[FL(sp)-1] = v;
 			NEXT_OP;
@@ -1499,25 +1511,11 @@
 
 		OP(OP_ADD)
 			n = *ip++;
+			if(n == 2)
+				goto do_add2;
 		apply_add:
-			s = 0;
-			i = FL(sp)-n;
-			for(; i < FL(sp); i++){
-				if(isfixnum(FL(stack)[i])){
-					s += numval(FL(stack)[i]);
-					if(__unlikely(!fits_fixnum(s))){
-						i++;
-						goto add_ovf;
-					}
-				}else{
-				add_ovf:
-					FL(stack)[ipd] = (uintptr_t)ip;
-					v = fl_add_any(&FL(stack)[i], FL(sp)-i, s);
-					break;
-				}
-			}
-			if(i == FL(sp))
-				v = fixnum(s);
+			FL(stack)[ipd] = (uintptr_t)ip;
+			v = fl_add_any(&FL(stack)[FL(sp)-n], n);
 			POPN(n);
 			PUSH(v);
 			NEXT_OP;
@@ -1535,27 +1533,13 @@
 			// so it can handle rest args properly
 			PUSH(FL(stack)[i]);
 			FL(stack)[i] = fixnum(0);
-			FL(stack)[i+1] = fl_neg(fl_add_any(&FL(stack)[i], n, 0));
+			FL(stack)[i+1] = fl_neg(fl_add_any(&FL(stack)[i], n));
 			FL(stack)[i] = POP();
-			v = fl_add_any(&FL(stack)[i], 2, 0);
+			v = fl_add_any(&FL(stack)[i], 2);
 			POPN(n);
 			PUSH(v);
 			NEXT_OP;
 
-		OP(OP_SUB2)
-		do_sub2:
-			if(bothfixnums(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1])){
-				s = numval(FL(stack)[FL(sp)-2]) - numval(FL(stack)[FL(sp)-1]);
-				v = fits_fixnum(s) ? fixnum(s) : mk_xlong(s);
-			}else{
-				FL(stack)[ipd] = (uintptr_t)ip;
-				FL(stack)[FL(sp)-1] = fl_neg(FL(stack)[FL(sp)-1]);
-				v = fl_add_any(&FL(stack)[FL(sp)-2], 2, 0);
-			}
-			POPN(1);
-			FL(stack)[FL(sp)-1] = v;
-			NEXT_OP;
-
 		OP(OP_MUL)
 			n = *ip++;
 		apply_mul:
@@ -1857,7 +1841,7 @@
 		OP(OP_NOP)
 			NEXT_OP;
 
-#ifdef COMPUTED_GOTO
+#if defined(COMPUTED_GOTO)
 #pragma GCC diagnostic pop
 #else
 		}
@@ -2184,8 +2168,8 @@
 
 	FL(heapsize) = initial_heapsize;
 
-	FL(fromspace) = LLT_ALLOC(FL(heapsize));
-	FL(tospace)   = LLT_ALLOC(FL(heapsize));
+	FL(fromspace) = MEM_ALLOC(FL(heapsize));
+	FL(tospace)   = MEM_ALLOC(FL(heapsize));
 	FL(curheap) = FL(fromspace);
 	FL(lim) = FL(curheap)+FL(heapsize)-sizeof(cons_t);
 	FL(consflags) = bitvector_new(FL(heapsize)/sizeof(cons_t), 1);
@@ -2192,7 +2176,7 @@
 	htable_new(&FL(printconses), 32);
 	comparehash_init();
 	FL(nstack) = 262144;
-	FL(stack) = LLT_ALLOC(FL(nstack)*sizeof(value_t));
+	FL(stack) = MEM_ALLOC(FL(nstack)*sizeof(value_t));
 
 	FL(Nil) = builtin(OP_THE_EMPTY_LIST);
 	FL(t) = builtin(OP_BOOL_CONST_T);
@@ -2262,21 +2246,7 @@
 	setc(symbol("procedure?"), builtin(OP_FUNCTIONP));
 	setc(symbol("top-level-bound?"), builtin(OP_BOUNDP));
 
-#if defined(__linux__)
-	set(symbol("*os-name*"), symbol("linux"));
-#elif defined(__OpenBSD__)
-	set(symbol("*os-name*"), symbol("openbsd"));
-#elif defined(__FreeBSD__)
-	set(symbol("*os-name*"), symbol("freebsd"));
-#elif defined(__NetBSD__)
-	set(symbol("*os-name*"), symbol("netbsd"));
-#elif defined(__DragonFly__)
-	set(symbol("*os-name*"), symbol("dragonflybsd"));
-#elif defined(__plan9__)
-	set(symbol("*os-name*"), symbol("plan9"));
-#else
-	set(symbol("*os-name*"), symbol("unknown"));
-#endif
+	set(symbol("*os-name*"), symbol(__os_name__));
 
 	FL(the_empty_vector) = tagptr(alloc_words(1), TAG_VECTOR);
 	vector_setsize(FL(the_empty_vector), 0);
--- a/flisp.h
+++ b/flisp.h
@@ -1,5 +1,12 @@
 #pragma once
 
+#include "platform.h"
+#include "utf8.h"
+#include "ios.h"
+#include "bitvector.h"
+#include "htableh.inc"
+HTPROT(ptrhash)
+
 enum {
 	TAG_NUM,
 	TAG_CPRIM,
@@ -26,9 +33,22 @@
 	T_DOUBLE,
 }numerictype_t;
 
-typedef uintptr_t value_t;
-typedef lltint_t fixnum_t;
+#ifdef BITS64
+typedef uint64_t value_t;
+typedef int64_t fixnum_t;
+#define FIXNUM_BITS 62
+#define TOP_BIT (1ULL<<63)
+#define T_FIXNUM T_INT64
+#else
+typedef uint32_t value_t;
+typedef int32_t fixnum_t;
+#define FIXNUM_BITS 30
+#define TOP_BIT (1U<<31)
+#define T_FIXNUM T_INT32
+#endif
 
+#define ALIGNED(x, sz) (((x) + (sz-1)) & (-sz))
+
 typedef struct {
 	value_t car;
 	value_t cdr;
@@ -68,15 +88,8 @@
 
 typedef value_t (*builtin_t)(value_t*, uint32_t);
 
-#ifdef BITS64
-#define T_FIXNUM T_INT64
-#define fits_fixnum(x) (((x)>>61) == 0 || (~((x)>>61)) == 0)
-#define mk_xlong mk_int64
-#else
-#define T_FIXNUM T_INT32
-#define fits_fixnum(x) (((x)>>29) == 0 || (~((x)>>29)) == 0)
-#define mk_xlong mk_int32
-#endif
+#define fits_bits(x, b) (((x)>>(b-1)) == 0 || (~((x)>>(b-1))) == 0)
+#define fits_fixnum(x) fits_bits(x, FIXNUM_BITS)
 
 #define ANYARGS -10000
 #define NONNUMERIC (0xff)
@@ -88,7 +101,6 @@
 #define tagptr(p, t) ((value_t)(p) | (t))
 #define fixnum(x) ((value_t)(x)<<2)
 #define numval(x)  ((fixnum_t)(x)>>2)
-#define fits_bits(x, b) (((x)>>(b-1)) == 0 || (~((x)>>(b-1))) == 0) /* mag: UNUSED? */
 #define uintval(x) (((unsigned int)(x))>>3)
 #define builtin(n) tagptr(((int)n<<3), TAG_FUNCTION)
 #define iscons(x) (tag(x) == TAG_CONS)
@@ -428,3 +440,8 @@
 
 extern Fl fl;
 #define FL(f) fl.f
+
+extern double D_PNAN, D_NNAN, D_PINF, D_NINF;
+extern float F_PNAN, F_NNAN, F_PINF, F_NINF;
+
+_Noreturn void flmain(const uint8_t *boot, int bootsz, int argc, char **argv);
--- a/flmain.c
+++ b/flmain.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "cvalues.h"
 #include "print.h"
--- a/hashing.c
+++ b/hashing.c
@@ -1,9 +1,9 @@
-#include "llt.h"
+#include "flisp.h"
 #include "hashing.h"
 #include "spooky.h"
 
-lltuint_t
-nextipow2(lltuint_t i)
+value_t
+nextipow2(value_t i)
 {
 	if(i == 0)
 		return 1;
@@ -12,7 +12,7 @@
 	i |= i >> 4;
 	i |= i >> 8;
 	i |= i >> 16;
-#ifdef BITS64
+#if defined(BITS64)
 	i |= i >> 32;
 #endif
 	i++;
--- a/hashing.h
+++ b/hashing.h
@@ -1,6 +1,6 @@
 #pragma once
 
-lltuint_t nextipow2(lltuint_t i);
+value_t nextipow2(value_t i);
 uint32_t int32hash(uint32_t a);
 uint64_t int64hash(uint64_t key);
 uint32_t int64to32hash(uint64_t key);
--- a/htable.c
+++ b/htable.c
@@ -2,7 +2,7 @@
   functions common to all hash table instantiations
 */
 
-#include "llt.h"
+#include "flisp.h"
 #include "htable.h"
 #include "hashing.h"
 
@@ -17,7 +17,7 @@
 		size *= 2; // 2 pointers per key/value pair
 		size *= 2; // aim for 50% occupancy
 		h->size = size;
-		h->table = LLT_ALLOC(size*sizeof(void*));
+		h->table = MEM_ALLOC(size*sizeof(void*));
 	}
 	if(h->table == nil)
 		return nil;
@@ -31,7 +31,7 @@
 htable_free(htable_t *h)
 {
 	if(h->table != &h->_space[0])
-		LLT_FREE(h->table);
+		MEM_FREE(h->table);
 }
 
 // empty and reduce size
@@ -41,7 +41,7 @@
 	sz = nextipow2(sz);
 	if(h->size > sz*4 && h->size > HT_N_INLINE){
 		size_t newsz = sz*4;
-		void **newtab = LLT_REALLOC(h->table, newsz*sizeof(void*));
+		void **newtab = MEM_REALLOC(h->table, newsz*sizeof(void*));
 		if(newtab == nil)
 			return;
 		h->size = newsz;
--- a/htable.inc
+++ b/htable.inc
@@ -13,7 +13,7 @@
 static void ** \
 HTNAME##_lookup_bp(htable_t *h, void *key) \
 { \
-	lltuint_t hv; \
+	value_t hv; \
 	size_t i, orig, index, iter; \
 	size_t newsz, sz = hash_size(h); \
 	size_t maxprobe = max_probe(sz); \
@@ -52,7 +52,7 @@
 		newsz = HT_N_INLINE; \
 	else \
 		newsz = sz<<2; \
-	tab = (void**)LLT_ALLOC(newsz*sizeof(void*)); \
+	tab = (void**)MEM_ALLOC(newsz*sizeof(void*)); \
 	if(tab == nil) \
 		return nil; \
 	for(i = 0; i < newsz; i++) \
@@ -64,7 +64,7 @@
 			(*HTNAME##_lookup_bp(h, ol[i])) = ol[i+1]; \
 	} \
 	if(ol != &h->_space[0]) \
-		LLT_FREE(ol); \
+		MEM_FREE(ol); \
 	sz = hash_size(h); \
 	maxprobe = max_probe(sz); \
 	tab = h->table; \
--- a/ios.c
+++ b/ios.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 #include "timefuncs.h"
 
 #define MOST_OF(x) ((x) - ((x)>>4))
@@ -26,7 +26,7 @@
 static int
 _enonfatal(int err)
 {
-	return err == EAGAIN || err == EINPROGRESS || err == EINTR || err == EWOULDBLOCK;
+	return err == 0 || err == EAGAIN || err == EINPROGRESS || err == EINTR || err == EWOULDBLOCK;
 }
 #define SLEEP_TIME 5//ms
 #endif
@@ -39,6 +39,9 @@
 	ssize_t r;
 
 	while(1){
+#if !defined(__plan9__)
+		errno = 0;
+#endif
 		r = read(fd, buf, n);
 		if(r > -1){
 			*nread = (size_t)r;
@@ -81,6 +84,9 @@
 	ssize_t r;
 
 	while(1){
+#if !defined(__plan9__)
+		errno = 0;
+#endif
 		r = write(fd, buf, n);
 		if(r > -1){
 			*nwritten = (size_t)r;
@@ -140,11 +146,11 @@
 		// if we own the buffer we're free to resize it
 		// always allocate 1 bigger in case user wants to add a NUL
 		// terminator after taking over the buffer
-		temp = LLT_REALLOC(s->buf, sz);
+		temp = MEM_REALLOC(s->buf, sz);
 		if(temp == nil)
 			return nil;
 	}else{
-		temp = LLT_ALLOC(sz);
+		temp = MEM_ALLOC(sz);
 		if(temp == nil)
 			return nil;
 		s->ownbuf = 1;
@@ -533,11 +539,11 @@
 		close(s->fd);
 	s->fd = -1;
 	if(s->buf != nil && s->ownbuf && s->buf != &s->local[0])
-		LLT_FREE(s->buf);
+		MEM_FREE(s->buf);
 	s->buf = nil;
 	s->size = s->maxsize = s->bpos = 0;
 	if(s->filename != emptystr){
-		LLT_FREE(s->filename);
+		MEM_FREE(s->filename);
 		s->filename = emptystr;
 	}
 }
@@ -564,13 +570,13 @@
 	ios_flush(s);
 
 	if(s->buf == &s->local[0] || s->buf == nil || (!s->ownbuf && s->size == s->maxsize)){
-		buf = LLT_ALLOC(s->size+1);
+		buf = MEM_ALLOC(s->size+1);
 		if(buf == nil)
 			return nil;
 		if(s->size)
 			memcpy(buf, s->buf, s->size);
 	}else if(s->size == s->maxsize){
-		buf = LLT_REALLOC(s->buf, s->size + 1);
+		buf = MEM_REALLOC(s->buf, s->size + 1);
 		if(buf == nil)
 			return nil;
 	}else{
@@ -601,7 +607,7 @@
 	s->size = nvalid;
 
 	if(s->buf != nil && s->ownbuf && s->buf != &s->local[0])
-		LLT_FREE(s->buf);
+		MEM_FREE(s->buf);
 	s->buf = buf;
 	s->maxsize = size;
 	s->ownbuf = own;
@@ -738,7 +744,7 @@
 		goto open_file_err;
 	if(!wr)
 		s->readonly = 1;
-	s->filename = LLT_STRDUP(fname);
+	s->filename = MEM_STRDUP(fname);
 	return s;
 open_file_err:
 	s->fd = -1;
@@ -793,19 +799,19 @@
 void
 ios_init_stdstreams(void)
 {
-	ios_stdin = LLT_ALLOC(sizeof(ios_t));
+	ios_stdin = MEM_ALLOC(sizeof(ios_t));
 	ios_fd(ios_stdin, STDIN_FILENO, 0, 0);
-	ios_stdin->filename = LLT_STRDUP("*stdin*");
+	ios_stdin->filename = MEM_STRDUP("*stdin*");
 
-	ios_stdout = LLT_ALLOC(sizeof(ios_t));
+	ios_stdout = MEM_ALLOC(sizeof(ios_t));
 	ios_fd(ios_stdout, STDOUT_FILENO, 0, 0);
 	ios_stdout->bm = bm_line;
-	ios_stdout->filename = LLT_STRDUP("*stdout*");
+	ios_stdout->filename = MEM_STRDUP("*stdout*");
 
-	ios_stderr = LLT_ALLOC(sizeof(ios_t));
+	ios_stderr = MEM_ALLOC(sizeof(ios_t));
 	ios_fd(ios_stderr, STDERR_FILENO, 0, 0);
 	ios_stderr->bm = bm_none;
-	ios_stderr->filename = LLT_STRDUP("*stderr*");
+	ios_stderr->filename = MEM_STRDUP("*stderr*");
 }
 
 /* higher level interface */
@@ -873,7 +879,7 @@
 		return 1;
 	if(s->_eof)
 		return IOS_EOF;
-#ifdef __plan9__
+#if defined(__plan9__)
 	USED(ws);
 	return 1; // FIXME(sigrid): wait for input, but not too much
 #else
@@ -939,21 +945,24 @@
 	char *str;
 	int c;
 
-#if defined(__plan9__)
-	str = vsmprint(format, args);
-	if((c = strlen(str)) >= 0)
-#else
+	/* skip allocations if no buffering needed */
+	if(s->bm == bm_none && (s->state == bst_none || s->state == bst_wr))
+		return vdprintf(s->fd, format, args);
+
 	if((c = vsnprintf(buf, sizeof(buf), format, args)) < nelem(buf))
 		str = buf;
-	else{
-		str = LLT_ALLOC(c+1);
-		vsnprintf(str, sizeof(c+1), format, args);
+	else if(s->state == bst_none || s->state == bst_wr){
+		/* doesn't fit? prefer no allocations */
+		ios_flush(s);
+		return vdprintf(s->fd, format, args);
+	}else{
+		str = MEM_ALLOC(c+1);
+		c = vsnprintf(str, sizeof(c+1), format, args);
 	}
 	if(c > 0)
-#endif
-		ios_write(s, str, c);
+		c = ios_write(s, str, c);
 	if(str != buf)
-		LLT_FREE(str);
+		MEM_FREE(str);
 
 	return c;
 }
--- a/iostream.c
+++ b/iostream.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "cvalues.h"
 #include "types.h"
@@ -69,7 +68,7 @@
 ios_t *
 toiostream(value_t v)
 {
-	if(!isiostream(v))
+	if(__unlikely(!isiostream(v)))
 		type_error("iostream", v);
 	return value2c(ios_t*, v);
 }
@@ -204,7 +203,7 @@
 {
 	argcount(nargs, 2);
 	ios_t *s = toiostream(args[0]);
-	size_t pos = toulong(args[1]);
+	size_t pos = tosize(args[1]);
 	off_t res = ios_seek(s, (off_t)pos);
 	if(res < 0)
 		return FL(f);
@@ -241,7 +240,7 @@
 	if(nargs == 3){
 		// form (io.read s type count)
 		ft = get_array_type(args[1]);
-		n = toulong(args[2]) * ft->elsz;
+		n = tosize(args[2]) * ft->elsz;
 	}else{
 		ft = get_type(args[1]);
 		if(ft->eltype != nil && !iscons(cdr_(cdr_(args[1]))))
@@ -265,8 +264,8 @@
 get_start_count_args(value_t *args, uint32_t nargs, size_t sz, size_t *offs, size_t *nb)
 {
 	if(nargs > 1){
-		*offs = toulong(args[1]);
-		*nb = nargs > 2 ? toulong(args[2]) : sz - *offs;
+		*offs = tosize(args[1]);
+		*nb = nargs > 2 ? tosize(args[2]) : sz - *offs;
 		if(*offs >= sz || *offs + *nb > sz)
 			bounds_error(args[0], args[1]);
 	}
@@ -297,7 +296,7 @@
 static uint8_t
 get_delim_arg(value_t arg)
 {
-	size_t uldelim = toulong(arg);
+	size_t uldelim = tosize(arg);
 	if(uldelim > 0x7f){
 		// runes > 0x7f, or anything else > 0xff, are out of range
 		if((iscprim(arg) && cp_class(ptr(arg)) == FL(runetype)) || uldelim > 0xff)
@@ -348,7 +347,7 @@
 	ios_t *dest = toiostream(args[0]);
 	ios_t *src = toiostream(args[1]);
 	if(nargs == 3)
-		return size_wrap(ios_copy(dest, src, toulong(args[2])));
+		return size_wrap(ios_copy(dest, src, tosize(args[2])));
 	return size_wrap(ios_copyall(dest, src));
 }
 
@@ -367,7 +366,7 @@
 BUILTIN("io-set-line!", io_set_line)
 {
 	argcount(nargs, 2);
-	toiostream(args[0])->lineno = toulong(args[1]);
+	toiostream(args[0])->lineno = tosize(args[1]);
 	return FL(t);
 }
 
@@ -380,7 +379,7 @@
 BUILTIN("io-set-column!", io_set_column)
 {
 	argcount(nargs, 2);
-	toiostream(args[0])->colno = toulong(args[1]);
+	toiostream(args[0])->colno = tosize(args[1]);
 	return FL(t);
 }
 
--- a/llt.h
+++ /dev/null
@@ -1,33 +1,0 @@
-#pragma once
-
-#include "platform.h"
-#include "utf8.h"
-#include "ios.h"
-#include "bitvector.h"
-
-#include "htableh.inc"
-HTPROT(ptrhash)
-
-#define DBL_MAXINT (1LL<<53)
-#define FLT_MAXINT (1<<24)
-#define BIT63 0x8000000000000000ULL
-#define BIT31 0x80000000UL
-
-#ifdef BITS64
-#define TOP_BIT BIT63
-typedef uint64_t lltuint_t;
-typedef int64_t lltint_t;
-#else
-#define TOP_BIT BIT31
-typedef uint32_t lltuint_t;
-typedef int32_t lltint_t;
-#endif
-
-#define LOG2_10 3.3219280948873626
-#define rel_zero(a, b) (fabs((a)/(b)) < DBL_EPSILON)
-#define LLT_ALIGN(x, sz) (((x) + (sz-1)) & (-sz))
-
-extern double D_PNAN, D_NNAN, D_PINF, D_NINF;
-extern float F_PNAN, F_NNAN, F_PINF, F_NINF;
-
-_Noreturn void flmain(const uint8_t *boot, int bootsz, int argc, char **argv);
--- a/main_plan9.c
+++ b/main_plan9.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 
 extern uchar bootcode[];
 extern ulong bootlen;
--- a/main_posix.c
+++ b/main_posix.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 #include "ieee754.h"
 
 static const uint8_t boot[] =
--- a/meson.build
+++ b/meson.build
@@ -98,9 +98,8 @@
 endif
 
 sixel = get_option('sixel')
-
+libsixel_dep = []
 if sixel.disabled()
-	libsixel_dep = []
 	src += ['sixel_disabled.c']
 else
 	libsixel = dependency('libsixel', required: sixel)
@@ -107,7 +106,7 @@
 	if libsixel.found()
 		src += ['sixel.c']
 		libsixel_dep = [libsixel]
-	elif
+	else
 		src += ['sixel_disabled.c']
 	endif
 endif
@@ -164,8 +163,8 @@
 
 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)
+test('perf', flisp, args: ['perf.lsp'], workdir: tests_dir, timeout: 60)
 test('tme', flisp, args: ['tme.lsp'], workdir: tests_dir)
-test('torture', flisp, args: ['torture.scm'], workdir: tests_dir)
+test('torture', flisp, args: ['torture.scm'], workdir: tests_dir, timeout: 60)
 test('torus', flisp, args: ['torus.lsp'], workdir: tests_dir)
 test('unit', flisp, args: ['unittest.lsp'], workdir: tests_dir)
--- a/mkfile
+++ b/mkfile
@@ -2,12 +2,13 @@
 
 BIN=/$objtype/bin
 TARG=flisp
-CFLAGS=$CFLAGS -p -D__plan9__ -D__${objtype}__ -I3rd -Iplan9
+CFLAGS=$CFLAGS -p -I. -I3rd -Iplan9 -D__plan9__ -D__${objtype}__ -DNDEBUG
 CLEANFILES=plan9/flisp.boot.s plan9/builtin_fns.h
 
 HFILES=\
 	equalhash.h\
 	flisp.h\
+	plan9/platform.h\
 
 OFILES=\
 	3rd/mt19937-64.$O\
@@ -46,9 +47,10 @@
 	sed -n 's/^BUILTIN[_]?(\(".*)/BUILTIN_FN\1/gp' \
 		`{ls `{echo $OFILES | sed 's/\.'$O'/.c/g'} >[2]/dev/null} | sort >$target
 
-main_plan9.$O: plan9/builtin_fns.h
-flisp.$O: maxstack.inc opcodes.h plan9/builtin_fns.h
 builtins.$O: plan9/builtin_fns.h
+cvalues.$O: fl_arith_any.inc
+flisp.$O: maxstack.inc opcodes.h plan9/builtin_fns.h
+main_plan9.$O: plan9/builtin_fns.h
 
 plan9/flisp.boot.s:D: flisp.boot
 	aux/data2s boot <flisp.boot >$target
--- a/operators.c
+++ b/operators.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 
--- a/operators.h
+++ b/operators.h
@@ -14,11 +14,3 @@
 int32_t conv_to_int32(void *data, numerictype_t tag);
 uint32_t conv_to_uint32(void *data, numerictype_t tag);
 Rune conv_to_Rune(void *data, numerictype_t tag);
-
-#if defined(ULONG64)
-#define conv_to_long conv_to_int64
-#define conv_to_ulong conv_to_uint64
-#else
-#define conv_to_long conv_to_int32
-#define conv_to_ulong conv_to_uint32
-#endif
--- a/overflows.h
+++ /dev/null
@@ -1,29 +1,0 @@
-
-#define addof_int64(c,a,b) ( \
-  (b < 1)? \
-  ((INT64_MIN-(b) <= (a))?((c=(a)+(b))?0:1):1): \
-  ((INT64_MAX-(b) >= (a))?((c=(a)+(b))?0:1):1) \
-)
-
-#define subof_int64(c,a,b) ( \
-  (b < 1)? \
-  ((INT64_MAX+(b) >= (a))?((c=(a)-(b))?0:1):1): \
-  ((INT64_MIN+(b) <= (a))?((c=(a)-(b))?0:1):1) \
-)
-
-#define addof_uint64(c,a,b) ( \
-  b? \
-  ((UINT64_MAX-(b) >= (a))?((c=(a)+(b)),0):1): \
-  0 \
-)
-
-#define subof_uint64(c,a,b) ( \
-  (b < 1)? \
-  ((UINT64_MAX+(b) >= (a))?((c=(a)-(b))?0:1):1): \
-  (((b) <= (a))?((c=(a)-(b))?0:1):1) \
-)
-
-#define mulof(c,a,b) ( \
-  (((a) != 0) && ((c=(a)*(b))/(a) != (b)))?1:0 \
-)
-
--- a/plan9/platform.h
+++ b/plan9/platform.h
@@ -3,13 +3,35 @@
 #include <ctype.h>
 #include <mp.h>
 
+#ifdef NDEBUG
+#undef assert
+#define assert(x)
+#endif
+
+#define __os_name__ "plan9"
+
 #define __thread
 
-#define LLT_ALLOC(n) malloc(n)
-#define LLT_REALLOC(p, n) realloc((p), (n))
-#define LLT_FREE(x) free(x)
-#define LLT_STRDUP(s) strdup(s)
+#define MEM_ALLOC(n) malloc(n)
+#define MEM_REALLOC(p, n) realloc((p), (n))
+#define MEM_FREE(x) free(x)
+#define MEM_STRDUP(s) strdup(s)
 
+/* FIXME(sigrid): s*_overflow_* can be more optimal */
+
+#define sadd_overflow_64(a, b, c) ( \
+  (b < 1) ? \
+  ((INT64_MAX-(b) <= (a)) ? ((*(c)=(a)+(b)), 0) : 1) : \
+  ((INT64_MAX-(b) >= (a)) ? ((*(c)=(a)+(b)), 0) : 1) \
+)
+
+#define smul_overflow_64(a, b, c) ( \
+	((a)>0 ? ((b)>0 ? (a)>INT64_MAX/(b) : (b)<INT64_MIN/(a)) \
+	       : ((b)>0 ? (a)<INT64_MIN/(b) : ((a)!=0 && (b)<INT64_MAX/(a)))) \
+	? 1 \
+	: ((*(c)=(a)*(b)), 0) \
+)
+
 #if defined(__amd64__) || \
     defined(__arm64__) || \
     defined(__mips64__) || \
@@ -16,6 +38,15 @@
     defined(__power64__) || \
     defined(__sparc64__)
 #define BITS64
+#define PRIdPTR PRId64
+#define sadd_overflow(a, b, c) sadd_overflow_64(a, b, c)
+#else
+#define PRIdPTR "ld"
+#define sadd_overflow(a, b, c) ( \
+  (b < 1) ? \
+  ((INT32_MAX-(b) <= (a)) ? ((*(c)=(a)+(b)), 0) : 1) : \
+  ((INT32_MAX-(b) >= (a)) ? ((*(c)=(a)+(b)), 0) : 1) \
+)
 #endif
 
 #define unsetenv(name) putenv(name, "")
@@ -25,6 +56,7 @@
 
 #define getcwd getwd
 #define vsnprintf vsnprint
+#define vdprintf fprint
 #define snprintf snprint
 #define strcasecmp cistrcmp
 #define lseek seek
@@ -31,17 +63,12 @@
 #define towupper toupperrune
 #define towlower tolowerrune
 #define iswalpha isalpharune
-#define signbit(r) ((*(uint64_t*)&(r)) & BIT63)
+#define signbit(r) ((*(uint64_t*)&(r)) & (1ULL<<63))
 #define isfinite(d) (((*(uint64_t*)&(d))&0x7ff0000000000000ULL) != 0x7ff0000000000000ULL)
 
 #define PRIu32 "ud"
 #define PRId64 "lld"
 #define PRIu64 "llud"
-#ifdef BITS64
-#define PRIdPTR PRId64
-#else
-#define PRIdPTR "ld"
-#endif
 
 #define INT32_MAX 0x7fffffff
 #define UINT32_MAX 0xffffffffU
--- a/posix/platform.h
+++ b/posix/platform.h
@@ -25,17 +25,34 @@
 #include <wctype.h>
 #include <wchar.h>
 
-#define LLT_ALLOC(n) malloc((size_t)(n))
-#define LLT_REALLOC(p, n) realloc((p), (size_t)(n))
-#define LLT_FREE(x) free(x)
-#define LLT_STRDUP(s) strdup(s)
+#if defined(__linux__)
+#define __os_name__ "linux"
+#elif defined(__OpenBSD__)
+#define __os_name__ "openbsd"
+#elif defined(__FreeBSD__)
+#define __os_name__ "freebsd"
+#elif defined(__NetBSD__)
+#define __os_name__ "netbsd"
+#elif defined(__DragonFly__)
+#define __os_name__ "dragonflybsd"
+#else
+#define __os_name__ "unknown"
+#endif
 
+#define MEM_ALLOC(n) malloc((size_t)(n))
+#define MEM_REALLOC(p, n) realloc((p), (size_t)(n))
+#define MEM_FREE(x) free(x)
+#define MEM_STRDUP(s) strdup(s)
+
 #ifndef __SIZEOF_POINTER__
 #error pointer size unknown
 #elif __SIZEOF_POINTER__ == 8
-#define BITS64 1
-#define ULONG64 1
+#define BITS64
 #endif
+
+#define sadd_overflow __builtin_add_overflow
+#define sadd_overflow_64 __builtin_add_overflow
+#define smul_overflow_64 __builtin_mul_overflow
 
 #define nil NULL
 #define USED(x) ((void)(x))
--- a/posix/utf.h
+++ b/posix/utf.h
@@ -7,7 +7,7 @@
 	UTFmax = 4,
 };
 
-typedef int32_t Rune;
+typedef uint32_t Rune;
 
 int chartorune(Rune *rune, const char *str);
 int runetochar(char *str, const Rune *rune);
--- a/print.c
+++ b/print.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 #include "opcodes.h"
@@ -7,6 +6,8 @@
 #include "print.h"
 #include "read.h"
 
+#define LOG2_10 3.321928094887362347870319429489
+
 static void
 outc(char c, ios_t *f)
 {
@@ -120,7 +121,7 @@
 	if((name[0] == '\0') ||
 		(name[0] == '.' && name[1] == '\0') ||
 		(name[0] == '#') ||
-		isnumtok(name, nil))
+		fl_read_numtok(name, nil, 0))
 		escape = 1;
 	i = 0;
 	while(name[i]){
@@ -592,27 +593,31 @@
 	if(fpart == 0)
 		dec = 0;
 	if(width == 0)
-		snprintf(format, 8, "%%.%d%s", dec, num_format);
+		snprintf(format, sizeof(format), "%%.%d%s", dec, num_format);
 	else
-		snprintf(format, 8, "%%%d.%d%s", width, dec, num_format);
+		snprintf(format, sizeof(format), "%%%d.%d%s", width, dec, num_format);
 	sz = snprintf(s, cnt, format, r);
 	/* trim trailing zeros from fractions. not when using scientific
 	   notation, since we might have e.g. 1.2000e+100. also not when we
 	   need a specific output width */
 	if(width == 0 && !keepz){
-		if(sz > 2 && fpart && num_format[1] != 'e'){
+		if(sz > 2 && fpart){
+			char *e = nil;
+			if(num_format[1] == 'e'){
+				while(s[--sz] != 'e');
+				e = s + sz--;
+			}
 			while(s[sz-1] == '0'){
 				s[sz-1] = '\0';
 				sz--;
 			}
 			// don't need trailing .
-			if(s[sz-1] == '.'){
+			if(s[sz-1] == '.')
 				s[--sz] = '\0';
-			}
+			if(num_format[1] == 'e')
+				strcpy(s+sz, e);
 		}
 	}
-	// TODO. currently 1.1e20 prints as 1.1000000000000000e+20; be able to
-	// get rid of all those zeros.
 }
 
 // 'weak' means we don't need to accurately reproduce the type, so
@@ -696,11 +701,7 @@
 			if(type == FL(floatsym) && !FL(print_princ) && !weak)
 				outc('f', f);
 		}
-#if defined(ULONG64)
-	}else if(type == FL(uint64sym) || type == FL(ulongsym)){
-#else
 	}else if(type == FL(uint64sym)){
-#endif
 		uint64_t ui64 = *(uint64_t*)data;
 		if(weak || FL(print_princ))
 			FL(hpos) += ios_printf(f, "%"PRIu64, ui64);
@@ -709,11 +710,8 @@
 	}else if(type == FL(bignumsym)){
 		mpint *i = *(mpint**)data;
 		char *s = mptoa(i, 10, nil, 0);
-		if(weak || FL(print_princ))
-			FL(hpos) += ios_printf(f, "%s", s);
-		else
-			FL(hpos) += ios_printf(f, "#%s(%s)", symbol_name(type), s);
-		LLT_FREE(s);
+		FL(hpos) += ios_printf(f, "%s", s);
+		MEM_FREE(s);
 	}else if(issymbol(type)){
 		// handle other integer prims. we know it's smaller than uint64
 		// at this point, so int64 is big enough to capture everything.
@@ -733,7 +731,7 @@
 			value_t eltype = car(cdr_(type));
 			size_t cnt, elsize;
 			if(iscons(cdr_(cdr_(type)))){
-				cnt = toulong(car_(cdr_(cdr_(type))));
+				cnt = tosize(car_(cdr_(cdr_(type))));
 				elsize = cnt ? len/cnt : 0;
 			}else{
 				// incomplete array type
--- a/ptrhash.c
+++ b/ptrhash.c
@@ -3,11 +3,11 @@
   optimized for storing info about particular values
 */
 
-#include "llt.h"
+#include "flisp.h"
 
 #define OP_EQ(x, y) ((x) == (y))
 
-#ifdef BITS64
+#if defined(BITS64)
 static uint64_t
 _pinthash(uint64_t key)
 {
--- a/random.c
+++ b/random.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 #include "mt19937-64.h"
 #include "timefuncs.h"
 #include "random.h"
--- a/read.c
+++ b/read.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "cvalues.h"
 #include "read.h"
@@ -21,85 +20,15 @@
 
 static value_t do_read_sexpr(Rctx *ctx, value_t label);
 
-#if defined(__plan9__)
-static int errno;
-static mpint *mp_vlong_min, *mp_vlong_max, *mp_uvlong_max;
-#endif
-
-static int64_t
-strtoll_mp(const char *nptr, char **rptr, int base, mpint **mp)
-{
-	int64_t x;
-	mpint *m;
-
-	*mp = nil;
-	errno = 0;
-	x = strtoll(nptr, rptr, base);
-#if defined(__plan9__)
-	if((x != INT64_MAX && x != INT64_MIN) || *rptr == nptr)
-		return x;
-	mpint *c;
-	m = strtomp(nptr, rptr, base, nil);
-	if(x == INT64_MAX){
-		if(mp_vlong_max == nil)
-			mp_vlong_max = vtomp(INT64_MAX, nil);
-		c = mp_vlong_max;
-	}else{
-		if(mp_vlong_min == nil)
-			mp_vlong_min = vtomp(INT64_MIN, nil);
-		c = mp_vlong_min;
-	}
-	if(mpcmp(c, m) == 0){
-		mpfree(m);
-		m = nil;
-	}
-#else
-	m = nil;
-	if(errno == ERANGE && (x == LLONG_MAX || x == LLONG_MIN))
-		m = strtomp(nptr, rptr, base, nil);
-#endif
-	*mp = m;
-	return x;
-}
-
-static uint64_t
-strtoull_mp(const char *nptr, char **rptr, int base, mpint **mp)
-{
-	uint64_t x;
-	mpint *m;
-
-	*mp = nil;
-	errno = 0;
-	x = strtoull(nptr, rptr, base);
-#if defined(__plan9__)
-	if(x != INT64_MAX || *rptr == nptr)
-		return x;
-	m = strtomp(nptr, rptr, base, nil);
-	if(mp_uvlong_max == nil)
-		mp_uvlong_max = uvtomp(INT64_MAX, nil);
-	if(mpcmp(mp_uvlong_max, m) == 0){
-		mpfree(m);
-		m = nil;
-	}
-#else
-	m = nil;
-	if(errno == ERANGE && x == ULLONG_MAX)
-		m = strtomp(nptr, rptr, base, nil);
-#endif
-	*mp = m;
-	return x;
-}
-
 #define RS value2c(ios_t*, FL(readstate)->source)
 
 bool
-isnumtok_base(const char *tok, value_t *pval, int base)
+fl_read_numtok(const char *tok, value_t *pval, int base)
 {
 	char *end;
 	int64_t i64;
-	uint64_t ui64;
 	double d;
-	mpint *mp = nil;
+	mpint *mp;
 	if(*tok == '\0')
 		return false;
 	if(!((tok[0] == '0' && tok[1] == 'x') || (base >= 15)) && strpbrk(tok, ".eEpP")){
@@ -141,31 +70,15 @@
 				*pval = mk_double(D_NINF);
 			return true;
 		}
-		i64 = strtoll_mp(tok, &end, base, &mp);
-		bool ok = *end == '\0';
-		if(pval)
-			*pval = mp == nil ? return_from_int64(i64) : mk_mpint(mp);
-		return ok;
 	}
-	ui64 = strtoull_mp(tok, &end, base, &mp);
+	i64 = strtoll(tok, &end, base);
+	mp = fits_fixnum(i64) ? nil : strtomp(tok, &end, base, nil);
 	bool ok = *end == '\0';
 	if(pval)
-		*pval = mp == nil ? return_from_uint64(ui64) : mk_mpint(mp);
+		*pval = mp == nil ? fixnum(i64) : mk_mpint(mp);
 	return ok;
 }
 
-bool
-isnumtok(const char *tok, value_t *pval)
-{
-	return isnumtok_base(tok, pval, 0);
-}
-
-static bool
-read_numtok(const char *tok, value_t *pval, int base)
-{
-	return isnumtok_base(tok, pval, base);
-}
-
 static char
 nextchar(void)
 {
@@ -317,7 +230,7 @@
 			if(cval == 'u' || cval == 'U' || cval == 'x'){
 				read_token(ctx, 'u', 0);
 				if(ctx->buf[1] != '\0'){ // not a solitary 'u','U','x'
-					if(!read_numtok(&ctx->buf[1], &ctx->tokval, 16))
+					if(!fl_read_numtok(&ctx->buf[1], &ctx->tokval, 16))
 						parse_error("invalid hex character constant");
 					cval = numval(ctx->tokval);
 				}
@@ -415,7 +328,7 @@
 			    (c == 'o' && (base = 8)) ||
 			    (c == 'd' && (base = 10)) ||
 			    (c == 'x' && (base = 16))) && (isdigit_base(ctx->buf[1], base) || ctx->buf[1] == '-')){
-				if(!read_numtok(&ctx->buf[1], &ctx->tokval, base))
+				if(!fl_read_numtok(&ctx->buf[1], &ctx->tokval, base))
 					parse_error("invalid base %d constant", base);
 				return (ctx->toktype = TOK_NUM);
 			}
@@ -441,7 +354,7 @@
 		if(!read_token(ctx, c, 0)){
 			if(ctx->buf[0] == '.' && ctx->buf[1] == '\0')
 				return (ctx->toktype = TOK_DOT);
-			if(read_numtok(ctx->buf, &ctx->tokval, 0))
+			if(fl_read_numtok(ctx->buf, &ctx->tokval, 0))
 				return (ctx->toktype = TOK_NUM);
 		}
 		ctx->toktype = TOK_SYM;
@@ -512,13 +425,13 @@
 	value_t s;
 	Rune r = 0;
 
-	buf = LLT_ALLOC(sz);
+	buf = MEM_ALLOC(sz);
 	while(1){
 		if(i >= sz-UTFmax){ // -UTFmax: leaves room for longest utf8 sequence
 			sz *= 2;
-			temp = LLT_REALLOC(buf, sz);
+			temp = MEM_REALLOC(buf, sz);
 			if(temp == nil){
-				LLT_FREE(buf);
+				MEM_FREE(buf);
 				parse_error("out of memory reading string");
 			}
 			buf = temp;
@@ -525,7 +438,7 @@
 		}
 		c = ios_getc(RS);
 		if(c == IOS_EOF){
-			LLT_FREE(buf);
+			MEM_FREE(buf);
 			parse_error("unexpected end of input in string");
 		}
 		if(c == '"')
@@ -533,7 +446,7 @@
 		else if(c == '\\'){
 			c = ios_getc(RS);
 			if(c == IOS_EOF){
-				LLT_FREE(buf);
+				MEM_FREE(buf);
 				parse_error("end of input in escape sequence");
 			}
 			j = 0;
@@ -561,7 +474,7 @@
 				if(j)
 					r = strtol(eseq, nil, 16);
 				if(!j || r > Runemax){
-					LLT_FREE(buf);
+					MEM_FREE(buf);
 					parse_error("invalid escape sequence");
 				}
 				if(ndig == 2)
@@ -573,7 +486,7 @@
 			}else{
 				char esc = read_escape_control_char((char)c);
 				if(esc == (char)c && !strchr("\\'\"`", esc)){
-					LLT_FREE(buf);
+					MEM_FREE(buf);
 					parse_error("invalid escape sequence: \\%c", (char)c);
 				}
 				buf[i++] = esc;
@@ -584,7 +497,7 @@
 	}
 	s = cvalue_string(i);
 	memcpy(cvalue_data(s), buf, i);
-	LLT_FREE(buf);
+	MEM_FREE(buf);
 	return s;
 }
 
--- a/read.h
+++ b/read.h
@@ -1,8 +1,7 @@
 #pragma once
 
 value_t fl_read_sexpr(value_t f);
-bool isnumtok_base(const char *tok, value_t *pval, int base);
-bool isnumtok(const char *tok, value_t *pval);
+bool fl_read_numtok(const char *tok, value_t *pval, int base);
 
 // defines which characters are ordinary symbol characters.
 // exceptions are '.', which is an ordinary symbol character
--- a/sixel.c
+++ b/sixel.c
@@ -1,5 +1,4 @@
 #include <sixel.h>
-#include "llt.h"
 #include "flisp.h"
 #include "cvalues.h"
 #include "types.h"
@@ -48,7 +47,7 @@
 	int numcolors = 256;
 	if(nargs > 0){
 		argcount(nargs, 1);
-		numcolors = toulong(args[0]);
+		numcolors = tosize(args[0]);
 	}
 	if(numcolors < 1 || numcolors > 256)
 		lerrorf(FL(ArgError), "invalid number of colors: %d", numcolors);
@@ -79,10 +78,10 @@
 	if(!issixeloutput(args[0]))
 		type_error("sixel-output", args[0]);
 	fso_t *f = value2c(fso_t*, args[0]);
-	int scalex = toulong(args[1]);
+	int scalex = tosize(args[1]);
 	int scaley = scalex;
 	if(nargs > 2)
-		scaley = toulong(args[2]);
+		scaley = tosize(args[2]);
 	if(scalex < 1 || scalex > 32 || scaley < 1 || scaley > 32)
 		lerrorf(FL(ArgError), "invalid scale factor: %dx%d", scalex, scaley);
 	f->scalex = scalex;
@@ -175,8 +174,8 @@
 	uint8_t *pix;
 	size_t sz;
 	to_sized_ptr(args[2], &pix, &sz);
-	size_t w = toulong(args[3]);
-	size_t h = toulong(args[4]);
+	size_t w = tosize(args[3]);
+	size_t h = tosize(args[4]);
 	if(w <= 0 || w > sz)
 		bounds_error(args[2], args[3]);
 	if(h <= 0 || w*h > sz)
@@ -187,7 +186,7 @@
 		if(ow < 1 || oh < 1 || osz < ow || osz < oh)
 			lerrorf(FL(ArgError), "scaling out of range");
 		if(f->bufsz < osz){
-			f->buf = LLT_REALLOC(f->buf, osz);
+			f->buf = MEM_REALLOC(f->buf, osz);
 			f->bufsz = osz;
 		}
 		r = sixel_helper_scale_image(
@@ -205,7 +204,7 @@
 		h = oh;
 		pix = f->buf;
 	}else if(f->buf != nil){
-		LLT_FREE(f->buf);
+		MEM_FREE(f->buf);
 		f->buf = nil;
 		f->bufsz = 0;
 	}
@@ -240,7 +239,7 @@
 	fso_t *f = value2c(fso_t*, self);
 	sixel_dither_destroy(f->dither);
 	sixel_output_destroy(f->out);
-	LLT_FREE(f->buf);
+	MEM_FREE(f->buf);
 }
 
 static cvtable_t fso_vtable = {
--- a/string.c
+++ b/string.c
@@ -1,7 +1,6 @@
 /*
   string functions
 */
-#include "llt.h"
 #include "flisp.h"
 #include "operators.h"
 #include "cvalues.h"
@@ -26,11 +25,11 @@
 	size_t len = cv_len((cvalue_t*)ptr(args[0]));
 	size_t stop = len;
 	if(nargs > 1){
-		start = toulong(args[1]);
+		start = tosize(args[1]);
 		if(start > len)
 			bounds_error(args[0], args[1]);
 		if(nargs > 2){
-			stop = toulong(args[2]);
+			stop = tosize(args[2]);
 			if(stop > len)
 				bounds_error(args[0], args[2]);
 			if(stop <= start)
@@ -185,7 +184,7 @@
 		argcount(nargs, 3);
 	char *s = tostring(args[0]);
 	size_t lenbytes = cv_len((cvalue_t*)ptr(args[0]));
-	size_t startbytes, n, startchar = toulong(args[1]);
+	size_t startbytes, n, startchar = tosize(args[1]);
 	for(startbytes = n = 0; n < startchar && startbytes < lenbytes; n++)
 		startbytes += u8_seqlen(s+startbytes);
 	if(n != startchar)
@@ -192,7 +191,7 @@
 		bounds_error(args[0], args[1]);
 	size_t endbytes = lenbytes;
 	if(nargs == 3){
-		size_t endchar = toulong(args[2]);
+		size_t endchar = tosize(args[2]);
 		for(endbytes = startbytes; n < endchar && endbytes < lenbytes; n++)
 			endbytes += u8_seqlen(s+endbytes);
 		if(n != endchar)
@@ -211,7 +210,7 @@
 	argcount(nargs, 2);
 	char *s = tostring(args[0]);
 	size_t lenbytes = cv_len(ptr(args[0]));
-	size_t startbytes, n, startchar = toulong(args[1]);
+	size_t startbytes, n, startchar = tosize(args[1]);
 	for(startbytes = n = 0; n < startchar && startbytes < lenbytes; n++)
 		startbytes += u8_seqlen(s+startbytes);
 	if(n != startchar)
@@ -307,7 +306,7 @@
 	char cbuf[UTFmax+1];
 	size_t start = 0;
 	if(nargs == 3)
-		start = toulong(args[2]);
+		start = tosize(args[2]);
 	else
 		argcount(nargs, 2);
 	char *s = tostring(args[0]);
@@ -350,7 +349,7 @@
 static unsigned long
 get_radix_arg(value_t arg)
 {
-	unsigned long radix = toulong(arg);
+	unsigned long radix = tosize(arg);
 	if(radix < 2 || radix > 36)
 		lerrorf(FL(ArgError), "invalid radix");
 	return radix;
@@ -392,7 +391,7 @@
 	unsigned long radix = 0;
 	if(nargs == 2)
 		radix = get_radix_arg(args[1]);
-	if(!isnumtok_base(str, &n, (int)radix))
+	if(!fl_read_numtok(str, &n, (int)radix))
 		return FL(f);
 	return n;
 }
--- a/table.c
+++ b/table.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "equalhash.h"
 #include "cvalues.h"
--- a/terminal_posix.c
+++ b/terminal_posix.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include <sys/ioctl.h>
 #include <termios.h>
--- a/test/number-boundaries.lsp
+++ b/test/number-boundaries.lsp
@@ -81,17 +81,16 @@
 
 ; mul signed
 (assert (= 18446744073709551614 (* (high-border int64) 2)))
-;(assert (= -18446744073709551614 (* (high-border int64) -2)))
+(assert (= -18446744073709551614 (* (high-border int64) -2)))
 (assert (= 18446744073709551614 (* 2 (high-border int64))))
-;(assert (= -18446744073709551616 (* (low-border int64) 2)))
-;(assert (= -18446744073709551616 (* 2 (low-border int64))))
+(assert (= -18446744073709551616 (* (low-border int64) 2)))
+(assert (= -18446744073709551616 (* 2 (low-border int64))))
 
 ; mul unsigned
-;(assert (= 36893488147419103230 (* (high-border uint64) 2)))
-;(assert (= 36893488147419103230 (* 2 (high-border uint64))))
-;(assert (= -36893488147419103230 (* (high-border uint64) -2)))
-;(assert (= -36893488147419103230 (* -2 (high-border uint64))))
+(assert (= 36893488147419103230 (* (high-border uint64) 2)))
+(assert (= 36893488147419103230 (* 2 (high-border uint64))))
+(assert (= -36893488147419103230 (* (high-border uint64) -2)))
+(assert (= -36893488147419103230 (* -2 (high-border uint64))))
 
 (princ "all number boundaries tests pass\n\n")
 #t
-
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -64,7 +64,7 @@
 (assert (< (- #uint32(0x80000000)) 0))
 (assert (> (- #int32(0x80000000)) 0))
 (assert (< (- #uint64(0x8000000000000000)) 0))
-(assert (> (- #int64(0x8000000000000000)) 0))
+(assert (< (- #int64(0x8000000000000000)) 0))
 ; fixnum versions
 (assert (= (- -536870912) 536870912))
 (assert (= (- -2305843009213693952) 2305843009213693952))
@@ -93,11 +93,12 @@
 (assert (> 0x10000000000000000 0x8fffffffffffffff))
 (assert (< 0x8fffffffffffffff 0x10000000000000000))
 
-(assert (not (bignum? (ash 2 60))))
-(assert (not (bignum? (- (ash 2 60) 1))))
+(assert (bignum? (ash 2 60)))
+(define (bignum-on-32? x) (if #.(fixnum? 0xffffffff) (not (bignum? x)) (bignum? x)))
+(assert (bignum-on-32? (- (ash 2 60) 1)))
 (assert (bignum? 1606938044258990275541962092341162602522202993782792835301376))
 (assert (bignum? 0xfffffffffffffffff))
-(assert (not (bignum? 0xfffffffffffffff)))
+(assert (bignum-on-32? 0xfffffffffffffff))
 
 (assert (= 4764984380238568507752444984131552966909
         (* 66405897020462343733 71755440315342536873)))
--- a/time_plan9.c
+++ b/time_plan9.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 #include "timefuncs.h"
 #include <tos.h>
 
--- a/time_posix.c
+++ b/time_posix.c
@@ -1,4 +1,4 @@
-#include "llt.h"
+#include "flisp.h"
 #include "timefuncs.h"
 
 double
--- a/types.c
+++ b/types.c
@@ -1,4 +1,3 @@
-#include "llt.h"
 #include "flisp.h"
 #include "cvalues.h"
 #include "equalhash.h"
@@ -40,7 +39,7 @@
 		if(isarray){
 			fltype_t *eltype = get_type(car_(cdr_(t)));
 			if(eltype->size == 0){
-				LLT_FREE(ft);
+				MEM_FREE(ft);
 				lerrorf(FL(ArgError), "invalid array element type");
 			}
 			ft->elsz = eltype->size;
--- a/utf8.c
+++ b/utf8.c
@@ -13,7 +13,7 @@
   A UTF-8 validation routine is included.
 */
 
-#include "llt.h"
+#include "flisp.h"
 
 static const uint32_t offsetsFromUTF8[6] = {
 	0x00000000UL, 0x00003080UL, 0x000E2080UL,