2005-01-06 21:42:07 -05:00
|
|
|
! Copyright (C) 2005 Slava Pestov.
|
2005-05-07 22:39:00 -04:00
|
|
|
! 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-07 22:39:00 -04:00
|
|
|
|
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 -- )
|
2005-05-07 22:39:00 -04:00
|
|
|
#! 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
|
2005-05-07 22:39:00 -04:00
|
|
|
<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.
|
2005-05-07 22:39:00 -04:00
|
|
|
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
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum+ generate-node ( vop -- )
|
2005-05-10 00:09:16 -04:00
|
|
|
dest/src 2dup ADD \ SUB \ ADD simple-overflow ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum- generate-node ( vop -- )
|
2005-05-10 00:09:16 -04:00
|
|
|
dest/src 2dup SUB \ ADD \ SUB simple-overflow ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum* generate-node ( vop -- )
|
2005-01-06 23:16:13 -05:00
|
|
|
drop
|
2005-05-07 22:39:00 -04:00
|
|
|
! 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
|
2005-05-07 22:39:00 -04:00
|
|
|
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
|
2005-05-07 22:39:00 -04:00
|
|
|
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
|
2005-05-07 22:39:00 -04:00
|
|
|
! 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
|
2005-05-07 22:39:00 -04:00
|
|
|
! 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
|
2005-05-07 22:39:00 -04:00
|
|
|
! 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
|
|
|
|
2005-05-24 01:26:45 -04:00
|
|
|
: load-boolean ( dest cond -- )
|
2005-05-07 22:39:00 -04:00
|
|
|
#! 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 ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum< generate-node ( vop -- )
|
2005-05-24 01:26:45 -04:00
|
|
|
fixnum-compare \ JL load-boolean ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum<= generate-node ( vop -- )
|
2005-05-24 01:26:45 -04:00
|
|
|
fixnum-compare \ JLE load-boolean ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum> generate-node ( vop -- )
|
2005-05-24 01:26:45 -04:00
|
|
|
fixnum-compare \ JG load-boolean ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %fixnum>= generate-node ( vop -- )
|
2005-05-24 01:26:45 -04:00
|
|
|
fixnum-compare \ JGE load-boolean ;
|
2005-05-07 22:39:00 -04:00
|
|
|
|
|
|
|
M: %eq? generate-node ( vop -- )
|
2005-05-24 01:26:45 -04:00
|
|
|
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 ;
|