factor/library/compiler/x86/fixnum.factor

130 lines
4.3 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.
IN: compiler
USING: arrays assembler errors kernel kernel-internals
2005-12-10 01:02:13 -05:00
math math-internals memory namespaces words ;
2005-12-06 20:42:17 -05:00
: literal-overflow ( -- dest src )
#! Called if the src operand is a literal.
#! Untag the dest operand.
dest/src over tag-bits SAR tag-bits neg shift ;
: computed-overflow ( -- dest src )
#! Called if the src operand is a register.
#! Untag both operands.
dest/src 2dup tag-bits SAR tag-bits SAR ;
: simple-overflow ( inverse 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.
<label> "end" set
"end" get JNO
2005-05-10 00:09:16 -04:00
! There was an overflow. Recompute the original operand.
2005-12-06 20:42:17 -05:00
>r >r dest/src r> execute
0 input integer? [ literal-overflow ] [ computed-overflow ] if
2005-05-10 00:09:16 -04:00
! Compute a result, this time it will fit.
2005-12-06 20:42:17 -05:00
r> execute
2005-05-10 00:09:16 -04:00
! Create a bignum.
2006-02-24 02:26:08 -05:00
"s48_long_to_bignum" f 0 output-operand
1array compile-c-call*
! An untagged pointer to the bignum is now in EAX; tag it
2005-12-24 16:08:15 -05:00
T{ int-regs } return-reg bignum-tag OR
2005-05-15 21:17:56 -04:00
"end" get save-xt ; inline
M: %fixnum+ generate-node ( vop -- )
2005-12-06 20:42:17 -05:00
drop dest/src ADD \ SUB \ ADD simple-overflow ;
M: %fixnum- generate-node ( vop -- )
2005-12-06 20:42:17 -05:00
drop dest/src 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.
2005-12-07 03:37:05 -05:00
1 input-operand tag-bits SAR
0 input-operand IMUL
<label> "end" set
"end" get JNO
2005-12-20 21:36:52 -05:00
"s48_fixnum_pair_to_bignum" f
2006-02-24 02:26:08 -05:00
1 input-operand remainder-reg 2array compile-c-call*
! now we have to shift it by three bits to remove the second
! tag
2005-12-10 01:02:13 -05:00
"s48_bignum_arithmetic_shift" f
2006-02-24 02:26:08 -05:00
1 input-operand tag-bits neg 2array compile-c-call*
! an untagged pointer to the bignum is now in EAX; tag it
2005-12-24 16:08:15 -05:00
T{ int-regs } return-reg bignum-tag OR
"end" get save-xt ;
M: %fixnum-mod generate-node ( vop -- )
#! This has specific register requirements. Inputs are in
2005-12-07 03:37:05 -05:00
#! ECX and EAX, and the result is in EDX.
2005-01-06 23:16:13 -05:00
drop
2005-12-07 03:37:05 -05:00
prepare-division
0 input-operand IDIV ;
: generate-fixnum/mod
#! The same code is used for %fixnum/i and %fixnum/mod.
#! This has specific register requirements. Inputs are in
2005-12-07 03:37:05 -05:00
#! ECX and EAX, and the result is in EDX.
<label> "end" set
2005-12-07 03:37:05 -05:00
prepare-division
0 input-operand IDIV
! Make a copy since following shift is destructive
2005-12-07 03:37:05 -05:00
0 input-operand 1 input-operand MOV
! Tag the value, since division cancelled tags from both
! inputs
2005-12-07 03:37:05 -05:00
1 input-operand 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.
2005-12-10 03:03:45 -05:00
remainder-reg PUSH
2005-12-10 01:02:13 -05:00
"s48_long_to_bignum" f
2006-02-24 02:26:08 -05:00
0 input-operand 1array compile-c-call*
! An untagged pointer to the bignum is now in EAX; tag it
2005-12-24 16:08:15 -05:00
T{ int-regs } return-reg bignum-tag OR
! the remainder is now in EDX
remainder-reg POP
"end" get save-xt ;
2005-12-06 20:42:17 -05:00
M: %fixnum/i generate-node drop generate-fixnum/mod ;
2005-12-06 20:42:17 -05:00
M: %fixnum/mod generate-node drop generate-fixnum/mod ;
2005-12-06 20:42:17 -05:00
M: %fixnum-bitand generate-node ( vop -- ) drop dest/src AND ;
2005-12-06 20:42:17 -05:00
M: %fixnum-bitor generate-node ( vop -- ) drop dest/src OR ;
2005-12-06 20:42:17 -05:00
M: %fixnum-bitxor generate-node ( vop -- ) drop dest/src XOR ;
M: %fixnum-bitnot generate-node ( vop -- )
2005-12-06 20:42:17 -05:00
drop
! Negate the bits of the operand
2005-12-06 20:42:17 -05:00
0 output-operand NOT
! Mask off the low 3 bits to give a fixnum tag
2005-12-06 20:42:17 -05:00
0 output-operand tag-mask XOR ;
2005-05-09 22:34:47 -04:00
M: %fixnum>> generate-node
2005-12-06 20:42:17 -05:00
drop
2005-05-09 22:34:47 -04:00
! shift register
2005-12-06 20:42:17 -05:00
0 output-operand 0 input SAR
2005-05-09 22:34:47 -04:00
! give it a fixnum tag
2005-12-06 20:42:17 -05:00
0 output-operand tag-mask bitnot AND ;
2005-05-09 22:34:47 -04:00
M: %fixnum-sgn generate-node
2005-12-06 21:34:18 -05:00
#! This has specific register requirements.
2005-12-06 20:42:17 -05:00
drop
2005-05-09 22:34:47 -04:00
! store 0 in EDX if EAX is >=0, otherwise store -1.
2005-12-07 03:37:05 -05:00
prepare-division
2005-05-09 22:34:47 -04:00
! give it a fixnum tag.
2005-12-06 20:42:17 -05:00
0 output-operand tag-bits SHL ;
2005-05-09 22:34:47 -04:00
2005-12-06 20:42:17 -05:00
: fixnum-jump ( -- label )
1 input-operand 0 input-operand CMP label ;
2005-05-09 02:34:15 -04:00
2005-12-06 20:42:17 -05:00
M: %jump-fixnum< generate-node ( vop -- ) drop fixnum-jump JL ;
M: %jump-fixnum<= generate-node ( vop -- ) drop fixnum-jump JLE ;
M: %jump-fixnum> generate-node ( vop -- ) drop fixnum-jump JG ;
M: %jump-fixnum>= generate-node ( vop -- ) drop fixnum-jump JGE ;
M: %jump-eq? generate-node ( vop -- ) drop fixnum-jump JE ;