factor/basis/cpu/x86/intrinsics/intrinsics.factor

466 lines
12 KiB
Factor
Raw Normal View History

2008-01-12 23:50:22 -05:00
! Copyright (C) 2005, 2008 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.accessors arrays cpu.x86.assembler
2008-02-01 00:00:08 -05:00
cpu.x86.allot cpu.x86.architecture cpu.architecture kernel
kernel.private math math.private namespaces quotations sequences
2007-09-20 18:09:08 -04:00
words generic byte-arrays hashtables hashtables.private
sequences.private sbufs sbufs.private
2008-08-12 04:31:48 -04:00
vectors vectors.private layouts system strings.private
slots.private
compiler.constants
compiler.intrinsics
compiler.generator
compiler.generator.fixup
compiler.generator.registers ;
2007-09-20 18:09:08 -04:00
IN: cpu.x86.intrinsics
! Type checks
\ tag [
"in" operand tag-mask get AND
"in" operand %tag-fixnum
] H{
{ +input+ { { f "in" } } }
{ +output+ { "in" } }
} define-intrinsic
! Slots
2008-06-08 16:32:55 -04:00
: %slot-literal-known-tag ( -- op )
2007-09-22 19:31:28 -04:00
"obj" operand
"n" get cells
"obj" get operand-tag - [+] ;
2007-09-22 19:31:28 -04:00
2008-06-08 16:32:55 -04:00
: %slot-literal-any-tag ( -- op )
2007-09-22 19:31:28 -04:00
"obj" operand %untag
"obj" operand "n" get cells [+] ;
2008-06-08 16:32:55 -04:00
: %slot-any ( -- op )
2007-09-22 19:31:28 -04:00
"obj" operand %untag
"n" operand fixnum>slot@
"obj" operand "n" operand [+] ;
2007-09-20 18:09:08 -04:00
\ slot {
2007-09-22 19:31:28 -04:00
! Slot number is literal and the tag is known
{
2007-09-30 00:34:19 -04:00
[ "val" operand %slot-literal-known-tag MOV ] H{
2007-09-22 19:31:28 -04:00
{ +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
2007-09-30 00:34:19 -04:00
{ +scratch+ { { f "val" } } }
{ +output+ { "val" } }
2007-09-22 19:31:28 -04:00
}
}
2007-09-20 18:09:08 -04:00
! Slot number is literal
{
2007-09-22 19:31:28 -04:00
[ "obj" operand %slot-literal-any-tag MOV ] H{
2007-09-20 18:09:08 -04:00
{ +input+ { { f "obj" } { [ small-slot? ] "n" } } }
{ +output+ { "obj" } }
}
}
! Slot number in a register
{
2007-09-22 19:31:28 -04:00
[ "obj" operand %slot-any MOV ] H{
2007-09-20 18:09:08 -04:00
{ +input+ { { f "obj" } { f "n" } } }
{ +output+ { "obj" } }
{ +clobber+ { "n" } }
}
}
} define-intrinsics
: generate-write-barrier ( -- )
#! Mark the card pointed to by vreg.
"val" get operand-immediate? "obj" get fresh-object? or [
2008-05-07 22:39:20 -04:00
! Mark the card
2007-09-20 18:09:08 -04:00
"obj" operand card-bits SHR
2007-09-30 00:34:19 -04:00
"cards_offset" f temp-reg v>operand %alien-global
2008-05-09 00:21:46 -04:00
temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
2008-05-07 22:39:20 -04:00
! Mark the card deck
"obj" operand deck-bits card-bits - SHR
"decks_offset" f temp-reg v>operand %alien-global
temp-reg v>operand "obj" operand [+] card-mark <byte> MOV
2007-09-20 18:09:08 -04:00
] unless ;
\ set-slot {
2007-09-22 19:31:28 -04:00
! Slot number is literal and the tag is known
{
2007-09-23 15:26:15 -04:00
[ %slot-literal-known-tag "val" operand MOV generate-write-barrier ] H{
2007-09-22 19:31:28 -04:00
{ +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
2008-06-30 04:57:00 -04:00
{ +clobber+ { "obj" } }
2007-09-22 19:31:28 -04:00
}
}
2007-09-20 18:09:08 -04:00
! Slot number is literal
{
2007-09-22 19:31:28 -04:00
[ %slot-literal-any-tag "val" operand MOV generate-write-barrier ] H{
2007-09-20 18:09:08 -04:00
{ +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
2008-06-30 04:57:00 -04:00
{ +clobber+ { "obj" } }
2007-09-20 18:09:08 -04:00
}
}
! Slot number in a register
{
2007-09-22 19:31:28 -04:00
[ %slot-any "val" operand MOV generate-write-barrier ] H{
2007-09-20 18:09:08 -04:00
{ +input+ { { f "val" } { f "obj" } { f "n" } } }
2008-07-04 19:17:01 -04:00
{ +clobber+ { "obj" "n" } }
2007-09-20 18:09:08 -04:00
}
}
} define-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 = RBX EBX ? ; inline
: small-reg-8 BL ; inline
: small-reg-16 BX ; inline
: small-reg-32 EBX ; inline
! Fixnums
: fixnum-op ( op hash -- pair )
>r [ "x" operand "y" operand ] swap suffix r> 2array ;
2007-09-20 18:09:08 -04:00
: fixnum-value-op ( op -- pair )
H{
{ +input+ { { f "x" } { [ small-tagged? ] "y" } } }
{ +output+ { "x" } }
} fixnum-op ;
: fixnum-register-op ( op -- pair )
H{
{ +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
] H{
{ +input+ { { f "x" } } }
{ +output+ { "x" } }
} define-intrinsic
\ fixnum*fast {
{
[
"x" operand "y" get IMUL2
] H{
{ +input+ { { f "x" } { [ small-tagged? ] "y" } } }
{ +output+ { "x" } }
}
} {
[
"out" operand "x" operand MOV
"out" operand %untag-fixnum
"y" operand "out" operand IMUL2
] H{
{ +input+ { { f "x" } { f "y" } } }
{ +scratch+ { { f "out" } } }
{ +output+ { "out" } }
}
}
} define-intrinsics
: %untag-fixnums ( seq -- )
[ %untag-fixnum ] unique-operands ;
2008-01-12 23:50:22 -05:00
\ fixnum-shift-fast [
"x" operand "y" get
dup 0 < [ neg SAR ] [ SHL ] if
! Mask off low bits
"x" operand %untag
] H{
{ +input+ { { f "x" } { [ ] "y" } } }
{ +output+ { "x" } }
} define-intrinsic
2007-09-20 18:09:08 -04:00
: overflow-check ( word -- )
"end" define-label
"z" operand "x" operand MOV
"z" operand "y" operand pick execute
! If the previous arithmetic operation overflowed, then we
! turn the result into a bignum and leave it in EAX.
"end" get JNO
! There was an overflow. Recompute the original operand.
{ "y" "x" } %untag-fixnums
"x" operand "y" operand rot execute
"z" get "x" get %allot-bignum-signed-1
"end" resolve-label ; inline
: overflow-template ( word insn -- )
[ overflow-check ] curry H{
{ +input+ { { f "x" } { f "y" } } }
{ +scratch+ { { f "z" } } }
{ +output+ { "z" } }
{ +clobber+ { "x" "y" } }
} define-intrinsic ;
\ fixnum+ \ ADD overflow-template
\ fixnum- \ SUB overflow-template
: fixnum-jump ( op inputs -- pair )
>r [ "x" operand "y" operand CMP ] swap suffix r> 2array ;
2007-09-20 18:09:08 -04:00
: 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 ] keep fixnum-register-jump
2array define-if-intrinsics ;
{
2008-04-17 04:06:55 -04:00
{ fixnum< JGE }
{ fixnum<= JG }
{ fixnum> JLE }
{ fixnum>= JL }
{ eq? JNE }
2007-09-20 18:09:08 -04:00
} [
first2 define-fixnum-jump
] each
\ fixnum>bignum [
"x" operand %untag-fixnum
"x" get dup %allot-bignum-signed-1
] H{
{ +input+ { { f "x" } } }
{ +output+ { "x" } }
} define-intrinsic
\ 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 v>operand 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
] H{
{ +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
] H{
{ +input+ { { f "n" } } }
{ +scratch+ { { f "x" } } }
{ +output+ { "n" } }
} define-intrinsic
\ setenv [
%userenv "n" operand [] "val" operand MOV
] H{
{ +input+ { { f "val" } { f "n" } } }
{ +scratch+ { { f "x" } } }
{ +clobber+ { "n" } }
} define-intrinsic
\ (tuple) [
tuple "layout" get size>> 2 + cells [
! Store layout
"layout" get "scratch" get load-literal
1 object@ "scratch" operand MOV
! Store tagged ptr in reg
"tuple" get tuple %store-tagged
] %allot
] H{
{ +input+ { { [ ] "layout" } } }
{ +scratch+ { { f "tuple" } { f "scratch" } } }
{ +output+ { "tuple" } }
} define-intrinsic
\ (array) [
array "n" get 2 + cells [
! Store length
1 object@ "n" operand MOV
! Store tagged ptr in reg
"array" get object %store-tagged
] %allot
] H{
{ +input+ { { [ ] "n" } } }
{ +scratch+ { { f "array" } } }
{ +output+ { "array" } }
} define-intrinsic
\ (byte-array) [
byte-array "n" get 2 cells + [
! Store length
1 object@ "n" operand MOV
! Store tagged ptr in reg
"array" get object %store-tagged
] %allot
] H{
{ +input+ { { [ ] "n" } } }
{ +scratch+ { { f "array" } } }
{ +output+ { "array" } }
} define-intrinsic
2007-09-20 18:09:08 -04:00
\ <ratio> [
ratio 3 cells [
1 object@ "numerator" operand MOV
2 object@ "denominator" operand MOV
! Store tagged ptr in reg
"ratio" get ratio %store-tagged
] %allot
] H{
{ +input+ { { f "numerator" } { f "denominator" } } }
{ +scratch+ { { f "ratio" } } }
{ +output+ { "ratio" } }
} define-intrinsic
\ <complex> [
complex 3 cells [
1 object@ "real" operand MOV
2 object@ "imaginary" operand MOV
! Store tagged ptr in reg
"complex" get complex %store-tagged
] %allot
] H{
{ +input+ { { f "real" } { f "imaginary" } } }
{ +scratch+ { { f "complex" } } }
{ +output+ { "complex" } }
} define-intrinsic
\ <wrapper> [
wrapper 2 cells [
1 object@ "obj" operand MOV
! Store tagged ptr in reg
"wrapper" get object %store-tagged
] %allot
] H{
{ +input+ { { f "obj" } } }
{ +scratch+ { { f "wrapper" } } }
{ +output+ { "wrapper" } }
} define-intrinsic
! Alien intrinsics
: %alien-accessor ( quot -- )
2007-09-20 18:09:08 -04:00
"offset" operand %untag-fixnum
"offset" operand "alien" operand ADD
2007-09-30 00:34:19 -04:00
"offset" operand [] swap call ; inline
2007-09-20 18:09:08 -04:00
: %alien-integer-get ( quot reg -- )
2007-09-30 00:34:19 -04:00
small-reg PUSH
swap %alien-accessor
"value" operand small-reg MOV
"value" operand %tag-fixnum
small-reg POP ; inline
2007-09-20 18:09:08 -04:00
: alien-integer-get-template
H{
{ +input+ {
{ unboxed-c-ptr "alien" c-ptr }
2007-09-20 18:09:08 -04:00
{ f "offset" fixnum }
} }
{ +scratch+ { { f "value" } } }
{ +output+ { "value" } }
{ +clobber+ { "offset" } }
2007-09-20 18:09:08 -04:00
} ;
2008-06-08 16:32:55 -04:00
: define-getter ( word quot reg -- )
2007-09-20 18:09:08 -04:00
[ %alien-integer-get ] 2curry
alien-integer-get-template
define-intrinsic ;
2008-06-08 16:32:55 -04:00
: define-unsigned-getter ( word reg -- )
2007-09-20 18:09:08 -04:00
[ small-reg dup XOR MOV ] swap define-getter ;
2008-06-08 16:32:55 -04:00
: define-signed-getter ( word reg -- )
2007-09-20 18:09:08 -04:00
[ [ >r MOV small-reg r> MOVSX ] curry ] keep define-getter ;
: %alien-integer-set ( quot reg -- )
2007-09-30 00:34:19 -04:00
small-reg PUSH
small-reg "value" operand MOV
2008-08-29 01:26:47 -04:00
small-reg %untag-fixnum
2007-09-30 00:34:19 -04:00
swap %alien-accessor
small-reg POP ; inline
2007-09-20 18:09:08 -04:00
: alien-integer-set-template
H{
{ +input+ {
{ f "value" fixnum }
{ unboxed-c-ptr "alien" c-ptr }
2007-09-20 18:09:08 -04:00
{ f "offset" fixnum }
} }
{ +clobber+ { "value" "offset" } }
2007-09-20 18:09:08 -04:00
} ;
2008-06-08 16:32:55 -04:00
: define-setter ( word reg -- )
2007-09-20 18:09:08 -04:00
[ swap MOV ] swap
[ %alien-integer-set ] 2curry
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 [
2007-09-30 00:34:19 -04:00
"value" operand [ MOV ] %alien-accessor
] H{
{ +input+ {
{ unboxed-c-ptr "alien" c-ptr }
{ f "offset" fixnum }
} }
{ +scratch+ { { unboxed-alien "value" } } }
{ +output+ { "value" } }
{ +clobber+ { "offset" } }
2007-09-30 00:34:19 -04:00
} define-intrinsic
\ set-alien-cell [
2007-09-30 00:34:19 -04:00
"value" operand [ swap MOV ] %alien-accessor
] H{
{ +input+ {
{ unboxed-c-ptr "value" pinned-c-ptr }
{ unboxed-c-ptr "alien" c-ptr }
{ f "offset" fixnum }
} }
{ +clobber+ { "offset" } }
2007-09-30 00:34:19 -04:00
} define-intrinsic