ref: d5715fb848737d39f465381c60ddc2a81b8b34c5
parent: e28a69a81ebef87d000b2ab7bb5f920868784e61
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Apr 1 00:15:12 EDT 2025
unboxed: store/pass most of C primitives by values on stack This covers [su]{8,16} (and [su]32 on 64-bit CPUs). References: https://todo.sr.ht/~ft/sl/46
--- a/src/builtins.c
+++ b/src/builtins.c
@@ -226,7 +226,7 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- if(isfixnum(v) || ismp(v))
+ if(isfixnum(v) || isunboxednum(v) || ismp(v))
return sl_t;
if(iscprim(v)){
sl_numtype nt = cp_numtype(ptr(v));
@@ -256,7 +256,7 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- return (isfixnum(v) || ismp(v) ||
+ return (isfixnum(v) || isunboxednum(v) || ismp(v) ||
(iscprim(v) && cp_numtype(ptr(v)) < T_FLOAT)) ?
sl_t : sl_nil;
}
@@ -274,6 +274,8 @@
sl_v v = args[0];
if(isfixnum(v))
return v;
+ if(isunboxednum(v))
+ return isunboxedunum(v) ? fixnum(unboxednumuval(v)) : fixnum(unboxednumsval(v));
if(iscprim(v)){
void *p = ptr(v);
return fixnum(conv_to_s64(cp_data(p), cp_numtype(p)));
@@ -291,7 +293,7 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- if(isfixnum(v) || ismp(v))
+ if(isfixnum(v) || isunboxednum(v) || ismp(v))
return v;
if(iscprim(v)){
sl_cprim *cp = ptr(v);
@@ -352,6 +354,8 @@
{
if(isfixnum(a))
return (double)numval(a);
+ if(isunboxednum(a))
+ return isunboxedunum(a) ? (double)unboxednumuval(a) : (double)unboxednumsval(a);
if(iscprim(a)){
sl_cprim *cp = ptr(a);
sl_numtype nt = cp_numtype(cp);
--- a/src/compress.c
+++ b/src/compress.c
@@ -17,7 +17,8 @@
type_error("arr", args[0]);
u8int *in;
usize insz;
- to_sized_ptr(args[0], &in, &insz);
+ uintptr u;
+ to_sized_ptr(args[0], &in, &insz, &u);
int level = nargs > 1 ? tofixnum(args[1]) : 0;
if(level < 0)
level = 0;
@@ -47,7 +48,8 @@
u8int *in;
usize insz;
- to_sized_ptr(args[0], &in, &insz);
+ uintptr u;
+ to_sized_ptr(args[0], &in, &insz, &u);
if(!isarr(args[0]))
type_error("arr", args[0]);
usize outsz;
@@ -59,7 +61,7 @@
out = cvalue_data(v);
}else if(args[1] == sl_tosym){
v = args[2];
- to_sized_ptr(v, &out, &outsz);
+ to_sized_ptr(v, &out, &outsz, &u);
}else{
lerrorf(sl_errarg, "either :size or :to must be specified");
}
--- a/src/cvalues.c
+++ b/src/cvalues.c
@@ -15,6 +15,9 @@
#define owned(cv) ((uintptr)(cv)->type & CV_OWNED)
#define isinlined(cv) ((cv)->data == (cv)->_space)
+sl_type *unboxedtypes[T_UNBOXED_NUM];
+sl_v unboxedtypesyms[T_UNBOXED_NUM];
+
static void cvalue_init(sl_type *type, sl_v v, void *dest);
void
@@ -199,21 +202,29 @@
#define num_init(ctype, cnvt, tag) \
static void \
- cvalue_##ctype##_init(sl_type *type, sl_v arg, void *dest) \
+ cvalue_##ctype##_init(sl_type *type, sl_v a, void *dest) \
{ \
ctype n; \
USED(type); \
- if(isfixnum(arg)) \
- n = (ctype)numval(arg); \
- else if(iscprim(arg)){ \
- sl_cprim *cp = ptr(arg); \
+ if(isfixnum(a)) \
+ n = (ctype)numval(a); \
+ else if(isunboxednum(a)){ \
+ uintptr v; \
+ void *p = &v; \
+ if(isunboxedunum(a)) \
+ v = unboxednumuval(a); \
+ else \
+ v = unboxednumsval(a); \
+ n = (ctype)conv_to_##cnvt(p, unboxednumtype(a)); \
+ }else if(iscprim(a)){ \
+ sl_cprim *cp = ptr(a); \
void *p = cp_data(cp); \
n = (ctype)conv_to_##cnvt(p, cp_numtype(cp)); \
- }else if(ismp(arg)){ \
- void *p = cv_data(ptr(arg)); \
+ }else if(ismp(a)){ \
+ void *p = cv_data(ptr(a)); \
n = (ctype)conv_to_##cnvt(p, T_MP); \
}else \
- type_error("num", arg); \
+ type_error("num", a); \
*((ctype*)dest) = n; \
}
@@ -236,29 +247,70 @@
PUSH(fixnum(0)); \
args = sl.sp-1; \
} \
- sl_v cp = cprim(sl_##typenam##type, sizeof(ctype)); \
- cvalue_##ctype##_init(sl_##typenam##type, args[0], cp_data(ptr(cp))); \
- return cp; \
+ sl_v v = cprim(sl_##typenam##type, sizeof(ctype)); \
+ cvalue_##ctype##_init(sl_##typenam##type, args[0], cp_data(ptr(v))); \
+ return v; \
}
+#define num_ctor_init_unboxed(typenam, ctype, tag) \
+ static \
+ BUILTIN(#typenam, typenam) \
+ { \
+ if(nargs == 0){ \
+ PUSH(fixnum(0)); \
+ args = sl.sp-1; \
+ } \
+ sl_v v; \
+ if(tag < T_UNBOXED_NUM && sizeof(ctype) < sizeof(sl_v) && sl_##typenam##type != sl_runetype){ \
+ ctype u; \
+ cvalue_##ctype##_init(sl_##typenam##type, args[0], &u); \
+ if(tag & 1) \
+ v = (uintptr)u; \
+ else \
+ v = (intptr)u; \
+ v = v<<8 | tag<<4 | TAG_UNBOXED; \
+ }else{ \
+ v = cprim(sl_##typenam##type, sizeof(ctype)); \
+ cvalue_##ctype##_init(sl_##typenam##type, args[0], cp_data(ptr(v))); \
+ } \
+ return v; \
+ }
+
#define num_ctor_ctor(typenam, ctype, tag) \
sl_v mk_##typenam(ctype n) \
{ \
- sl_v cp = cprim(sl_##typenam##type, sizeof(ctype)); \
- *(ctype*)cp_data(ptr(cp)) = n; \
- return cp; \
+ sl_v v = cprim(sl_##typenam##type, sizeof(n)); \
+ *(ctype*)cp_data(ptr(v)) = n; \
+ return v; \
}
+#define num_ctor_ctor_unboxed(typenam, ctype, tag) \
+ sl_v mk_##typenam(ctype n) \
+ { \
+ sl_v v; \
+ if(tag < T_UNBOXED_NUM && sizeof(n) < sizeof(sl_v) && sl_##typenam##type != sl_runetype){ \
+ v = n<<8 | tag<<4 | TAG_UNBOXED; \
+ }else{ \
+ v = cprim(sl_##typenam##type, sizeof(n)); \
+ *(ctype*)cp_data(ptr(v)) = n; \
+ } \
+ return v; \
+ }
+
#define num_ctor(typenam, ctype, tag) \
num_ctor_init(typenam, ctype, tag) \
num_ctor_ctor(typenam, ctype, tag)
-num_ctor_init(s8, s8int, T_S8)
-num_ctor_init(u8, u8int, T_U8)
-num_ctor_init(s16, s16int, T_S16)
-num_ctor_init(u16, u16int, T_U16)
-num_ctor(s32, s32int, T_S32)
-num_ctor(u32, u32int, T_U32)
+#define num_ctor_unboxed(typenam, ctype, tag) \
+ num_ctor_init_unboxed(typenam, ctype, tag) \
+ num_ctor_ctor_unboxed(typenam, ctype, tag)
+
+num_ctor_init_unboxed(s8, s8int, T_S8)
+num_ctor_init_unboxed(u8, u8int, T_U8)
+num_ctor_init_unboxed(s16, s16int, T_S16)
+num_ctor_init_unboxed(u16, u16int, T_U16)
+num_ctor_unboxed(s32, s32int, T_S32)
+num_ctor_unboxed(u32, u32int, T_U32)
num_ctor(s64, s64int, T_S64)
num_ctor(u64, u64int, T_U64)
num_ctor_init(utf8, u8int, T_U8)
@@ -267,22 +319,30 @@
num_ctor(rune, u32int, T_U32)
static void
-cvalue_mp_init(sl_type *type, sl_v arg, void *dest)
+cvalue_mp_init(sl_type *type, sl_v a, void *dest)
{
mpint *n;
USED(type);
- if(isfixnum(arg)){
- n = vtomp(numval(arg), nil);
- }else if(iscvalue(arg)){
- sl_cv *cv = ptr(arg);
+ if(isfixnum(a))
+ n = vtomp(numval(a), nil);
+ else if(isunboxednum(a)){
+ uintptr v;
+ void *p = &v;
+ if(isunboxedunum(a))
+ v = unboxednumuval(a);
+ else
+ v = unboxednumsval(a);
+ n = conv_to_mp(p, unboxednumtype(a));
+ }else if(iscvalue(a)){
+ sl_cv *cv = ptr(a);
void *p = cv_data(cv);
n = conv_to_mp(p, cv_numtype(cv));
- }else if(iscprim(arg)){
- sl_cprim *cp = ptr(arg);
+ }else if(iscprim(a)){
+ sl_cprim *cp = ptr(a);
void *p = cp_data(cp);
n = conv_to_mp(p, cp_numtype(cp));
}else
- type_error("num", arg);
+ type_error("num", a);
*((mpint**)dest) = n;
}
@@ -330,6 +390,8 @@
{
if(isfixnum(n))
return (usize)numval(n);
+ if(isunboxednum(n))
+ return (usize)unboxednumuval(n);
if(iscprim(n)){
sl_cprim *cp = ptr(n);
if(sizeof(usize) == 8)
@@ -344,6 +406,10 @@
{
if(isfixnum(n))
return numval(n);
+ if(isunboxedunum(n))
+ return unboxednumuval(n);
+ if(isunboxedsnum(n))
+ return unboxednumsval(n);
if(iscprim(n)){
sl_cprim *cp = ptr(n);
return conv_to_s64(cp_data(cp), cp_numtype(cp));
@@ -522,8 +588,20 @@
// get pointer and size for any plain-old-data value
void
-to_sized_ptr(sl_v v, u8int **pdata, usize *psz)
+to_sized_ptr(sl_v v, u8int **pdata, usize *psz, uintptr *u)
{
+ if(isunboxedunum(v)){
+ *u = unboxednumuval(v);
+ *pdata = (u8int*)u;
+ *psz = unboxedtypes[unboxednumtype(v)]->size;
+ return;
+ }
+ if(isunboxedsnum(v)){
+ *u = unboxednumsval(v);
+ *pdata = (u8int*)u;
+ *psz = unboxedtypes[unboxednumtype(v)]->size;
+ return;
+ }
if(iscvalue(v)){
sl_cv *pcv = ptr(v);
sl_ios *x;
@@ -554,7 +632,8 @@
return size_wrap(ctype_sizeof(args[0]));
usize n;
u8int *data;
- to_sized_ptr(args[0], &data, &n);
+ uintptr u;
+ to_sized_ptr(args[0], &data, &n, &u);
return size_wrap(n);
}
@@ -565,6 +644,7 @@
switch(tag(args[0])){
case TAG_CONS: return sl_conssym;
case TAG_FIXNUM: return sl_fixnumsym;
+ case TAG_UNBOXED: return unboxedtypesyms[unboxednumtype(args[0])];
case TAG_SYM: return sl_symsym;
case TAG_VEC:return sl_vecsym;
case TAG_FN:
@@ -647,7 +727,8 @@
BUILTIN("plain-old-data?", plain_old_datap)
{
argcount(nargs, 1);
- return (iscprim(args[0]) ||
+ return (isunboxednum(args[0]) ||
+ iscprim(args[0]) ||
(iscvalue(args[0]) && cv_isPOD(ptr(args[0])))) ?
sl_t : sl_nil;
}
@@ -927,6 +1008,14 @@
*pp = pi;
*pt = T_FIXNUM;
return true;
+ }else if(isunboxednum(a)){
+ if(isunboxedunum(a))
+ *pi = unboxednumuval(a);
+ else
+ *pi = unboxednumsval(a);
+ *pp = pi;
+ *pt = unboxednumtype(a);
+ return true;
}else if(iscprim(a)){
cp = ptr(a);
*pp = cp_data(cp);
@@ -1215,6 +1304,10 @@
if(isfixnum(a))
return fixnum(~numval(a));
+ if(isunboxedunum(a))
+ return (~unboxednumuval(a) & ~0xff) | (a & 0xff);
+ if(isunboxedsnum(a))
+ return (~unboxednumsval(a) & ~0xff) | (a & 0xff);
if(iscprim(a)){
cp = ptr(a);
ta = cp_numtype(cp);
@@ -1248,6 +1341,7 @@
{
sl_fx n;
s64int accum;
+ u64int u;
sl_cprim *cp;
int ta;
mpint *mp;
@@ -1259,8 +1353,8 @@
if(n == 0)
return a;
mp = nil;
- if(isfixnum(a)){
- accum = numval(a);
+ if(isfixnum(a) || isunboxedsnum(a)){
+ accum = isfixnum(a) ? numval(a) : unboxednumsval(a);
if(n > -64 && n < 0)
return fixnum(accum>>(-n));
if(n < 0 || n >= 64 || sash_overflow_64(accum, n, &accum)){
@@ -1269,6 +1363,15 @@
}else
return fits_fixnum(accum) ? fixnum(accum) : return_from_s64(accum);
}
+ if(isunboxedunum(a)){
+ u = unboxednumuval(a);
+ if(n > 0)
+ u = n < 64 ? u<<n : 0;
+ else
+ u = n > -64 ? u>>-n : 0;
+ accum = u;
+ return (accum >= 0 && fits_fixnum(accum)) ? fixnum(accum) : return_from_u64(u);
+ }
if(iscprim(a)){
cp = ptr(a);
ta = cp_numtype(cp);
@@ -1346,6 +1449,23 @@
sl_mptype = get_type(sl_bignumsym);
sl_mptype->init = cvalue_mp_init;
sl_mptype->vtable = &mp_vtable;
+
+ unboxedtypes[T_S8] = sl_s8type;
+ unboxedtypes[T_U8] = sl_u8type;
+ unboxedtypes[T_S16] = sl_s16type;
+ unboxedtypes[T_U16] = sl_u16type;
+ unboxedtypes[T_S32] = sl_s32type;
+ unboxedtypes[T_U32] = sl_u32type;
+ unboxedtypes[T_S64] = sl_s64type;
+ unboxedtypes[T_U64] = sl_u64type;
+ unboxedtypesyms[T_S8] = sl_s8sym;
+ unboxedtypesyms[T_U8] = sl_u8sym;
+ unboxedtypesyms[T_S16] = sl_s16sym;
+ unboxedtypesyms[T_U16] = sl_u16sym;
+ unboxedtypesyms[T_S32] = sl_s32sym;
+ unboxedtypesyms[T_U32] = sl_u32sym;
+ unboxedtypesyms[T_S64] = sl_s64sym;
+ unboxedtypesyms[T_U64] = sl_u64sym;
sl_strtype = get_type(mk_list2(sl_arrsym, sl_utf8sym));
sl_emptystr = cvalue_from_ref(sl_strtype, (char*)"", 0);
--- a/src/cvalues.h
+++ b/src/cvalues.h
@@ -26,7 +26,7 @@
void cvalue_arr_init(sl_type *ft, sl_v arg, void *dest);
usize cvalue_arrlen(sl_v v) sl_purefn;
usize ctype_sizeof(sl_v type);
-void to_sized_ptr(sl_v v, u8int **pdata, usize *psz);
+void to_sized_ptr(sl_v v, u8int **pdata, usize *psz, uintptr *u);
sl_v cvalue_relocate(sl_v v);
sl_v cvalue_copy(sl_v v);
sl_v cvalue_compare(sl_v a, sl_v b) sl_purefn;
--- a/src/equal.c
+++ b/src/equal.c
@@ -15,9 +15,6 @@
#define doublehash(a) int64to32hash(a)
#endif
-// comparable tag
-#define cmptag(v) (isfixnum(v) ? TAG_FIXNUM : tag(v))
-
static sl_v
eq_class(sl_htable *table, sl_v key)
{
@@ -77,12 +74,14 @@
if(bound <= 0)
return sl_nil;
int taga = tag(a);
- int tagb = cmptag(b);
+ int tagb = tag(b);
int c;
switch(taga){
case TAG_FIXNUM:
if(isfixnum(b))
return (sl_fx)a < (sl_fx)b ? fixnum(-1) : fixnum(1);
+ if(isunboxednum(b))
+ return fixnum(numeric_compare(a, b, eq, true, false));
if(iscprim(b)){
if(cp_class(ptr(b)) == sl_runetype)
return fixnum(1);
@@ -94,6 +93,20 @@
return fixnum(numeric_compare(a, b, eq, true, false));
}
return fixnum(-1);
+ case TAG_UNBOXED:
+ if(isfixnum(b) || isunboxednum(b))
+ return fixnum(numeric_compare(a, b, eq, true, false));
+ if(iscprim(b)){
+ if(cp_class(ptr(b)) == sl_runetype)
+ return fixnum(1);
+ return fixnum(numeric_compare(a, b, eq, true, false));
+ }
+ if(iscvalue(b)){
+ cv = ptr(b);
+ if(valid_numtype(cv_numtype(cv)))
+ return fixnum(numeric_compare(a, b, eq, true, false));
+ }
+ return fixnum(-1);
case TAG_SYM:
if(eq || tagb < TAG_SYM)
return fixnum(1);
@@ -333,6 +346,14 @@
switch(tg){
case TAG_FIXNUM:
u.d = (double)numval(a);
+ return doublehash(u.i64);
+ case TAG_UNBOXED:
+ if(isunboxedunum(a))
+ u.d = unboxednumuval(a);
+ else if(isunboxedsnum(a))
+ u.d = unboxednumsval(a);
+ else // FIXME(sigrid): unboxed
+ u.d = 0;
return doublehash(u.i64);
case TAG_FN:
if(uintval(a) > N_BUILTINS)
--- a/src/io.c
+++ b/src/io.c
@@ -334,7 +334,8 @@
}
u8int *data;
usize sz, offs = 0;
- to_sized_ptr(v, &data, &sz);
+ uintptr u;
+ to_sized_ptr(v, &data, &sz, &u);
usize nb = sz;
if(nargs > 2){
get_start_count_args(args+1, nargs-1, sz, &offs, &nb);
--- a/src/plan9/lsd.c
+++ b/src/plan9/lsd.c
@@ -242,8 +242,8 @@
argcount(nargs, 3);
for(a = args; a < args+3; a++)
- if(sl_unlikely(!sl_isnum(*a)))
- type_error("num", *a);
+ if(sl_unlikely(!sl_isnum(*a)))
+ type_error("num", *a);
pc = tosize(args[0]);
sp = tosize(args[1]);
@@ -277,8 +277,8 @@
if(sl_unlikely(!sl_isstr(args[0]) && !sl_isnum(args[0])))
type_error("str|num", args[0]);
- if(isfixnum(args[0])){
- pid = numval(args[0]);
+ if(sl_isnum(args[0])){
+ pid = tosize(args[0]);
snprint(aout, sizeof(aout), "/proc/%d/text", pid);
}else{
len = cv_len(ptr(args[0]));
--- a/src/print.c
+++ b/src/print.c
@@ -187,7 +187,7 @@
if(sl_isstr(v))
return cv_len(ptr(v)) < SMALL_STR_LEN;
return (
- isfixnum(v) || isbuiltin(v) || iscprim(v) ||
+ isfixnum(v) || isunboxed(v) || isbuiltin(v) || iscprim(v) ||
v == sl_t || v == sl_nil || v == sl_eof || v == sl_void
);
}
@@ -385,6 +385,7 @@
}
}
+static void unboxed_print(sl_ios *f, sl_v v);
static void cvalue_print(sl_ios *f, sl_v v);
static bool
@@ -427,6 +428,9 @@
lerrorf(sl_errio, "write failed");
sl.hpos += n;
break;
+ case TAG_UNBOXED:
+ unboxed_print(f, v);
+ break;
case TAG_SYM:
name = sym_name(v);
if(sl.print_princ)
@@ -846,6 +850,23 @@
}
static void
+unboxed_print(sl_ios *f, sl_v v)
+{
+ uintptr u;
+
+ if(isunboxedunum(v))
+ u = unboxednumuval(v);
+ else if(isunboxedsnum(v))
+ u = unboxednumsval(v);
+ else // FIXME(sigrid): unboxed
+ u = 0;
+ int numtype = unboxednumtype(v);
+ sl_v typesym = unboxedtypesyms[numtype];
+ sl_type *type = unboxedtypes[numtype];
+ cvalue_printdata(f, &u, type->size, typesym, 0);
+}
+
+static void
cvalue_print(sl_ios *f, sl_v v)
{
sl_cv *cv = ptr(v);
@@ -874,10 +895,13 @@
static void
set_print_width(void)
{
- sl_v pw = sym_value(sl_printwidthsym);
- if(!isfixnum(pw))
- return;
- sl.scr_width = numval(pw);
+ sl_v v = sym_value(sl_printwidthsym);
+ if(isfixnum(v))
+ sl.scr_width = numval(v);
+ else if(isunboxedunum(v))
+ sl.scr_width = unboxednumuval(v);
+ else if(isunboxedsnum(v))
+ sl.scr_width = unboxednumsval(v);
}
void
@@ -888,9 +912,9 @@
set_print_width();
sl.print_princ = sym_value(sl_printreadablysym) == sl_nil;
sl_v pl = sym_value(sl_printlengthsym);
- sl.print_length = isfixnum(pl) ? numval(pl) : -1;
+ sl.print_length = sl_isnum(pl) ? numtofx(pl) : -1;
pl = sym_value(sl_printlevelsym);
- sl.print_level = isfixnum(pl) ? numval(pl) : -1;
+ sl.print_level = sl_isnum(pl) ? numtofx(pl) : -1;
sl.p_level = 0;
sl.printlabel = 0;
--- a/src/sl.c
+++ b/src/sl.c
@@ -385,7 +385,7 @@
{
sl_v a, d, nc, first, *pcdr;
- if(isfixnum(v))
+ if(isfixnum(v) || isunboxed(v))
return v;
uintptr t = tag(v);
@@ -692,12 +692,16 @@
bool
sl_isnum(sl_v v)
{
- if(isfixnum(v) || ismp(v))
+ if(isfixnum(v))
return true;
+ if(isunboxednum(v))
+ return true;
if(iscprim(v)){
sl_cprim *c = ptr(v);
return c->type != sl_runetype && valid_numtype(c->type->numtype);
}
+ if(ismp(v))
+ return true;
return false;
}
--- a/src/sl.h
+++ b/src/sl.h
@@ -15,11 +15,13 @@
TAG_CPRIM,
TAG_FN,
TAG_VEC,
- TAG_EXT,
+ TAG_UNBOXED,
TAG_CVALUE,
TAG_SYM,
TAG_CONS,
+ TAG_BITS = 3,
+
/* those were set to 7 and 3 strategically on purpose */
TAG_NONLEAF_MASK = TAG_CONS & TAG_VEC,
};
@@ -34,9 +36,9 @@
T_S16, T_U16,
T_S32, T_U32,
T_S64, T_U64,
- T_MP,
- T_FLOAT,
- T_DOUBLE,
+ T_UNBOXED_NUM,
+ T_MP = T_UNBOXED_NUM,
+ T_FLOAT, T_DOUBLE,
}sl_numtype;
typedef uintptr sl_v;
@@ -43,13 +45,13 @@
#if defined(BITS64)
typedef s64int sl_fx;
-#define FIXNUM_BITS 61
+#define FIXNUM_BITS (64-TAG_BITS)
#define TOP_BIT (1ULL<<63)
#define T_FIXNUM T_S64
#define PRIdFIXNUM PRId64
#else
typedef s32int sl_fx;
-#define FIXNUM_BITS 29
+#define FIXNUM_BITS (32-TAG_BITS)
#define TOP_BIT (1U<<31)
#define T_FIXNUM T_S32
#define PRIdFIXNUM PRId32
@@ -100,12 +102,15 @@
#define valid_numtype(v) ((v) <= T_DOUBLE)
#define UNBOUND ((sl_v)1) // an invalid value
#define tag(x) ((x) & 7)
+#define tagext(x) ((x) & 0xff)
#define ptr(x) ((void*)((uintptr)(x) & (~(uintptr)7)))
#define tagptr(p, t) ((sl_v)(p) | (t))
-#define fixnum(x) ((sl_v)(x)<<3)
-#define numval(x) ((sl_fx)(x)>>3)
-#define uintval(x) (((unsigned int)(x))>>3)
-#define builtin(n) tagptr(((sl_v)n<<3), TAG_FN)
+#define fixnum(x) ((sl_v)(x)<<TAG_BITS)
+#define numval(x) ((sl_fx)(x)>>TAG_BITS)
+#define unboxednumsval(x) ((intptr)(x)>>(TAG_BITS+1+4))
+#define unboxednumuval(x) ((uintptr)(x)>>(TAG_BITS+1+4))
+#define uintval(x) (((unsigned int)(x))>>TAG_BITS)
+#define builtin(n) tagptr(((sl_v)n<<TAG_BITS), TAG_FN)
#define iscons(x) (tag(x) == TAG_CONS)
#define issym(x) (tag(x) == TAG_SYM)
#define isfixnum(x) (tag(x) == TAG_FIXNUM)
@@ -113,9 +118,24 @@
#define isvec(x) (tag(x) == TAG_VEC)
#define iscvalue(x) (tag(x) == TAG_CVALUE)
#define iscprim(x) (tag(x) == TAG_CPRIM)
+#define isunboxed(x) (tag(x) == TAG_UNBOXED)
// doesn't lead to other values
#define leafp(a) (((a)&TAG_NONLEAF_MASK) != TAG_NONLEAF_MASK)
+/* UNBOXED
+ * integers/runes: ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|tttt0100|
+ * strings: ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|sss01100|
+ * special: ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|00011100|
+ */
+#define isunboxednum(x) ((tagext(x) & ((1<<(TAG_BITS+1))-1)) == (0<<TAG_BITS | TAG_UNBOXED))
+#define isunboxedsnum(x) ((tagext(x) & ((2<<(TAG_BITS+1))-1)) == (0<<TAG_BITS | TAG_UNBOXED))
+#define isunboxedunum(x) ((tagext(x) & ((2<<(TAG_BITS+1))-1)) == (2<<TAG_BITS | TAG_UNBOXED))
+#define unboxednumtype(x) ((tagext(x)>>(TAG_BITS+1))&(0xff>>(TAG_BITS+1)))
+extern sl_type *unboxedtypes[T_UNBOXED_NUM];
+extern sl_v unboxedtypesyms[T_UNBOXED_NUM];
+
+#define numtofx(v) (sl_fx)tooffset(v)
+
// allocate n consecutive conses
#define cons_reserve(n) tagptr(alloc_words((n)*2), TAG_CONS)
#define cons_index(c) (((sl_cons*)ptr(c))-((sl_cons*)slg.fromspace))
@@ -130,8 +150,8 @@
*(sl_v*)ptr(v) = (sl_v)(to) | FWD_BIT; \
}while(0)
-#define vec_size(v) (((usize*)ptr(v))[0]>>3)
-#define vec_setsize(v, n) (((usize*)ptr(v))[0] = ((n)<<3))
+#define vec_size(v) (((usize*)ptr(v))[0]>>TAG_BITS)
+#define vec_setsize(v, n) (((usize*)ptr(v))[0] = ((n)<<TAG_BITS))
#define vec_elt(v, i) (((sl_v*)ptr(v))[1+(i)])
#define vec_grow_amt(x) ((x)<8 ? 5 : 6*((x)>>3))
// functions ending in _ are unsafe, faster versions
@@ -156,7 +176,7 @@
#define sym_to_numtype(s) (((sl_sym*)ptr(s))->numtype)
#define ismanaged(v) ((((u8int*)ptr(v)) >= slg.fromspace) && (((u8int*)ptr(v)) < slg.fromspace+slg.heapsize))
#define isgensym(x) (issym(x) && ismanaged(x))
-#define isfn(x) (tag(x) == TAG_FN && (x) > (N_BUILTINS<<3))
+#define isfn(x) (tag(x) == TAG_FN && (x) > (N_BUILTINS<<TAG_BITS))
#define iscbuiltin(x) (iscvalue(x) && cv_class(ptr(x)) == sl_builtintype)
// utility for iterating over all arguments in a builtin
// i=index, i0=start index, arg = var for each arg, args = arg array
@@ -278,7 +298,7 @@
void (*relocate)(sl_v oldv, sl_v newv);
void (*finalize)(sl_v self);
void (*print_traverse)(sl_v self);
-} sl_cvtable;
+}sl_cvtable;
typedef void (*cvinitfunc_t)(sl_type*, sl_v, void*);
--- a/src/sl_arith_any.h
+++ b/src/sl_arith_any.h
@@ -20,7 +20,15 @@
if(isfixnum(arg))
x = numval(arg);
else{
- if(iscprim(arg)){
+ if(isunboxedunum(arg)){
+ u64 = unboxednumuval(arg);
+ a = &u64;
+ pt = unboxednumtype(arg);
+ }else if(isunboxedsnum(arg)){
+ u64 = unboxednumsval(arg);
+ a = &u64;
+ pt = unboxednumtype(arg);
+ }else if(iscprim(arg)){
cp = ptr(arg);
a = cp_data(cp);
pt = cp_numtype(cp);
--- a/src/str.c
+++ b/src/str.c
@@ -358,6 +358,10 @@
radix = get_radix_arg(args[1]);
if(isfixnum(n))
num = numval(n);
+ else if(isunboxedunum(n))
+ num = unboxednumuval(n);
+ else if(isunboxedsnum(n))
+ num = unboxednumsval(n);
else if(iscprim(n)){
void *data = ptr(n);
if(cp_numtype(data) < T_FLOAT)
--
⑨