~ chicken-core (chicken-5) 84391f76b2be6833c11bcf1d8e86f339ddc11d1b
commit 84391f76b2be6833c11bcf1d8e86f339ddc11d1b
Author: Peter Bex <peter@more-magic.net>
AuthorDate: Sat Mar 28 20:02:11 2015 +0100
Commit: Peter Bex <peter@more-magic.net>
CommitDate: Sun May 31 14:55:24 2015 +0200
Re-implement variadic * in C, in order to avoid consing up rest lists.
diff --git a/c-platform.scm b/c-platform.scm
index b9b5b05a..c3c42bf3 100644
--- a/c-platform.scm
+++ b/c-platform.scm
@@ -654,6 +654,7 @@
(rewrite '>= 13 #f "C_greater_or_equal_p" #t)
(rewrite '<= 13 #f "C_less_or_equal_p" #t)
+(rewrite '* 13 #f "C_times" #t)
(rewrite '+ 13 #f "C_plus" #t)
(rewrite '- 13 '(1 . #f) "C_minus" #t)
diff --git a/library.scm b/library.scm
index 27ddfdd6..3be55736 100644
--- a/library.scm
+++ b/library.scm
@@ -954,6 +954,7 @@ EOF
(define + (##core#primitive "C_plus"))
(define - (##core#primitive "C_minus"))
+(define * (##core#primitive "C_times"))
(define (add1 n) (+ n 1))
(define (sub1 n) (- n 1))
@@ -1112,23 +1113,6 @@ EOF
(define (abs x) (##core#inline_allocate ("C_s_a_i_abs" 10) x))
-(define (* . args)
- (if (null? args)
- 1
- (let ((x (##sys#slot args 0))
- (args (##sys#slot args 1)))
- (if (null? args)
- (if (number? x) x (##sys#error-bad-number x '*))
- (let loop ((args (##sys#slot args 1))
- (x (##core#inline_allocate
- ("C_s_a_i_times" 40) x (##sys#slot args 0))))
- (if (null? args)
- x
- (loop (##sys#slot args 1)
- (##core#inline_allocate
- ("C_s_a_i_times" 40)
- x (##sys#slot args 0))) ) ) ) ) ) )
-
(define (/ arg1 . args)
(if (null? args)
(##sys#/-2 1 arg1)
diff --git a/runtime.c b/runtime.c
index 65b92b0e..b0a728b9 100644
--- a/runtime.c
+++ b/runtime.c
@@ -7848,53 +7848,26 @@ bignum_times_bignum_karatsuba(C_word **ptr, C_word x, C_word y, C_word negp)
return n;
}
-
void C_ccall C_times(C_word c, C_word closure, C_word k, ...)
{
+ C_word next_val, result = C_fix(1), prev_result = result;
+ C_word ab[2][C_SIZEOF_STRUCTURE(3) * 3 + C_SIZEOF_BIGNUM(2) * 4], *a;
va_list v;
- C_word x, y;
- C_word iresult = C_fix(1);
- double fresult;
- C_alloc_flonum;
+ c -= 2;
va_start(v, k);
- c -= 2;
-
- while(c--) {
- x = va_arg(v, C_word);
-
- if(x & C_FIXNUM_BIT) {
- y = C_i_o_fixnum_times(iresult, x);
-
- if(y == C_SCHEME_FALSE) {
- fresult = (double)C_unfix(iresult) * (double)C_unfix(x);
- goto flonum_result;
- }
- else iresult = y;
- }
- else if(!C_immediatep(x) && C_block_header(x) == C_FLONUM_TAG) {
- fresult = (double)C_unfix(iresult) * C_flonum_magnitude(x);
- goto flonum_result;
- }
- else barf(C_BAD_ARGUMENT_TYPE_ERROR, "*", x);
- }
- va_end(v);
- C_kontinue(k, iresult);
-
- flonum_result:
- while(c--) {
- x = va_arg(v, C_word);
-
- if(x & C_FIXNUM_BIT)
- fresult *= (double)C_unfix(x);
- else if(!C_immediatep(x) && C_block_header(x) == C_FLONUM_TAG)
- fresult *= C_flonum_magnitude(x);
- else barf(C_BAD_ARGUMENT_TYPE_ERROR, "*", x);
+ 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_times(&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_flonum(k, fresult);
+ C_kontinue(k, result);
}
Trap