Rewrite remaining fixnum primitives in assembly (work in progress)
parent
d927ed5620
commit
e78121f38c
|
@ -12,6 +12,10 @@ and the callstack top is passed in EDX */
|
||||||
|
|
||||||
#define NV_TEMP_REG %ebx
|
#define NV_TEMP_REG %ebx
|
||||||
|
|
||||||
|
#define ARITH_TEMP_1 %ebp
|
||||||
|
#define ARITH_TEMP_2 %ebx
|
||||||
|
#define DIV_RESULT %eax
|
||||||
|
|
||||||
#define CELL_SIZE 4
|
#define CELL_SIZE 4
|
||||||
#define STACK_PADDING 12
|
#define STACK_PADDING 12
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
|
|
||||||
#define NV_TEMP_REG %rbp
|
#define NV_TEMP_REG %rbp
|
||||||
|
|
||||||
|
#define ARITH_TEMP_1 %r8
|
||||||
|
#define ARITH_TEMP_2 %r9
|
||||||
|
#define DIV_RESULT %rax
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
|
||||||
#define ARG0 %rcx
|
#define ARG0 %rcx
|
||||||
|
|
36
vm/cpu-x86.S
36
vm/cpu-x86.S
|
@ -1,3 +1,39 @@
|
||||||
|
DEF(void,primitive_fixnum_add,(void)):
|
||||||
|
mov (DS_REG),ARG0
|
||||||
|
mov -CELL_SIZE(DS_REG),ARG1
|
||||||
|
sub $CELL_SIZE,DS_REG
|
||||||
|
mov ARG1,ARITH_TEMP_1
|
||||||
|
add ARG0,ARITH_TEMP_1
|
||||||
|
jo MANGLE(overflow_fixnum_add)
|
||||||
|
mov ARITH_TEMP_1,(DS_REG)
|
||||||
|
ret
|
||||||
|
|
||||||
|
DEF(void,primitive_fixnum_subtract,(void)):
|
||||||
|
mov (DS_REG),ARG1
|
||||||
|
mov -CELL_SIZE(DS_REG),ARG0
|
||||||
|
sub $CELL_SIZE,DS_REG
|
||||||
|
mov ARG0,ARITH_TEMP_1
|
||||||
|
sub ARG1,ARITH_TEMP_1
|
||||||
|
jo MANGLE(overflow_fixnum_subtract)
|
||||||
|
mov ARITH_TEMP_1,(DS_REG)
|
||||||
|
ret
|
||||||
|
|
||||||
|
DEF(void,primitive_fixnum_multiply,(void)):
|
||||||
|
mov (DS_REG),ARITH_TEMP_1
|
||||||
|
mov ARITH_TEMP_1,DIV_RESULT
|
||||||
|
mov -CELL_SIZE(DS_REG),ARITH_TEMP_2
|
||||||
|
sar $3,ARITH_TEMP_2
|
||||||
|
sub $CELL_SIZE,DS_REG
|
||||||
|
imul ARITH_TEMP_2
|
||||||
|
jo multiply_overflow
|
||||||
|
mov DIV_RESULT,(DS_REG)
|
||||||
|
ret
|
||||||
|
multiply_overflow:
|
||||||
|
sar $3,ARITH_TEMP_1
|
||||||
|
mov ARITH_TEMP_1,ARG0
|
||||||
|
mov ARITH_TEMP_2,ARG1
|
||||||
|
jmp MANGLE(overflow_fixnum_multiply)
|
||||||
|
|
||||||
DEF(F_FASTCALL void,c_to_factor,(CELL quot)):
|
DEF(F_FASTCALL void,c_to_factor,(CELL quot)):
|
||||||
PUSH_NONVOLATILE
|
PUSH_NONVOLATILE
|
||||||
mov ARG0,NV_TEMP_REG
|
mov ARG0,NV_TEMP_REG
|
||||||
|
|
|
@ -129,7 +129,7 @@ void print_nested_obj(CELL obj, F_FIXNUM nesting)
|
||||||
print_string(" ]");
|
print_string(" ]");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print_string("#<type "); print_cell(type_of(obj)); print_string(" @ "); print_cell_hex(obj);
|
print_string("#<type "); print_cell(type_of(obj)); print_string(" @ "); print_cell_hex(obj); print_string(">");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
61
vm/math.c
61
vm/math.c
|
@ -1,7 +1,6 @@
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
|
|
||||||
/* Fixnums */
|
/* Fixnums */
|
||||||
|
|
||||||
F_FIXNUM to_fixnum(CELL tagged)
|
F_FIXNUM to_fixnum(CELL tagged)
|
||||||
{
|
{
|
||||||
switch(TAG(tagged))
|
switch(TAG(tagged))
|
||||||
|
@ -31,37 +30,21 @@ void primitive_float_to_fixnum(void)
|
||||||
drepl(tag_fixnum(float_to_fixnum(dpeek())));
|
drepl(tag_fixnum(float_to_fixnum(dpeek())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define POP_FIXNUMS(x,y) \
|
/* The fixnum+, fixnum- and fixnum* primitives are defined in cpu_*.S. On
|
||||||
F_FIXNUM y = untag_fixnum_fast(dpop()); \
|
overflow, they call these functions. */
|
||||||
F_FIXNUM x = untag_fixnum_fast(dpeek());
|
F_FASTCALL void overflow_fixnum_add(F_FIXNUM x, F_FIXNUM y)
|
||||||
|
|
||||||
void primitive_fixnum_add(void)
|
|
||||||
{
|
{
|
||||||
POP_FIXNUMS(x,y)
|
drepl(tag_bignum(fixnum_to_bignum(
|
||||||
drepl(allot_integer(x + y));
|
untag_fixnum_fast(x) + untag_fixnum_fast(y))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void primitive_fixnum_subtract(void)
|
F_FASTCALL void overflow_fixnum_subtract(F_FIXNUM x, F_FIXNUM y)
|
||||||
{
|
{
|
||||||
POP_FIXNUMS(x,y)
|
drepl(tag_bignum(fixnum_to_bignum(
|
||||||
drepl(allot_integer(x - y));
|
untag_fixnum_fast(x) - untag_fixnum_fast(y))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Multiply two integers, and trap overflow.
|
F_FASTCALL void overflow_fixnum_multiply(F_FIXNUM x, F_FIXNUM y)
|
||||||
Thanks to David Blaikie (The_Vulture from freenode #java) for the hint. */
|
|
||||||
void primitive_fixnum_multiply(void)
|
|
||||||
{
|
|
||||||
POP_FIXNUMS(x,y)
|
|
||||||
|
|
||||||
if(x == 0 || y == 0)
|
|
||||||
drepl(tag_fixnum(0));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
F_FIXNUM prod = x * y;
|
|
||||||
/* if this is not equal, we have overflow */
|
|
||||||
if(prod / x == y)
|
|
||||||
drepl(allot_integer(prod));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
F_ARRAY *bx = fixnum_to_bignum(x);
|
F_ARRAY *bx = fixnum_to_bignum(x);
|
||||||
REGISTER_BIGNUM(bx);
|
REGISTER_BIGNUM(bx);
|
||||||
|
@ -69,12 +52,13 @@ void primitive_fixnum_multiply(void)
|
||||||
UNREGISTER_BIGNUM(bx);
|
UNREGISTER_BIGNUM(bx);
|
||||||
drepl(tag_bignum(bignum_multiply(bx,by)));
|
drepl(tag_bignum(bignum_multiply(bx,by)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Division can only overflow when we are dividing the most negative fixnum
|
||||||
|
by -1. */
|
||||||
void primitive_fixnum_divint(void)
|
void primitive_fixnum_divint(void)
|
||||||
{
|
{
|
||||||
POP_FIXNUMS(x,y)
|
F_FIXNUM y = untag_fixnum_fast(dpop()); \
|
||||||
|
F_FIXNUM x = untag_fixnum_fast(dpeek());
|
||||||
F_FIXNUM result = x / y;
|
F_FIXNUM result = x / y;
|
||||||
if(result == -FIXNUM_MIN)
|
if(result == -FIXNUM_MIN)
|
||||||
drepl(allot_integer(-FIXNUM_MIN));
|
drepl(allot_integer(-FIXNUM_MIN));
|
||||||
|
@ -99,31 +83,30 @@ void primitive_fixnum_divmod(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note the hairy overflow check.
|
|
||||||
* If we're shifting right by n bits, we won't overflow as long as none of the
|
* If we're shifting right by n bits, we won't overflow as long as none of the
|
||||||
* high WORD_SIZE-TAG_BITS-n bits are set.
|
* high WORD_SIZE-TAG_BITS-n bits are set.
|
||||||
*/
|
*/
|
||||||
|
#define SIGN_MASK(x) ((x) >> (CELLS * 8 - 1))
|
||||||
|
#define BRANCHLESS_MAX(x,y) (x - ((x - y) & SIGN_MASK(x - y)))
|
||||||
|
#define BRANCHLESS_ABS(x) ((x ^ SIGN_MASK(x)) - SIGN_MASK(x))
|
||||||
|
|
||||||
void primitive_fixnum_shift(void)
|
void primitive_fixnum_shift(void)
|
||||||
{
|
{
|
||||||
POP_FIXNUMS(x,y)
|
F_FIXNUM y = untag_fixnum_fast(dpop()); \
|
||||||
|
F_FIXNUM x = untag_fixnum_fast(dpeek());
|
||||||
|
|
||||||
if(x == 0 || y == 0)
|
if(x == 0)
|
||||||
{
|
|
||||||
drepl(tag_fixnum(x));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
else if(y < 0)
|
else if(y < 0)
|
||||||
{
|
{
|
||||||
if(y <= -WORD_SIZE)
|
y = BRANCHLESS_MAX(y,-WORD_SIZE + 1);
|
||||||
drepl(x < 0 ? tag_fixnum(-1) : tag_fixnum(0));
|
|
||||||
else
|
|
||||||
drepl(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)
|
||||||
{
|
{
|
||||||
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(!(BRANCHLESS_ABS(x) & mask))
|
||||||
{
|
{
|
||||||
drepl(tag_fixnum(x << y));
|
drepl(tag_fixnum(x << y));
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue