~ chicken-core (chicken-5) 4859e34b0f6102b60ddf44dfc5aabbe388e40b6a
commit 4859e34b0f6102b60ddf44dfc5aabbe388e40b6a Author: Peter Bex <peter@more-magic.net> AuthorDate: Mon Apr 6 13:34:38 2015 +0200 Commit: Peter Bex <peter@more-magic.net> CommitDate: Sun May 31 14:55:25 2015 +0200 Convert dyadic integer division functions to use scratch space. diff --git a/chicken.h b/chicken.h index 26ffce02..b99dd946 100644 --- a/chicken.h +++ b/chicken.h @@ -1956,9 +1956,7 @@ C_fctexport void C_ccall C_minus(C_word c, C_word closure, C_word k, C_word n1, /* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_fctexport void C_ccall C_divide(C_word c, C_word closure, C_word k, C_word n1, ...) C_noret; C_fctexport void C_ccall C_basic_quotient(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_quotient(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret; C_fctexport void C_ccall C_basic_remainder(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_remainder(C_word c, C_word self, C_word k, C_word x, C_word y) C_noret; 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; @@ -2179,6 +2177,8 @@ C_fctexport C_word C_fcall C_s_a_i_times(C_word **ptr, C_word n, C_word x, C_wor C_fctexport C_word C_fcall C_s_a_u_i_integer_times(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_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_u_i_integer_quotient(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_integer_remainder(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_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; diff --git a/library.scm b/library.scm index 435995db..0e4c5c77 100644 --- a/library.scm +++ b/library.scm @@ -1126,12 +1126,15 @@ EOF (loop (##sys#slot args 1) (##sys#/-2 x (##sys#slot args 0))) ) ) ) ) +(define-inline (%integer-quotient a b) + (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 6) a b)) + (define (##sys#/-2 x y) (when (eq? y 0) (##sys#error-hook (foreign-value "C_DIVISION_BY_ZERO_ERROR" int) '/ x y)) (cond ((and (exact-integer? x) (exact-integer? y)) (let ((g (%integer-gcd x y))) - (ratnum (##sys#integer-quotient x g) (##sys#integer-quotient y g)))) + (ratnum (%integer-quotient x g) (%integer-quotient y g)))) ;; Compnum *must* be checked first ((or (cplxnum? x) (cplxnum? y)) (let* ((a (real-part x)) (b (imag-part x)) @@ -1241,12 +1244,9 @@ EOF result))) (define quotient (##core#primitive "C_basic_quotient")) -(define ##sys#integer-quotient (##core#primitive "C_u_integer_quotient")) (define remainder (##core#primitive "C_basic_remainder")) -(define ##sys#integer-remainder (##core#primitive "C_u_integer_remainder")) -(define ##sys#integer-quotient&remainder (##core#primitive "C_u_integer_divrem")) - (define quotient&remainder (##core#primitive "C_basic_divrem")) + ;; Modulo's sign follows y (whereas remainder's sign follows x) (define (quotient&modulo x y) (receive (div rem) (quotient&remainder x y) @@ -1403,7 +1403,7 @@ EOF ((mask) (- (arithmetic-shift 1 len/4) 1)) ((a0) (bitwise-and a mask)) ((a1) (bitwise-and (arithmetic-shift a (fxneg len/4)) mask)) - ((q u) (##sys#integer-quotient&remainder + ((q u) ((##core#primitive "C_u_integer_divrem") (+ (arithmetic-shift r^ len/4) a1) (arithmetic-shift s^ 1))) ((s) (+ (arithmetic-shift s^ len/4) q)) @@ -1586,7 +1586,7 @@ EOF (define (##sys#integer->string/recursive n base expected-string-size) (let*-values (((halfsize) (fxshr (fx+ expected-string-size 1) 1)) ((b^M/2) (##sys#integer-power base halfsize)) - ((hi lo) (quotient&remainder n b^M/2)) + ((hi lo) ((##core#primitive "C_u_integer_divrem") n b^M/2)) ((strhi) (number->string hi base)) ((strlo) (number->string (abs lo) base))) (string-append strhi @@ -1643,7 +1643,7 @@ EOF ;; Should we export this? (define (round-quotient n d) - (let ((q (##sys#integer-quotient n d))) + (let ((q (%integer-quotient n d))) (if ((if (even? q) > >=) (* (abs (remainder n d)) 2) (abs d)) (+ q (if (eqv? (negative? n) (negative? d)) 1 -1)) q))) diff --git a/runtime.c b/runtime.c index 73f210b1..d8c92f42 100644 --- a/runtime.c +++ b/runtime.c @@ -525,10 +525,9 @@ static C_word rat_times_rat(C_word **ptr, C_word x, C_word y); static C_word cplx_times(C_word **ptr, C_word rx, C_word ix, C_word ry, C_word iy); static C_word bignum_minus_unsigned(C_word **ptr, C_word x, C_word y); static C_regparm void basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_r, C_word return_q) C_noret; -static C_regparm void integer_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_q, C_word return_r) C_noret; -static C_word bignum_remainder_unsigned_halfdigit(C_word num, C_word den); +static C_regparm void integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r); +static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y); static C_regparm void bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r); -static void divrem_intflo_2(C_word c, C_word self, ...) C_noret; static C_word rat_cmp(C_word x, C_word y); static void flo_to_int_2(C_word c, C_word self, C_word result) C_noret; static void fabs_frexp_to_digits(C_uword exp, double sign, C_uword *start, C_uword *scan); @@ -568,7 +567,7 @@ static C_uword bignum_digits_destructive_shift_right(C_uword *start, C_uword *en static C_uword bignum_digits_destructive_shift_left(C_uword *start, C_uword *end, int shift_left); static C_regparm void bignum_digits_multiply(C_word x, C_word y, C_word result); static void bignum_divide_unsigned(C_word **ptr, C_word num, C_word denom, C_word *q, C_word q_negp, C_word *r, C_word r_negp); -static void bignum_destructive_divide_unsigned_small(C_word c, C_word self, C_word quotient); +static C_regparm void bignum_destructive_divide_unsigned_small(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r); static C_regparm void bignum_destructive_divide_full(C_word numerator, C_word denominator, C_word quotient, C_word remainder, C_word return_remainder); static C_regparm void bignum_destructive_divide_normalized(C_word big_u, C_word big_v, C_word big_q); static void make_structure_2(void *dummy) C_noret; @@ -846,7 +845,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) * 70); + C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 68); int i = 0; if(pt == NULL) @@ -916,8 +915,6 @@ static C_PTABLE_ENTRY *create_initial_ptable() C_pte(C_basic_quotient); C_pte(C_basic_remainder); C_pte(C_basic_divrem); - C_pte(C_u_integer_quotient); - C_pte(C_u_integer_remainder); C_pte(C_u_integer_divrem); C_pte(C_bitwise_and); C_pte(C_bitwise_ior); @@ -8578,7 +8575,10 @@ basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_ RETURN_Q_AND_OR_R(C_a_i_flonum_actual_quotient_checked(&a, 2, x, y), C_a_i_flonum_remainder_checked(&a, 2, x, y)); } else if (C_truep(C_bignump(y))) { - integer_divrem(6, (C_word)NULL, k, x, y, return_q, return_r); + C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r; + integer_divrem(&a, x, y, C_truep(return_q) ? &q : NULL, + C_truep(return_r) ? &r : NULL); + RETURN_Q_AND_OR_R(q, r); } else { barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, y); } @@ -8603,16 +8603,27 @@ basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_ RETURN_Q_AND_OR_R(C_a_i_flonum_actual_quotient_checked(&a, 2, x, y), C_a_i_flonum_remainder_checked(&a, 2, x, y)); } else if (C_truep(C_bignump(y))) { - C_word k2, ab[C_SIZEOF_CLOSURE(3)], *a = ab; + C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, + q = C_fix(0), r = C_fix(0); x = flo_to_tmp_bignum(x); - k2 = C_closure(&a, 3, (C_word)divrem_intflo_2, k, x); - integer_divrem(6, (C_word)NULL, k2, x, y, return_q, return_r); + integer_divrem(&a, x, y, C_truep(return_q) ? &q : NULL, + C_truep(return_r) ? &r : NULL); + free_tmp_bignum(x); + if (q & C_FIXNUM_BIT) q = C_a_i_fix_to_flo(&a, 1, q); + else q = C_a_u_i_big_to_flo(&a, 1, q); + if (r & C_FIXNUM_BIT) r = C_a_i_fix_to_flo(&a, 1, r); + else r = C_a_u_i_big_to_flo(&a, 1, r); + RETURN_Q_AND_OR_R(q, r); } else { barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, y); } } else if (C_truep(C_bignump(x))) { if (y & C_FIXNUM_BIT) { - integer_divrem(6, (C_word)NULL, k, x, y, return_q, return_r); + C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r; + if (y == C_fix(0)) C_div_by_zero_error(DIVREM_LOC); + integer_divrem(&a, x, y, C_truep(return_q) ? &q : NULL, + C_truep(return_r) ? &r : NULL); + RETURN_Q_AND_OR_R(q, r); } else if (C_immediatep(y)) { barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, DIVREM_LOC, y); } else if (C_block_header(y) == C_FLONUM_TAG) { @@ -8621,10 +8632,17 @@ basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_ } else if (C_flonum_magnitude(y) == 0.0) { C_div_by_zero_error(DIVREM_LOC); } else { - C_word k2, ab[C_SIZEOF_CLOSURE(3)], *a = ab; + C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, + q = C_fix(0), r = C_fix(0); y = flo_to_tmp_bignum(y); - k2 = C_closure(&a, 3, (C_word)divrem_intflo_2, k, y); - integer_divrem(6, (C_word)NULL, k2, x, y, return_q, return_r); + integer_divrem(&a, x, y, C_truep(return_q) ? &q : NULL, + C_truep(return_r) ? &r : NULL); + free_tmp_bignum(y); + if (q & C_FIXNUM_BIT) q = C_a_i_fix_to_flo(&a, 1, q); + else q = C_a_u_i_big_to_flo(&a, 1, q); + if (r & C_FIXNUM_BIT) r = C_a_i_fix_to_flo(&a, 1, r); + else r = C_a_u_i_big_to_flo(&a, 1, r); + RETURN_Q_AND_OR_R(q, r); } } else if (C_truep(C_bignump(y))) { C_word ab[C_SIZEOF_BIGNUM_WRAPPER*2], *a = ab, q, r; @@ -8639,88 +8657,44 @@ basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, x); } } - -static void divrem_intflo_2(C_word c, C_word self, ...) -{ - C_word k = C_block_item(self, 1), x, y; - va_list v; - - va_start(v, self); - if (c == 2) { - C_word ab[C_SIZEOF_FLONUM], *a = ab; - x = va_arg(v, C_word); - va_end(v); - if (x & C_FIXNUM_BIT) x = C_a_i_fix_to_flo(&a, 1, x); - else x = C_a_u_i_big_to_flo(&a, 1, x); - free_tmp_bignum(C_block_item(self, 2)); - C_kontinue(k, x); - } else { /* c == 3 */ - C_word ab[C_SIZEOF_FLONUM*2], *a = ab; - x = va_arg(v, C_word); - y = va_arg(v, C_word); - va_end(v); - - if (x & C_FIXNUM_BIT) x = C_a_i_fix_to_flo(&a, 1, x); - else x = C_a_u_i_big_to_flo(&a, 1, x); - if (y & C_FIXNUM_BIT) y = C_a_i_fix_to_flo(&a, 1, y); - else y = C_a_u_i_big_to_flo(&a, 1, y); - free_tmp_bignum(C_block_item(self, 2)); - C_values(4, C_SCHEME_UNDEFINED, k, x, y); - } -} +#undef RETURN_Q_AND_OR_R static C_regparm void -integer_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_q, C_word return_r) +integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r) { if (!(y & C_FIXNUM_BIT)) { /* y is bignum. */ if (x & C_FIXNUM_BIT) { /* abs(x) < abs(y), so it will always be [0, x] except for this case: */ if (x == C_fix(C_MOST_NEGATIVE_FIXNUM) && C_bignum_negated_fitsinfixnump(y)) { - RETURN_Q_AND_OR_R(C_fix(-1), C_fix(0)); + if (q != NULL) *q = C_fix(-1); + if (r != NULL) *r = C_fix(0); } else { - RETURN_Q_AND_OR_R(C_fix(0), x); + if (q != NULL) *q = C_fix(0); + if (r != NULL) *r = x; } } else { - C_word ab[C_SIZEOF_BIGNUM_WRAPPER*2], *a = ab, q, r; - bignum_divrem(&a, x, y, - C_truep(return_q) ? &q : NULL, - C_truep(return_r) ? &r : NULL); - RETURN_Q_AND_OR_R(q, r); + bignum_divrem(ptr, x, y, q, r); } } else if (x & C_FIXNUM_BIT) { /* both x and y are fixnum. */ - C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab; - if (y == C_fix(0)) C_div_by_zero_error(DIVREM_LOC); - - RETURN_Q_AND_OR_R(C_a_i_fixnum_quotient_checked(&a, 2, x, y), - C_i_fixnum_remainder_checked(x, y)); + if (q != NULL) *q = C_a_i_fixnum_quotient_checked(ptr, 2, x, y); + if (r != NULL) *r = C_i_fixnum_remainder_checked(x, y); } else { /* x is bignum, y is fixnum. */ C_word absy = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y); if (y == C_fix(1)) { - RETURN_Q_AND_OR_R(x, C_fix(0)); - } else if (y == C_fix(0)) { - C_div_by_zero_error(DIVREM_LOC); + if (q != NULL) *q = x; + if (r != NULL) *r = C_fix(0); } else if (y == C_fix(-1)) { - C_word *a = C_alloc(C_SIZEOF_FIX_BIGNUM); - RETURN_Q_AND_OR_R(C_s_a_u_i_integer_negate(&a, 1, x), C_fix(0)); + if (q != NULL) *q = C_s_a_u_i_integer_negate(ptr, 1, x); + if (r != NULL) *r = C_fix(0); } else if (C_fitsinbignumhalfdigitp(absy) || ((((C_uword)1 << (C_ilen(absy)-1)) == absy) && C_fitsinfixnump(absy))) { - if (C_truep(return_q)) { - C_word q_negp = C_mk_bool((y & C_INT_SIGN_BIT) ? - !(C_bignum_negativep(x)) : - C_bignum_negativep(x)), - r_negp = C_mk_bool(C_bignum_negativep(x)), - *ka, k2, size; - ka = C_alloc(C_SIZEOF_CLOSURE(9)); - size = C_fix(C_bignum_size(x)); - k2 = C_closure(&ka, 7, - (C_word)bignum_destructive_divide_unsigned_small, - k, x, C_fix(absy), - return_q, return_r, C_SCHEME_FALSE); - C_allocate_bignum(5, (C_word)NULL, k2, size, q_negp, C_SCHEME_FALSE); - } else { + assert(y != C_fix(0)); /* _must_ be checked by caller */ + if (q != NULL) { + bignum_destructive_divide_unsigned_small(ptr, x, y, q, r); + } else { /* We assume r isn't NULL here (that makes no sense) */ C_word rem; C_uword next_power = (C_uword)1 << (C_ilen(absy)-1); @@ -8729,18 +8703,16 @@ integer_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word retur } else { /* Too bad, we have to do some real work */ rem = bignum_remainder_unsigned_halfdigit(x, absy); } - C_kontinue(k, C_bignum_negativep(x) ? C_fix(-rem) : C_fix(rem)); + *r = C_bignum_negativep(x) ? C_fix(-rem) : C_fix(rem); } } else { /* Just divide it as two bignums */ - C_word ab[C_SIZEOF_BIGNUM_WRAPPER*2+C_SIZEOF_FIX_BIGNUM], *a = ab, q, r; - bignum_divrem(&a, x, C_a_u_i_fix_to_big(&a, y), - C_truep(return_q) ? &q : NULL, - C_truep(return_r) ? &r : NULL); - RETURN_Q_AND_OR_R(q, r); + C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab; + bignum_divrem(ptr, x, C_a_u_i_fix_to_big(&a, y), q, r); + if (q != NULL) *q = move_buffer_object(ptr, ab, *q); + if (r != NULL) *r = move_buffer_object(ptr, ab, *r); } } } -#undef RETURN_Q_AND_OR_R /* This _always_ needs two bignum wrappers in ptr! */ static C_regparm void @@ -8767,17 +8739,17 @@ bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r) } } -static C_word bignum_remainder_unsigned_halfdigit(C_word num, C_word den) +static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y) { - C_uword *start = C_bignum_digits(num), - *scan = start + C_bignum_size(num), + C_uword *start = C_bignum_digits(x), + *scan = start + C_bignum_size(x), rem = 0, two_digits; - assert((den > 1) && (C_fitsinbignumhalfdigitp(den))); + assert((y > 1) && (C_fitsinbignumhalfdigitp(y))); while (start < scan) { two_digits = (*--scan); - rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_HI_HALF(two_digits)) % den; - rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_LO_HALF(two_digits)) % den; + rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_HI_HALF(two_digits)) % y; + rem = C_BIGNUM_DIGIT_COMBINE(rem, C_BIGNUM_DIGIT_LO_HALF(two_digits)) % y; } return rem; } @@ -8790,10 +8762,14 @@ C_basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y) basic_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_TRUE, C_SCHEME_TRUE); } +/* There doesn't seem to be a way to return two values from inline functions */ void C_ccall C_u_integer_divrem(C_word c, C_word self, C_word k, C_word x, C_word y) { - integer_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_TRUE, C_SCHEME_TRUE); + C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r; + if (y == C_fix(0)) C_div_by_zero_error("quotient&remainder"); + integer_divrem(&a, x, y, &q, &r); + C_values(4, C_SCHEME_UNDEFINED, k, q, r); } void C_ccall @@ -8803,10 +8779,13 @@ C_basic_remainder(C_word c, C_word self, C_word k, C_word x, C_word y) basic_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_FALSE, C_SCHEME_TRUE); } -void C_ccall -C_u_integer_remainder(C_word c, C_word self, C_word k, C_word x, C_word y) +C_regparm C_word C_fcall +C_s_a_u_i_integer_remainder(C_word **ptr, C_word n, C_word x, C_word y) { - integer_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_FALSE, C_SCHEME_TRUE); + C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, r; + if (y == C_fix(0)) C_div_by_zero_error("remainder"); + integer_divrem(ptr, x, y, NULL, &r); + return move_buffer_object(ptr, ab, r); } void C_ccall @@ -8816,10 +8795,13 @@ C_basic_quotient(C_word c, C_word self, C_word k, C_word x, C_word y) basic_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_TRUE, C_SCHEME_FALSE); } -void C_ccall -C_u_integer_quotient(C_word c, C_word self, C_word k, C_word x, C_word y) +C_regparm C_word C_fcall +C_s_a_u_i_integer_quotient(C_word **ptr, C_word n, C_word x, C_word y) { - integer_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_TRUE, C_SCHEME_FALSE); + C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q; + if (y == C_fix(0)) C_div_by_zero_error("quotient"); + integer_divrem(ptr, x, y, &q, NULL); + return move_buffer_object(ptr, ab, q); } @@ -10023,39 +10005,37 @@ bignum_digits_multiply(C_word x, C_word y, C_word result) /* "small" is either a number that fits a halfdigit, or a power of two */ -static void -bignum_destructive_divide_unsigned_small(C_word c, C_word self, C_word quotient) +static C_regparm void +bignum_destructive_divide_unsigned_small(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r) { - C_word k = C_block_item(self, 1), - numerator = C_block_item(self, 2), - denominator = C_unfix(C_block_item(self, 3)), - /* return_quotient = C_block_item(self, 4), */ - return_remainder = C_block_item(self, 5), - remainder_negp = C_block_item(self, 6); - C_uword *start = C_bignum_digits(quotient), - *end = start + C_bignum_size(quotient), - remainder; + C_word size, quotient, q_negp = C_mk_bool((y & C_INT_SIGN_BIT) ? + !(C_bignum_negativep(x)) : + C_bignum_negativep(x)), + r_negp = C_mk_bool(C_bignum_negativep(x)); + C_uword *start, *end, remainder; int shift_amount; - bignum_digits_destructive_copy(quotient, numerator); + size = C_fix(C_bignum_size(x)); + quotient = C_allocate_scratch_bignum(ptr, size, q_negp, C_SCHEME_FALSE); + bignum_digits_destructive_copy(quotient, x); - shift_amount = C_ilen(denominator)-1; - if (((C_uword)1 << shift_amount) == denominator) { /* Power of two? Shift! */ + start = C_bignum_digits(quotient); + end = start + C_bignum_size(quotient); + + y = (y & C_INT_SIGN_BIT) ? -C_unfix(y) : C_unfix(y); + + shift_amount = C_ilen(y) - 1; + if (((C_uword)1 << shift_amount) == y) { /* Power of two? Shift! */ remainder = bignum_digits_destructive_shift_right(start,end,shift_amount,0); assert(C_ufitsinfixnump(remainder)); } else { - remainder = bignum_digits_destructive_scale_down(start, end, denominator); + remainder = bignum_digits_destructive_scale_down(start, end, y); assert(C_fitsinbignumhalfdigitp(remainder)); } - quotient = C_bignum_simplify(quotient); - - if (C_truep(return_remainder)) { - remainder = C_truep(remainder_negp) ? -remainder : remainder; - C_values(4, C_SCHEME_UNDEFINED, k, quotient, C_fix(remainder)); - } else { - C_kontinue(k, quotient); - } + if (r != NULL) *r = C_truep(r_negp) ? C_fix(-remainder) : C_fix(remainder); + /* Calling this function only makes sense if quotient is needed */ + *q = C_bignum_simplify(quotient); } static C_regparm void diff --git a/types.db b/types.db index 22ddaac8..8986e577 100644 --- a/types.db +++ b/types.db @@ -444,7 +444,7 @@ (##core#inline_allocate ("C_a_i_fixnum_quotient_checked" 6) #(1) #(2))) ((integer integer) (integer) - (##sys#integer-quotient #(1) #(2)))) + (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 6) #(1) #(2)))) (remainder (#(procedure #:clean #:enforce #:foldable) remainder ((or integer float) (or integer float)) (or integer float)) ((float float) (float) @@ -453,8 +453,8 @@ ;;XXX flonum/mixed case ((fixnum fixnum) (fixnum) (##core#inline "C_i_fixnum_remainder_checked" #(1) #(2))) - ((integer integer) (integer) - (##sys#integer-remainder #(1) #(2)))) + ((integer integer) (integer) + (##core#inline_allocate ("C_s_a_u_i_integer_remainder" 6) #(1) #(2)))) (quotient&remainder (#(procedure #:clean #:enforce #:foldable) quotient&remainder ((or integer float) (or integer float)) (or integer float) (or integer float)) ((float float) (float float) @@ -475,7 +475,7 @@ (##core#inline "C_i_fixnum_remainder_checked" #(tmp1) #(tmp2)))))) ((integer integer) (integer integer) - (##sys#integer-quotient&remainder #(1) #(2)))) + ((##core#primitive "C_u_integer_divrem") #(1) #(2)))) ;; TODO: Add nonspecializing type specific entries, to help flow analysis? (quotient&modulo (#(procedure #:clean #:enforce #:foldable) quotient&modulo ((or integer float) (or integer float)) (or integer float) (or integer float)))Trap