--- /dev/null
+! 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