factor/library/compiler/x86/fixnum.factor

208 lines
5.5 KiB
Factor
Raw Normal View History

2005-01-06 21:42:07 -05:00
! Copyright (C) 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
2005-05-09 02:34:15 -04:00
IN: compiler-backend
USING: assembler compiler errors kernel math math-internals
memory namespaces words ;
2005-05-10 00:09:16 -04:00
: literal-overflow
#! If the src operand is a literal.
! Untag the operand.
over tag-bits SAR
tag-bits neg shift ;
: computed-overflow
#! If the src operand is a register.
! Untag both operands.
2dup tag-bits SAR tag-bits SAR ;
: simple-overflow ( dest src inv word -- )
#! If the previous arithmetic operation overflowed, then we
2005-05-10 00:09:16 -04:00
#! turn the result into a bignum and leave it in EAX.
>r >r
<label> "end" set
"end" get JNO
2005-05-10 00:09:16 -04:00
! There was an overflow. Recompute the original operand.
2dup r> execute
dup integer? [
literal-overflow
] [
computed-overflow
] ifte
! Compute a result, this time it will fit.
dupd r> execute
! Create a bignum.
PUSH
"s48_long_to_bignum" f compile-c-call
! An untagged pointer to the bignum is now in EAX; tag it
EAX bignum-tag OR
ESP 4 ADD
2005-05-15 21:17:56 -04:00
"end" get save-xt ; inline
M: %fixnum+ generate-node ( vop -- )
2005-05-10 00:09:16 -04:00
dest/src 2dup ADD \ SUB \ ADD simple-overflow ;
M: %fixnum- generate-node ( vop -- )
2005-05-10 00:09:16 -04:00
dest/src 2dup SUB \ ADD \ SUB simple-overflow ;
M: %fixnum* generate-node ( vop -- )
2005-01-06 23:16:13 -05:00
drop
! both inputs are tagged, so one of them needs to have its
! tag removed.
EAX tag-bits SAR
ECX IMUL
<label> "end" set
"end" get JNO
EDX PUSH
EAX PUSH
"s48_long_long_to_bignum" f compile-c-call
ESP 8 ADD
! now we have to shift it by three bits to remove the second
! tag
tag-bits neg PUSH
EAX PUSH
"s48_bignum_arithmetic_shift" f compile-c-call
! an untagged pointer to the bignum is now in EAX; tag it
EAX bignum-tag OR
ESP 8 ADD
"end" get save-xt ;
M: %fixnum-mod generate-node ( vop -- )
#! This has specific register requirements. Inputs are in
#! EAX and ECX, and the result is in EDX.
2005-01-06 23:16:13 -05:00
drop
CDQ
ECX IDIV ;
: generate-fixnum/mod
#! The same code is used for %fixnum/i and %fixnum/mod.
#! This has specific register requirements. Inputs are in
#! EAX and ECX, and the result is in EDX.
<label> "end" set
2005-01-06 23:16:13 -05:00
drop
CDQ
ECX IDIV
! Make a copy since following shift is destructive
ECX EAX MOV
! Tag the value, since division cancelled tags from both
! inputs
2005-05-09 22:34:47 -04:00
EAX tag-bits SHL
! Did it overflow?
"end" get JNO
! There was an overflow, so make ECX into a bignum. we must
! save EDX since its volatile.
EDX PUSH
ECX PUSH
"s48_long_to_bignum" f compile-c-call
! An untagged pointer to the bignum is now in EAX; tag it
EAX bignum-tag OR
2005-05-09 22:34:47 -04:00
ESP cell ADD
! the remainder is now in EDX
EDX POP
"end" get save-xt ;
M: %fixnum/i generate-node generate-fixnum/mod ;
M: %fixnum/mod generate-node generate-fixnum/mod ;
M: %fixnum-bitand generate-node ( vop -- ) dest/src AND ;
M: %fixnum-bitor generate-node ( vop -- ) dest/src OR ;
M: %fixnum-bitxor generate-node ( vop -- ) dest/src XOR ;
M: %fixnum-bitnot generate-node ( vop -- )
! Negate the bits of the operand
2005-05-16 17:01:39 -04:00
vop-out-1 v>operand dup NOT
! Mask off the low 3 bits to give a fixnum tag
tag-mask XOR ;
2005-05-09 22:34:47 -04:00
M: %fixnum<< generate-node
! This has specific register requirements.
<label> "no-overflow" set
<label> "end" set
! make a copy
ECX EAX MOV
2005-05-16 17:01:39 -04:00
vop-in-1
2005-05-09 22:34:47 -04:00
! check for potential overflow
1 over cell 8 * swap 1 - - shift ECX over ADD
2 * 1 - ECX swap CMP
! is there going to be an overflow?
"no-overflow" get JBE
! there is going to be an overflow, make a bignum
EAX tag-bits SAR
dup ( n) PUSH
EAX PUSH
"s48_long_to_bignum" f compile-c-call
EDX POP
EAX PUSH
"s48_bignum_arithmetic_shift" f compile-c-call
! tag the result
EAX bignum-tag OR
ESP cell 2 * ADD
"end" get JMP
! there is not going to be an overflow
"no-overflow" get save-xt
EAX swap SHL
"end" get save-xt ;
M: %fixnum>> generate-node
! shift register
2005-05-16 17:01:39 -04:00
dup vop-out-1 v>operand dup rot vop-in-1 SAR
2005-05-09 22:34:47 -04:00
! give it a fixnum tag
tag-mask bitnot AND ;
M: %fixnum-sgn generate-node
! store 0 in EDX if EAX is >=0, otherwise store -1.
CDQ
! give it a fixnum tag.
2005-05-16 17:01:39 -04:00
vop-out-1 v>operand tag-bits SHL ;
2005-05-09 22:34:47 -04:00
: load-boolean ( dest cond -- )
#! Compile this after a conditional jump to store f or t
#! in dest depending on the jump being taken or not.
<label> "true" set
<label> "end" set
"true" get swap execute
dup f address MOV
"end" get JMP
"true" get save-xt
t load-indirect
"end" get save-xt ; inline
: fixnum-compare ( vop -- dest )
2005-05-16 17:01:39 -04:00
dup vop-out-1 v>operand dup rot vop-in-1 v>operand CMP ;
M: %fixnum< generate-node ( vop -- )
fixnum-compare \ JL load-boolean ;
M: %fixnum<= generate-node ( vop -- )
fixnum-compare \ JLE load-boolean ;
M: %fixnum> generate-node ( vop -- )
fixnum-compare \ JG load-boolean ;
M: %fixnum>= generate-node ( vop -- )
fixnum-compare \ JGE load-boolean ;
M: %eq? generate-node ( vop -- )
fixnum-compare \ JE load-boolean ;
2005-05-09 02:34:15 -04:00
: fixnum-branch ( vop -- label )
2005-05-16 17:01:39 -04:00
dup vop-in-2 v>operand over vop-in-1 v>operand CMP
2005-05-09 02:34:15 -04:00
vop-label ;
M: %jump-fixnum< generate-node ( vop -- )
fixnum-branch JL ;
M: %jump-fixnum<= generate-node ( vop -- )
fixnum-branch JLE ;
M: %jump-fixnum> generate-node ( vop -- )
fixnum-branch JG ;
M: %jump-fixnum>= generate-node ( vop -- )
fixnum-branch JGE ;
M: %jump-eq? generate-node ( vop -- )
fixnum-branch JE ;