~ chicken-core (master) 40e30a4534399ffe720821017a771951e309952d
commit 40e30a4534399ffe720821017a771951e309952d
Author: Peter Bex <peter@more-magic.net>
AuthorDate: Mon Apr 6 20:16:14 2015 +0200
Commit: Peter Bex <peter@more-magic.net>
CommitDate: Sun May 31 14:55:25 2015 +0200
Make quotient, remainder *and* modulo inlineable, and restore compiler rewrites for them.
Fix fxmod to work according to Scheme rather than C %-operator semantics.
diff --git a/c-platform.scm b/c-platform.scm
index c3c42bf3..8e4525eb 100644
--- a/c-platform.scm
+++ b/c-platform.scm
@@ -641,6 +641,9 @@
(rewrite '+ 16 2 "C_s_a_i_plus" #t 36)
(rewrite '- 16 2 "C_s_a_i_minus" #t 36)
(rewrite '* 16 2 "C_s_a_i_times" #t 40)
+(rewrite 'quotient 16 2 "C_s_a_i_quotient" #t 6)
+(rewrite 'remainder 16 2 "C_s_a_i_remainder" #t 6)
+(rewrite 'modulo 16 2 "C_s_a_i_modulo" #t 6)
(rewrite '= 17 2 "C_i_nequalp")
(rewrite '> 17 2 "C_i_greaterp")
diff --git a/chicken.h b/chicken.h
index b99dd946..5fc43756 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1289,8 +1289,6 @@ extern double trunc(double);
#define C_u_fixnum_difference(n1, n2) ((n1) - (n2) + C_FIXNUM_BIT)
#define C_fixnum_difference(n1, n2) (C_u_fixnum_difference(n1, n2) | C_FIXNUM_BIT)
#define C_u_fixnum_divide(n1, n2) (C_fix(C_unfix(n1) / C_unfix(n2)))
-/* XXX TODO OBSOLETE, but still used by C_fixnum_modulo, which is fxmod */
-#define C_u_fixnum_modulo(n1, n2) (C_fix(C_unfix(n1) % C_unfix(n2)))
#define C_u_fixnum_and(n1, n2) ((n1) & (n2))
#define C_fixnum_and(n1, n2) (C_u_fixnum_and(n1, n2) | C_FIXNUM_BIT)
#define C_u_fixnum_or(n1, n2) ((n1) | (n2))
@@ -1955,10 +1953,8 @@ C_fctexport void C_ccall C_plus(C_word c, C_word closure, C_word k, ...) C_noret
C_fctexport void C_ccall C_minus(C_word c, C_word closure, C_word k, C_word n1, ...) C_noret;
/* 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_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_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_quotient_and_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_quotient_and_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_flo_to_int(C_word c, C_word self, C_word k, C_word x) 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;
@@ -2177,8 +2173,12 @@ 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_i_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_quotient(C_word **ptr, C_word n, C_word x, C_word y) C_regparm;
+C_fctexport C_word C_fcall C_s_a_i_remainder(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_modulo(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_modulo(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;
@@ -2969,8 +2969,14 @@ C_inline C_word C_fixnum_divide(C_word x, C_word y)
C_inline C_word C_fixnum_modulo(C_word x, C_word y)
{
- if(y == C_fix(0)) C_div_by_zero_error("fxmod");
- return C_u_fixnum_modulo(x, y);
+ if(y == C_fix(0)) {
+ C_div_by_zero_error("fxmod");
+ } else {
+ y = C_unfix(y);
+ x = C_unfix(x) % y;
+ if ((y < 0 && x > 0) || (y > 0 && x < 0)) x += y;
+ return C_fix(x);
+ }
}
/* XXX: Naming convention is inconsistent! There's C_fixnum_divide()
@@ -3177,6 +3183,25 @@ C_a_i_flonum_remainder_checked(C_word **ptr, int c, C_word x, C_word y)
}
}
+C_inline C_word
+C_a_i_flonum_modulo_checked(C_word **ptr, int c, C_word x, C_word y)
+{
+ double dx = C_flonum_magnitude(x),
+ dy = C_flonum_magnitude(y), r;
+
+ if(dy == 0.0) {
+ C_div_by_zero_error("modulo");
+ } else if (!C_truep(C_u_i_fpintegerp(x))) {
+ C_not_an_integer_error("modulo", x);
+ } else if (!C_truep(C_u_i_fpintegerp(y))) {
+ C_not_an_integer_error("modulo", y);
+ } else {
+ modf(dx / dy, &r);
+ r = dx - r * dy;
+ if ((dy < 0 && r > 0) || (dy > 0 && r < 0)) r += y;
+ return C_flonum(ptr, r);
+ }
+}
C_inline C_word C_i_safe_pointerp(C_word x)
{
diff --git a/irregex.scm b/irregex.scm
index 9d575e8c..bd45695f 100644
--- a/irregex.scm
+++ b/irregex.scm
@@ -126,8 +126,7 @@
(##sys#setslot ,%cache ,%index ,%arg)
(##sys#setslot ,%cache (,%fx+ ,%index 1) ,%tmp)
(##sys#setislot
- ,%cache ,n2
- (##core#inline "C_u_fixnum_modulo" (,%fx+ ,%index 2) ,n2))
+ ,%cache ,n2 (,%fxmod (,%fx+ ,%index 2) ,n2))
,%tmp)
`(,%if (,%equal? (##sys#slot ,%cache ,(* i 2)) ,%arg)
(##sys#slot ,%cache ,(add1 (* i 2)))
diff --git a/library.scm b/library.scm
index 0e4c5c77..3ec0f6ed 100644
--- a/library.scm
+++ b/library.scm
@@ -1243,11 +1243,13 @@ EOF
(exact->inexact result)
result)))
-(define quotient (##core#primitive "C_basic_quotient"))
-(define remainder (##core#primitive "C_basic_remainder"))
-(define quotient&remainder (##core#primitive "C_basic_divrem"))
+(define (quotient a b) (##core#inline_allocate ("C_s_a_i_quotient" 6) a b))
+(define (remainder a b) (##core#inline_allocate ("C_s_a_i_remainder" 6) a b))
+(define (modulo a b) (##core#inline_allocate ("C_s_a_i_modulo" 6) a b))
+(define quotient&remainder (##core#primitive "C_quotient_and_remainder"))
-;; Modulo's sign follows y (whereas remainder's sign follows x)
+;; Modulo's sign follows y (whereas remainder's sign follows x)
+;; Inlining this is not much use: quotient&remainder is primitive
(define (quotient&modulo x y)
(receive (div rem) (quotient&remainder x y)
(if (positive? y)
@@ -1258,13 +1260,6 @@ EOF
(values div (+ rem y))
(values div rem)))))
-;; Modulo's sign follows y (whereas remainder's sign follows x)
-(define (modulo x y)
- (let ((r (remainder x y)))
- (if (positive? y)
- (if (negative? r) (+ r y) r)
- (if (positive? r) (+ r y) r))))
-
(define (even? n) (##core#inline "C_i_evenp" n))
(define (odd? n) (##core#inline "C_i_oddp" n))
@@ -1403,7 +1398,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) ((##core#primitive "C_u_integer_divrem")
+ ((q u) ((##core#primitive "C_u_integer_quotient_and_remainder")
(+ (arithmetic-shift r^ len/4) a1)
(arithmetic-shift s^ 1)))
((s) (+ (arithmetic-shift s^ len/4) q))
@@ -1586,7 +1581,8 @@ 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) ((##core#primitive "C_u_integer_divrem") n b^M/2))
+ ((hi lo) ((##core#primitive "C_u_integer_quotient_and_remainder")
+ n b^M/2))
((strhi) (number->string hi base))
((strlo) (number->string (abs lo) base)))
(string-append strhi
diff --git a/runtime.c b/runtime.c
index bd322469..bfb530d7 100644
--- a/runtime.c
+++ b/runtime.c
@@ -524,7 +524,6 @@ static C_word rat_times_integer(C_word **ptr, C_word x, C_word y);
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 **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);
@@ -845,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) * 68);
+ C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 66);
int i = 0;
if(pt == NULL)
@@ -896,6 +895,7 @@ static C_PTABLE_ENTRY *create_initial_ptable()
C_pte(C_software_version);
C_pte(C_build_platform);
C_pte(C_make_pointer);
+ /* IMPORTANT: have you read the comments at the start and the end of this function? */
C_pte(C_make_tagged_pointer);
C_pte(C_peek_signed_integer);
C_pte(C_peek_unsigned_integer);
@@ -910,12 +910,9 @@ static C_PTABLE_ENTRY *create_initial_ptable()
C_pte(C_fixnum_to_string);
C_pte(C_integer_to_string);
C_pte(C_flonum_to_string);
- /* IMPORTANT: have you read the comments at the start and the end of this function? */
C_pte(C_signum);
- C_pte(C_basic_quotient);
- C_pte(C_basic_remainder);
- C_pte(C_basic_divrem);
- C_pte(C_u_integer_divrem);
+ C_pte(C_quotient_and_remainder);
+ C_pte(C_u_integer_quotient_and_remainder);
C_pte(C_bitwise_and);
C_pte(C_bitwise_ior);
C_pte(C_bitwise_xor);
@@ -8516,131 +8513,6 @@ void C_ccall C_divide(C_word c, C_word closure, C_word k, C_word n1, ...)
C_kontinue(k, n1);
}
-
-/* This is ugly but really cleans up the code below */
-#define RETURN_Q_AND_OR_R(calc_q, calc_r) \
- if (C_truep(C_and(return_q, return_r))) { \
- C_values(4, C_SCHEME_UNDEFINED, k, calc_q, calc_r); \
- } else if (C_truep(return_r)) { \
- C_kontinue(k, calc_r); \
- } else { \
- C_kontinue(k, calc_q); \
- }
-
-/* Lossy; we could be in "quotient&remainder" or "modulo" */
-#define DIVREM_LOC ((C_truep(C_and(return_q, return_r))) ? "/" : \
- (C_truep(return_q) ? "quotient" : "remainder"))
-
-/* Another huge and ugly dispatch function. This is the fundamental
- * division function. It decides what functions to call depending on
- * whether we want to see the quotient and/or the remainder. It only
- * knows about the "basic" types: fixnums, bignums and flonums. The
- * Scheme "##sys#/" procedure handles ratnums and cplxnums.
- */
-static C_regparm void
-basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y, C_word return_q, C_word return_r)
-{
- if (x & C_FIXNUM_BIT) {
- if (y & C_FIXNUM_BIT) {
- 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));
- } else if (C_immediatep(y)) {
- barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, y);
- } else if (C_block_header(y) == C_FLONUM_TAG) {
- C_word ab[C_SIZEOF_FLONUM*3], *a = ab;
- if (C_flonum_magnitude(y) == 0.0) C_div_by_zero_error(DIVREM_LOC);
-
- x = C_a_i_fix_to_flo(&a, 1, x);
- 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 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);
- }
- } else if (C_immediatep(x)) {
- barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, DIVREM_LOC, x);
- } else if (C_block_header(x) == C_FLONUM_TAG) {
- if (!C_truep(C_u_i_fpintegerp(x))) {
- barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, x);
- } else if (y & C_FIXNUM_BIT) {
- C_word ab[C_SIZEOF_FLONUM*3], *a = ab;
- if (y == C_fix(0)) C_div_by_zero_error(DIVREM_LOC);
-
- y = C_a_i_fix_to_flo(&a, 1, y);
- 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_immediatep(y)) {
- barf(C_BAD_ARGUMENT_TYPE_NO_NUMBER_ERROR, DIVREM_LOC, y);
- } else if (C_block_header(y) == C_FLONUM_TAG) {
- C_word ab[C_SIZEOF_FLONUM*3], *a = ab;
- if (C_flonum_magnitude(y) == 0.0) C_div_by_zero_error(DIVREM_LOC);
-
- 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 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);
- 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) {
- 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) {
- if (!C_truep(C_u_i_fpintegerp(y))) {
- barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, y);
- } else if (C_flonum_magnitude(y) == 0.0) {
- C_div_by_zero_error(DIVREM_LOC);
- } else {
- 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);
- 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;
- bignum_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);
- }
- } else {
- barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, DIVREM_LOC, x);
- }
-}
-#undef RETURN_Q_AND_OR_R
-
static C_regparm void
integer_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r)
{
@@ -8736,17 +8608,56 @@ static C_regparm C_word bignum_remainder_unsigned_halfdigit(C_word x, C_word y)
return rem;
}
-/* External interface for the above internal divrem functions */
+/* There doesn't seem to be a way to return two values from inline functions */
void C_ccall
-C_basic_divrem(C_word c, C_word self, C_word k, C_word x, C_word y)
+C_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y)
{
+ C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, q, r,
+ nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
+
if (c != 4) C_bad_argc_2(c, 4, self);
- basic_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_TRUE, C_SCHEME_TRUE);
+ if (!C_truep(C_i_integerp(x)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", x);
+ if (!C_truep(C_i_integerp(y)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient&remainder", y);
+ if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient&remainder");
+
+ if (C_truep(C_i_flonump(x))) {
+ if C_truep(C_i_flonump(y)) {
+ double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
+
+ C_modf(dx / dy, &tmp);
+ q = C_flonum(&a, tmp);
+ r = C_flonum(&a, dx - tmp * dy);
+ C_values(4, C_SCHEME_UNDEFINED, k, q, r);
+ }
+ nx = flo_to_tmp_bignum(x);
+ x = C_bignum_simplify(nx);
+ }
+ if (C_truep(C_i_flonump(y))) {
+ ny = flo_to_tmp_bignum(y);
+ y = C_bignum_simplify(ny);
+ }
+
+ integer_divrem(&a, x, y, &q, &r);
+
+ if (C_truep(nx) || C_truep(ny)) {
+ C_word newq, newr;
+ newq = C_a_i_exact_to_inexact(&a, 1, q);
+ newr = C_a_i_exact_to_inexact(&a, 1, r);
+ clear_buffer_object(ab, q);
+ clear_buffer_object(ab, r);
+ q = newq;
+ r = newr;
+
+ if (C_truep(nx)) free_tmp_bignum(nx);
+ if (C_truep(ny)) free_tmp_bignum(ny);
+ }
+ C_values(4, C_SCHEME_UNDEFINED, k, q, r);
}
-/* 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)
+C_u_integer_quotient_and_remainder(C_word c, C_word self, C_word k, C_word x, C_word y)
{
C_word ab[C_SIZEOF_FIX_BIGNUM*2], *a = ab, q, r;
if (y == C_fix(0)) C_div_by_zero_error("quotient&remainder");
@@ -8754,11 +8665,44 @@ C_u_integer_divrem(C_word c, C_word self, C_word k, C_word x, C_word y)
C_values(4, C_SCHEME_UNDEFINED, k, q, r);
}
-void C_ccall
-C_basic_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_i_remainder(C_word **ptr, C_word n, C_word x, C_word y)
{
- if (c != 4) C_bad_argc_2(c, 4, self);
- basic_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_FALSE, C_SCHEME_TRUE);
+ C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, r,
+ nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
+
+ if (!C_truep(C_i_integerp(x)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", x);
+ if (!C_truep(C_i_integerp(y)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "remainder", y);
+ if (C_truep(C_i_zerop(y))) C_div_by_zero_error("remainder");
+
+ if (C_truep(C_i_flonump(x))) {
+ if C_truep(C_i_flonump(y)) {
+ double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
+
+ C_modf(dx / dy, &tmp);
+ return C_flonum(ptr, dx - tmp * dy);
+ }
+ nx = flo_to_tmp_bignum(x);
+ x = C_bignum_simplify(nx);
+ }
+ if (C_truep(C_i_flonump(y))) {
+ ny = flo_to_tmp_bignum(y);
+ y = C_bignum_simplify(ny);
+ }
+
+ integer_divrem(&a, x, y, NULL, &r);
+
+ if (C_truep(nx) || C_truep(ny)) {
+ C_word newr = C_a_i_exact_to_inexact(ptr, 1, r);
+ clear_buffer_object(ab, r);
+ r = newr;
+
+ if (C_truep(nx)) free_tmp_bignum(nx);
+ if (C_truep(ny)) free_tmp_bignum(ny);
+ }
+ return move_buffer_object(ptr, ab, r);
}
C_regparm C_word C_fcall
@@ -8770,11 +8714,82 @@ C_s_a_u_i_integer_remainder(C_word **ptr, C_word n, C_word x, C_word y)
return move_buffer_object(ptr, ab, r);
}
-void C_ccall
-C_basic_quotient(C_word c, C_word self, C_word k, C_word x, C_word y)
+/* Modulo's sign follows y (whereas remainder's sign follows x) */
+C_regparm C_word C_fcall
+C_s_a_i_modulo(C_word **ptr, C_word n, C_word x, C_word y)
{
- if (c != 4) C_bad_argc_2(c, 4, self);
- basic_divrem(6, (C_word)NULL, k, x, y, C_SCHEME_TRUE, C_SCHEME_FALSE);
+ C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r;
+
+ if (!C_truep(C_i_integerp(x)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", x);
+ if (!C_truep(C_i_integerp(y)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "modulo", y);
+ if (C_truep(C_i_zerop(y))) C_div_by_zero_error("modulo");
+
+ r = C_s_a_i_remainder(&a, 2, x, y);
+ if (C_i_positivep(y) != C_i_positivep(r) && !C_truep(C_i_zerop(r))) {
+ C_word m = C_s_a_i_plus(ptr, 2, r, y);
+ m = move_buffer_object(ptr, ab, m);
+ clear_buffer_object(ab, r);
+ r = m;
+ }
+ return move_buffer_object(ptr, ab, r);
+}
+
+C_regparm C_word C_fcall
+C_s_a_u_i_integer_modulo(C_word **ptr, C_word n, C_word x, C_word y)
+{
+ C_word ab[C_SIZEOF_FIX_BIGNUM], *a = ab, r;
+ if (y == C_fix(0)) C_div_by_zero_error("modulo");
+
+ r = C_s_a_i_remainder(&a, 2, x, y);
+ if (C_i_positivep(y) != C_i_positivep(r) && r != C_fix(0)) {
+ C_word m = C_s_a_u_i_integer_plus(ptr, 2, r, y);
+ m = move_buffer_object(ptr, ab, m);
+ clear_buffer_object(ab, r);
+ r = m;
+ }
+ return move_buffer_object(ptr, ab, r);
+}
+
+C_regparm C_word C_fcall
+C_s_a_i_quotient(C_word **ptr, C_word n, C_word x, C_word y)
+{
+ C_word ab[C_SIZEOF_FIX_BIGNUM*2+C_SIZEOF_FLONUM*2], *a = ab, q,
+ nx = C_SCHEME_FALSE, ny = C_SCHEME_FALSE;
+
+ if (!C_truep(C_i_integerp(x)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", x);
+ if (!C_truep(C_i_integerp(y)))
+ barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, "quotient", y);
+ if (C_truep(C_i_zerop(y))) C_div_by_zero_error("quotient");
+
+ if (C_truep(C_i_flonump(x))) {
+ if C_truep(C_i_flonump(y)) {
+ double dx = C_flonum_magnitude(x), dy = C_flonum_magnitude(y), tmp;
+
+ C_modf(dx / dy, &tmp);
+ return C_flonum(ptr, tmp);
+ }
+ nx = flo_to_tmp_bignum(x);
+ x = C_bignum_simplify(nx);
+ }
+ if (C_truep(C_i_flonump(y))) {
+ ny = flo_to_tmp_bignum(y);
+ y = C_bignum_simplify(ny);
+ }
+
+ integer_divrem(&a, x, y, &q, NULL);
+
+ if (C_truep(nx) || C_truep(ny)) {
+ C_word newq = C_a_i_exact_to_inexact(ptr, 1, q);
+ clear_buffer_object(ab, q);
+ q = newq;
+
+ if (C_truep(nx)) free_tmp_bignum(nx);
+ if (C_truep(ny)) free_tmp_bignum(ny);
+ }
+ return move_buffer_object(ptr, ab, q);
}
C_regparm C_word C_fcall
diff --git a/types.db b/types.db
index 8986e577..7f0c87bf 100644
--- a/types.db
+++ b/types.db
@@ -444,7 +444,8 @@
(##core#inline_allocate ("C_a_i_fixnum_quotient_checked" 6)
#(1) #(2)))
((integer integer) (integer)
- (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 6) #(1) #(2))))
+ (##core#inline_allocate ("C_s_a_u_i_integer_quotient" 6) #(1) #(2)))
+ ((* *) (##core#inline_allocate ("C_s_a_i_quotient" 6) #(1) #(2))))
(remainder (#(procedure #:clean #:enforce #:foldable) remainder ((or integer float) (or integer float)) (or integer float))
((float float) (float)
@@ -454,7 +455,8 @@
((fixnum fixnum) (fixnum)
(##core#inline "C_i_fixnum_remainder_checked" #(1) #(2)))
((integer integer) (integer)
- (##core#inline_allocate ("C_s_a_u_i_integer_remainder" 6) #(1) #(2))))
+ (##core#inline_allocate ("C_s_a_u_i_integer_remainder" 6) #(1) #(2)))
+ ((* *) (##core#inline_allocate ("C_s_a_i_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,12 +477,21 @@
(##core#inline
"C_i_fixnum_remainder_checked" #(tmp1) #(tmp2))))))
((integer integer) (integer integer)
- ((##core#primitive "C_u_integer_divrem") #(1) #(2))))
+ ((##core#primitive "C_u_integer_quotient_and_remainder") #(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)))
-(modulo (#(procedure #:clean #:enforce #:foldable) modulo ((or integer float) (or integer float)) (or integer float)))
+(modulo (#(procedure #:clean #:enforce #:foldable) modulo ((or integer float) (or integer float)) (or integer float))
+ ((float float) (float)
+ (##core#inline_allocate
+ ("C_a_i_flonum_modulo_checked" 4) #(1) #(2)))
+ ;;XXX flonum/mixed case
+ ((fixnum fixnum) (fixnum)
+ (##core#inline "C_fixnum_modulo" #(1) #(2)))
+ ((integer integer) (integer)
+ (##core#inline_allocate ("C_s_a_u_i_integer_modulo" 6) #(1) #(2)))
+ ((* *) (##core#inline_allocate ("C_s_a_i_modulo" 6) #(1) #(2))))
(gcd (#(procedure #:clean #:enforce #:foldable) gcd (#!rest (or integer float)) (or integer float))
(() '0)
Trap