329 lines
8.4 KiB
Factor
329 lines
8.4 KiB
Factor
! Copyright (C) 2005, 2008 Slava Pestov.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: accessors arrays byte-arrays alien.accessors kernel
|
|
kernel.private math memory namespaces make sequences words
|
|
system layouts combinators math.order math.private alien
|
|
alien.c-types slots.private locals fry cpu.architecture
|
|
cpu.x86.assembler cpu.x86.assembler.private cpu.x86.architecture
|
|
compiler.codegen.fixup compiler.constants compiler.intrinsics
|
|
compiler.cfg.builder compiler.cfg.registers compiler.cfg.stacks
|
|
compiler.cfg.templates compiler.codegen ;
|
|
IN: cpu.x86.intrinsics
|
|
|
|
! Type checks
|
|
\ tag [
|
|
"in" operand tag-mask get AND
|
|
"in" operand %tag-fixnum
|
|
] T{ template
|
|
{ input { { f "in" } } }
|
|
{ output { "in" } }
|
|
} define-intrinsic
|
|
|
|
! Slots
|
|
: %constant-slot ( -- op )
|
|
"obj" operand
|
|
"n" literal cells "tag" literal - [+] ;
|
|
|
|
: %computed-slot ( -- op )
|
|
"n" operand fixnum>slot@
|
|
"n" operand "obj" operand ADD
|
|
"n" operand "tag" literal neg [+] ;
|
|
|
|
\ (slot) {
|
|
{
|
|
[ "val" operand %constant-slot MOV ] T{ template
|
|
{ input { { f "obj" } { small-slot "n" } { small-slot "tag" } } }
|
|
{ scratch { { f "val" } } }
|
|
{ output { "val" } }
|
|
}
|
|
}
|
|
{
|
|
[ "val" operand %computed-slot MOV ] T{ template
|
|
{ input { { f "obj" } { f "n" } { small-slot "tag" } } }
|
|
{ scratch { { f "val" } } }
|
|
{ output { "val" } }
|
|
{ clobber { "n" } }
|
|
}
|
|
}
|
|
} define-intrinsics
|
|
|
|
\ (set-slot) {
|
|
{
|
|
[ %constant-slot "val" operand MOV ] T{ template
|
|
{ input { { f "val" } { f "obj" } { small-slot "n" } { small-slot "tag" } } }
|
|
}
|
|
}
|
|
{
|
|
[ %computed-slot "val" operand MOV ] T{ template
|
|
{ input { { f "val" } { f "obj" } { f "n" } { small-slot "tag" } } }
|
|
{ clobber { "n" } }
|
|
}
|
|
}
|
|
} define-intrinsics
|
|
|
|
! Fixnums
|
|
: fixnum-op ( op hash -- pair )
|
|
>r [ "x" operand "y" operand ] swap suffix r> 2array ;
|
|
|
|
: fixnum-value-op ( op -- pair )
|
|
T{ template
|
|
{ input { { f "x" } { small-tagged "y" } } }
|
|
{ output { "x" } }
|
|
} fixnum-op ;
|
|
|
|
: fixnum-register-op ( op -- pair )
|
|
T{ template
|
|
{ input { { f "x" } { f "y" } } }
|
|
{ output { "x" } }
|
|
} fixnum-op ;
|
|
|
|
: define-fixnum-op ( word op -- )
|
|
[ fixnum-value-op ] keep fixnum-register-op
|
|
2array define-intrinsics ;
|
|
|
|
{
|
|
{ fixnum+fast ADD }
|
|
{ fixnum-fast SUB }
|
|
{ fixnum-bitand AND }
|
|
{ fixnum-bitor OR }
|
|
{ fixnum-bitxor XOR }
|
|
} [
|
|
first2 define-fixnum-op
|
|
] each
|
|
|
|
\ fixnum-bitnot [
|
|
"x" operand NOT
|
|
"x" operand tag-mask get XOR
|
|
] T{ template
|
|
{ input { { f "x" } } }
|
|
{ output { "x" } }
|
|
} define-intrinsic
|
|
|
|
\ fixnum*fast {
|
|
{
|
|
[
|
|
"x" operand "y" literal IMUL2
|
|
] T{ template
|
|
{ input { { f "x" } { small-tagged "y" } } }
|
|
{ output { "x" } }
|
|
}
|
|
} {
|
|
[
|
|
"out" operand "x" operand MOV
|
|
"out" operand %untag-fixnum
|
|
"y" operand "out" operand IMUL2
|
|
] T{ template
|
|
{ input { { f "x" } { f "y" } } }
|
|
{ scratch { { f "out" } } }
|
|
{ output { "out" } }
|
|
}
|
|
}
|
|
} define-intrinsics
|
|
|
|
\ fixnum-shift-fast [
|
|
"x" operand "y" literal
|
|
dup 0 < [ neg SAR ] [ SHL ] if
|
|
! Mask off low bits
|
|
"x" operand %untag
|
|
] T{ template
|
|
{ input { { f "x" } { small-tagged "y" } } }
|
|
{ output { "x" } }
|
|
} define-intrinsic
|
|
|
|
: fixnum-jump ( op inputs -- pair )
|
|
>r [ "x" operand "y" operand CMP ] swap suffix r> 2array ;
|
|
|
|
: fixnum-value-jump ( op -- pair )
|
|
{ { f "x" } { small-tagged "y" } } fixnum-jump ;
|
|
|
|
: fixnum-register-jump ( op -- pair )
|
|
{ { f "x" } { f "y" } } fixnum-jump ;
|
|
|
|
: define-fixnum-jump ( word op -- )
|
|
[ fixnum-value-jump ] [ fixnum-register-jump ] bi
|
|
2array define-if-intrinsics ;
|
|
|
|
{
|
|
{ fixnum< JL }
|
|
{ fixnum<= JLE }
|
|
{ fixnum> JG }
|
|
{ fixnum>= JGE }
|
|
{ eq? JE }
|
|
} [
|
|
first2 define-fixnum-jump
|
|
] each
|
|
|
|
\ bignum>fixnum [
|
|
"nonzero" define-label
|
|
"positive" define-label
|
|
"end" define-label
|
|
"x" operand %untag
|
|
"y" operand "x" operand cell [+] MOV
|
|
! if the length is 1, its just the sign and nothing else,
|
|
! so output 0
|
|
"y" operand 1 tag-fixnum CMP
|
|
"nonzero" get JNE
|
|
"y" operand 0 MOV
|
|
"end" get JMP
|
|
"nonzero" resolve-label
|
|
! load the value
|
|
"y" operand "x" operand 3 cells [+] MOV
|
|
! load the sign
|
|
"x" operand "x" operand 2 cells [+] MOV
|
|
! is the sign negative?
|
|
"x" operand 0 CMP
|
|
"positive" get JE
|
|
"y" operand -1 IMUL2
|
|
"positive" resolve-label
|
|
"y" operand 3 SHL
|
|
"end" resolve-label
|
|
] T{ template
|
|
{ input { { f "x" } } }
|
|
{ scratch { { f "y" } } }
|
|
{ clobber { "x" } }
|
|
{ output { "y" } }
|
|
} define-intrinsic
|
|
|
|
! User environment
|
|
: %userenv ( -- )
|
|
"x" operand 0 MOV
|
|
"userenv" f rc-absolute-cell rel-dlsym
|
|
"n" operand fixnum>slot@
|
|
"n" operand "x" operand ADD ;
|
|
|
|
\ getenv [
|
|
%userenv "n" operand dup [] MOV
|
|
] T{ template
|
|
{ input { { f "n" } } }
|
|
{ scratch { { f "x" } } }
|
|
{ output { "n" } }
|
|
} define-intrinsic
|
|
|
|
\ setenv [
|
|
%userenv "n" operand [] "val" operand MOV
|
|
] T{ template
|
|
{ input { { f "val" } { f "n" } } }
|
|
{ scratch { { f "x" } } }
|
|
{ clobber { "n" } }
|
|
} define-intrinsic
|
|
|
|
! Alien intrinsics
|
|
|
|
! Sometimes, we need to do stuff with operands which are
|
|
! less than the word size. Instead of teaching the register
|
|
! allocator about the different sized registers, with all
|
|
! the complexity this entails, we just push/pop a register
|
|
! which is guaranteed to be unused (the tempreg)
|
|
: small-reg cell 8 = RDX EDX ? ; inline
|
|
: small-reg-8 DL ; inline
|
|
: small-reg-16 DX ; inline
|
|
: small-reg-32 EDX ; inline
|
|
|
|
: %prepare-alien-accessor ( -- )
|
|
"offset" operand %untag-fixnum
|
|
"offset" operand "alien" operand ADD ;
|
|
|
|
:: (%alien-integer-get) ( reg quot -- )
|
|
reg "offset" operand [] MOV
|
|
"value" operand reg quot call ; inline
|
|
|
|
: %alien-integer-get ( reg quot -- )
|
|
%prepare-alien-accessor
|
|
"value" operand small-reg = [
|
|
(%alien-integer-get)
|
|
] [
|
|
small-reg PUSH
|
|
(%alien-integer-get)
|
|
small-reg POP
|
|
] if
|
|
"value" operand %tag-fixnum ; inline
|
|
|
|
: alien-integer-get-template
|
|
T{ template
|
|
{ input {
|
|
{ unboxed-c-ptr "alien" c-ptr }
|
|
{ f "offset" fixnum }
|
|
} }
|
|
{ scratch { { f "value" } } }
|
|
{ output { "value" } }
|
|
{ clobber { "offset" } }
|
|
} ;
|
|
|
|
: define-getter ( word reg quot -- )
|
|
'[ _ _ %alien-integer-get ]
|
|
alien-integer-get-template
|
|
define-intrinsic ;
|
|
|
|
: define-unsigned-getter ( word reg -- )
|
|
[ MOVZX ] define-getter ;
|
|
|
|
: define-signed-getter ( word reg -- )
|
|
[ MOVSX ] define-getter ;
|
|
|
|
: %alien-integer-set ( reg -- )
|
|
"value" operand "offset" operand = [
|
|
"value" operand %untag-fixnum
|
|
] unless
|
|
%prepare-alien-accessor
|
|
small-reg "offset" operand = [
|
|
"value" operand "offset" operand XCHG
|
|
"value" operand [] swap MOV
|
|
] [
|
|
small-reg PUSH
|
|
small-reg "value" operand MOV
|
|
"offset" operand [] swap MOV
|
|
small-reg POP
|
|
] if ; inline
|
|
|
|
: alien-integer-set-template
|
|
T{ template
|
|
{ input {
|
|
{ f "value" fixnum }
|
|
{ unboxed-c-ptr "alien" c-ptr }
|
|
{ f "offset" fixnum }
|
|
} }
|
|
{ clobber { "value" "offset" } }
|
|
} ;
|
|
|
|
: define-setter ( word reg -- )
|
|
'[ _ %alien-integer-set ]
|
|
alien-integer-set-template
|
|
define-intrinsic ;
|
|
|
|
\ alien-unsigned-1 small-reg-8 define-unsigned-getter
|
|
\ set-alien-unsigned-1 small-reg-8 define-setter
|
|
|
|
\ alien-signed-1 small-reg-8 define-signed-getter
|
|
\ set-alien-signed-1 small-reg-8 define-setter
|
|
|
|
\ alien-unsigned-2 small-reg-16 define-unsigned-getter
|
|
\ set-alien-unsigned-2 small-reg-16 define-setter
|
|
|
|
\ alien-signed-2 small-reg-16 define-signed-getter
|
|
\ set-alien-signed-2 small-reg-16 define-setter
|
|
|
|
\ alien-cell [
|
|
%prepare-alien-accessor
|
|
"value" operand "offset" operand [] MOV
|
|
] T{ template
|
|
{ input {
|
|
{ unboxed-c-ptr "alien" c-ptr }
|
|
{ f "offset" fixnum }
|
|
} }
|
|
{ scratch { { unboxed-alien "value" } } }
|
|
{ output { "value" } }
|
|
{ clobber { "offset" } }
|
|
} define-intrinsic
|
|
|
|
\ set-alien-cell [
|
|
%prepare-alien-accessor
|
|
"offset" operand [] "value" operand MOV
|
|
] T{ template
|
|
{ input {
|
|
{ unboxed-c-ptr "value" pinned-c-ptr }
|
|
{ unboxed-c-ptr "alien" c-ptr }
|
|
{ f "offset" fixnum }
|
|
} }
|
|
{ clobber { "offset" } }
|
|
} define-intrinsic
|