diff options
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; |