2007-09-20 18:09:08 -04:00
|
|
|
! Copyright (C) 2005, 2007 Slava Pestov.
|
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2008-07-03 20:09:33 -04:00
|
|
|
USING: accessors alien.c-types arrays cpu.x86.assembler
|
2007-09-20 18:09:08 -04:00
|
|
|
cpu.x86.architecture cpu.x86.intrinsics cpu.x86.sse2
|
|
|
|
cpu.x86.allot cpu.architecture kernel kernel.private math
|
2008-09-11 01:48:23 -04:00
|
|
|
namespaces make sequences compiler.generator
|
|
|
|
compiler.generator.registers compiler.generator.fixup system
|
|
|
|
layouts alien alien.accessors alien.structs slots splitting
|
|
|
|
assocs ;
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: cpu.x86.64
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 ds-reg R14 ;
|
|
|
|
M: x86.64 rs-reg R15 ;
|
|
|
|
M: x86.64 stack-reg RSP ;
|
|
|
|
M: x86.64 stack-save-reg RSI ;
|
2008-04-19 05:52:34 -04:00
|
|
|
M: x86.64 temp-reg-1 RAX ;
|
|
|
|
M: x86.64 temp-reg-2 RCX ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2007-09-22 03:09:18 -04:00
|
|
|
M: temp-reg v>operand drop RBX ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: int-regs return-reg drop RAX ;
|
2007-09-22 03:09:18 -04:00
|
|
|
M: int-regs vregs drop { RAX RCX RDX RBP RSI RDI R8 R9 R10 R11 R12 R13 } ;
|
2007-09-20 18:09:08 -04:00
|
|
|
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
|
|
|
|
XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15
|
|
|
|
} ;
|
|
|
|
|
|
|
|
M: float-regs param-regs
|
|
|
|
drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 address-operand ( address -- operand )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! 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.
|
|
|
|
temp-reg v>operand [ swap MOV ] keep ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 fixnum>slot@ drop ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 prepare-division CQO ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 load-indirect ( literal reg -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
0 [] MOV rc-relative rel-literal ;
|
|
|
|
|
|
|
|
M: stack-params %load-param-reg
|
|
|
|
drop
|
|
|
|
>r temp-reg v>operand swap stack@ MOV
|
|
|
|
r> stack@ temp-reg v>operand MOV ;
|
|
|
|
|
|
|
|
M: stack-params %save-param-reg
|
|
|
|
>r stack-frame* + cell + swap r> %load-param-reg ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %prepare-unbox ( -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
! First parameter is top of stack
|
|
|
|
RDI R14 [] MOV
|
|
|
|
R14 cell SUB ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %unbox ( n reg-class func -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
! Call the unboxer
|
2007-10-30 01:46:41 -04:00
|
|
|
f %alien-invoke
|
2007-09-20 18:09:08 -04:00
|
|
|
! Store the return value on the C stack
|
|
|
|
over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %unbox-long-long ( n func -- )
|
2008-04-04 04:46:30 -04:00
|
|
|
int-regs swap %unbox ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %unbox-struct-1 ( -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! Alien must be in RDI.
|
2007-10-30 01:46:41 -04:00
|
|
|
"alien_offset" f %alien-invoke
|
2007-09-20 18:09:08 -04:00
|
|
|
! Load first cell
|
|
|
|
RAX RAX [] MOV ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %unbox-struct-2 ( -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! Alien must be in RDI.
|
2007-10-30 01:46:41 -04:00
|
|
|
"alien_offset" f %alien-invoke
|
2007-09-20 18:09:08 -04:00
|
|
|
! Load second cell
|
|
|
|
RDX RAX cell [+] MOV
|
|
|
|
! Load first cell
|
|
|
|
RAX RAX [] MOV ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %unbox-large-struct ( n size -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
! Source is in RDI
|
|
|
|
! Load destination address
|
|
|
|
RSI RSP roll [+] LEA
|
|
|
|
! Load structure size
|
|
|
|
RDX swap MOV
|
|
|
|
! Copy the struct to the C stack
|
2007-10-30 01:46:41 -04:00
|
|
|
"to_value_struct" f %alien-invoke ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: load-return-value ( reg-class -- )
|
|
|
|
0 over param-reg swap return-reg
|
|
|
|
2dup eq? [ 2drop ] [ MOV ] if ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %box ( n reg-class func -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
rot [
|
|
|
|
rot [ 0 swap param-reg ] keep %load-param-reg
|
|
|
|
] [
|
|
|
|
swap load-return-value
|
|
|
|
] if*
|
2007-10-30 01:46:41 -04:00
|
|
|
f %alien-invoke ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %box-long-long ( n func -- )
|
2008-04-04 04:46:30 -04:00
|
|
|
int-regs swap %box ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 struct-small-enough? ( size -- ? ) 2 cells <= ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %box-small-struct ( size -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! Box a <= 16-byte struct returned in RAX:RDX.
|
|
|
|
RDI RAX MOV
|
|
|
|
RSI RDX MOV
|
|
|
|
RDX swap MOV
|
2007-10-30 01:46:41 -04:00
|
|
|
"box_small_struct" f %alien-invoke ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %box-large-struct ( n size -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
! 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
|
2007-10-30 01:46:41 -04:00
|
|
|
"box_value_struct" f %alien-invoke ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %prepare-box-struct ( size -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
! Compute target address for value struct return
|
|
|
|
RAX RSP rot f struct-return@ [+] LEA
|
|
|
|
RSP 0 [+] RAX MOV ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %prepare-var-args RAX RAX XOR ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-05-09 00:21:46 -04:00
|
|
|
M: x86.64 %alien-global
|
|
|
|
[ 0 MOV rc-absolute-cell rel-dlsym ] [ dup [] MOV ] bi ;
|
|
|
|
|
|
|
|
M: x86.64 %alien-invoke
|
2007-10-30 01:46:41 -04:00
|
|
|
0 address-operand >r rc-absolute-cell rel-dlsym r> CALL ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %prepare-alien-indirect ( -- )
|
2007-10-30 01:46:41 -04:00
|
|
|
"unbox_alien" f %alien-invoke
|
2007-09-20 18:09:08 -04:00
|
|
|
cell temp@ RAX MOV ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %alien-indirect ( -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
cell temp@ CALL ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %alien-callback ( quot -- )
|
2007-10-30 01:46:41 -04:00
|
|
|
RDI load-indirect "c_to_factor" f %alien-invoke ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %callback-value ( ctype -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
! Save top of data stack
|
|
|
|
%prepare-unbox
|
|
|
|
! Put former top of data stack in RDI
|
2007-09-22 03:09:18 -04:00
|
|
|
cell temp@ RDI MOV
|
2007-09-20 18:09:08 -04:00
|
|
|
! Restore data/call/retain stacks
|
|
|
|
"unnest_stacks" f %alien-invoke
|
|
|
|
! Put former top of data stack in RDI
|
2007-09-22 03:09:18 -04:00
|
|
|
RDI cell temp@ MOV
|
2007-09-20 18:09:08 -04:00
|
|
|
! Unbox former top of data stack to return registers
|
|
|
|
unbox-return ;
|
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %cleanup ( alien-node -- ) drop ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-04-02 18:07:38 -04:00
|
|
|
M: x86.64 %unwind ( n -- ) drop %epilogue-later 0 RET ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
USE: cpu.x86.intrinsics
|
|
|
|
|
|
|
|
! On 64-bit systems, the result of reading 4 bytes from memory
|
|
|
|
! is a fixnum.
|
|
|
|
\ alien-unsigned-4 small-reg-32 define-unsigned-getter
|
|
|
|
\ set-alien-unsigned-4 small-reg-32 define-setter
|
|
|
|
|
|
|
|
\ alien-signed-4 small-reg-32 define-signed-getter
|
|
|
|
\ set-alien-signed-4 small-reg-32 define-setter
|
|
|
|
|
2007-10-09 18:06:44 -04:00
|
|
|
! The ABI for passing structs by value is pretty messed up
|
2008-01-12 23:50:22 -05:00
|
|
|
<< "void*" c-type clone "__stack_value" define-primitive-type
|
2008-08-31 08:45:33 -04:00
|
|
|
stack-params "__stack_value" c-type (>>reg-class) >>
|
2007-10-09 18:06:44 -04:00
|
|
|
|
2007-10-10 00:20:45 -04:00
|
|
|
: struct-types&offset ( struct-type -- pairs )
|
2008-08-31 08:45:33 -04:00
|
|
|
fields>> [
|
2008-09-03 19:47:52 -04:00
|
|
|
[ type>> ] [ offset>> ] bi 2array
|
2007-10-09 18:06:44 -04:00
|
|
|
] map ;
|
|
|
|
|
|
|
|
: split-struct ( pairs -- seq )
|
|
|
|
[
|
2008-01-10 20:29:11 -05:00
|
|
|
[ 8 mod zero? [ t , ] when , ] assoc-each
|
2008-05-14 00:36:55 -04:00
|
|
|
] { } make { t } split harvest ;
|
2007-10-09 18:06:44 -04:00
|
|
|
|
|
|
|
: flatten-large-struct ( type -- )
|
|
|
|
heap-size cell align
|
2007-10-10 00:20:45 -04:00
|
|
|
cell /i "__stack_value" c-type <repetition> % ;
|
2007-10-09 18:06:44 -04:00
|
|
|
|
|
|
|
M: struct-type flatten-value-type ( type -- seq )
|
2007-10-10 00:20:45 -04:00
|
|
|
dup heap-size 16 > [
|
2007-10-09 18:06:44 -04:00
|
|
|
flatten-large-struct
|
|
|
|
] [
|
|
|
|
struct-types&offset split-struct [
|
|
|
|
[ c-type c-type-reg-class ] map
|
2008-04-04 04:46:30 -04:00
|
|
|
int-regs swap member?
|
2007-10-10 00:20:45 -04:00
|
|
|
"void*" "double" ? c-type ,
|
2007-10-09 18:06:44 -04:00
|
|
|
] each
|
|
|
|
] if ;
|