factor/basis/cpu/x86/64/64.factor

220 lines
5.9 KiB
Factor
Raw Normal View History

! Copyright (C) 2005, 2008 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
2008-10-20 06:55:57 -04:00
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.intrinsics ;
2007-09-20 18:09:08 -04:00
IN: cpu.x86.64
2008-10-07 21:00:38 -04:00
M: x86.64 machine-registers
{
2008-10-13 15:03:21 -04:00
{ int-regs { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 R13 } }
2008-10-07 21:00:38 -04:00
{ double-float-regs {
XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15
} }
} ;
M: x86.64 ds-reg R14 ;
M: x86.64 rs-reg R15 ;
M: x86.64 stack-reg RSP ;
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
M: int-regs return-reg drop RAX ;
M: int-regs param-regs drop { RDI RSI RDX RCX R8 R9 } ;
M: float-regs return-reg drop XMM0 ;
M: float-regs param-regs
drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
2008-10-20 06:55:57 -04:00
M: x86.64 %load-indirect
0 [] MOV rc-relative rel-literal ;
2007-09-20 18:09:08 -04:00
M: stack-params %load-param-reg
drop
2008-09-13 15:25:06 -04:00
>r R11 swap stack@ MOV
r> stack@ R11 MOV ;
2007-09-20 18:09:08 -04:00
M: stack-params %save-param-reg
2008-10-05 22:30:29 -04:00
drop
R11 swap next-stack@ MOV
stack@ R11 MOV ;
2007-09-20 18:09:08 -04:00
: with-return-regs ( quot -- )
[
V{ RDX RAX } clone int-regs set
V{ XMM1 XMM0 } clone float-regs set
call
] with-scope ; inline
! The ABI for passing structs by value is pretty messed up
2008-10-20 06:55:57 -04:00
"void*" c-type clone "__stack_value" define-primitive-type
stack-params "__stack_value" c-type (>>reg-class)
: struct-types&offset ( struct-type -- pairs )
fields>> [
[ type>> ] [ offset>> ] bi 2array
] map ;
: split-struct ( pairs -- seq )
[
[ 8 mod zero? [ t , ] when , ] assoc-each
] { } make { t } split harvest ;
: flatten-small-struct ( c-type -- seq )
struct-types&offset split-struct [
[ c-type c-type-reg-class ] map
int-regs swap member? "void*" "double" ? c-type
] map ;
: flatten-large-struct ( c-type -- seq )
heap-size cell align
cell /i "__stack_value" c-type <repetition> ;
M: struct-type flatten-value-type ( type -- seq )
dup heap-size 16 > [
flatten-large-struct
] [
flatten-small-struct
] if ;
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 ;
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 ;
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
: %unbox-struct-field ( c-type i -- )
! Alien must be in RDI.
RDI swap cells [+] swap reg-class>> {
{ int-regs [ int-regs get pop swap MOV ] }
{ double-float-regs [ float-regs get pop swap MOVSD ] }
} case ;
2007-09-20 18:09:08 -04:00
M: x86.64 %unbox-small-struct ( c-type -- )
! Alien must be in RDI.
2007-10-30 01:46:41 -04:00
"alien_offset" f %alien-invoke
! Move alien_offset() return value to RDI so that we don't
! clobber it.
RDI RAX MOV
[
flatten-small-struct [ %unbox-struct-field ] each-index
] with-return-regs ;
2007-09-20 18:09:08 -04:00
M: x86.64 %unbox-large-struct ( n c-type -- )
2007-09-20 18:09:08 -04:00
! Source is in RDI
heap-size
2007-09-20 18:09:08 -04:00
! Load destination address
2008-10-05 22:30:29 -04:00
RSI rot stack@ LEA
2007-09-20 18:09:08 -04:00
! 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 ;
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
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
M: x86.64 struct-small-enough? ( size -- ? )
heap-size 2 cells <= ;
2007-09-20 18:09:08 -04:00
2008-10-05 22:30:29 -04:00
: box-struct-field@ ( i -- operand ) 1+ cells stack@ ;
: %box-struct-field ( c-type i -- )
box-struct-field@ swap reg-class>> {
{ int-regs [ int-regs get pop MOV ] }
{ double-float-regs [ float-regs get pop MOVSD ] }
} case ;
M: x86.64 %box-small-struct ( c-type -- )
#! Box a <= 16-byte struct.
[
[ flatten-small-struct [ %box-struct-field ] each-index ]
[ RDX swap heap-size MOV ] bi
RDI 0 box-struct-field@ MOV
RSI 1 box-struct-field@ MOV
"box_small_struct" f %alien-invoke
] with-return-regs ;
2007-09-20 18:09:08 -04:00
2008-10-06 01:20:00 -04:00
: struct-return@ ( n -- operand )
[ stack-frame get params>> ] unless* stack@ ;
M: x86.64 %box-large-struct ( n c-type -- )
2007-09-20 18:09:08 -04:00
! Struct size is parameter 2
2008-10-06 01:20:00 -04:00
RSI swap heap-size MOV
2007-09-20 18:09:08 -04:00
! Compute destination address
2008-10-06 01:20:00 -04:00
RDI swap struct-return@ LEA
2007-09-20 18:09:08 -04:00
! 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-10-06 01:20:00 -04:00
M: x86.64 %prepare-box-struct ( -- )
! Compute target address for value struct return
RAX f struct-return@ LEA
! Store it as the first parameter
2008-10-05 22:30:29 -04:00
0 stack@ RAX MOV ;
2007-09-20 18:09:08 -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
2008-09-13 15:25:06 -04:00
R11 0 MOV
rc-absolute-cell rel-dlsym
R11 CALL ;
2007-09-20 18:09:08 -04:00
M: x86.64 %prepare-alien-indirect ( -- )
2007-10-30 01:46:41 -04:00
"unbox_alien" f %alien-invoke
2008-10-05 22:30:29 -04:00
RBP RAX MOV ;
2007-09-20 18:09:08 -04:00
M: x86.64 %alien-indirect ( -- )
2008-10-05 22:30:29 -04:00
RBP CALL ;
2007-09-20 18:09:08 -04:00
M: x86.64 %alien-callback ( quot -- )
2008-10-20 06:55:57 -04:00
RDI %load-indirect "c_to_factor" f %alien-invoke ;
2007-09-20 18:09:08 -04:00
M: x86.64 %callback-value ( ctype -- )
2007-09-20 18:09:08 -04:00
! Save top of data stack
%prepare-unbox
2008-10-05 22:30:29 -04:00
! Save top of data stack
RSP 8 SUB
RDI PUSH
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
2008-10-05 22:30:29 -04:00
RDI POP
RSP 8 ADD
2007-09-20 18:09:08 -04:00
! Unbox former top of data stack to return registers
unbox-return ;
2008-10-20 06:55:57 -04:00
! The result of reading 4 bytes from memory is a fixnum on
! x86-64.
enable-alien-4-intrinsics
2008-10-20 06:55:57 -04:00
! SSE2 is always available on x86-64.
enable-float-intrinsics