151 lines
4.0 KiB
Factor
151 lines
4.0 KiB
Factor
! Copyright (C) 2005, 2007 Slava Pestov.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
IN: generator
|
|
USING: alien arrays assembler-x86 generic kernel
|
|
kernel-internals math namespaces sequences ;
|
|
|
|
! AMD64 register assignments
|
|
! RAX RCX RDX RSI RDI R8 R9 R10 integer vregs
|
|
! XMM0 - XMM7 float vregs
|
|
! R14 data stack
|
|
! R15 retain stack
|
|
|
|
: ds-reg R14 ; inline
|
|
: rs-reg R15 ; inline
|
|
: allot-tmp-reg RBX ; inline
|
|
: stack-reg RSP ; inline
|
|
|
|
M: int-regs return-reg drop RAX ;
|
|
M: int-regs vregs drop { RAX RCX RDX RSI RDI R8 R9 R10 R11 } ;
|
|
M: int-regs param-regs drop { RDI RSI RDX RCX R8 R9 } ;
|
|
|
|
M: float-regs return-reg drop XMM0 ;
|
|
M: float-regs vregs drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
|
|
M: float-regs param-regs vregs ;
|
|
|
|
: address-operand ( address -- operand )
|
|
#! On AMD64, we have to load 64-bit addresses into a
|
|
#! scratch register first. The usage of R11 here is a hack.
|
|
#! This word can only be called right before a subroutine
|
|
#! call, where all vregs have been flushed anyway.
|
|
R11 [ swap MOV ] keep ; inline
|
|
|
|
: compile-c-call ( symbol dll -- )
|
|
0 address-operand >r rc-absolute-cell rel-dlsym r> CALL ;
|
|
|
|
: fixnum>slot@ drop ; inline
|
|
|
|
: prepare-division CQO ; inline
|
|
|
|
: load-indirect ( literal vreg -- )
|
|
0 [] MOV rc-relative rel-literal ;
|
|
|
|
M: stack-params %load-param-reg
|
|
drop >r R11 swap stack@ MOV r> stack@ R11 MOV ;
|
|
|
|
M: stack-params %save-param-reg
|
|
>r stack-increment + cell + swap r> %load-param-reg ;
|
|
|
|
: %unbox-struct-1 ( -- )
|
|
#! Alien must be in RDI.
|
|
"alien_offset" f compile-c-call
|
|
! Load first cell
|
|
RAX RAX [] MOV ;
|
|
|
|
: %unbox-struct-2 ( -- )
|
|
#! Alien must be in RDI.
|
|
"alien_offset" f compile-c-call
|
|
! Load second cell
|
|
RDX RAX cell [+] MOV
|
|
! Load first cell
|
|
RAX RAX [] MOV ;
|
|
|
|
: %unbox-large-struct ( n size -- )
|
|
! Source is in RDI
|
|
! Load destination address
|
|
RSI RSP roll [+] LEA
|
|
! Load structure size
|
|
RDX swap MOV
|
|
! Copy the struct to the C stack
|
|
"to_value_struct" f compile-c-call ;
|
|
|
|
: %prepare-unbox ( -- )
|
|
! First parameter is top of stack
|
|
RDI R14 [] MOV
|
|
R14 cell SUB ;
|
|
|
|
: %unbox ( n reg-class func -- )
|
|
! Call the unboxer
|
|
f compile-c-call
|
|
! Store the return value on the C stack
|
|
over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
|
|
|
|
: struct-small-enough? ( size -- ? ) 2 cells <= ;
|
|
|
|
: %box-struct-1 ( -- )
|
|
#! Box a 8-byte struct returned in RAX.
|
|
RDI RAX MOV
|
|
"box_struct_1" f compile-c-call ;
|
|
|
|
: %box-struct-2 ( -- )
|
|
#! Box a 16-byte struct returned in RAX:RDX.
|
|
RDI RAX MOV
|
|
RSI RDX MOV
|
|
"box_struct_2" f compile-c-call ;
|
|
|
|
: %box-large-struct ( n size -- )
|
|
! Struct size is parameter 2
|
|
RSI over MOV
|
|
! Compute destination address
|
|
swap struct-return@ RDI RSP rot [+] LEA
|
|
! Copy the struct from the C stack
|
|
"box_value_struct" f compile-c-call ;
|
|
|
|
: %prepare-box-struct ( size -- )
|
|
! Compute target address for value struct return
|
|
RAX RSP rot f struct-return@ [+] LEA
|
|
RSP 0 [+] RAX MOV ;
|
|
|
|
: load-return-value ( reg-class -- )
|
|
0 over param-reg swap return-reg
|
|
2dup eq? [ 2drop ] [ MOV ] if ;
|
|
|
|
: %box ( n reg-class func -- )
|
|
rot [
|
|
rot [ 0 swap param-reg ] keep %load-param-reg
|
|
] [
|
|
swap load-return-value
|
|
] if*
|
|
f compile-c-call ;
|
|
|
|
: reset-sse RAX RAX XOR ;
|
|
|
|
: %alien-invoke ( symbol dll -- )
|
|
reset-sse compile-c-call ;
|
|
|
|
: %prepare-alien-indirect ( -- )
|
|
"unbox_alien" f compile-c-call
|
|
RSP stack-increment cell - [+] RAX MOV ;
|
|
|
|
: %alien-indirect ( -- )
|
|
reset-sse RSP stack-increment cell - [+] CALL ;
|
|
|
|
: %alien-callback ( quot -- )
|
|
RDI load-indirect "run_callback" f compile-c-call ;
|
|
|
|
: %callback-value ( ctype -- )
|
|
! Save top of data stack
|
|
%prepare-unbox
|
|
! Put former top of data stack in RDI
|
|
RSP stack-increment cell - [+] RDI MOV
|
|
! Restore data/call/retain stacks
|
|
"unnest_stacks" f %alien-invoke
|
|
! Put former top of data stack in RDI
|
|
RDI RSP stack-increment cell - [+] MOV
|
|
! Unbox former top of data stack to return registers
|
|
unbox-return ;
|
|
|
|
: %cleanup ( alien-node -- ) drop ;
|
|
|
|
: %unwind ( n -- ) drop %return ;
|