diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-01-29 19:07:10 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-01-29 19:07:10 -0800 |
commit | a11dd30b417e1f48da573748fa4ab5fe09f0b212 (patch) | |
tree | 0f2a5852563b34861421aab59972698f0d4e6c40 /arith.c | |
parent | d04250b7e3d809ded65b767f34baf398ca03eae1 (diff) | |
download | txr-a11dd30b417e1f48da573748fa4ab5fe09f0b212.tar.gz txr-a11dd30b417e1f48da573748fa4ab5fe09f0b212.tar.bz2 txr-a11dd30b417e1f48da573748fa4ab5fe09f0b212.zip |
* arith.c (make_ubignum): New static function.
(sign_extend): New function.
* eval.c (eval_init): Register sign-extend intrinsic.
* lib.h (sign_extend): Declared.
* txr.1: Documented sign-extend.
* tl.vim, txr.vim: Updated.
Diffstat (limited to 'arith.c')
-rw-r--r-- | arith.c | 34 |
1 files changed, 34 insertions, 0 deletions
@@ -58,6 +58,13 @@ val make_bignum(void) return n; } +static val make_ubignum(void) +{ + val n = make_obj(); + n->bn.type = BGNUM; + return n; +} + val bignum(cnum cn) { val n = make_bignum(); @@ -1893,6 +1900,33 @@ bad3: uw_throwf(error_s, lit("logtrunc: non-integral operand ~s"), a, nao); } +val sign_extend(val n, val nbits) +{ + val msb = minus(nbits, one); + val ntrunc = logtrunc(n, nbits); + + if (bit(ntrunc, msb)) { + switch (type(ntrunc)) { + case NUM: + { + cnum cn = c_num(ntrunc); + cnum nb = c_num(nbits); + return num(cn | (INT_PTR_MAX << nb)); + } + case BGNUM: + { + val out = make_ubignum(); + mp_2comp(mp(ntrunc), mp(out), mp(ntrunc)->used); + mp_neg(mp(out), mp(out)); + return normalize(out); + } + default: + internal_error("impossible case"); + } + } + return ntrunc; +} + val ash(val a, val bits) { cnum an, bn; |