Faster /mod and /i primitives

db4
Slava Pestov 2008-11-21 01:54:45 -06:00
parent 1addde1567
commit 27503bf67f
1 changed files with 28 additions and 15 deletions

View File

@ -33,18 +33,18 @@ void primitive_float_to_fixnum(void)
#define POP_FIXNUMS(x,y) \ #define POP_FIXNUMS(x,y) \
F_FIXNUM y = untag_fixnum_fast(dpop()); \ F_FIXNUM y = untag_fixnum_fast(dpop()); \
F_FIXNUM x = untag_fixnum_fast(dpop()); F_FIXNUM x = untag_fixnum_fast(dpeek());
void primitive_fixnum_add(void) void primitive_fixnum_add(void)
{ {
POP_FIXNUMS(x,y) POP_FIXNUMS(x,y)
box_signed_cell(x + y); drepl(allot_integer(x + y));
} }
void primitive_fixnum_subtract(void) void primitive_fixnum_subtract(void)
{ {
POP_FIXNUMS(x,y) POP_FIXNUMS(x,y)
box_signed_cell(x - y); drepl(allot_integer(x - y));
} }
/* Multiply two integers, and trap overflow. /* Multiply two integers, and trap overflow.
@ -54,20 +54,20 @@ void primitive_fixnum_multiply(void)
POP_FIXNUMS(x,y) POP_FIXNUMS(x,y)
if(x == 0 || y == 0) if(x == 0 || y == 0)
dpush(tag_fixnum(0)); drepl(tag_fixnum(0));
else else
{ {
F_FIXNUM prod = x * y; F_FIXNUM prod = x * y;
/* if this is not equal, we have overflow */ /* if this is not equal, we have overflow */
if(prod / x == y) if(prod / x == y)
box_signed_cell(prod); drepl(allot_integer(prod));
else else
{ {
F_ARRAY *bx = fixnum_to_bignum(x); F_ARRAY *bx = fixnum_to_bignum(x);
REGISTER_BIGNUM(bx); REGISTER_BIGNUM(bx);
F_ARRAY *by = fixnum_to_bignum(y); F_ARRAY *by = fixnum_to_bignum(y);
UNREGISTER_BIGNUM(bx); UNREGISTER_BIGNUM(bx);
dpush(tag_bignum(bignum_multiply(bx,by))); drepl(tag_bignum(bignum_multiply(bx,by)));
} }
} }
} }
@ -75,14 +75,27 @@ void primitive_fixnum_multiply(void)
void primitive_fixnum_divint(void) void primitive_fixnum_divint(void)
{ {
POP_FIXNUMS(x,y) POP_FIXNUMS(x,y)
box_signed_cell(x / y); F_FIXNUM result = x / y;
if(result == -FIXNUM_MIN)
drepl(allot_integer(-FIXNUM_MIN));
else
drepl(tag_fixnum(result));
} }
void primitive_fixnum_divmod(void) void primitive_fixnum_divmod(void)
{ {
POP_FIXNUMS(x,y) F_FIXNUM y = get(ds);
box_signed_cell(x / y); F_FIXNUM x = get(ds - CELLS);
dpush(tag_fixnum(x % y)); if(y == -1 && x == tag_fixnum(FIXNUM_MIN))
{
put(ds - CELLS,allot_integer(-FIXNUM_MIN));
put(ds,tag_fixnum(0));
}
else
{
put(ds - CELLS,tag_fixnum(x / y));
put(ds,x % y);
}
} }
/* /*
@ -96,15 +109,15 @@ void primitive_fixnum_shift(void)
if(x == 0 || y == 0) if(x == 0 || y == 0)
{ {
dpush(tag_fixnum(x)); drepl(tag_fixnum(x));
return; return;
} }
else if(y < 0) else if(y < 0)
{ {
if(y <= -WORD_SIZE) if(y <= -WORD_SIZE)
dpush(x < 0 ? tag_fixnum(-1) : tag_fixnum(0)); drepl(x < 0 ? tag_fixnum(-1) : tag_fixnum(0));
else else
dpush(tag_fixnum(x >> -y)); drepl(tag_fixnum(x >> -y));
return; return;
} }
else if(y < WORD_SIZE - TAG_BITS) else if(y < WORD_SIZE - TAG_BITS)
@ -112,12 +125,12 @@ void primitive_fixnum_shift(void)
F_FIXNUM mask = -((F_FIXNUM)1 << (WORD_SIZE - 1 - TAG_BITS - y)); F_FIXNUM mask = -((F_FIXNUM)1 << (WORD_SIZE - 1 - TAG_BITS - y));
if((x > 0 && (x & mask) == 0) || (x & mask) == mask) if((x > 0 && (x & mask) == 0) || (x & mask) == mask)
{ {
dpush(tag_fixnum(x << y)); drepl(tag_fixnum(x << y));
return; return;
} }
} }
dpush(tag_bignum(bignum_arithmetic_shift( drepl(tag_bignum(bignum_arithmetic_shift(
fixnum_to_bignum(x),y))); fixnum_to_bignum(x),y)));
} }