summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog32
-rw-r--r--arith.c120
-rw-r--r--eval.c2
-rw-r--r--lib.h2
-rw-r--r--mpi-patches/add-bitops117
5 files changed, 262 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index fbd21451..c6c065dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2012-09-17 Kaz Kylheku <kaz@kylheku.com>
+
+ * arith.c (highest_significant_bit): New static function.
+ (comp_clamp): Bugfix: avoid shifting left into sign bit. Function
+ renamed to comp_trunc.
+ (logtrunc, ash): New functions.
+
+ * eval.c (eval_init): Registered logtrunc and ash intrinsics.
+
+ * lib.h (logtrunc, ash): Declared.
+
+ * mpi-patches/add-bitops (s_highest_bit_mp): Forward declaration for
+ added.
+ (mp_clamp_comp): Bugfix in handling remainder bits. Function
+ renamed to mp_trunc_comp.
+ (mp_trunc, mp_shift): New functions.
+
+2012-09-17 Kaz Kylheku <kaz@kylheku.com>
+
+ * arith.c (highest_significant_bit): New static function.
+ (comp_clamp): Bugfix: avoid shifting left into sign bit.
+ (logclamp, ash): New functions.
+
+ * eval.c (eval_init): Registered logclamp and ash intrinsics.
+
+ * lib.h (logclamp, ash): Declared.
+
+ * mpi-patches/add-bitops (s_highest_bit_mp): Forward declaration for
+ added.
+ (mp_comp_clamp): Bugfix in handling remainder bits.
+ (mp_clamp, mp_shift): New functions.
+
2012-09-16 Kaz Kylheku <kaz@kylheku.com>
* mpi-patches/add-bitops: Bugfixes: mp_2comp is extended to properly
diff --git a/arith.c b/arith.c
index ff15daff..75f4748d 100644
--- a/arith.c
+++ b/arith.c
@@ -268,6 +268,13 @@ int highest_bit(int_ptr_t n)
abort();
}
+static int highest_significant_bit(int_ptr_t n)
+{
+ if (n >= 0)
+ return highest_bit(n);
+ return highest_bit(n ^ INT_PTR_MAX);
+}
+
val plus(val anum, val bnum)
{
tail:
@@ -1611,7 +1618,7 @@ bad:
uw_throwf(error_s, lit("logxor: operation failed on ~s ~s"), a, b, nao);
}
-static val comp_clamp(val a, val bits)
+static val comp_trunc(val a, val bits)
{
cnum an, bn;
val b;
@@ -1626,7 +1633,7 @@ static val comp_clamp(val a, val bits)
switch (type(a)) {
case NUM:
an = c_num(a);
- if (bn <= num_bits) {
+ if (bn < num_bits) {
cnum mask = num_mask >> (num_bits - bn);
return num_fast((an & mask) ^ mask);
}
@@ -1634,7 +1641,7 @@ static val comp_clamp(val a, val bits)
/* fallthrough */
case BGNUM:
b = make_bignum();
- if (mp_clamp_comp(mp(a), mp(b), bn) != MP_OKAY)
+ if (mp_trunc_comp(mp(a), mp(b), bn) != MP_OKAY)
goto bad;
return normalize(b);
default:
@@ -1656,7 +1663,7 @@ val logcomp(val a, val bits)
val b;
if (bits)
- return comp_clamp(a, bits);
+ return comp_trunc(a, bits);
switch (type(a)) {
case NUM:
@@ -1674,6 +1681,111 @@ bad:
uw_throwf(error_s, lit("logcomp: operation failed on ~s"), a, nao);
}
+val logtrunc(val a, val bits)
+{
+ cnum an, bn;
+ val b;
+ const cnum num_mask = (NUM_MAX << 1) | 1;
+ const int num_bits = CHAR_BIT * sizeof (cnum) - 2;
+
+ if (!fixnump(bits))
+ goto bad2;
+
+ bn = c_num(bits);
+
+ switch (type(a)) {
+ case NUM:
+ an = c_num(a);
+ if (bn <= num_bits) {
+ cnum mask = num_mask >> (num_bits - bn);
+ return num_fast(an & mask);
+ }
+ a = bignum(an);
+ /* fallthrough */
+ case BGNUM:
+ b = make_bignum();
+ if (mp_trunc(mp(a), mp(b), bn) != MP_OKAY)
+ goto bad;
+ return normalize(b);
+ default:
+ goto bad3;
+ }
+
+bad:
+ uw_throwf(error_s, lit("logtrunc: operation failed on ~s"), a, nao);
+
+bad2:
+ uw_throwf(error_s, lit("logtrunc: bits value ~s is not a fixnum"), bits, nao);
+
+bad3:
+ uw_throwf(error_s, lit("logtrunc: non-integral operand ~s"), a, nao);
+}
+
+val ash(val a, val bits)
+{
+ cnum an, bn;
+ val b;
+ int hb;
+ const int num_bits = CHAR_BIT * sizeof (cnum) - 2;
+
+ if (!fixnump(bits))
+ goto bad2;
+
+ bn = c_num(bits);
+
+ if (bn == 0) {
+ switch (type(a)) {
+ case NUM:
+ case BGNUM:
+ return a;
+ default:
+ goto bad3;
+ }
+ } else if (bn > 0) {
+ switch (type(a)) {
+ case NUM:
+ an = c_num(a);
+ hb = highest_significant_bit(an);
+ if (bn + hb < num_bits)
+ return num_fast(an << bn);
+ a = bignum(an);
+ /* fallthrough */
+ case BGNUM:
+ b = make_bignum();
+ if (mp_shift(mp(a), mp(b), bn) != MP_OKAY)
+ goto bad;
+ return normalize(b);
+ default:
+ goto bad3;
+ }
+ } else {
+ switch (type(a)) {
+ case NUM:
+ an = c_num(a);
+ if (bn <= num_bits)
+ return num_fast(an >> -bn);
+ return num_fast(an >> num_bits);
+ case BGNUM:
+ b = make_bignum();
+ if (mp_shift(mp(a), mp(b), bn) != MP_OKAY)
+ goto bad;
+ return normalize(b);
+ default:
+ goto bad3;
+ }
+
+ }
+
+bad:
+ uw_throwf(error_s, lit("ashift: operation failed on ~s"), a, nao);
+
+bad2:
+ uw_throwf(error_s, lit("ashift: bits value ~s is not a fixnum"), bits, nao);
+
+bad3:
+ uw_throwf(error_s, lit("ashift: non-integral operand ~s"), a, nao);
+}
+
void arith_init(void)
{
mp_init(&NUM_MAX_MP);
diff --git a/eval.c b/eval.c
index 4050a2ea..ec5db76a 100644
--- a/eval.c
+++ b/eval.c
@@ -2235,6 +2235,8 @@ void eval_init(void)
reg_fun(intern(lit("logior"), user_package), func_n2(logior));
reg_fun(intern(lit("logxor"), user_package), func_n2(logxor));
reg_fun(intern(lit("logcomp"), user_package), func_n2o(logcomp, 1));
+ reg_fun(intern(lit("logtrunc"), user_package), func_n2(logtrunc));
+ reg_fun(intern(lit("ash"), user_package), func_n2(ash));
reg_fun(intern(lit("regex-compile"), user_package), func_n1(regex_compile));
reg_fun(intern(lit("regexp"), user_package), func_n1(regexp));
diff --git a/lib.h b/lib.h
index 91cca628..2f49d347 100644
--- a/lib.h
+++ b/lib.h
@@ -475,6 +475,8 @@ val logand(val, val);
val logior(val, val);
val logxor(val, val);
val logcomp(val, val);
+val logtrunc(val a, val bits);
+val ash(val a, val bits);
val string_own(wchar_t *str);
val string(const wchar_t *str);
val string_utf8(const char *str);
diff --git a/mpi-patches/add-bitops b/mpi-patches/add-bitops
index 7e8dc696..7eae01cb 100644
--- a/mpi-patches/add-bitops
+++ b/mpi-patches/add-bitops
@@ -1,7 +1,7 @@
Index: mpi-1.8.6/mpi.c
===================================================================
--- mpi-1.8.6.orig/mpi.c 2012-09-16 10:50:08.270639006 -0700
-+++ mpi-1.8.6/mpi.c 2012-09-16 23:09:57.601600506 -0700
++++ mpi-1.8.6/mpi.c 2012-09-17 07:33:38.563334756 -0700
@@ -16,6 +16,9 @@
#include <ctype.h>
#include <math.h>
@@ -12,7 +12,15 @@ Index: mpi-1.8.6/mpi.c
typedef unsigned char mem_t;
extern mem_t *chk_malloc(size_t size);
extern mem_t *chk_calloc(size_t n, size_t size);
-@@ -2330,6 +2333,321 @@
+@@ -159,6 +162,7 @@
+ mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */
+ mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */
+
++static int s_highest_bit(mp_digit n);
+ int s_highest_bit_mp(mp_int *a);
+ mp_err s_mp_set_bit(mp_int *a, int bit);
+
+@@ -2330,6 +2334,414 @@
/* }}} */
@@ -287,7 +295,7 @@ Index: mpi-1.8.6/mpi.c
+ return MP_OKAY;
+}
+
-+mp_err mp_clamp_comp(mp_int *a, mp_int *b, mp_digit bits)
++mp_err mp_trunc_comp(mp_int *a, mp_int *b, mp_digit bits)
+{
+ mp_err res;
+ mp_size ix, dig = bits / DIGIT_BIT, rembits = bits % DIGIT_BIT;
@@ -319,7 +327,51 @@ Index: mpi-1.8.6/mpi.c
+
+ if (rembits) {
+ mp_digit mask = (MP_DIGIT_MAX >> (DIGIT_BIT - rembits));
-+ pb[ix] = (pa[ix] & mask) ^ mask;
++ pb[ix] = (((ix < adig) ? pa[ix] : padding) & mask) ^ mask;
++ }
++
++ USED(b) = dig + extra;
++
++ if (ISNEG(a))
++ mp_clear(&tmp);
++
++ s_mp_clamp(b);
++ return MP_OKAY;
++}
++
++mp_err mp_trunc(mp_int *a, mp_int *b, mp_digit bits)
++{
++ mp_err res;
++ mp_size ix, dig = bits / DIGIT_BIT, rembits = bits % DIGIT_BIT;
++ mp_size adig = USED(a);
++ mp_digit padding = ISNEG(a) ? MP_DIGIT_MAX : 0;
++ int extra = (rembits != 0);
++ mp_digit *pa, *pb;
++ mp_int tmp;
++
++ ARGCHK(a != NULL && b != NULL, MP_BADARG);
++
++ if (a != b)
++ res = mp_init_size(b, dig + extra);
++ else
++ res = s_mp_pad(b, dig + extra);
++
++ if (res != MP_OKAY)
++ return res;
++
++ if (ISNEG(a)) {
++ mp_init_size(&tmp, dig + extra);
++ if ((res = mp_2comp(a, &tmp, dig + extra)) != MP_OKAY)
++ return res;
++ a = &tmp;
++ }
++
++ for (pa = DIGITS(a), pb = DIGITS(b), ix = 0; ix < dig; ix++)
++ pb[ix] = (ix < adig) ? pa[ix] : padding;
++
++ if (rembits) {
++ mp_digit mask = (MP_DIGIT_MAX >> (DIGIT_BIT - rembits));
++ pb[ix] = ((ix < adig) ? pa[ix] : padding) & mask;
+ }
+
+ USED(b) = dig + extra;
@@ -331,13 +383,62 @@ Index: mpi-1.8.6/mpi.c
+ return MP_OKAY;
+}
+
++mp_err mp_shift(mp_int *a, mp_int *b, int bits)
++{
++ mp_int tmp;
++ mp_err res;
++ int a_neg = ISNEG(a);
++
++ if (bits == 0)
++ return mp_copy(a, b);
++
++ if (a_neg) {
++ mp_size ua = USED(a);
++ mp_init_size(&tmp, ua);
++ if ((res = mp_2comp(a, &tmp, ua)) != MP_OKAY)
++ return res;
++ SIGN(&tmp) = MP_ZPOS;
++ a = &tmp;
++ }
++
++ if (bits > 0)
++ res = mp_mul_2d(a, bits, b);
++ else
++ res = mp_div_2d(a, -bits, b, NULL);
++
++ if (res != MP_OKAY)
++ return res;
++
++ if (a_neg) {
++ int hb, msd;
++ mp_digit *db;
++
++ mp_clear(&tmp);
++
++ msd = USED(b)-1;
++ db = DIGITS(b);
++ hb = s_highest_bit(db[msd]);
++
++ if (hb < DIGIT_BIT)
++ db[msd] |= MP_DIGIT_MAX << hb;
++
++ if ((res = mp_2comp(b, b, USED(b))) != MP_OKAY)
++ return res;
++
++ SIGN(b) = MP_NEG;
++ s_mp_clamp(b);
++ }
++
++ return MP_OKAY;
++}
++
mp_err mp_to_double(mp_int *mp, double *d)
{
int ix;
Index: mpi-1.8.6/mpi.h
===================================================================
--- mpi-1.8.6.orig/mpi.h 2012-09-16 10:50:08.046513006 -0700
-+++ mpi-1.8.6/mpi.h 2012-09-16 21:45:17.713770006 -0700
++++ mpi-1.8.6/mpi.h 2012-09-17 07:32:54.738697256 -0700
@@ -54,6 +54,7 @@
/* Macros for accessing the mp_int internals */
@@ -346,7 +447,7 @@ Index: mpi-1.8.6/mpi.h
#define USED(MP) ((MP)->used)
#define ALLOC(MP) ((MP)->alloc)
#define DIGITS(MP) ((MP)->dp)
-@@ -187,6 +188,15 @@
+@@ -187,6 +188,17 @@
#endif /* end MP_NUMTH */
/*------------------------------------------------------------------------*/
@@ -356,7 +457,9 @@ Index: mpi-1.8.6/mpi.h
+mp_err mp_or(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_xor(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_comp(mp_int *a, mp_int *b);
-+mp_err mp_clamp_comp(mp_int *a, mp_int *b, mp_digit bits);
++mp_err mp_trunc_comp(mp_int *a, mp_int *b, mp_digit bits);
++mp_err mp_trunc(mp_int *a, mp_int *b, mp_digit bits);
++mp_err mp_shift(mp_int *a, mp_int *b, int bits); /* + left, - right */
+
+/*------------------------------------------------------------------------*/
/* Conversions */