463 lines
12 KiB
Factor
463 lines
12 KiB
Factor
|
! Copyright (C) 2007 Slava Pestov.
|
||
|
! See http://factorcode.org/license.txt for BSD license.
|
||
|
USING: alien arrays cpu.architecture cpu.arm.assembler
|
||
|
cpu.arm.architecture cpu.arm.allot kernel kernel.private math
|
||
|
math.private namespaces sequences words
|
||
|
quotations byte-arrays hashtables.private hashtables generator
|
||
|
generator.registers generator.fixup sequences.private sbufs
|
||
|
sbufs.private vectors vectors.private system
|
||
|
classes.tuple.private layouts strings.private slots.private ;
|
||
|
IN: cpu.arm.intrinsics
|
||
|
|
||
|
: %slot-literal-known-tag
|
||
|
"val" operand
|
||
|
"obj" operand
|
||
|
"n" get cells
|
||
|
"obj" get operand-tag - <+/-> ;
|
||
|
|
||
|
: %slot-literal-any-tag
|
||
|
"scratch" operand "obj" operand %untag
|
||
|
"val" operand "scratch" operand "n" get cells <+> ;
|
||
|
|
||
|
: %slot-any
|
||
|
"scratch" operand "obj" operand %untag
|
||
|
"n" operand dup 1 <LSR> MOV
|
||
|
"val" operand "scratch" operand "n" operand <+> ;
|
||
|
|
||
|
\ slot {
|
||
|
! Slot number is literal and the tag is known
|
||
|
{
|
||
|
[ %slot-literal-known-tag LDR ] H{
|
||
|
{ +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
|
||
|
{ +scratch+ { { f "val" } } }
|
||
|
{ +output+ { "val" } }
|
||
|
}
|
||
|
}
|
||
|
! Slot number is literal
|
||
|
{
|
||
|
[ %slot-literal-any-tag LDR ] H{
|
||
|
{ +input+ { { f "obj" } { [ small-slot? ] "n" } } }
|
||
|
{ +scratch+ { { f "scratch" } { f "val" } } }
|
||
|
{ +output+ { "val" } }
|
||
|
}
|
||
|
}
|
||
|
! Slot number in a register
|
||
|
{
|
||
|
[ %slot-any LDR ] H{
|
||
|
{ +input+ { { f "obj" } { f "n" } } }
|
||
|
{ +scratch+ { { f "val" } { f "scratch" } } }
|
||
|
{ +output+ { "val" } }
|
||
|
{ +clobber+ { "n" } }
|
||
|
}
|
||
|
}
|
||
|
} define-intrinsics
|
||
|
|
||
|
: %write-barrier ( -- )
|
||
|
"val" get operand-immediate? "obj" get fresh-object? or [
|
||
|
"cards_offset" f R12 %alien-global
|
||
|
"scratch" operand R12 "obj" operand card-bits <LSR> ADD
|
||
|
"val" operand "scratch" operand 0 <+> LDRB
|
||
|
"val" operand dup card-mark ORR
|
||
|
"val" operand "scratch" operand 0 <+> STRB
|
||
|
] unless ;
|
||
|
|
||
|
\ set-slot {
|
||
|
! Slot number is literal and tag is known
|
||
|
{
|
||
|
[ %slot-literal-known-tag STR %write-barrier ] H{
|
||
|
{ +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
|
||
|
{ +scratch+ { { f "scratch" } } }
|
||
|
{ +clobber+ { "val" } }
|
||
|
}
|
||
|
}
|
||
|
! Slot number is literal
|
||
|
{
|
||
|
[ %slot-literal-any-tag STR %write-barrier ] H{
|
||
|
{ +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
|
||
|
{ +scratch+ { { f "scratch" } } }
|
||
|
{ +clobber+ { "val" } }
|
||
|
}
|
||
|
}
|
||
|
! Slot number is in a register
|
||
|
{
|
||
|
[ %slot-any STR %write-barrier ] H{
|
||
|
{ +input+ { { f "val" } { f "obj" } { f "n" } } }
|
||
|
{ +scratch+ { { f "scratch" } } }
|
||
|
{ +clobber+ { "val" "n" } }
|
||
|
}
|
||
|
}
|
||
|
} define-intrinsics
|
||
|
|
||
|
: fixnum-op ( op -- quot )
|
||
|
[ "out" operand "x" operand "y" operand ] swap add ;
|
||
|
|
||
|
: fixnum-register-op ( op -- pair )
|
||
|
fixnum-op H{
|
||
|
{ +input+ { { f "x" } { f "y" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} 2array ;
|
||
|
|
||
|
: fixnum-value-op ( op -- pair )
|
||
|
fixnum-op H{
|
||
|
{ +input+ { { f "x" } { [ small-tagged? ] "y" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} 2array ;
|
||
|
|
||
|
: 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 ORR }
|
||
|
{ fixnum-bitxor EOR }
|
||
|
} [
|
||
|
first2 define-fixnum-op
|
||
|
] each
|
||
|
|
||
|
\ fixnum-bitnot [
|
||
|
"x" operand dup MVN
|
||
|
"x" operand dup %untag
|
||
|
] H{
|
||
|
{ +input+ { { f "x" } } }
|
||
|
{ +output+ { "x" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ fixnum*fast [
|
||
|
"out" operand "y" operand %untag-fixnum
|
||
|
"out" operand "x" operand "out" operand MUL
|
||
|
] H{
|
||
|
{ +input+ { { f "x" } { f "y" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ fixnum-shift [
|
||
|
"out" operand "x" operand "y" get neg <ASR> MOV
|
||
|
! Mask off low bits
|
||
|
"out" operand dup %untag
|
||
|
] H{
|
||
|
{ +input+ { { f "x" } { [ -31 0 between? ] "y" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
: %untag-fixnums ( seq -- )
|
||
|
[ dup %untag-fixnum ] unique-operands ;
|
||
|
|
||
|
: overflow-check ( insn -- )
|
||
|
[
|
||
|
"end" define-label
|
||
|
[ "out" operand "x" operand "y" operand roll S execute ] keep
|
||
|
"end" get VC B
|
||
|
{ "x" "y" } %untag-fixnums
|
||
|
"x" operand "x" operand "y" operand roll execute
|
||
|
"out" get "x" get %allot-bignum-signed-1
|
||
|
"end" resolve-label
|
||
|
] with-scope ; inline
|
||
|
|
||
|
: overflow-template ( word insn -- )
|
||
|
[ overflow-check ] curry H{
|
||
|
{ +input+ { { f "x" } { f "y" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
{ +clobber+ { "x" "y" } }
|
||
|
} define-intrinsic ;
|
||
|
|
||
|
\ fixnum+ \ ADD overflow-template
|
||
|
\ fixnum- \ SUB overflow-template
|
||
|
|
||
|
\ fixnum>bignum [
|
||
|
"x" operand dup %untag-fixnum
|
||
|
"out" get "x" get %allot-bignum-signed-1
|
||
|
] H{
|
||
|
{ +input+ { { f "x" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +clobber+ { "x" } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ bignum>fixnum [
|
||
|
"end" define-label
|
||
|
"x" operand dup %untag
|
||
|
"y" operand "x" operand cell <+> LDR
|
||
|
! if the length is 1, its just the sign and nothing else,
|
||
|
! so output 0
|
||
|
"y" operand 1 v>operand CMP
|
||
|
"y" operand 0 EQ MOV
|
||
|
"end" get EQ B
|
||
|
! load the value
|
||
|
"y" operand "x" operand 3 cells <+> LDR
|
||
|
! load the sign
|
||
|
"x" operand "x" operand 2 cells <+> LDR
|
||
|
! is the sign negative?
|
||
|
"x" operand 0 CMP
|
||
|
! Negate the value
|
||
|
"y" operand "y" operand 0 NE RSB
|
||
|
"y" operand dup %tag-fixnum
|
||
|
"end" resolve-label
|
||
|
] H{
|
||
|
{ +input+ { { f "x" } } }
|
||
|
{ +scratch+ { { f "y" } } }
|
||
|
{ +clobber+ { "x" } }
|
||
|
{ +output+ { "y" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
: fixnum-jump ( op -- quo )
|
||
|
[ "x" operand "y" operand CMP ] swap
|
||
|
1quotation [ B ] 3append ;
|
||
|
|
||
|
: fixnum-register-jump ( op -- pair )
|
||
|
fixnum-jump { { f "x" } { f "y" } } 2array ;
|
||
|
|
||
|
: fixnum-value-jump ( op -- pair )
|
||
|
fixnum-jump { { f "x" } { [ small-tagged? ] "y" } } 2array ;
|
||
|
|
||
|
: define-fixnum-jump ( word op -- )
|
||
|
[ fixnum-value-jump ] keep fixnum-register-jump
|
||
|
2array define-if-intrinsics ;
|
||
|
|
||
|
{
|
||
|
{ fixnum< LT }
|
||
|
{ fixnum<= LE }
|
||
|
{ fixnum> GT }
|
||
|
{ fixnum>= GE }
|
||
|
{ eq? EQ }
|
||
|
} [
|
||
|
first2 define-fixnum-jump
|
||
|
] each
|
||
|
|
||
|
\ tag [
|
||
|
"out" operand "in" operand tag-mask get AND
|
||
|
"out" operand dup %tag-fixnum
|
||
|
] H{
|
||
|
{ +input+ { { f "in" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ type [
|
||
|
! Get the tag
|
||
|
"out" operand "obj" operand tag-mask get AND
|
||
|
! Compare with object tag number (3).
|
||
|
"out" operand object tag-number CMP
|
||
|
! Tag the tag if it is not equal to 3
|
||
|
"out" operand dup NE %tag-fixnum
|
||
|
! Load the object header if tag is equal to 3
|
||
|
"out" operand "obj" operand object tag-number <-> EQ LDR
|
||
|
] H{
|
||
|
{ +input+ { { f "obj" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ class-hash [
|
||
|
"end" define-label
|
||
|
! Get the tag
|
||
|
"out" operand "obj" operand tag-mask get AND
|
||
|
! Compare with tuple tag number (2).
|
||
|
"out" operand tuple tag-number CMP
|
||
|
"out" operand "obj" operand tuple-class-offset <+/-> EQ LDR
|
||
|
"out" operand dup class-hash-offset <+/-> EQ LDR
|
||
|
"end" get EQ B
|
||
|
! Compare with object tag number (3).
|
||
|
"out" operand object tag-number CMP
|
||
|
"out" operand "obj" operand object tag-number <-> EQ LDR
|
||
|
! Tag the tag
|
||
|
"out" operand dup NE %tag-fixnum
|
||
|
"end" resolve-label
|
||
|
] H{
|
||
|
{ +input+ { { f "obj" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
: userenv ( reg -- )
|
||
|
#! Load the userenv pointer in a register.
|
||
|
"userenv" f rot compile-dlsym ;
|
||
|
|
||
|
\ getenv [
|
||
|
"n" operand dup 1 <ASR> MOV
|
||
|
"x" operand userenv
|
||
|
"x" operand "x" operand "n" operand <+> LDR
|
||
|
] H{
|
||
|
{ +input+ { { f "n" } } }
|
||
|
{ +scratch+ { { f "x" } } }
|
||
|
{ +output+ { "x" } }
|
||
|
{ +clobber+ { "n" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ setenv [
|
||
|
"n" operand dup 1 <ASR> MOV
|
||
|
"x" operand userenv
|
||
|
"val" operand "x" operand "n" operand <+> STR
|
||
|
] H{
|
||
|
{ +input+ { { f "val" } { f "n" } } }
|
||
|
{ +scratch+ { { f "x" } } }
|
||
|
{ +clobber+ { "n" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
: %set-slot R11 swap cells <+> STR ;
|
||
|
|
||
|
: %store-length
|
||
|
R12 "n" operand MOV
|
||
|
R12 1 %set-slot ;
|
||
|
|
||
|
: %fill-array swap 2 + %set-slot ;
|
||
|
|
||
|
\ <tuple> [
|
||
|
tuple "n" get 2 + cells %allot
|
||
|
%store-length
|
||
|
! Store class
|
||
|
"class" operand 2 %set-slot
|
||
|
! Zero out the rest of the tuple
|
||
|
"initial" operand f v>operand MOV
|
||
|
"n" get 1- [ 1+ "initial" operand %fill-array ] each
|
||
|
"out" get tuple %store-tagged
|
||
|
] H{
|
||
|
{ +input+ { { f "class" } { [ inline-array? ] "n" } } }
|
||
|
{ +scratch+ { { f "out" } { f "initial" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ <array> [
|
||
|
array "n" get 2 + cells %allot
|
||
|
%store-length
|
||
|
! Store initial element
|
||
|
"n" get [ "initial" operand %fill-array ] each
|
||
|
"out" get object %store-tagged
|
||
|
] H{
|
||
|
{ +input+ { { [ inline-array? ] "n" } { f "initial" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ <byte-array> [
|
||
|
byte-array "n" get 2 cells + %allot
|
||
|
%store-length
|
||
|
! Store initial element
|
||
|
R12 0 MOV
|
||
|
"n" get cell align cell /i [ R12 %fill-array ] each
|
||
|
"out" get object %store-tagged
|
||
|
] H{
|
||
|
{ +input+ { { [ inline-array? ] "n" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ <ratio> [
|
||
|
ratio 3 cells %allot
|
||
|
"numerator" operand 1 %set-slot
|
||
|
"denominator" operand 2 %set-slot
|
||
|
"out" get ratio %store-tagged
|
||
|
] H{
|
||
|
{ +input+ { { f "numerator" } { f "denominator" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ <complex> [
|
||
|
complex 3 cells %allot
|
||
|
"real" operand 1 %set-slot
|
||
|
"imaginary" operand 2 %set-slot
|
||
|
! Store tagged ptr in reg
|
||
|
"out" get complex %store-tagged
|
||
|
] H{
|
||
|
{ +input+ { { f "real" } { f "imaginary" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
\ <wrapper> [
|
||
|
wrapper 2 cells %allot
|
||
|
"obj" operand 1 %set-slot
|
||
|
! Store tagged ptr in reg
|
||
|
"out" get object %store-tagged
|
||
|
] H{
|
||
|
{ +input+ { { f "obj" } } }
|
||
|
{ +scratch+ { { f "out" } } }
|
||
|
{ +output+ { "out" } }
|
||
|
} define-intrinsic
|
||
|
|
||
|
! Alien intrinsics
|
||
|
: %alien-accessor ( quot -- )
|
||
|
"offset" operand dup %untag-fixnum
|
||
|
"offset" operand dup "alien" operand ADD
|
||
|
"value" operand "offset" operand 0 <+> roll call ; inline
|
||
|
|
||
|
: alien-integer-get-template
|
||
|
H{
|
||
|
{ +input+ {
|
||
|
{ unboxed-c-ptr "alien" c-ptr }
|
||
|
{ f "offset" fixnum }
|
||
|
} }
|
||
|
{ +scratch+ { { f "value" } } }
|
||
|
{ +output+ { "value" } }
|
||
|
{ +clobber+ { "offset" } }
|
||
|
} ;
|
||
|
|
||
|
: %alien-integer-get ( quot -- )
|
||
|
%alien-accessor
|
||
|
"value" operand dup %tag-fixnum ; inline
|
||
|
|
||
|
: alien-integer-set-template
|
||
|
H{
|
||
|
{ +input+ {
|
||
|
{ f "value" fixnum }
|
||
|
{ unboxed-c-ptr "alien" c-ptr }
|
||
|
{ f "offset" fixnum }
|
||
|
} }
|
||
|
{ +clobber+ { "value" "offset" } }
|
||
|
} ;
|
||
|
|
||
|
: %alien-integer-set ( quot -- )
|
||
|
"offset" get "value" get = [
|
||
|
"value" operand dup %untag-fixnum
|
||
|
] unless
|
||
|
%alien-accessor ; inline
|
||
|
|
||
|
: define-alien-integer-intrinsics ( word get-quot word set-quot -- )
|
||
|
[ %alien-integer-set ] curry
|
||
|
alien-integer-set-template
|
||
|
define-intrinsic
|
||
|
[ %alien-integer-get ] curry
|
||
|
alien-integer-get-template
|
||
|
define-intrinsic ;
|
||
|
|
||
|
\ alien-unsigned-1 [ LDRB ]
|
||
|
\ set-alien-unsigned-1 [ STRB ]
|
||
|
define-alien-integer-intrinsics
|
||
|
|
||
|
: alien-cell-template
|
||
|
H{
|
||
|
{ +input+ {
|
||
|
{ unboxed-c-ptr "alien" c-ptr }
|
||
|
{ f "offset" fixnum }
|
||
|
} }
|
||
|
{ +scratch+ { { unboxed-alien "value" } } }
|
||
|
{ +output+ { "value" } }
|
||
|
{ +clobber+ { "offset" } }
|
||
|
} ;
|
||
|
|
||
|
\ alien-cell
|
||
|
[ [ LDR ] %alien-accessor ]
|
||
|
alien-cell-template define-intrinsic
|
||
|
|
||
|
: set-alien-cell-template
|
||
|
H{
|
||
|
{ +input+ {
|
||
|
{ unboxed-c-ptr "value" pinned-c-ptr }
|
||
|
{ unboxed-c-ptr "alien" c-ptr }
|
||
|
{ f "offset" fixnum }
|
||
|
} }
|
||
|
{ +clobber+ { "offset" } }
|
||
|
} ;
|
||
|
|
||
|
\ set-alien-cell
|
||
|
[ [ STR ] %alien-accessor ]
|
||
|
set-alien-cell-template define-intrinsic
|