Update x86 backend for SSA codegen
							parent
							
								
									37cf7d9a9c
								
							
						
					
					
						commit
						508b1f52b8
					
				| 
						 | 
				
			
			@ -1,13 +1,12 @@
 | 
			
		|||
! Copyright (C) 2005, 2008 Slava Pestov.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: locals alien.c-types arrays kernel kernel.private math
 | 
			
		||||
namespaces sequences stack-checker.known-words system layouts io
 | 
			
		||||
vocabs.loader accessors init combinators command-line
 | 
			
		||||
cpu.x86.assembler cpu.x86.architecture cpu.x86.intrinsics
 | 
			
		||||
cpu.x86.allot cpu.architecture compiler compiler.units
 | 
			
		||||
USING: locals alien.c-types alien.syntax arrays kernel
 | 
			
		||||
math namespaces sequences system layouts io vocabs.loader
 | 
			
		||||
accessors init combinators command-line cpu.x86.assembler
 | 
			
		||||
cpu.x86.architecture cpu.architecture compiler compiler.units
 | 
			
		||||
compiler.constants compiler.alien compiler.codegen
 | 
			
		||||
compiler.codegen.fixup compiler.cfg.builder
 | 
			
		||||
compiler.cfg.instructions ;
 | 
			
		||||
compiler.codegen.fixup compiler.cfg.instructions
 | 
			
		||||
compiler.cfg.builder compiler.cfg.builder.calls ;
 | 
			
		||||
IN: cpu.x86.32
 | 
			
		||||
 | 
			
		||||
! We implement the FFI for Linux, OS X and Windows all at once.
 | 
			
		||||
| 
						 | 
				
			
			@ -75,12 +74,8 @@ M: float-regs store-return-reg
 | 
			
		|||
    [ [ align-sub ] [ call ] bi* ]
 | 
			
		||||
    [ [ align-add ] [ drop ] bi* ] 2bi ; inline
 | 
			
		||||
 | 
			
		||||
M: x86.32 fixnum>slot@ 1 SHR ;
 | 
			
		||||
 | 
			
		||||
M: x86.32 prepare-division CDQ ;
 | 
			
		||||
 | 
			
		||||
M: x86.32 %load-indirect
 | 
			
		||||
    swap 0 [] MOV rc-absolute-cell rel-literal ;
 | 
			
		||||
    0 [] MOV rc-absolute-cell rel-literal ;
 | 
			
		||||
 | 
			
		||||
M: object %load-param-reg 3drop ;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -222,7 +217,7 @@ M: x86.32 %alien-indirect ( -- )
 | 
			
		|||
 | 
			
		||||
M: x86.32 %alien-callback ( quot -- )
 | 
			
		||||
    4 [
 | 
			
		||||
        EAX load-indirect
 | 
			
		||||
        EAX %load-indirect
 | 
			
		||||
        EAX PUSH
 | 
			
		||||
        "c_to_factor" f %alien-invoke
 | 
			
		||||
    ] with-aligned-stack ;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,34 +274,17 @@ os windows? [
 | 
			
		|||
    4 "double" c-type (>>align)
 | 
			
		||||
] unless
 | 
			
		||||
 | 
			
		||||
: (sse2?) ( -- ? ) "Intrinsic" throw ;
 | 
			
		||||
FUNCTION: bool check_sse2 ( ) ;
 | 
			
		||||
 | 
			
		||||
<<
 | 
			
		||||
 | 
			
		||||
\ (sse2?) [
 | 
			
		||||
    { EAX EBX ECX EDX } [ PUSH ] each
 | 
			
		||||
    EAX 1 MOV
 | 
			
		||||
    CPUID
 | 
			
		||||
    EDX 26 SHR
 | 
			
		||||
    EDX 1 AND
 | 
			
		||||
    { EAX EBX ECX EDX } [ POP ] each
 | 
			
		||||
    JNE
 | 
			
		||||
] { } define-if-intrinsic
 | 
			
		||||
 | 
			
		||||
\ (sse2?) { } { object } define-primitive
 | 
			
		||||
 | 
			
		||||
>>
 | 
			
		||||
 | 
			
		||||
: sse2? ( -- ? ) (sse2?) ;
 | 
			
		||||
: sse2? ( -- ? )
 | 
			
		||||
    [ optimized-recompile-hook ] recompile-hook
 | 
			
		||||
    [ [ check_sse2 ] compile-call ] with-variable ;
 | 
			
		||||
 | 
			
		||||
"-no-sse2" cli-args member? [
 | 
			
		||||
    "Checking if your CPU supports SSE2..." print flush
 | 
			
		||||
    [ optimized-recompile-hook ] recompile-hook [
 | 
			
		||||
        [ sse2? ] compile-call
 | 
			
		||||
    ] with-variable
 | 
			
		||||
    [
 | 
			
		||||
    sse2? [
 | 
			
		||||
        " - yes" print
 | 
			
		||||
        "cpu.x86.sse2" require
 | 
			
		||||
        enable-float-intrinsics
 | 
			
		||||
        [
 | 
			
		||||
            sse2? [
 | 
			
		||||
                "This image was built to use SSE2, which your CPU does not support." print
 | 
			
		||||
| 
						 | 
				
			
			@ -315,7 +293,5 @@ os windows? [
 | 
			
		|||
                1 exit
 | 
			
		||||
            ] unless
 | 
			
		||||
        ] "cpu.x86" add-init-hook
 | 
			
		||||
    ] [
 | 
			
		||||
        " - no" print
 | 
			
		||||
    ] if
 | 
			
		||||
    ] [ " - no" print ] if
 | 
			
		||||
] unless
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,12 @@
 | 
			
		|||
! Copyright (C) 2005, 2008 Slava Pestov.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: accessors alien.c-types arrays kernel kernel.private math
 | 
			
		||||
namespaces make sequences system
 | 
			
		||||
layouts alien alien.accessors alien.structs slots splitting
 | 
			
		||||
assocs combinators cpu.x86.assembler
 | 
			
		||||
cpu.x86.architecture cpu.x86.intrinsics cpu.x86.sse2
 | 
			
		||||
cpu.x86.allot cpu.architecture compiler.constants
 | 
			
		||||
compiler.codegen compiler.codegen.fixup compiler.cfg.instructions
 | 
			
		||||
compiler.cfg.builder ;
 | 
			
		||||
USING: accessors arrays kernel math namespaces make sequences
 | 
			
		||||
system layouts alien alien.c-types alien.accessors alien.structs
 | 
			
		||||
slots splitting assocs combinators cpu.x86.assembler
 | 
			
		||||
cpu.x86.architecture cpu.architecture compiler.constants
 | 
			
		||||
compiler.codegen compiler.codegen.fixup
 | 
			
		||||
compiler.cfg.instructions compiler.cfg.builder
 | 
			
		||||
compiler.cfg.builder.calls ;
 | 
			
		||||
IN: cpu.x86.64
 | 
			
		||||
 | 
			
		||||
M: x86.64 machine-registers
 | 
			
		||||
| 
						 | 
				
			
			@ -33,12 +32,8 @@ M: float-regs return-reg drop XMM0 ;
 | 
			
		|||
M: float-regs param-regs
 | 
			
		||||
    drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
 | 
			
		||||
 | 
			
		||||
M: x86.64 fixnum>slot@ drop ;
 | 
			
		||||
 | 
			
		||||
M: x86.64 prepare-division CQO ;
 | 
			
		||||
 | 
			
		||||
M: x86.64 %load-indirect ( literal reg -- )
 | 
			
		||||
    swap 0 [] MOV rc-relative rel-literal ;
 | 
			
		||||
M: x86.64 %load-indirect
 | 
			
		||||
    0 [] MOV rc-relative rel-literal ;
 | 
			
		||||
 | 
			
		||||
M: stack-params %load-param-reg
 | 
			
		||||
    drop
 | 
			
		||||
| 
						 | 
				
			
			@ -58,8 +53,8 @@ M: stack-params %save-param-reg
 | 
			
		|||
    ] with-scope ; inline
 | 
			
		||||
 | 
			
		||||
! The ABI for passing structs by value is pretty messed up
 | 
			
		||||
<< "void*" c-type clone "__stack_value" define-primitive-type
 | 
			
		||||
stack-params "__stack_value" c-type (>>reg-class) >>
 | 
			
		||||
"void*" c-type clone "__stack_value" define-primitive-type
 | 
			
		||||
stack-params "__stack_value" c-type (>>reg-class)
 | 
			
		||||
 | 
			
		||||
: struct-types&offset ( struct-type -- pairs )
 | 
			
		||||
    fields>> [
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +195,7 @@ M: x86.64 %alien-indirect ( -- )
 | 
			
		|||
    RBP CALL ;
 | 
			
		||||
 | 
			
		||||
M: x86.64 %alien-callback ( quot -- )
 | 
			
		||||
    RDI load-indirect "c_to_factor" f %alien-invoke ;
 | 
			
		||||
    RDI %load-indirect "c_to_factor" f %alien-invoke ;
 | 
			
		||||
 | 
			
		||||
M: x86.64 %callback-value ( ctype -- )
 | 
			
		||||
    ! Save top of data stack
 | 
			
		||||
| 
						 | 
				
			
			@ -216,66 +211,9 @@ M: x86.64 %callback-value ( ctype -- )
 | 
			
		|||
    ! Unbox former top of data stack to return registers
 | 
			
		||||
    unbox-return ;
 | 
			
		||||
 | 
			
		||||
USE: cpu.x86.intrinsics
 | 
			
		||||
! The result of reading 4 bytes from memory is a fixnum on
 | 
			
		||||
! x86-64.
 | 
			
		||||
enable-alien-4-intrinsics
 | 
			
		||||
 | 
			
		||||
: (%alien-get-4) ( -- )
 | 
			
		||||
    small-reg-32 "offset" operand [] MOV ; inline
 | 
			
		||||
 | 
			
		||||
: %alien-unsigned-4 ( -- )
 | 
			
		||||
    %prepare-alien-accessor
 | 
			
		||||
    "value" operand small-reg = [
 | 
			
		||||
        (%alien-get-4)
 | 
			
		||||
    ] [
 | 
			
		||||
        small-reg PUSH
 | 
			
		||||
        (%alien-get-4)
 | 
			
		||||
        "value" operand small-reg MOV
 | 
			
		||||
        small-reg POP
 | 
			
		||||
    ] if
 | 
			
		||||
    "value" operand %tag-fixnum ; inline
 | 
			
		||||
 | 
			
		||||
: (%alien-signed-4) ( -- )
 | 
			
		||||
    (%alien-get-4)
 | 
			
		||||
    "value" operand small-reg-32 MOVSX ;
 | 
			
		||||
 | 
			
		||||
: %alien-signed-4 ( -- )
 | 
			
		||||
    %prepare-alien-accessor
 | 
			
		||||
    "value" operand small-reg = [
 | 
			
		||||
        (%alien-signed-4)
 | 
			
		||||
    ] [
 | 
			
		||||
        small-reg PUSH
 | 
			
		||||
        (%alien-signed-4)
 | 
			
		||||
        small-reg POP
 | 
			
		||||
    ] if
 | 
			
		||||
    "value" operand %tag-fixnum ; inline
 | 
			
		||||
 | 
			
		||||
: define-alien-unsigned-4-getter ( word -- )
 | 
			
		||||
    [ %alien-unsigned-4 ] alien-integer-get-template define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
: define-alien-signed-4-getter ( word -- )
 | 
			
		||||
    [ %alien-signed-4 ] alien-integer-get-template define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
: %set-alien-4 ( -- )
 | 
			
		||||
    "value" operand "offset" operand = [
 | 
			
		||||
        "value" operand %untag-fixnum
 | 
			
		||||
    ] unless
 | 
			
		||||
    %prepare-alien-accessor
 | 
			
		||||
    small-reg "offset" operand = [
 | 
			
		||||
        "value" operand "offset" operand XCHG
 | 
			
		||||
        "value" operand [] small-reg-32 MOV
 | 
			
		||||
    ] [
 | 
			
		||||
        small-reg PUSH
 | 
			
		||||
        small-reg "value" operand MOV
 | 
			
		||||
        "offset" operand [] small-reg-32 MOV
 | 
			
		||||
        small-reg POP
 | 
			
		||||
    ] if ; inline
 | 
			
		||||
 | 
			
		||||
: define-alien-4-setter ( word -- )
 | 
			
		||||
    [ %set-alien-4 ] alien-integer-set-template define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
! On 64-bit systems, the result of reading 4 bytes from memory
 | 
			
		||||
! is a fixnum.
 | 
			
		||||
\ alien-unsigned-4 define-alien-unsigned-4-getter
 | 
			
		||||
\ set-alien-unsigned-4 define-alien-4-setter
 | 
			
		||||
 | 
			
		||||
\ alien-signed-4 define-alien-signed-4-getter
 | 
			
		||||
\ set-alien-signed-4 define-alien-4-setter
 | 
			
		||||
! SSE2 is always available on x86-64.
 | 
			
		||||
enable-float-intrinsics
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,141 +0,0 @@
 | 
			
		|||
! Copyright (C) 2006, 2008 Slava Pestov.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: kernel words kernel.private namespaces math math.private
 | 
			
		||||
sequences generic arrays system layouts alien locals fry
 | 
			
		||||
cpu.architecture cpu.x86.assembler cpu.x86.architecture
 | 
			
		||||
compiler.constants compiler.cfg.templates compiler.cfg.builder
 | 
			
		||||
compiler.codegen compiler.codegen.fixup ;
 | 
			
		||||
IN: cpu.x86.allot
 | 
			
		||||
 | 
			
		||||
M:: x86 %write-barrier ( src card# table -- )
 | 
			
		||||
    #! Mark the card pointed to by vreg.
 | 
			
		||||
    ! Mark the card
 | 
			
		||||
    card# src MOV
 | 
			
		||||
    card# card-bits SHR
 | 
			
		||||
    "cards_offset" f table %alien-global
 | 
			
		||||
    table card# [+] card-mark <byte> MOV
 | 
			
		||||
 | 
			
		||||
    ! Mark the card deck
 | 
			
		||||
    card# deck-bits card-bits - SHR
 | 
			
		||||
    "decks_offset" f table %alien-global
 | 
			
		||||
    table card# [+] card-mark <byte> MOV ;
 | 
			
		||||
 | 
			
		||||
: load-zone-ptr ( reg -- )
 | 
			
		||||
    #! Load pointer to start of zone array
 | 
			
		||||
    0 MOV "nursery" f rc-absolute-cell rel-dlsym ;
 | 
			
		||||
 | 
			
		||||
: load-allot-ptr ( nursery-ptr allot-ptr -- )
 | 
			
		||||
    [ drop load-zone-ptr ] [ swap cell [+] MOV ] 2bi ;
 | 
			
		||||
 | 
			
		||||
: inc-allot-ptr ( nursery-ptr n -- )
 | 
			
		||||
    [ cell [+] ] dip 8 align ADD ;
 | 
			
		||||
 | 
			
		||||
: store-header ( temp type -- )
 | 
			
		||||
    [ [] ] [ type-number tag-fixnum ] bi* MOV ;
 | 
			
		||||
 | 
			
		||||
: store-tagged ( dst tag -- )
 | 
			
		||||
    tag-number OR ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %allot ( dst size type tag nursery-ptr -- )
 | 
			
		||||
    nursery-ptr dst load-allot-ptr
 | 
			
		||||
    dst type store-header
 | 
			
		||||
    dst tag store-tagged
 | 
			
		||||
    nursery-ptr size inc-allot-ptr ;
 | 
			
		||||
 | 
			
		||||
M: x86 %gc ( -- )
 | 
			
		||||
    "end" define-label
 | 
			
		||||
    temp-reg-1 load-zone-ptr
 | 
			
		||||
    temp-reg-2 temp-reg-1 cell [+] MOV
 | 
			
		||||
    temp-reg-2 1024 ADD
 | 
			
		||||
    temp-reg-1 temp-reg-1 3 cells [+] MOV
 | 
			
		||||
    temp-reg-2 temp-reg-1 CMP
 | 
			
		||||
    "end" get JLE
 | 
			
		||||
    %prepare-alien-invoke
 | 
			
		||||
    "minor_gc" f %alien-invoke
 | 
			
		||||
    "end" resolve-label ;
 | 
			
		||||
 | 
			
		||||
: bignum@ ( reg n -- op ) cells bignum tag-number - [+] ;
 | 
			
		||||
 | 
			
		||||
:: %allot-bignum-signed-1 ( dst src temp -- )
 | 
			
		||||
    #! on entry, inreg is a signed 32-bit quantity
 | 
			
		||||
    #! exits with tagged ptr to bignum in outreg
 | 
			
		||||
    #! 1 cell header, 1 cell length, 1 cell sign, + digits
 | 
			
		||||
    #! length is the # of digits + sign
 | 
			
		||||
    [
 | 
			
		||||
        { "end" "nonzero" "positive" "store" } [ define-label ] each
 | 
			
		||||
        src 0 CMP ! is it zero?
 | 
			
		||||
        "nonzero" get JNE
 | 
			
		||||
        ! Use cached zero value
 | 
			
		||||
        0 >bignum dst load-indirect
 | 
			
		||||
        "end" get JMP
 | 
			
		||||
        "nonzero" resolve-label
 | 
			
		||||
        ! Allocate a bignum
 | 
			
		||||
        dst 4 cells bignum bignum temp %allot
 | 
			
		||||
        ! Write length
 | 
			
		||||
        dst 1 bignum@ 2 tag-fixnum MOV
 | 
			
		||||
        ! Test sign
 | 
			
		||||
        src 0 CMP
 | 
			
		||||
        "positive" get JGE
 | 
			
		||||
        dst 2 bignum@ 1 MOV ! negative sign
 | 
			
		||||
        src NEG
 | 
			
		||||
        "store" get JMP
 | 
			
		||||
        "positive" resolve-label
 | 
			
		||||
        dst 2 bignum@ 0 MOV ! positive sign
 | 
			
		||||
        "store" resolve-label
 | 
			
		||||
        dst 3 bignum@ src MOV
 | 
			
		||||
        "end" resolve-label
 | 
			
		||||
    ] with-scope ;
 | 
			
		||||
 | 
			
		||||
: alien@ ( reg n -- op ) cells object tag-number - [+] ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %box-alien ( dst src temp -- )
 | 
			
		||||
    [
 | 
			
		||||
        { "end" "f" } [ define-label ] each
 | 
			
		||||
        src 0 CMP
 | 
			
		||||
        "f" get JE
 | 
			
		||||
        dst 4 cells alien object temp %allot
 | 
			
		||||
        dst 1 alien@ \ f tag-number MOV
 | 
			
		||||
        dst 2 alien@ \ f tag-number MOV
 | 
			
		||||
        ! Store src in alien-offset slot
 | 
			
		||||
        dst 3 alien@ src MOV
 | 
			
		||||
        "end" get JMP
 | 
			
		||||
        "f" resolve-label
 | 
			
		||||
        dst \ f tag-number MOV
 | 
			
		||||
        "end" resolve-label
 | 
			
		||||
    ] with-scope ;
 | 
			
		||||
 | 
			
		||||
: 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-fixnum ] unique-operands
 | 
			
		||||
    "x" operand "y" operand rot execute
 | 
			
		||||
    "z" operand "x" operand "y" operand %allot-bignum-signed-1
 | 
			
		||||
    "end" resolve-label ; inline
 | 
			
		||||
 | 
			
		||||
: overflow-template ( word insn -- )
 | 
			
		||||
    '[ _ overflow-check ] T{ template
 | 
			
		||||
        { input { { f "x" } { f "y" } } }
 | 
			
		||||
        { scratch { { f "z" } } }
 | 
			
		||||
        { output { "z" } }
 | 
			
		||||
        { clobber { "x" "y" } }
 | 
			
		||||
        { gc t }
 | 
			
		||||
    } define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
\ fixnum+ \ ADD overflow-template
 | 
			
		||||
\ fixnum- \ SUB overflow-template
 | 
			
		||||
 | 
			
		||||
\ fixnum>bignum [
 | 
			
		||||
    "x" operand %untag-fixnum
 | 
			
		||||
    "y" operand "x" operand "scratch" operand %allot-bignum-signed-1
 | 
			
		||||
] T{ template
 | 
			
		||||
    { input { { f "x" } } }
 | 
			
		||||
    { scratch { { f "y" } { f "scratch" } } }
 | 
			
		||||
    { output { "y" } }
 | 
			
		||||
    { clobber { "x" } }
 | 
			
		||||
    { gc t }
 | 
			
		||||
} define-intrinsic
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
Slava Pestov
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
unportable
 | 
			
		||||
| 
						 | 
				
			
			@ -3,16 +3,416 @@
 | 
			
		|||
USING: accessors assocs alien alien.c-types arrays
 | 
			
		||||
cpu.x86.assembler cpu.x86.assembler.private cpu.architecture
 | 
			
		||||
kernel kernel.private math memory namespaces make sequences
 | 
			
		||||
words system layouts combinators math.order locals
 | 
			
		||||
words system layouts combinators math.order fry locals
 | 
			
		||||
compiler.constants compiler.cfg.registers
 | 
			
		||||
compiler.cfg.instructions compiler.codegen
 | 
			
		||||
compiler.codegen.fixup ;
 | 
			
		||||
IN: cpu.x86.architecture
 | 
			
		||||
 | 
			
		||||
HOOK: temp-reg-1 cpu ( -- reg )
 | 
			
		||||
HOOK: temp-reg-2 cpu ( -- reg )
 | 
			
		||||
 | 
			
		||||
M: x86 %load-immediate MOV ;
 | 
			
		||||
 | 
			
		||||
HOOK: ds-reg cpu ( -- reg )
 | 
			
		||||
HOOK: rs-reg cpu ( -- reg )
 | 
			
		||||
 | 
			
		||||
: reg-stack ( n reg -- op ) swap cells neg [+] ;
 | 
			
		||||
 | 
			
		||||
GENERIC: loc>operand ( loc -- operand )
 | 
			
		||||
 | 
			
		||||
M: ds-loc loc>operand n>> ds-reg reg-stack ;
 | 
			
		||||
M: rs-loc loc>operand n>> rs-reg reg-stack ;
 | 
			
		||||
 | 
			
		||||
M: x86 %peek loc>operand MOV ;
 | 
			
		||||
M: x86 %replace loc>operand swap MOV ;
 | 
			
		||||
: (%inc) ( n reg -- ) swap cells dup 0 > [ ADD ] [ neg SUB ] if ; inline
 | 
			
		||||
M: x86 %inc-d ( n -- ) ds-reg (%inc) ;
 | 
			
		||||
M: x86 %inc-r ( n -- ) rs-reg (%inc) ;
 | 
			
		||||
 | 
			
		||||
: align-stack ( n -- n' )
 | 
			
		||||
    os macosx? cpu x86.64? or [ 16 align ] when ;
 | 
			
		||||
 | 
			
		||||
M: x86 stack-frame-size ( stack-frame -- i )
 | 
			
		||||
    [ spill-counts>> [ swap reg-size * ] { } assoc>map sum ]
 | 
			
		||||
    [ params>> ]
 | 
			
		||||
    [ return>> ]
 | 
			
		||||
    tri + +
 | 
			
		||||
    3 cells +
 | 
			
		||||
    align-stack ;
 | 
			
		||||
 | 
			
		||||
M: x86 %call ( label -- ) CALL ;
 | 
			
		||||
M: x86 %jump-label ( label -- ) JMP ;
 | 
			
		||||
M: x86 %return ( -- ) 0 RET ;
 | 
			
		||||
 | 
			
		||||
: code-alignment ( -- n )
 | 
			
		||||
    building get length dup cell align swap - ;
 | 
			
		||||
 | 
			
		||||
: align-code ( n -- )
 | 
			
		||||
    0 <repetition> % ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %dispatch ( src temp -- )
 | 
			
		||||
    ! Load jump table base. We use a temporary register
 | 
			
		||||
    ! since on AMD64 we have to load a 64-bit immediate. On
 | 
			
		||||
    ! x86, this is redundant.
 | 
			
		||||
    ! Add jump table base
 | 
			
		||||
    temp HEX: ffffffff MOV rc-absolute-cell rel-here
 | 
			
		||||
    src temp ADD
 | 
			
		||||
    src HEX: 7f [+] JMP
 | 
			
		||||
    ! Fix up the displacement above
 | 
			
		||||
    code-alignment dup bootstrap-cell 8 = 15 9 ? +
 | 
			
		||||
    building get dup pop* push
 | 
			
		||||
    align-code ;
 | 
			
		||||
 | 
			
		||||
M: x86 %dispatch-label ( word -- )
 | 
			
		||||
    0 cell, rc-absolute-cell rel-word ;
 | 
			
		||||
 | 
			
		||||
:: (%slot) ( obj slot tag temp -- op )
 | 
			
		||||
    temp slot obj [+] LEA
 | 
			
		||||
    temp tag neg [+] ; inline
 | 
			
		||||
 | 
			
		||||
:: (%slot-imm) ( obj slot tag -- op )
 | 
			
		||||
    obj slot cells tag - [+] ; inline
 | 
			
		||||
 | 
			
		||||
M: x86 %slot ( dst obj slot tag temp -- ) (%slot) MOV ;
 | 
			
		||||
M: x86 %slot-imm ( dst obj slot tag -- ) (%slot-imm) MOV ;
 | 
			
		||||
M: x86 %set-slot ( src obj slot tag temp -- ) (%slot) swap MOV ;
 | 
			
		||||
M: x86 %set-slot-imm ( src obj slot tag -- ) (%slot-imm) swap MOV ;
 | 
			
		||||
 | 
			
		||||
: ?MOV ( dst src -- )
 | 
			
		||||
    2dup = [ 2drop ] [ MOV ] if ; inline
 | 
			
		||||
 | 
			
		||||
: 1operand ( dst src -- dst' )
 | 
			
		||||
    dupd ?MOV ; inline
 | 
			
		||||
 | 
			
		||||
: 2operand ( dst src1 src2 -- dst src )
 | 
			
		||||
    [ 1operand ] dip ; inline
 | 
			
		||||
 | 
			
		||||
M: x86 %add     [+] LEA ;
 | 
			
		||||
M: x86 %add-imm [+] LEA ;
 | 
			
		||||
M: x86 %sub     2operand SUB ;
 | 
			
		||||
M: x86 %sub-imm neg [+] LEA ;
 | 
			
		||||
M: x86 %mul     2operand IMUL2 ;
 | 
			
		||||
M: x86 %mul-imm 2operand IMUL2 ;
 | 
			
		||||
M: x86 %and     2operand AND ;
 | 
			
		||||
M: x86 %and-imm 2operand AND ;
 | 
			
		||||
M: x86 %or      2operand OR ;
 | 
			
		||||
M: x86 %or-imm  2operand OR ;
 | 
			
		||||
M: x86 %xor     2operand XOR ;
 | 
			
		||||
M: x86 %xor-imm 2operand XOR ;
 | 
			
		||||
M: x86 %shl-imm 2operand SHL ;
 | 
			
		||||
M: x86 %shr-imm 2operand SHR ;
 | 
			
		||||
M: x86 %sar-imm 2operand SAR ;
 | 
			
		||||
M: x86 %not     1operand NOT ;
 | 
			
		||||
 | 
			
		||||
: bignum@ ( reg n -- op )
 | 
			
		||||
    cells bignum tag-number - [+] ; inline
 | 
			
		||||
 | 
			
		||||
M:: x86 %integer>bignum ( dst src temp -- )
 | 
			
		||||
    #! on entry, inreg is a signed 32-bit quantity
 | 
			
		||||
    #! exits with tagged ptr to bignum in outreg
 | 
			
		||||
    #! 1 cell header, 1 cell length, 1 cell sign, + digits
 | 
			
		||||
    #! length is the # of digits + sign
 | 
			
		||||
    [
 | 
			
		||||
        { "end" "nonzero" "positive" } [ define-label ] each
 | 
			
		||||
        src 0 CMP ! is it zero?
 | 
			
		||||
        "nonzero" get JNE
 | 
			
		||||
        ! Use cached zero value
 | 
			
		||||
        dst 0 >bignum %load-indirect
 | 
			
		||||
        "end" get JMP
 | 
			
		||||
        "nonzero" resolve-label
 | 
			
		||||
        ! Allocate a bignum
 | 
			
		||||
        dst 4 cells bignum bignum temp %allot
 | 
			
		||||
        ! Write length
 | 
			
		||||
        dst 1 bignum@ 2 tag-fixnum MOV
 | 
			
		||||
        ! Test sign
 | 
			
		||||
        src 0 CMP
 | 
			
		||||
        "positive" get JGE
 | 
			
		||||
        dst 2 bignum@ 1 MOV ! negative sign
 | 
			
		||||
        src NEG
 | 
			
		||||
        dst 3 bignum@ src MOV
 | 
			
		||||
        src NEG ! we don't want to clobber src
 | 
			
		||||
        "end" get JMP
 | 
			
		||||
        "positive" resolve-label
 | 
			
		||||
        dst 2 bignum@ 0 MOV ! positive sign
 | 
			
		||||
        dst 3 bignum@ src MOV
 | 
			
		||||
        "end" resolve-label
 | 
			
		||||
    ] with-scope ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %bignum>integer ( dst src -- )
 | 
			
		||||
    [
 | 
			
		||||
        "nonzero" define-label
 | 
			
		||||
        "positive" define-label
 | 
			
		||||
        "end" define-label
 | 
			
		||||
        dst src 1 bignum@ MOV
 | 
			
		||||
         ! if the length is 1, its just the sign and nothing else,
 | 
			
		||||
         ! so output 0
 | 
			
		||||
        dst 1 tag-fixnum CMP
 | 
			
		||||
        "nonzero" get JNE
 | 
			
		||||
        dst 0 MOV
 | 
			
		||||
        "end" get JMP
 | 
			
		||||
        "nonzero" resolve-label
 | 
			
		||||
        ! load the value
 | 
			
		||||
        dst src 3 bignum@ MOV
 | 
			
		||||
        ! is the sign negative?
 | 
			
		||||
        src 2 bignum@ 0 CMP
 | 
			
		||||
        "positive" get JE
 | 
			
		||||
        dst -1 IMUL2
 | 
			
		||||
        "positive" resolve-label
 | 
			
		||||
        dst 3 SHL
 | 
			
		||||
        "end" resolve-label
 | 
			
		||||
    ] with-scope ;
 | 
			
		||||
 | 
			
		||||
M: x86 %add-float 2operand ADDSD ;
 | 
			
		||||
M: x86 %sub-float 2operand SUBSD ;
 | 
			
		||||
M: x86 %mul-float 2operand MULSD ;
 | 
			
		||||
M: x86 %div-float 2operand DIVSD ;
 | 
			
		||||
 | 
			
		||||
M: x86 %integer>float CVTTSD2SI ;
 | 
			
		||||
M: x86 %float>integer CVTSI2SD ;
 | 
			
		||||
 | 
			
		||||
M: x86 %copy ( dst src -- ) MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %copy-float MOVSD ;
 | 
			
		||||
 | 
			
		||||
M: x86 %unbox-float ( dst src -- )
 | 
			
		||||
    float-offset [+] MOVSD ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %unbox-any-c-ptr ( dst src dst temp -- )
 | 
			
		||||
    [
 | 
			
		||||
        { "is-byte-array" "end" "start" } [ define-label ] each
 | 
			
		||||
        dst 0 MOV
 | 
			
		||||
        temp src MOV
 | 
			
		||||
        ! We come back here with displaced aliens
 | 
			
		||||
        "start" resolve-label
 | 
			
		||||
        ! Is the object f?
 | 
			
		||||
        temp \ f tag-number CMP
 | 
			
		||||
        "end" get JE
 | 
			
		||||
        ! Is the object an alien?
 | 
			
		||||
        temp header-offset [+] alien type-number tag-fixnum CMP
 | 
			
		||||
        "is-byte-array" get JNE
 | 
			
		||||
        ! If so, load the offset and add it to the address
 | 
			
		||||
        dst temp alien-offset [+] ADD
 | 
			
		||||
        ! Now recurse on the underlying alien
 | 
			
		||||
        temp temp underlying-alien-offset [+] MOV
 | 
			
		||||
        "start" get JMP
 | 
			
		||||
        "is-byte-array" resolve-label
 | 
			
		||||
        ! Add byte array address to address being computed
 | 
			
		||||
        dst temp ADD
 | 
			
		||||
        ! Add an offset to start of byte array's data
 | 
			
		||||
        dst byte-array-offset ADD
 | 
			
		||||
        "end" resolve-label
 | 
			
		||||
    ] with-scope ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %box-float ( dst src temp -- )
 | 
			
		||||
    dst 16 float float temp %allot
 | 
			
		||||
    dst 8 float tag-number - [+] src MOVSD ;
 | 
			
		||||
 | 
			
		||||
: alien@ ( reg n -- op ) cells object tag-number - [+] ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %box-alien ( dst src temp -- )
 | 
			
		||||
    [
 | 
			
		||||
        { "end" "f" } [ define-label ] each
 | 
			
		||||
        src 0 CMP
 | 
			
		||||
        "f" get JE
 | 
			
		||||
        dst 4 cells alien object temp %allot
 | 
			
		||||
        dst 1 alien@ \ f tag-number MOV
 | 
			
		||||
        dst 2 alien@ \ f tag-number MOV
 | 
			
		||||
        ! Store src in alien-offset slot
 | 
			
		||||
        dst 3 alien@ src MOV
 | 
			
		||||
        "end" get JMP
 | 
			
		||||
        "f" resolve-label
 | 
			
		||||
        dst \ f tag-number MOV
 | 
			
		||||
        "end" resolve-label
 | 
			
		||||
    ] with-scope ;
 | 
			
		||||
 | 
			
		||||
: small-reg-4 ( reg -- reg' )
 | 
			
		||||
    H{
 | 
			
		||||
        { EAX EAX }
 | 
			
		||||
        { ECX ECX }
 | 
			
		||||
        { EDX EDX }
 | 
			
		||||
        { EBX EBX }
 | 
			
		||||
        { ESP ESP }
 | 
			
		||||
        { EBP EBP }
 | 
			
		||||
        { ESI ESP }
 | 
			
		||||
        { EDI EDI }
 | 
			
		||||
 | 
			
		||||
        { RAX EAX }
 | 
			
		||||
        { RCX ECX }
 | 
			
		||||
        { RDX EDX }
 | 
			
		||||
        { RBX EBX }
 | 
			
		||||
        { RSP ESP }
 | 
			
		||||
        { RBP EBP }
 | 
			
		||||
        { RSI ESP }
 | 
			
		||||
        { RDI EDI }
 | 
			
		||||
    } at ; inline
 | 
			
		||||
 | 
			
		||||
: small-reg-2 ( reg -- reg' )
 | 
			
		||||
    small-reg-4 H{
 | 
			
		||||
        { EAX AX }
 | 
			
		||||
        { ECX CX }
 | 
			
		||||
        { EDX DX }
 | 
			
		||||
        { EBX BX }
 | 
			
		||||
        { ESP SP }
 | 
			
		||||
        { EBP BP }
 | 
			
		||||
        { ESI SI }
 | 
			
		||||
        { EDI DI }
 | 
			
		||||
    } at ; inline
 | 
			
		||||
 | 
			
		||||
: small-reg-1 ( reg -- reg' )
 | 
			
		||||
    small-reg-4 {
 | 
			
		||||
        { EAX AL }
 | 
			
		||||
        { ECX CL }
 | 
			
		||||
        { EDX DL }
 | 
			
		||||
        { EBX BL }
 | 
			
		||||
    } at ; inline
 | 
			
		||||
 | 
			
		||||
: small-reg ( reg size -- reg' )
 | 
			
		||||
    {
 | 
			
		||||
        { 1 small-reg-1 }
 | 
			
		||||
        { 2 small-reg-2 }
 | 
			
		||||
        { 4 small-reg-4 }
 | 
			
		||||
    } case ;
 | 
			
		||||
 | 
			
		||||
: small-regs ( -- regs ) { EAX ECX EDX EBX } ; inline
 | 
			
		||||
 | 
			
		||||
: small-reg-that-isn't ( exclude -- reg' )
 | 
			
		||||
    small-reg-4 small-regs [ eq? not ] with find nip ;
 | 
			
		||||
 | 
			
		||||
: with-save/restore ( reg quot -- )
 | 
			
		||||
    [ drop PUSH ] [ call ] [ drop POP ] 2tri ; inline
 | 
			
		||||
 | 
			
		||||
:: with-small-register ( dst src quot: ( dst src -- ) -- )
 | 
			
		||||
    #! If the destination register overlaps a small register, we
 | 
			
		||||
    #! call the quot with that. Otherwise, we find a small
 | 
			
		||||
    #! register that is not equal to src, and call quot, saving
 | 
			
		||||
    #! and restoring the small register.
 | 
			
		||||
    dst small-regs memq? [ src quot call ] [
 | 
			
		||||
        src small-reg-that-isn't
 | 
			
		||||
        [ src quot call ]
 | 
			
		||||
        with-save/restore
 | 
			
		||||
    ] if ; inline
 | 
			
		||||
 | 
			
		||||
: %alien-integer-getter ( dst src size quot -- )
 | 
			
		||||
    '[ [ _ small-reg ] dip @ ] with-small-register ; inline
 | 
			
		||||
 | 
			
		||||
: %alien-unsigned-getter ( dst src size -- )
 | 
			
		||||
    [ MOVZX ] %alien-integer-getter ; inline
 | 
			
		||||
 | 
			
		||||
M: x86 %alien-unsigned-1 1 %alien-unsigned-getter ;
 | 
			
		||||
M: x86 %alien-unsigned-2 2 %alien-unsigned-getter ;
 | 
			
		||||
M: x86 %alien-unsigned-4 4 %alien-unsigned-getter ;
 | 
			
		||||
 | 
			
		||||
: %alien-signed-getter ( dst src size -- )
 | 
			
		||||
    [ MOVSX ] %alien-integer-getter ; inline
 | 
			
		||||
 | 
			
		||||
M: x86 %alien-signed-1 1 %alien-signed-getter ;
 | 
			
		||||
M: x86 %alien-signed-2 2 %alien-signed-getter ;
 | 
			
		||||
M: x86 %alien-signed-4 4 %alien-signed-getter ;
 | 
			
		||||
 | 
			
		||||
M: x86 %alien-cell [] MOV ;
 | 
			
		||||
M: x86 %alien-float dupd [] MOVSS dup CVTSS2SD ;
 | 
			
		||||
M: x86 %alien-double [] MOVSD ;
 | 
			
		||||
 | 
			
		||||
:: %alien-integer-setter ( ptr value size -- )
 | 
			
		||||
    value ptr [| new-value ptr |
 | 
			
		||||
        new-value value ?MOV
 | 
			
		||||
        ptr [] new-value size small-reg MOV
 | 
			
		||||
    ] with-small-register ; inline
 | 
			
		||||
 | 
			
		||||
M: x86 %set-alien-integer-1 1 %alien-integer-setter ;
 | 
			
		||||
M: x86 %set-alien-integer-2 2 %alien-integer-setter ;
 | 
			
		||||
M: x86 %set-alien-integer-4 4 %alien-integer-setter ;
 | 
			
		||||
M: x86 %set-alien-cell [ [] ] dip MOV ;
 | 
			
		||||
M: x86 %set-alien-float dup dup CVTSD2SS [ [] ] dip MOVSS ;
 | 
			
		||||
M: x86 %set-alien-double [ [] ] dip MOVSD ;
 | 
			
		||||
 | 
			
		||||
: load-zone-ptr ( reg -- )
 | 
			
		||||
    #! Load pointer to start of zone array
 | 
			
		||||
    0 MOV "nursery" f rc-absolute-cell rel-dlsym ;
 | 
			
		||||
 | 
			
		||||
: load-allot-ptr ( nursery-ptr allot-ptr -- )
 | 
			
		||||
    [ drop load-zone-ptr ] [ swap cell [+] MOV ] 2bi ;
 | 
			
		||||
 | 
			
		||||
: inc-allot-ptr ( nursery-ptr n -- )
 | 
			
		||||
    [ cell [+] ] dip 8 align ADD ;
 | 
			
		||||
 | 
			
		||||
: store-header ( temp type -- )
 | 
			
		||||
    [ [] ] [ type-number tag-fixnum ] bi* MOV ;
 | 
			
		||||
 | 
			
		||||
: store-tagged ( dst tag -- )
 | 
			
		||||
    tag-number OR ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %allot ( dst size type tag nursery-ptr -- )
 | 
			
		||||
    nursery-ptr dst load-allot-ptr
 | 
			
		||||
    dst type store-header
 | 
			
		||||
    dst tag store-tagged
 | 
			
		||||
    nursery-ptr size inc-allot-ptr ;
 | 
			
		||||
 | 
			
		||||
HOOK: %alien-global cpu ( symbol dll register -- )
 | 
			
		||||
 | 
			
		||||
M:: x86 %write-barrier ( src card# table -- )
 | 
			
		||||
    #! Mark the card pointed to by vreg.
 | 
			
		||||
    ! Mark the card
 | 
			
		||||
    card# src MOV
 | 
			
		||||
    card# card-bits SHR
 | 
			
		||||
    "cards_offset" f table %alien-global
 | 
			
		||||
    table card# [+] card-mark <byte> MOV
 | 
			
		||||
 | 
			
		||||
    ! Mark the card deck
 | 
			
		||||
    card# deck-bits card-bits - SHR
 | 
			
		||||
    "decks_offset" f table %alien-global
 | 
			
		||||
    table card# [+] card-mark <byte> MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %gc ( -- )
 | 
			
		||||
    "end" define-label
 | 
			
		||||
    temp-reg-1 load-zone-ptr
 | 
			
		||||
    temp-reg-2 temp-reg-1 cell [+] MOV
 | 
			
		||||
    temp-reg-2 1024 ADD
 | 
			
		||||
    temp-reg-1 temp-reg-1 3 cells [+] MOV
 | 
			
		||||
    temp-reg-2 temp-reg-1 CMP
 | 
			
		||||
    "end" get JLE
 | 
			
		||||
    %prepare-alien-invoke
 | 
			
		||||
    "minor_gc" f %alien-invoke
 | 
			
		||||
    "end" resolve-label ;
 | 
			
		||||
 | 
			
		||||
HOOK: stack-reg cpu ( -- reg )
 | 
			
		||||
 | 
			
		||||
: decr-stack-reg ( n -- )
 | 
			
		||||
    dup 0 = [ drop ] [ stack-reg swap SUB ] if ;
 | 
			
		||||
 | 
			
		||||
M: x86 %prologue ( n -- )
 | 
			
		||||
    temp-reg-1 0 MOV rc-absolute-cell rel-this
 | 
			
		||||
    dup PUSH
 | 
			
		||||
    temp-reg-1 PUSH
 | 
			
		||||
    stack-reg swap 3 cells - SUB ;
 | 
			
		||||
 | 
			
		||||
: incr-stack-reg ( n -- )
 | 
			
		||||
    dup 0 = [ drop ] [ stack-reg swap ADD ] if ;
 | 
			
		||||
 | 
			
		||||
M: x86 %epilogue ( n -- ) cell - incr-stack-reg ;
 | 
			
		||||
 | 
			
		||||
M: x86 %compare-branch ( label cc src1 src2 -- )
 | 
			
		||||
    CMP {
 | 
			
		||||
        { cc< [ JL ] }
 | 
			
		||||
        { cc<= [ JLE ] }
 | 
			
		||||
        { cc> [ JG ] }
 | 
			
		||||
        { cc>= [ JGE ] }
 | 
			
		||||
        { cc= [ JE ] }
 | 
			
		||||
    } case ;
 | 
			
		||||
 | 
			
		||||
M: x86 %compare-imm-branch ( label src1 src2 cc -- )
 | 
			
		||||
    %compare-branch ;
 | 
			
		||||
 | 
			
		||||
M: x86 %compare-float-branch ( label cc src1 src2 -- )
 | 
			
		||||
    UCOMISD {
 | 
			
		||||
        { cc< [ JB ] }
 | 
			
		||||
        { cc<= [ JBE ] }
 | 
			
		||||
        { cc> [ JA ] }
 | 
			
		||||
        { cc>= [ JAE ] }
 | 
			
		||||
        { cc= [ JE ] }
 | 
			
		||||
    } case ;
 | 
			
		||||
 | 
			
		||||
: stack@ ( n -- op ) stack-reg swap [+] ;
 | 
			
		||||
 | 
			
		||||
: spill-integer-base ( stack-frame -- n )
 | 
			
		||||
| 
						 | 
				
			
			@ -34,19 +434,11 @@ HOOK: stack-reg cpu ( -- reg )
 | 
			
		|||
    stack-frame get spill-float-base
 | 
			
		||||
    + stack@ ;
 | 
			
		||||
 | 
			
		||||
: next-stack@ ( n -- operand )
 | 
			
		||||
    #! nth parameter from the next stack frame. Used to box
 | 
			
		||||
    #! input values to callbacks; the callback has its own
 | 
			
		||||
    #! stack frame set up, and we want to read the frame
 | 
			
		||||
    #! set up by the caller.
 | 
			
		||||
    stack-frame get total-size>> + stack@ ;
 | 
			
		||||
M: x86 %spill-integer ( src n -- ) spill-integer@ swap MOV ;
 | 
			
		||||
M: x86 %reload-integer ( dst n -- ) spill-integer@ MOV ;
 | 
			
		||||
 | 
			
		||||
: reg-stack ( n reg -- op ) swap cells neg [+] ;
 | 
			
		||||
 | 
			
		||||
GENERIC: loc>operand ( loc -- operand )
 | 
			
		||||
 | 
			
		||||
M: ds-loc loc>operand n>> ds-reg reg-stack ;
 | 
			
		||||
M: rs-loc loc>operand n>> rs-reg reg-stack ;
 | 
			
		||||
M: x86 %spill-float spill-float@ swap MOVSD ;
 | 
			
		||||
M: x86 %reload-float spill-float@ MOVSD ;
 | 
			
		||||
 | 
			
		||||
M: int-regs %save-param-reg drop >r stack@ r> MOV ;
 | 
			
		||||
M: int-regs %load-param-reg drop swap stack@ MOV ;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +446,6 @@ M: int-regs %load-param-reg drop swap stack@ MOV ;
 | 
			
		|||
GENERIC: MOVSS/D ( dst src reg-class -- )
 | 
			
		||||
 | 
			
		||||
M: single-float-regs MOVSS/D drop MOVSS ;
 | 
			
		||||
 | 
			
		||||
M: double-float-regs MOVSS/D drop MOVSD ;
 | 
			
		||||
 | 
			
		||||
M: float-regs %save-param-reg >r >r stack@ r> r> MOVSS/D ;
 | 
			
		||||
| 
						 | 
				
			
			@ -64,42 +455,6 @@ GENERIC: push-return-reg ( reg-class -- )
 | 
			
		|||
GENERIC: load-return-reg ( n reg-class -- )
 | 
			
		||||
GENERIC: store-return-reg ( n reg-class -- )
 | 
			
		||||
 | 
			
		||||
! Only used by inline allocation
 | 
			
		||||
HOOK: temp-reg-1 cpu ( -- reg )
 | 
			
		||||
HOOK: temp-reg-2 cpu ( -- reg )
 | 
			
		||||
 | 
			
		||||
HOOK: fixnum>slot@ cpu ( op -- )
 | 
			
		||||
HOOK: prepare-division cpu ( -- )
 | 
			
		||||
 | 
			
		||||
M: x86 %load-immediate MOV ;
 | 
			
		||||
 | 
			
		||||
: align-stack ( n -- n' )
 | 
			
		||||
    os macosx? cpu x86.64? or [ 16 align ] when ;
 | 
			
		||||
 | 
			
		||||
M: x86 stack-frame-size ( stack-frame -- i )
 | 
			
		||||
    [ spill-counts>> [ swap reg-size * ] { } assoc>map sum ]
 | 
			
		||||
    [ params>> ]
 | 
			
		||||
    [ return>> ]
 | 
			
		||||
    tri + +
 | 
			
		||||
    3 cells +
 | 
			
		||||
    align-stack ;
 | 
			
		||||
 | 
			
		||||
: decr-stack-reg ( n -- )
 | 
			
		||||
    dup 0 = [ drop ] [ stack-reg swap SUB ] if ;
 | 
			
		||||
 | 
			
		||||
M: x86 %prologue ( n -- )
 | 
			
		||||
    temp-reg-1 0 MOV rc-absolute-cell rel-this
 | 
			
		||||
    dup PUSH
 | 
			
		||||
    temp-reg-1 PUSH
 | 
			
		||||
    stack-reg swap 3 cells - SUB ;
 | 
			
		||||
 | 
			
		||||
: incr-stack-reg ( n -- )
 | 
			
		||||
    dup 0 = [ drop ] [ stack-reg swap ADD ] if ;
 | 
			
		||||
 | 
			
		||||
M: x86 %epilogue ( n -- ) cell - incr-stack-reg ;
 | 
			
		||||
 | 
			
		||||
HOOK: %alien-global cpu ( symbol dll register -- )
 | 
			
		||||
 | 
			
		||||
M: x86 %prepare-alien-invoke
 | 
			
		||||
    #! Save Factor stack pointers in case the C code calls a
 | 
			
		||||
    #! callback which does a GC, which must reliably trace
 | 
			
		||||
| 
						 | 
				
			
			@ -110,52 +465,6 @@ M: x86 %prepare-alien-invoke
 | 
			
		|||
    temp-reg-1 2 cells [+] ds-reg MOV
 | 
			
		||||
    temp-reg-1 3 cells [+] rs-reg MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %call ( label -- ) CALL ;
 | 
			
		||||
 | 
			
		||||
M: x86 %jump-label ( label -- ) JMP ;
 | 
			
		||||
 | 
			
		||||
! M: x86 %jump-f ( label reg -- )
 | 
			
		||||
!     \ f tag-number CMP JE ;
 | 
			
		||||
! 
 | 
			
		||||
! M: x86 %jump-t ( label reg -- )
 | 
			
		||||
!     \ f tag-number CMP JNE ;
 | 
			
		||||
 | 
			
		||||
: code-alignment ( -- n )
 | 
			
		||||
    building get length dup cell align swap - ;
 | 
			
		||||
 | 
			
		||||
: align-code ( n -- )
 | 
			
		||||
    0 <repetition> % ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %dispatch ( src temp -- )
 | 
			
		||||
    ! Load jump table base. We use a temporary register
 | 
			
		||||
    ! since on AMD64 we have to load a 64-bit immediate. On
 | 
			
		||||
    ! x86, this is redundant.
 | 
			
		||||
    ! Untag and multiply to get a jump table offset
 | 
			
		||||
    src fixnum>slot@
 | 
			
		||||
    ! Add jump table base
 | 
			
		||||
    temp HEX: ffffffff MOV rc-absolute-cell rel-here
 | 
			
		||||
    src temp ADD
 | 
			
		||||
    src HEX: 7f [+] JMP
 | 
			
		||||
    ! Fix up the displacement above
 | 
			
		||||
    code-alignment dup bootstrap-cell 8 = 15 9 ? +
 | 
			
		||||
    building get dup pop* push
 | 
			
		||||
    align-code ;
 | 
			
		||||
 | 
			
		||||
M: x86 %dispatch-label ( word -- )
 | 
			
		||||
    0 cell, rc-absolute-cell rel-word ;
 | 
			
		||||
 | 
			
		||||
M: x86 %peek loc>operand MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %replace loc>operand swap MOV ;
 | 
			
		||||
 | 
			
		||||
: (%inc) ( n reg -- ) swap cells dup 0 > [ ADD ] [ neg SUB ] if ;
 | 
			
		||||
 | 
			
		||||
M: x86 %inc-d ( n -- ) ds-reg (%inc) ;
 | 
			
		||||
 | 
			
		||||
M: x86 %inc-r ( n -- ) rs-reg (%inc) ;
 | 
			
		||||
 | 
			
		||||
M: x86 %copy ( dst src -- ) MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 fp-shadows-int? ( -- ? ) f ;
 | 
			
		||||
 | 
			
		||||
M: x86 value-structs? t ;
 | 
			
		||||
| 
						 | 
				
			
			@ -163,60 +472,9 @@ M: x86 value-structs? t ;
 | 
			
		|||
M: x86 small-enough? ( n -- ? )
 | 
			
		||||
    HEX: -80000000 HEX: 7fffffff between? ;
 | 
			
		||||
 | 
			
		||||
: %untag ( reg -- ) tag-mask get bitnot AND ;
 | 
			
		||||
 | 
			
		||||
: %untag-fixnum ( reg -- ) tag-bits get SAR ;
 | 
			
		||||
 | 
			
		||||
: %tag-fixnum ( reg -- ) tag-bits get SHL ;
 | 
			
		||||
 | 
			
		||||
M: x86 %return ( -- ) 0 RET ;
 | 
			
		||||
 | 
			
		||||
! Alien intrinsics
 | 
			
		||||
M: x86 %unbox-byte-array ( dst src -- )
 | 
			
		||||
    byte-array-offset [+] LEA ;
 | 
			
		||||
 | 
			
		||||
M: x86 %unbox-alien ( dst src -- )
 | 
			
		||||
    alien-offset [+] MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %unbox-f ( dst src -- )
 | 
			
		||||
    drop 0 MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %unbox-any-c-ptr ( dst src -- )
 | 
			
		||||
    { "is-byte-array" "end" "start" } [ define-label ] each
 | 
			
		||||
    ! Address is computed in ds-reg
 | 
			
		||||
    ds-reg PUSH
 | 
			
		||||
    ds-reg 0 MOV
 | 
			
		||||
    ! Object is stored in ds-reg
 | 
			
		||||
    rs-reg PUSH
 | 
			
		||||
    rs-reg swap MOV
 | 
			
		||||
    ! We come back here with displaced aliens
 | 
			
		||||
    "start" resolve-label
 | 
			
		||||
    ! Is the object f?
 | 
			
		||||
    rs-reg \ f tag-number CMP
 | 
			
		||||
    "end" get JE
 | 
			
		||||
    ! Is the object an alien?
 | 
			
		||||
    rs-reg header-offset [+] alien type-number tag-fixnum CMP
 | 
			
		||||
    "is-byte-array" get JNE
 | 
			
		||||
    ! If so, load the offset and add it to the address
 | 
			
		||||
    ds-reg rs-reg alien-offset [+] ADD
 | 
			
		||||
    ! Now recurse on the underlying alien
 | 
			
		||||
    rs-reg rs-reg underlying-alien-offset [+] MOV
 | 
			
		||||
    "start" get JMP
 | 
			
		||||
    "is-byte-array" resolve-label
 | 
			
		||||
    ! Add byte array address to address being computed
 | 
			
		||||
    ds-reg rs-reg ADD
 | 
			
		||||
    ! Add an offset to start of byte array's data
 | 
			
		||||
    ds-reg byte-array-offset ADD
 | 
			
		||||
    "end" resolve-label
 | 
			
		||||
    ! Done, store address in destination register
 | 
			
		||||
    ds-reg MOV
 | 
			
		||||
    ! Restore rs-reg
 | 
			
		||||
    rs-reg POP
 | 
			
		||||
    ! Restore ds-reg
 | 
			
		||||
    ds-reg POP ;
 | 
			
		||||
 | 
			
		||||
M: x86 %spill-integer ( src n -- )
 | 
			
		||||
    spill-integer@ swap MOV ;
 | 
			
		||||
 | 
			
		||||
M: x86 %reload-integer ( dst n -- )
 | 
			
		||||
    spill-integer@ MOV ;
 | 
			
		||||
: next-stack@ ( n -- operand )
 | 
			
		||||
    #! nth parameter from the next stack frame. Used to box
 | 
			
		||||
    #! input values to callbacks; the callback has its own
 | 
			
		||||
    #! stack frame set up, and we want to read the frame
 | 
			
		||||
    #! set up by the caller.
 | 
			
		||||
    stack-frame get total-size>> + stack@ ;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
Slava Pestov
 | 
			
		||||
| 
						 | 
				
			
			@ -1,328 +0,0 @@
 | 
			
		|||
! 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
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
unportable
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
Slava Pestov
 | 
			
		||||
| 
						 | 
				
			
			@ -1,115 +0,0 @@
 | 
			
		|||
! Copyright (C) 2005, 2008 Slava Pestov.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: alien alien.accessors arrays generic kernel
 | 
			
		||||
kernel.private math math.private memory namespaces sequences
 | 
			
		||||
words math.floats.private layouts quotations locals fry
 | 
			
		||||
system compiler.constants compiler.codegen compiler.cfg.templates
 | 
			
		||||
compiler.cfg.registers compiler.cfg.builder cpu.architecture
 | 
			
		||||
cpu.x86.assembler cpu.x86.architecture cpu.x86.intrinsics ;
 | 
			
		||||
IN: cpu.x86.sse2
 | 
			
		||||
 | 
			
		||||
M: x86 %spill-float ( src n -- )
 | 
			
		||||
    spill-float@ swap MOVSD ;
 | 
			
		||||
 | 
			
		||||
M: x86 %reload-float ( dst n -- )
 | 
			
		||||
    spill-float@ MOVSD ;
 | 
			
		||||
 | 
			
		||||
M: x86 %copy-float MOVSD ;
 | 
			
		||||
 | 
			
		||||
M:: x86 %box-float ( dst src temp -- )
 | 
			
		||||
    dst 16 float float temp %allot
 | 
			
		||||
    dst 8 float tag-number - [+] src MOVSD ;
 | 
			
		||||
 | 
			
		||||
M: x86 %unbox-float ( dst src -- )
 | 
			
		||||
    float-offset [+] MOVSD ;
 | 
			
		||||
 | 
			
		||||
: define-float-op ( word op -- )
 | 
			
		||||
    [ "x" operand "y" operand ] swap suffix T{ template
 | 
			
		||||
        { input { { float "x" } { float "y" } } }
 | 
			
		||||
        { output { "x" } }
 | 
			
		||||
    } define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    { float+ ADDSD }
 | 
			
		||||
    { float- SUBSD }
 | 
			
		||||
    { float* MULSD }
 | 
			
		||||
    { float/f DIVSD }
 | 
			
		||||
} [
 | 
			
		||||
    first2 define-float-op
 | 
			
		||||
] each
 | 
			
		||||
 | 
			
		||||
: define-float-jump ( word op -- )
 | 
			
		||||
    [ "x" operand "y" operand UCOMISD ] swap suffix
 | 
			
		||||
    { { float "x" } { float "y" } } define-if-intrinsic ;
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    { float< JB }
 | 
			
		||||
    { float<= JBE }
 | 
			
		||||
    { float> JA }
 | 
			
		||||
    { float>= JAE }
 | 
			
		||||
    { float= JE }
 | 
			
		||||
} [
 | 
			
		||||
    first2 define-float-jump
 | 
			
		||||
] each
 | 
			
		||||
 | 
			
		||||
\ float>fixnum [
 | 
			
		||||
    "out" operand "in" operand CVTTSD2SI
 | 
			
		||||
    "out" operand tag-bits get SHL
 | 
			
		||||
] T{ template
 | 
			
		||||
    { input { { float "in" } } }
 | 
			
		||||
    { scratch { { f "out" } } }
 | 
			
		||||
    { output { "out" } }
 | 
			
		||||
} define-intrinsic
 | 
			
		||||
 | 
			
		||||
\ fixnum>float [
 | 
			
		||||
    "in" operand %untag-fixnum
 | 
			
		||||
    "out" operand "in" operand CVTSI2SD
 | 
			
		||||
] T{ template
 | 
			
		||||
    { input { { f "in" } } }
 | 
			
		||||
    { scratch { { float "out" } } }
 | 
			
		||||
    { output { "out" } }
 | 
			
		||||
    { clobber { "in" } }
 | 
			
		||||
} define-intrinsic
 | 
			
		||||
 | 
			
		||||
: alien-float-get-template
 | 
			
		||||
    T{ template
 | 
			
		||||
        { input {
 | 
			
		||||
            { unboxed-c-ptr "alien" c-ptr }
 | 
			
		||||
            { f "offset" fixnum }
 | 
			
		||||
        } }
 | 
			
		||||
        { scratch { { float "value" } } }
 | 
			
		||||
        { output { "value" } }
 | 
			
		||||
        { clobber { "offset" } }
 | 
			
		||||
    } ;
 | 
			
		||||
 | 
			
		||||
: alien-float-set-template
 | 
			
		||||
    T{ template
 | 
			
		||||
        { input {
 | 
			
		||||
            { float "value" float }
 | 
			
		||||
            { unboxed-c-ptr "alien" c-ptr }
 | 
			
		||||
            { f "offset" fixnum }
 | 
			
		||||
        } }
 | 
			
		||||
        { clobber { "offset" } }
 | 
			
		||||
    } ;
 | 
			
		||||
 | 
			
		||||
: define-float-getter ( word get-quot -- )
 | 
			
		||||
    '[
 | 
			
		||||
        %prepare-alien-accessor
 | 
			
		||||
        "value" operand "offset" operand [] @
 | 
			
		||||
    ]
 | 
			
		||||
    alien-float-get-template
 | 
			
		||||
    define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
: define-float-setter ( word set-quot -- )
 | 
			
		||||
    '[
 | 
			
		||||
        %prepare-alien-accessor
 | 
			
		||||
        "offset" operand [] "value" operand @
 | 
			
		||||
    ]
 | 
			
		||||
    alien-float-set-template
 | 
			
		||||
    define-intrinsic ;
 | 
			
		||||
 | 
			
		||||
\ alien-double [ MOVSD ] define-float-getter
 | 
			
		||||
\ set-alien-double [ MOVSD ] define-float-setter
 | 
			
		||||
 | 
			
		||||
\ alien-float [ dupd MOVSS dup CVTSS2SD ] define-float-getter
 | 
			
		||||
\ set-alien-float [ dup dup CVTSD2SS MOVSS ] define-float-setter
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
SSE2 floating point intrinsics for Pentium 4 and above
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
unportable
 | 
			
		||||
		Loading…
	
		Reference in New Issue