]> gitweb.factorcode.org Git - factor.git/commitdiff
First approximation at x86 intrinsic definitions
authorslava <slava@factorcode.org>
Sun, 30 Apr 2006 20:13:35 +0000 (20:13 +0000)
committerslava <slava@factorcode.org>
Sun, 30 Apr 2006 20:13:35 +0000 (20:13 +0000)
library/compiler/x86/intrinsics.factor

index 2bb78d6c1566368d5f24fe82656346f8a3874312..7e41ac6564c411abf8984269bae8e2861b90805c 100644 (file)
 ! Copyright (C) 2005, 2006 Slava Pestov.
-! See http://factor.sf.net/license.txt for BSD license.
+! See http://factorcode.org/license.txt for BSD license.
 IN: compiler
+USING: alien assembler kernel kernel-internals math
+math-internals namespaces sequences ;
 
-M: %type generate-node ( vop -- )
+\ tag [
+    "in" operand tag-mask AND
+    "in" operand tag-bits SHL
+] H{
+    { +input { { f "in" } } }
+    { +output { "in" } }
+} define-intrinsic
+
+\ type [
     #! Intrinstic version of type primitive.
-    drop
     <label> "header" set
     <label> "f" set
     <label> "end" set
     ! Make a copy
-    0 scratch 0 output-operand MOV
+    "x" operand "obj" operand MOV
     ! Get the tag
-    0 output-operand tag-mask AND
+    "obj" operand tag-mask AND
     ! Compare with object tag number (3).
-    0 output-operand object-tag CMP
+    "obj" operand object-tag CMP
     ! Jump if the object doesn't store type info in its header
     "header" get JE
     ! It doesn't store type info in its header
-    0 output-operand tag-bits SHL
+    "obj" operand tag-bits SHL
     "end" get JMP
     "header" get save-xt
     ! It does store type info in its header
     ! Is the pointer itself equal to 3? Then its F_TYPE (9).
-    0 scratch object-tag CMP
+    "x" operand object-tag CMP
     "f" get JE
     ! The pointer is not equal to 3. Load the object header.
-    0 output-operand 0 scratch object-tag neg [+] MOV
+    "obj" operand "x" operand object-tag neg [+] MOV
     ! Mask off header tag, making a fixnum.
-    0 output-operand object-tag XOR
+    "obj" operand object-tag XOR
     "end" get JMP
     "f" get save-xt
     ! The pointer is equal to 3. Load F_TYPE (9).
-    0 output-operand f type tag-bits shift MOV
-    "end" get save-xt ;
-
-M: %tag generate-node ( vop -- )
-    drop
-    0 input-operand tag-mask AND
-    0 input-operand tag-bits SHL ;
+    "obj" operand f type tag-bits shift MOV
+    "end" get save-xt
+] H{
+    { +input { { f "obj" } } }
+    { +scratch { { f "x" } { f "y" } } }
+    { +output { "obj" } }
+} define-intrinsic
 
-M: %untag generate-node ( vop -- )
-    drop
-    0 output-operand tag-mask bitnot AND ;
+: untag ( reg -- ) tag-mask bitnot AND ;
 
-M: %slot generate-node ( vop -- )
-    drop
+\ slot [
+    "obj" operand untag
     ! turn tagged fixnum slot # into an offset, multiple of 4
-    0 input-operand fixnum>slot@
+    "n" operand fixnum>slot@
     ! compute slot address
-    dest/src ADD
+    "obj" operand "n" operand ADD
     ! load slot value
-    0 output-operand dup [] MOV ;
+    "obj" operand dup [] MOV
+] H{
+    { +input { { f "obj" } { f "n" } } }
+    { +output { "obj" } }
+    { +clobber { "n" } }
+} define-intrinsic
 
 : card-offset 1 getenv ; inline
 
-M: %write-barrier generate-node ( vop -- )
+: generate-write-barrier ( -- )
     #! Mark the card pointed to by vreg.
-    drop
-    0 input-operand card-bits SHR
-    0 input-operand card-offset ADD rel-absolute-cell rel-cards
-    0 input-operand [] card-mark OR ;
+    "obj" operand card-bits SHR
+    "obj" operand card-offset ADD rel-absolute-cell rel-cards
+    "obj" operand [] card-mark OR ;
 
-M: %set-slot generate-node ( vop -- )
-    drop
+\ set-slot [
+    "obj" operand untag
     ! turn tagged fixnum slot # into an offset
-    2 input-operand fixnum>slot@
+    "slot" operand fixnum>slot@
     ! compute slot address
-    2 input-operand 1 input-operand ADD
+    "obj" operand "slot" operand ADD
     ! store new slot value
-    2 input-operand [] 0 input-operand MOV ;
-
-: >register-16 ( reg -- reg )
-    "register" word-prop { AX CX DX } nth ;
-
-: scratch-16 ( n -- reg ) scratch >register-16 ;
-
-M: %char-slot generate-node ( vop -- )
-    drop
-    0 input-operand 2 SHR
-    0 scratch dup XOR
-    dest/src ADD
-    0 scratch-16 0 output-operand string-offset [+] MOV
-    0 scratch tag-bits SHL
-    0 output-operand 0 scratch MOV ;
-
-M: %set-char-slot generate-node ( vop -- )
-    drop
-    0 input-operand tag-bits SHR
-    2 input-operand 2 SHR
-    2 input-operand 1 input-operand ADD
-    2 input-operand string-offset [+]
-    0 input-operand >register-16 MOV ;
-
-: 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
-    #! turn the result into a bignum and leave it in EAX.
-    <label> "end" set
-    "end" get JNO
-    ! There was an overflow. Recompute the original operand.
-    >r >r dest/src r> execute
-    0 input integer? [ literal-overflow ] [ computed-overflow ] if
-    ! Compute a result, this time it will fit.
-    r> execute
-    ! Create a bignum.
-    "s48_long_to_bignum" f 0 output-operand
-    1array compile-c-call*
-    ! An untagged pointer to the bignum is now in EAX; tag it
-    T{ int-regs } return-reg bignum-tag OR
-    "end" get save-xt ; inline
-
-M: %fixnum+ generate-node ( vop -- )
-    drop dest/src ADD  \ SUB \ ADD simple-overflow ;
-
-M: %fixnum+fast generate-node ( vop -- ) drop dest/src ADD ;
-
-M: %fixnum- generate-node ( vop -- )
-    drop dest/src SUB  \ ADD \ SUB simple-overflow ;
-
-M: %fixnum-fast generate-node ( vop -- ) drop dest/src SUB ;
-
-M: %fixnum* generate-node ( vop -- )
-    drop
-    ! both inputs are tagged, so one of them needs to have its
-    ! tag removed.
-    1 input-operand tag-bits SAR
-    0 input-operand IMUL
-    <label> "end" set
-    "end" get JNO
-    "s48_fixnum_pair_to_bignum" f
-    1 input-operand remainder-reg 2array compile-c-call*
-    ! now we have to shift it by three bits to remove the second
-    ! tag
-    "s48_bignum_arithmetic_shift" f
-    1 input-operand tag-bits neg 2array compile-c-call*
-    ! an untagged pointer to the bignum is now in EAX; tag it
-    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
-    #! ECX and EAX, and the result is in EDX.
-    drop
-    prepare-division
-    0 input-operand IDIV ;
+    "obj" operand [] "val" operand MOV
+    generate-write-barrier
+] H{
+    { +input { { f "val" } { f "obj" } { f "slot" } } }
+    { +scratch { { f "x" } } }
+    { +clobber { "obj" } }
+} define-intrinsic
 
-: generate-fixnum/mod
-    #! The same code is used for %fixnum/i and %fixnum/mod.
-    #! This has specific register requirements. Inputs are in
-    #! ECX and EAX, and the result is in EDX.
-    <label> "end" set
-    prepare-division
-    0 input-operand IDIV
-    ! Make a copy since following shift is destructive
-    0 input-operand 1 input-operand MOV
-    ! Tag the value, since division cancelled tags from both
-    ! inputs
-    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.
-    remainder-reg PUSH
-    "s48_long_to_bignum" f
-    0 input-operand 1array compile-c-call*
-    ! An untagged pointer to the bignum is now in EAX; tag it
-    T{ int-regs } return-reg bignum-tag OR
-    ! the remainder is now in EDX
-    remainder-reg POP
-    "end" get save-xt ;
-
-M: %fixnum/i generate-node drop generate-fixnum/mod ;
-
-M: %fixnum/mod generate-node drop generate-fixnum/mod ;
-
-M: %fixnum-bitand generate-node ( vop -- ) drop dest/src AND ;
-
-M: %fixnum-bitor generate-node ( vop -- ) drop dest/src OR ;
-
-M: %fixnum-bitxor generate-node ( vop -- ) drop dest/src XOR ;
-
-M: %fixnum-bitnot generate-node ( vop -- )
-    drop
-    ! Negate the bits of the operand
-    0 output-operand NOT
-    ! Mask off the low 3 bits to give a fixnum tag
-    0 output-operand tag-mask XOR ;
-
-M: %fixnum>> generate-node
-    drop
-    ! shift register
-    0 output-operand 0 input SAR
-    ! give it a fixnum tag
-    0 output-operand tag-mask bitnot AND ;
-
-M: %fixnum-sgn generate-node
-    #! This has specific register requirements.
-    drop
-    ! store 0 in EDX if EAX is >=0, otherwise store -1.
+\ char-slot [
+    EBX PUSH
+    "n" operand 2 SHR
+    EBX dup XOR
+    EBX "n" operand ADD
+    BX "obj" operand string-offset [+] MOV
+    EBX tag-bits SHL
+    "obj" operand EBX MOV
+    EBX POP
+] H{
+    { +input { { f "n" } { f "obj" } } }
+    { +output { "obj" } }
+    { +clobber { "n" } }
+} define-intrinsic
+
+\ set-char-slot [
+    "obj" operand untag
+    EBX PUSH
+    "val" operand tag-bits SHR
+    "slot" operand 2 SHR
+    "obj" operand "slot" operand ADD
+    EBX "val" operand MOV
+    "obj" operand string-offset [+] BX MOV
+    EBX POP
+] H{
+    { +input { { f "val" } { f "slot" } { f "obj" } } }
+    { +clobber { "obj" } }
+} define-intrinsic
+
+: define-binary-op ( word op -- )
+    [ [ "x" operand "y" operand ] % , ] [ ] make H{
+        { +input { { f "x" } { f "y" } } }
+        { +output { "x" } }
+    } define-intrinsic ;
+
+{
+    { fixnum+fast ADD }
+    { fixnum-fast SUB }
+    { fixnum-bitand AND }
+    { fixnum-bitor OR }
+    { fixnum-bitxor XOR }
+} [
+    first2 define-binary-op
+] each
+
+\ fixnum-bitnot [
+    "x" operand NOT
+    "x" operand tag-mask XOR
+] H{
+    { +input { { f "x" } } }
+    { +output { "x" } }
+} define-intrinsic
+
+! This has specific register requirements. Inputs are in
+! ECX and EAX, and the result is in EDX.
+\ fixnum-mod [
     prepare-division
-    ! give it a fixnum tag.
-    0 output-operand tag-bits SHL ;
+    "x" operand IDIV
+] H{
+    { +input { { 0 "x" } { 2 "y" } } }
+    { +output { "x" } }
+} define-intrinsic
+
+! : 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
+!     #! turn the result into a bignum and leave it in EAX.
+!     <label> "end" set
+!     "end" get JNO
+!     ! There was an overflow. Recompute the original operand.
+!     >r >r dest/src r> execute
+!     0 input integer? [ literal-overflow ] [ computed-overflow ] if
+!     ! Compute a result, this time it will fit.
+!     r> execute
+!     ! Create a bignum.
+!     "s48_long_to_bignum" f 0 output-operand
+!     1array compile-c-call*
+!     ! An untagged pointer to the bignum is now in EAX; tag it
+!     T{ int-regs } return-reg bignum-tag OR
+!     "end" get save-xt ; inline
+! 
+! M: %fixnum+ generate-node ( vop -- )
+!     drop dest/src ADD  \ SUB \ ADD simple-overflow ;
+! 
+! M: %fixnum- generate-node ( vop -- )
+!     drop dest/src SUB  \ ADD \ SUB simple-overflow ;
+! 
+! M: %fixnum* generate-node ( vop -- )
+!     drop
+!     ! both inputs are tagged, so one of them needs to have its
+!     ! tag removed.
+!     1 input-operand tag-bits SAR
+!     0 input-operand IMUL
+!     <label> "end" set
+!     "end" get JNO
+!     "s48_fixnum_pair_to_bignum" f
+!     1 input-operand remainder-reg 2array compile-c-call*
+!     ! now we have to shift it by three bits to remove the second
+!     ! tag
+!     "s48_bignum_arithmetic_shift" f
+!     1 input-operand tag-bits neg 2array compile-c-call*
+!     ! an untagged pointer to the bignum is now in EAX; tag it
+!     T{ int-regs } return-reg bignum-tag OR
+!     "end" get save-xt ;
+! 
+! : generate-fixnum/mod
+!     #! The same code is used for %fixnum/i and %fixnum/mod.
+!     #! This has specific register requirements. Inputs are in
+!     #! ECX and EAX, and the result is in EDX.
+!     <label> "end" set
+!     prepare-division
+!     0 input-operand IDIV
+!     ! Make a copy since following shift is destructive
+!     0 input-operand 1 input-operand MOV
+!     ! Tag the value, since division cancelled tags from both
+!     ! inputs
+!     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.
+!     remainder-reg PUSH
+!     "s48_long_to_bignum" f
+!     0 input-operand 1array compile-c-call*
+!     ! An untagged pointer to the bignum is now in EAX; tag it
+!     T{ int-regs } return-reg bignum-tag OR
+!     ! the remainder is now in EDX
+!     remainder-reg POP
+!     "end" get save-xt ;
+! 
+! M: %fixnum/i generate-node drop generate-fixnum/mod ;
+! 
+! M: %fixnum/mod generate-node drop generate-fixnum/mod ;
+
+: define-binary-jump ( word op -- )
+    [
+        [ end-basic-block "x" operand "y" operand CMP ] % ,
+    ] [ ] make H{
+        { +input { { f "x" } { f "y" } } }
+    } define-if-intrinsic ;
+
+{
+    { fixnum< JL }
+    { fixnum<= JLE }
+    { fixnum> JG }
+    { fixnum>= JGE }
+    { eq? JE }
+} [
+    first2 define-binary-jump
+] each
+
+: %userenv ( -- )
+    "x" operand "userenv" f dlsym MOV
+    rel-absolute-cell rel-userenv
+    "n" operand 1 SHR
+    "n" operand "x" operand ADD ;
 
-: fixnum-jump ( -- label )
-    1 input-operand 0 input-operand CMP label ;
+\ getenv [
+    %userenv  "n" operand dup [] MOV
+] H{
+    { +input { { f "n" } } }
+    { +scratch { { f "x" } } }
+    { +output { "n" } }
+} define-intrinsic
 
-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 ;
+\ setenv [
+    %userenv  "n" operand [] "val" operand MOV
+] H{
+    { +input { { f "val" } { f "n" } } }
+    { +scratch { { f "x" } } }
+    { +clobber { "n" } }
+} define-intrinsic