~ chicken-core (chicken-5) ef6fe73f7e1c09aa752308c471fd2c55f134ac22


commit ef6fe73f7e1c09aa752308c471fd2c55f134ac22
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Sun Mar 22 19:35:26 2015 +0100
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Sun May 31 14:55:24 2015 +0200

    Make dyadic bitwise operators inlineable again and restore compiler rewrites.  Also move variadic versions of bitwise operators to C.

diff --git a/c-platform.scm b/c-platform.scm
index 48091d08..b6091cbe 100644
--- a/c-platform.scm
+++ b/c-platform.scm
@@ -548,6 +548,12 @@
 
 (rewrite 'abs 14 'fixnum 1 "C_fixnum_abs" "C_fixnum_abs")
 
+(rewrite 'bitwise-and 21 -1 "C_fixnum_and" "C_u_fixnum_and" "C_s_a_i_bitwise_and" 6)
+(rewrite 'bitwise-xor 21 0 "C_fixnum_xor" "C_fixnum_xor" "C_s_a_i_bitwise_xor" 6)
+(rewrite 'bitwise-ior 21 0 "C_fixnum_or" "C_u_fixnum_or" "C_s_a_i_bitwise_ior" 6)
+
+(rewrite 'bitwise-not 22 1 "C_s_a_i_bitwise_not" #t 6 "C_fixnum_not")
+
 (rewrite 'fp+ 16 2 "C_a_i_flonum_plus" #f words-per-flonum)
 (rewrite 'fp- 16 2 "C_a_i_flonum_difference" #f words-per-flonum)
 (rewrite 'fp* 16 2 "C_a_i_flonum_times" #f words-per-flonum)
diff --git a/chicken.h b/chicken.h
index 788fe305..4160d8a1 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1973,9 +1973,9 @@ C_fctexport void C_ccall C_u_integer_remainder(C_word c, C_word self, C_word k,
 C_fctexport void C_ccall C_basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
 C_fctexport void C_ccall C_u_integer_divrem(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
 C_fctexport void C_ccall C_u_flo_to_int(C_word c, C_word self, C_word k, C_word x) C_noret;
-C_fctexport void C_ccall C_u_2_integer_bitwise_and(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
-C_fctexport void C_ccall C_u_2_integer_bitwise_ior(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
-C_fctexport void C_ccall C_u_2_integer_bitwise_xor(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret;
+C_fctexport void C_ccall C_bitwise_and(C_word c, C_word closure, C_word k, ...) C_noret;
+C_fctexport void C_ccall C_bitwise_ior(C_word c, C_word closure, C_word k, ...) C_noret;
+C_fctexport void C_ccall C_bitwise_xor(C_word c, C_word closure, C_word k, ...) C_noret;
 
 C_fctexport void C_ccall C_nequalp(C_word c, C_word closure, C_word k, ...) C_noret;
 C_fctexport void C_ccall C_greaterp(C_word c, C_word closure, C_word k, ...) C_noret;
@@ -2190,6 +2190,10 @@ C_fctexport C_word C_fcall C_s_a_u_i_integer_plus(C_word **ptr, C_word n, C_word
 C_fctexport C_word C_fcall C_s_a_u_i_integer_gcd(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
 C_fctexport C_word C_fcall C_s_a_i_arithmetic_shift(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
 C_fctexport C_word C_fcall C_s_a_u_i_bignum_extract_digits(C_word **ptr, C_word n, C_word x, C_word start, C_word end) C_regparm;
+C_fctexport C_word C_fcall C_s_a_i_bitwise_and(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
+C_fctexport C_word C_fcall C_s_a_i_bitwise_ior(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
+C_fctexport C_word C_fcall C_s_a_i_bitwise_xor(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
+C_fctexport C_word C_fcall C_s_a_i_bitwise_not(C_word **ptr, C_word n, C_word x) C_regparm;
 
 
 C_fctexport C_word C_fcall C_i_foreign_char_argumentp(C_word x) C_regparm;
diff --git a/library.scm b/library.scm
index 352af4ba..3951d6fc 100644
--- a/library.scm
+++ b/library.scm
@@ -1578,9 +1578,8 @@ EOF
            ((s^ r^) (##sys#exact-integer-sqrt
 		     (arithmetic-shift a (fxneg len/2))))
            ((mask)  (- (arithmetic-shift 1 len/4) 1))
-           ((a0)    (##sys#integer-bitwise-and a mask))
-           ((a1)    (##sys#integer-bitwise-and
-		     (arithmetic-shift a (fxneg len/4)) mask))
+           ((a0)    (bitwise-and a mask))
+           ((a1)    (bitwise-and (arithmetic-shift a (fxneg len/4)) mask))
            ((q u)   (##sys#integer-quotient&remainder
 		     (+ (arithmetic-shift r^ len/4) a1)
 		     (arithmetic-shift s^ 1)))
@@ -4374,62 +4373,15 @@ EOF
 
 ;; From SRFI-33
 (define (integer-length x) (##core#inline "C_i_integer_length" x))
- 
-(define ##sys#integer-bitwise-and (##core#primitive "C_u_2_integer_bitwise_and"))
-(define ##sys#integer-bitwise-ior (##core#primitive "C_u_2_integer_bitwise_ior"))
-(define ##sys#integer-bitwise-xor (##core#primitive "C_u_2_integer_bitwise_xor"))
-
-(define (bitwise-and . xs)
-  (if (null? xs)
-      -1
-      (let ((x1 (##sys#slot xs 0)))
-	(##sys#check-exact-integer x1 'bitwise-and)
-        (let loop ((x x1) (xs (##sys#slot xs 1)))
-          (if (null? xs)
-              x
-              (let ((xi (##sys#slot xs 0)))
-		(##sys#check-exact-integer xi 'bitwise-and)
-                (loop
-                 (##sys#integer-bitwise-and x xi)
-                 (##sys#slot xs 1) ) ) ) ))) )
-
-(define (bitwise-ior . xs)
-  (if (null? xs)
-      0
-      (let ((x1 (##sys#slot xs 0)))
-	(##sys#check-exact-integer x1 'bitwise-ior)
-        (let loop ((x x1) (xs (##sys#slot xs 1)))
-          (if (null? xs)
-              x
-              (let ((xi (##sys#slot xs 0)))
-		(##sys#check-exact-integer xi 'bitwise-ior)
-                (loop
-		 (##sys#integer-bitwise-ior x xi)
-                 (##sys#slot xs 1) ) ) ) ))) )
-
-(define (bitwise-xor . xs)
-  (if (null? xs)
-      0
-      (let ((x1 (##sys#slot xs 0)))
-	(##sys#check-exact-integer x1 'bitwise-xor)
-        (let loop ((x x1) (xs (##sys#slot xs 1)))
-          (if (null? xs)
-              x
-              (let ((xi (##sys#slot xs 0)))
-		(##sys#check-exact-integer xi 'bitwise-xor)
-                (loop
-		 (##sys#integer-bitwise-xor x xi)
-                 (##sys#slot xs 1) ) ) ) ))) )
-
-(define (bitwise-not n)
-  (##sys#check-exact-integer n 'bitwise-not)
-  (##core#inline_allocate ("C_s_a_u_i_integer_minus" 6) -1 n))
+(define (bit-set? n i) (##core#inline "C_i_bit_setp" n i))
 
+(define bitwise-and (##core#primitive "C_bitwise_and"))
+(define bitwise-ior (##core#primitive "C_bitwise_ior"))
+(define bitwise-xor (##core#primitive "C_bitwise_xor"))
+(define (bitwise-not n) (##core#inline_allocate ("C_s_a_i_bitwise_not" 6) n))
 (define (arithmetic-shift n m)
   (##core#inline_allocate ("C_s_a_i_arithmetic_shift" 6) n m))
 
-(define (bit-set? n i) (##core#inline "C_i_bit_setp" n i))
-
 ;;; String ports:
 ;
 ; - Port-slots:
diff --git a/runtime.c b/runtime.c
index 83be4c05..d2b8d7f5 100644
--- a/runtime.c
+++ b/runtime.c
@@ -512,9 +512,6 @@ static WEAK_TABLE_ENTRY *C_fcall lookup_weak_table_entry(C_word item, C_word con
 static C_ccall void values_continuation(C_word c, C_word closure, C_word dummy, ...) C_noret;
 static C_word add_symbol(C_word **ptr, C_word key, C_word string, C_SYMBOL_TABLE *stable);
 static C_regparm int C_fcall C_in_new_heapp(C_word x);
-static void bignum_bitwise_and_2(C_word c, C_word self, C_word result) C_noret;
-static void bignum_bitwise_ior_2(C_word c, C_word self, C_word result) C_noret;
-static void bignum_bitwise_xor_2(C_word c, C_word self, C_word result) C_noret;
 static void bignum_times_bignum_unsigned(C_word k, C_word x, C_word y, C_word negp) C_noret;
 static void bignum_times_bignum_unsigned_2(C_word c, C_word self, C_word result) C_noret;
 static void integer_times_2(C_word c, C_word self, C_word new_big) C_noret;
@@ -847,7 +844,7 @@ static C_PTABLE_ENTRY *create_initial_ptable()
 {
   /* IMPORTANT: hardcoded table size -
      this must match the number of C_pte calls + 1 (NULL terminator)! */
-  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 72);
+  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 73);
   int i = 0;
 
   if(pt == NULL)
@@ -924,9 +921,9 @@ static C_PTABLE_ENTRY *create_initial_ptable()
   C_pte(C_u_integer_quotient);
   C_pte(C_u_integer_remainder);
   C_pte(C_u_integer_divrem);
-  C_pte(C_u_2_integer_bitwise_and);
-  C_pte(C_u_2_integer_bitwise_ior);
-  C_pte(C_u_2_integer_bitwise_xor);
+  C_pte(C_bitwise_and);
+  C_pte(C_bitwise_ior);
+  C_pte(C_bitwise_xor);
 
   /* IMPORTANT: did you remember the hardcoded pte table size? */
   pt[ i ].id = NULL;
@@ -6016,160 +6013,242 @@ C_regparm C_word C_fcall C_a_i_bitwise_not(C_word **a, int c, C_word n)
   else return C_flonum(a, nn);
 }
 
-void C_ccall
-C_u_2_integer_bitwise_and(C_word c, C_word self, C_word k, C_word x, C_word y)
+C_regparm C_word C_fcall
+C_s_a_i_bitwise_and(C_word **ptr, C_word n, C_word x, C_word y)
 {
   if ((x & y) & C_FIXNUM_BIT) {
-    C_kontinue(k, C_u_fixnum_and(x, y));
+    return C_u_fixnum_and(x, y);
+  } else if (!C_truep(C_i_exact_integerp(x))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", x);
+  } else if (!C_truep(C_i_exact_integerp(y))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", y);
   } else {
-    C_word kab[C_SIZEOF_FIX_BIGNUM*2], *ka = kab, negp, size, k2;
-    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&ka, x);
-    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&ka, y);
+    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
+    C_uword *scanr, *endr, *scans1, *ends1, *scans2;
+
+    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
+    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 
     negp = C_mk_bool(C_bignum_negativep(x) && C_bignum_negativep(y));
     /* Allow negative 1-bits to propagate */
     if (C_bignum_negativep(x) || C_bignum_negativep(y))
-      size = C_fix(nmax(C_bignum_size(x), C_bignum_size(y)) + 1);
+      size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
     else
-      size = C_fix(nmin(C_bignum_size(x), C_bignum_size(y)));
+      size = nmin(C_bignum_size(x), C_bignum_size(y));
+
+    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
+    scanr = C_bignum_digits(res);
+    endr = scanr + C_bignum_size(res);
+    
+    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
+    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
 
-    ka = C_alloc(C_SIZEOF_CLOSURE(4)); /* Why faster than static alloc? */
-    k2 = C_closure(&ka, 4, (C_word)bignum_bitwise_and_2, k, x, y);
-    C_allocate_bignum(5, (C_word)NULL, k2, C_fix(size), negp, C_SCHEME_FALSE);
+    if (C_bignum_size(x) < C_bignum_size(y)) {
+      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
+      scans2 = C_bignum_digits(y);
+    } else {
+      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
+      scans2 = C_bignum_digits(x);
+    }
+
+    while (scans1 < ends1) *scanr++ = *scans1++ & *scans2++;
+    C_memset(scanr, 0, C_wordstobytes(endr - scanr));
+
+    if (C_truep(nx)) free_tmp_bignum(nx);
+    if (C_truep(ny)) free_tmp_bignum(ny);
+    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
+    
+    return C_bignum_simplify(res);
   }
 }
 
-static void bignum_bitwise_and_2(C_word c, C_word self, C_word result)
+void C_ccall C_bitwise_and(C_word c, C_word closure, C_word k, ...)
 {
-  C_word k = C_block_item(self, 1),
-	 x = C_block_item(self, 2),
-	 y = C_block_item(self, 3),
-         size = C_bignum_size(result), nx, ny;
-  C_uword *scanr = C_bignum_digits(result),
-          *endr = scanr + C_bignum_size(result),
-          *scans1, *ends1, *scans2;
-
-  if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
-  if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
-
-  if (C_bignum_size(x) < C_bignum_size(y)) {
-    scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
-    scans2 = C_bignum_digits(y);
-  } else {
-    scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
-    scans2 = C_bignum_digits(x);
-  }
+  C_word next_val, result, prev_result;
+  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
+  va_list v;
 
-  while (scans1 < ends1) *scanr++ = *scans1++ & *scans2++;
-  C_memset(scanr, 0, C_wordstobytes(endr - scanr));
+  c -= 2; 
+  va_start(v, k);
 
-  if (C_truep(nx)) free_tmp_bignum(nx);
-  if (C_truep(ny)) free_tmp_bignum(ny);
-  if (C_bignum_negativep(result)) bignum_digits_destructive_negate(result);
+  if (c == 0) C_kontinue(k, C_fix(-1));
 
-  C_kontinue(k, C_bignum_simplify(result));
+  prev_result = result = va_arg(v, C_word);
+
+  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-and", result);
+
+  while (c--) {
+    next_val = va_arg(v, C_word);
+    a = ab[c&1]; /* One may hold last iteration result, the other is unused */
+    result = C_s_a_i_bitwise_and(&a, 2, result, next_val);
+    result = move_buffer_object(&a, ab[(c+1)&1], result);
+    clear_buffer_object(ab[(c+1)&1], prev_result);
+    prev_result = result;
+  }
+
+  va_end(v);
+  C_kontinue(k, result);
 }
 
-void C_ccall
-C_u_2_integer_bitwise_ior(C_word c, C_word self, C_word k, C_word x, C_word y)
+C_regparm C_word C_fcall
+C_s_a_i_bitwise_ior(C_word **ptr, C_word n, C_word x, C_word y)
 {
   if ((x & y) & C_FIXNUM_BIT) {
-    C_kontinue(k, C_u_fixnum_or(x, y));
+    return C_u_fixnum_or(x, y);
+  } else if (!C_truep(C_i_exact_integerp(x))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", x);
+  } else if (!C_truep(C_i_exact_integerp(y))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", y);
   } else {
-    C_word kab[C_SIZEOF_FIX_BIGNUM*2], *ka = kab, negp, size, k2;
-    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&ka, x);
-    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&ka, y);
+    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
+    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
+
+    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
+    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 
-    ka = C_alloc(C_SIZEOF_CLOSURE(4)); /* Why faster than static alloc? */
-    k2 = C_closure(&ka, 4, (C_word)bignum_bitwise_ior_2, k, x, y);
-    size = C_fix(nmax(C_bignum_size(x), C_bignum_size(y)) + 1);
     negp = C_mk_bool(C_bignum_negativep(x) || C_bignum_negativep(y));
-    C_allocate_bignum(5, (C_word)NULL, k2, size, negp, C_SCHEME_FALSE);
+    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
+    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
+    scanr = C_bignum_digits(res);
+    endr = scanr + C_bignum_size(res);
+    
+    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
+    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
+
+    if (C_bignum_size(x) < C_bignum_size(y)) {
+      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
+      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
+    } else {
+      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
+      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
+    }
+
+    while (scans1 < ends1) *scanr++ = *scans1++ | *scans2++;
+    while (scans2 < ends2) *scanr++ = *scans2++;
+    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
+    assert(scanr == endr);
+
+    if (C_truep(nx)) free_tmp_bignum(nx);
+    if (C_truep(ny)) free_tmp_bignum(ny);
+    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
+
+    return C_bignum_simplify(res);
   }
 }
 
-static void bignum_bitwise_ior_2(C_word c, C_word self, C_word result)
+void C_ccall C_bitwise_ior(C_word c, C_word closure, C_word k, ...)
 {
-  C_word k = C_block_item(self, 1),
-	 x = C_block_item(self, 2),
-	 y = C_block_item(self, 3),
-         size = C_bignum_size(result), nx, ny;
-  C_uword *scanr = C_bignum_digits(result),
-          *endr = scanr + C_bignum_size(result),
-          *scans1, *ends1, *scans2, *ends2;
-
-  if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
-  if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
-
-  if (C_bignum_size(x) < C_bignum_size(y)) {
-    scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
-    scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
-  } else {
-    scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
-    scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
-  }
+  C_word next_val, result, prev_result;
+  C_word ab[2][C_SIZEOF_BIGNUM_WRAPPER], *a;
+  va_list v;
 
-  while (scans1 < ends1) *scanr++ = *scans1++ | *scans2++;
-  while (scans2 < ends2) *scanr++ = *scans2++;
-  if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
-  assert(scanr == endr);
+  c -= 2; 
+  va_start(v, k);
 
-  if (C_truep(nx)) free_tmp_bignum(nx);
-  if (C_truep(ny)) free_tmp_bignum(ny);
-  if (C_bignum_negativep(result)) bignum_digits_destructive_negate(result);
+  if (c == 0) C_kontinue(k, C_fix(0));
 
-  C_kontinue(k, C_bignum_simplify(result));
+  prev_result = result = va_arg(v, C_word);
+
+  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-ior", result);
+
+  while (c--) {
+    next_val = va_arg(v, C_word);
+    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
+    result = C_s_a_i_bitwise_ior(&a, 2, result, next_val);
+    result = move_buffer_object(&a, ab[(c+1)&1], result);
+    clear_buffer_object(ab[(c+1)&1], prev_result);
+    prev_result = result;
+  }
+
+  va_end(v);
+  C_kontinue(k, result);
 }
 
-void C_ccall
-C_u_2_integer_bitwise_xor(C_word c, C_word self, C_word k, C_word x, C_word y)
+C_regparm C_word C_fcall
+C_s_a_i_bitwise_xor(C_word **ptr, C_word n, C_word x, C_word y)
 {
   if ((x & y) & C_FIXNUM_BIT) {
-    C_kontinue(k, C_fixnum_xor(x, y));
+    return C_fixnum_xor(x, y);
+  } else if (!C_truep(C_i_exact_integerp(x))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", x);
+  } else if (!C_truep(C_i_exact_integerp(y))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", y);
   } else {
-    C_word kab[C_SIZEOF_FIX_BIGNUM*2], *ka = kab, size, k2, negp;
-    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&ka, x);
-    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&ka, y);
+    C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, negp, size, res, nx, ny;
+    C_uword *scanr, *endr, *scans1, *ends1, *scans2, *ends2;
+
+    if (x & C_FIXNUM_BIT) x = C_a_u_i_fix_to_big(&a, x);
+    if (y & C_FIXNUM_BIT) y = C_a_u_i_fix_to_big(&a, y);
 
-    ka = C_alloc(C_SIZEOF_CLOSURE(4)); /* Why faster than static alloc? */
-    k2 = C_closure(&ka, 4, (C_word)bignum_bitwise_xor_2, k, x, y);
-    size = C_fix(nmax(C_bignum_size(x), C_bignum_size(y)) + 1);
+    size = nmax(C_bignum_size(x), C_bignum_size(y)) + 1;
     negp = C_mk_bool(C_bignum_negativep(x) != C_bignum_negativep(y));
-    C_allocate_bignum(5, (C_word)NULL, k2, size, negp, C_SCHEME_FALSE);
+    res = C_allocate_scratch_bignum(ptr, C_fix(size), negp, C_SCHEME_FALSE);
+    scanr = C_bignum_digits(res);
+    endr = scanr + C_bignum_size(res);
+
+    if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
+    if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
+
+    if (C_bignum_size(x) < C_bignum_size(y)) {
+      scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
+      scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
+    } else {
+      scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
+      scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
+    }
+
+    while (scans1 < ends1) *scanr++ = *scans1++ ^ *scans2++;
+    while (scans2 < ends2) *scanr++ = *scans2++;
+    if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
+    assert(scanr == endr);
+
+    if (C_truep(nx)) free_tmp_bignum(nx);
+    if (C_truep(ny)) free_tmp_bignum(ny);
+    if (C_bignum_negativep(res)) bignum_digits_destructive_negate(res);
+
+    return C_bignum_simplify(res);
   }
 }
 
-static void bignum_bitwise_xor_2(C_word c, C_word self, C_word result)
+void C_ccall C_bitwise_xor(C_word c, C_word closure, C_word k, ...)
 {
-  C_word k = C_block_item(self, 1),
-	 x = C_block_item(self, 2),
-	 y = C_block_item(self, 3),
-         size = C_bignum_size(result), nx, ny;
-  C_uword *scanr = C_bignum_digits(result),
-          *endr = scanr + C_bignum_size(result),
-          *scans1, *ends1, *scans2, *ends2;
-
-  if (C_truep(nx = maybe_negate_bignum_for_bitwise_op(x, size))) x = nx;
-  if (C_truep(ny = maybe_negate_bignum_for_bitwise_op(y, size))) y = ny;
-
-  if (C_bignum_size(x) < C_bignum_size(y)) {
-    scans1 = C_bignum_digits(x); ends1 = scans1 + C_bignum_size(x);
-    scans2 = C_bignum_digits(y); ends2 = scans2 + C_bignum_size(y);
-  } else {
-    scans1 = C_bignum_digits(y); ends1 = scans1 + C_bignum_size(y);
-    scans2 = C_bignum_digits(x); ends2 = scans2 + C_bignum_size(x);
-  }
+  C_word next_val, result, prev_result;
+  C_word ab[2][C_SIZEOF_STRUCTURE(3) * 3 + C_SIZEOF_FIX_BIGNUM * 4], *a;
+  va_list v;
 
-  while (scans1 < ends1) *scanr++ = *scans1++ ^ *scans2++;
-  while (scans2 < ends2) *scanr++ = *scans2++;
-  if (scanr < endr) *scanr++ = 0; /* Only done when result is positive */
-  assert(scanr == endr);
+  c -= 2; 
+  va_start(v, k);
 
-  if (C_truep(nx)) free_tmp_bignum(nx);
-  if (C_truep(ny)) free_tmp_bignum(ny);
-  if (C_bignum_negativep(result)) bignum_digits_destructive_negate(result);
+  if (c == 0) C_kontinue(k, C_fix(0));
 
-  C_kontinue(k, C_bignum_simplify(result));
+  prev_result = result = va_arg(v, C_word);
+
+  if (c-- == 1 && !C_truep(C_i_exact_integerp(result)))
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-xor", result);
+
+  while (c--) {
+    next_val = va_arg(v, C_word);
+    a = ab[c&1]; /* One may hold prev iteration result, the other is unused */
+    result = C_s_a_i_bitwise_xor(&a, 2, result, next_val);
+    result = move_buffer_object(&a, ab[(c+1)&1], result);
+    clear_buffer_object(ab[(c+1)&1], prev_result);
+    prev_result = result;
+  }
+
+  va_end(v);
+  C_kontinue(k, result);
+}
+
+C_regparm C_word C_fcall
+C_s_a_i_bitwise_not(C_word **ptr, C_word n, C_word x)
+{
+  if (!C_truep(C_i_exact_integerp(x))) {
+    barf(C_BAD_ARGUMENT_TYPE_NO_EXACT_INTEGER_ERROR, "bitwise-not", x);
+  } else {
+    return C_s_a_u_i_integer_minus(ptr, 2, C_fix(-1), x);
+  }
 }
 
 /* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */
diff --git a/types.db b/types.db
index 840cc12f..2574dae5 100644
--- a/types.db
+++ b/types.db
@@ -882,25 +882,24 @@
            ((fixnum) (fixnum) #(1))
            ((integer) #(1))
            ((fixnum fixnum) (fixnum) (##core#inline "C_u_fixnum_and" #(1) #(2)))
-           ((integer integer) (##sys#integer-bitwise-and #(1) #(2))))
+           ((* *) (##core#inline_allocate ("C_s_a_i_bitwise_and" 6) #(1) #(2))))
 
 (bitwise-ior (#(procedure #:clean #:enforce #:foldable) bitwise-ior (#!rest integer) integer)
            (() '0)
            ((fixnum) (fixnum) #(1))
            ((integer) #(1))
            ((fixnum fixnum) (fixnum) (##core#inline "C_u_fixnum_or" #(1) #(2)))
-           ((integer integer) (##sys#integer-bitwise-ior #(1) #(2))))
+	   ((* *) (##core#inline_allocate ("C_s_a_i_bitwise_ior" 6) #(1) #(2))))
 
 (bitwise-xor (#(procedure #:clean #:enforce #:foldable) bitwise-xor (#!rest integer) integer)
            (() '0)
            ((fixnum) (fixnum) #(1))
            ((integer) #(1))
            ((fixnum fixnum) (fixnum) (##core#inline "C_fixnum_xor" #(1) #(2)))
-           ((integer integer) (##sys#integer-bitwise-xor #(1) #(2))))
+           ((* *) (##core#inline_allocate ("C_s_a_i_bitwise_xor" 6) #(1) #(2))))
 
 (bitwise-not (#(procedure #:clean #:enforce #:foldable) bitwise-not (integer) integer)
-	     ((integer)
-	      (##core#inline_allocate ("C_s_a_u_i_integer_minus" 6) '1 #(1))))
+	     ((* *) (##core#inline_allocate ("C_s_a_i_bitwise_not" 6) #(1))))
 
 (blob->string (#(procedure #:clean #:enforce) blob->string (blob) string))
 
Trap