summaryrefslogtreecommitdiffstats
path: root/hash.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-09-13 07:17:44 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-09-13 07:17:44 -0700
commit516dd3d1bf29ffd72e6f868896738ffd29df588e (patch)
tree1a5c81f7fd26542010f531ae17fb4fbf36e850c7 /hash.c
parent7b399ee696036fe6d1acbbb64cd8a15d6a53078d (diff)
downloadtxr-516dd3d1bf29ffd72e6f868896738ffd29df588e.tar.gz
txr-516dd3d1bf29ffd72e6f868896738ffd29df588e.tar.bz2
txr-516dd3d1bf29ffd72e6f868896738ffd29df588e.zip
Implement NaN boxing.
On platforms with 64 bit pointers, and therefore 64-bit-wide TXR values, we can use a representation technique which allows double floating-point values to be unboxed. Fixnum integers are reduced from 62 bits to 50, and there is a little more complexity in the run-time type checking and dispatch which costs extra cycles. The support is currently off by default; it must be explicitly enabled with ./configure --nan-boxing. * lib.h (NUM_MAX, NUM_MIN, NUM_BIT): Define separately for NaN boxing. (TAG_FLNUM, TAG_WIDTH, NAN_TAG_BIT, NAN_TAG_MASK, TAG_BIGMASK, TAG_BIGSHIFT, NAN_FLNUM_DELTA): New preprocessor symbols. (enum type, type_t): The FLNUM enumeration constant moves to just after LIT, so that its value is the same as TAG_FLNUM. (struct flonum): Does not exist under NaN boxing. (union obj): No fl member under NaN boxing. (tag, is_ptr): Separately defined for NaN boxing. (is_flo): New function under NaN boxing. (tag_ex): New function. It's like tag, but identifies floating-point values as TAG_FLNUM. The tag function continues to map them to TAG_PTR, which is wrong under NaN boxing, but needed in order not to separately write tons of cases in the arith.c module. (type): Use tag_ex, so TAG_FLNUM is handled, if it exists. (auto_str, static_str, litptr, num_fast, chr, c_n, c_u): Different definition for NaN boxing. (c_ch, c_f): New function. (throw_mismatch): Attribute with NORETURN. (nao): Separate definition for NaN boxing. * lib.c (seq_kind_tab): Reorder initializer to follow enum reordering. (seq_iter_rewind): use c_n and c_ch functions, since type checking has been done in those cases. The self parameter is no longer needed. (iter_more): use c_ch on CHR object. (equal): Use c_f accessor to get double value rather than assuming there is a struct flonum representation. (stringp): Use tag_ex, otherwise a floating-point number is identified as TAG_PTR. (diff, isec, isecp): Don't pass removed self parameter to seq_iter_rewind. * arith.c (c_unum, c_dbl_num, c_dbl_unum, plus, minus, signum, gt, lt, ge, le, numeq, logand, logior, logxor, logxor_old, bit, bitset, tofloat, toint, width, c_num, c_fixnum): Extract floating-point value using c_f accessor. Handle CHR type separately from NUM because the storage representation is no longer identical; CHR values have a two bit tag over bits where NUM has ordinary value bits. NUM is tagged at the NaN level with the upper 14 bits being 0xFFFC. The remaining 50 bits are the value. (flo): Construct unboxed float under NaN boxing by taking image of double as a 64 bit value, and adding the delta offset, then casting to the val pointer type. (c_flo): Separate implementation for NaN boxing. (integerp, numberp): Use tag_ex. * buf.c (str_buf, buf_int): Separate CHR and NUM cases, like in numerous arith.c functions. * chksum.c (sha256_hash, md5_hash): Use c_ch accessor for CHR value. * hash.c (equal_hash, eql_hash): Handle CHR separately. Use c_f accessor for floating-point value. (eq_hash): Use tag_ex and handle TAG_FLNUM value under NaN boxing. Handle CHR separately from NUM. * ffi.c (ffi_float_put, ffi_double_put, carray_uint, carray_int): Handle CHR and NUM separately. * stream.c (formatv): Use c_f accessor. * configure: disable automatic selection of NaN boxing on 64 bit platforms, for now. Add test whether -Wno-strict-aliasing is supported by the compiler, performed only if NaN boxing is enabled. We need to disable this warning because it goes off on the code that reinterprets an integer as a double and vice versa.
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/hash.c b/hash.c
index 70471382..4982c8b5 100644
--- a/hash.c
+++ b/hash.c
@@ -317,6 +317,7 @@ ucnum equal_hash(val obj, int *count, ucnum seed)
case STR:
return hash_c_str(obj->st.str, seed, count);
case CHR:
+ return c_ch(obj);
case NUM:
return c_u(obj);
case SYM:
@@ -358,7 +359,7 @@ ucnum equal_hash(val obj, int *count, ucnum seed)
case BGNUM:
return mp_hash(mp(obj)) * if3(seed, seed, 1);
case FLNUM:
- return hash_double(obj->fl.n) * if3(seed, seed, 1);
+ return hash_double(c_f(obj)) * if3(seed, seed, 1);
case COBJ:
case CPTR:
if (obj->co.ops->equalsub) {
@@ -394,7 +395,7 @@ static ucnum eql_hash(val obj, int *count)
case BGNUM:
return mp_hash(mp(obj));
case FLNUM:
- return hash_double(obj->fl.n);
+ return hash_double(c_f(obj));
case RNG:
return eql_hash(obj->rn.from, count) + 2 * eql_hash(obj->rn.to, count);
default:
@@ -406,6 +407,7 @@ static ucnum eql_hash(val obj, int *count)
}
}
case TAG_CHR:
+ return c_ch(obj);
case TAG_NUM:
return c_u(obj);
case TAG_LIT:
@@ -422,7 +424,7 @@ static ucnum eql_hash(val obj, int *count)
static ucnum eq_hash(val obj)
{
- switch (tag(obj)) {
+ switch (tag_ex(obj)) {
case TAG_PTR:
switch (CHAR_BIT * sizeof (mem_t *)) {
case 32:
@@ -431,6 +433,7 @@ static ucnum eq_hash(val obj)
return coerce(ucnum, obj) >> 5;
}
case TAG_CHR:
+ return c_ch(obj);
case TAG_NUM:
return c_u(obj);
case TAG_LIT:
@@ -440,6 +443,10 @@ static ucnum eq_hash(val obj)
case 64: default:
return coerce(ucnum, obj) >> 3;
}
+#if CONFIG_NAN_BOXING
+ case TAG_FLNUM:
+ return coerce(ucnum, obj);
+#endif
}
/* notreached */
abort();