factor/unfinished/compiler/codegen/codegen.factor

382 lines
9.7 KiB
Factor
Raw Normal View History

2008-09-10 23:11:03 -04:00
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
2008-09-17 01:46:38 -04:00
USING: namespaces make math math.parser sequences accessors
kernel kernel.private layouts assocs words summary arrays
threads continuations.private libc combinators
alien alien.c-types alien.structs alien.strings
compiler.errors
compiler.alien
compiler.backend
compiler.codegen.fixup
compiler.cfg
compiler.cfg.instructions
compiler.cfg.registers ;
IN: compiler.codegen
GENERIC: generate-insn ( insn -- )
: generate-insns ( insns -- code )
[
[
dup regs>> registers set
generate-insn
] each
] { } make fixup ;
2008-09-10 23:11:03 -04:00
2008-09-17 01:46:38 -04:00
TUPLE: asm label code calls ;
SYMBOL: calls
: add-call ( word -- )
#! Compile this word later.
calls get push ;
SYMBOL: compiling-word
: compiled-stack-traces? ( -- ? ) 59 getenv ;
! Mapping _label IDs to label instances
SYMBOL: labels
: init-generator ( word -- )
H{ } clone labels set
V{ } clone literal-table set
V{ } clone calls set
compiling-word set
compiled-stack-traces? compiling-word get f ? add-literal drop ;
: generate ( mr -- asm )
[
[ label>> ]
[ word>> init-generator ]
[ instructions>> generate-insns ] tri
calls get
asm boa
] with-scope ;
: lookup-label ( id -- label )
labels get [ drop <label> ] cache ;
M: _label generate-insn
id>> lookup-label , ;
M: _prologue generate-insn
n>> %prologue ;
M: _epilogue generate-insn
n>> %epilogue ;
M: ##load-literal generate-insn [ obj>> ] [ dst>> ] bi load-literal ;
M: ##peek generate-insn [ dst>> ] [ loc>> ] bi %peek ;
M: ##replace generate-insn [ src>> ] [ loc>> ] bi %replace ;
M: ##inc-d generate-insn n>> %inc-d ;
M: ##inc-r generate-insn n>> %inc-r ;
M: ##return generate-insn drop %return ;
2008-09-10 23:11:03 -04:00
2008-09-17 01:46:38 -04:00
M: ##call generate-insn word>> [ add-call ] [ %call ] bi ;
2008-09-10 23:11:03 -04:00
2008-09-17 01:46:38 -04:00
M: ##jump generate-insn word>> [ add-call ] [ %jump-label ] bi ;
M: ##intrinsic generate-insn
[ init-intrinsic ] [ quot>> call ] bi ;
M: _if-intrinsic generate-insn
[ init-intrinsic ]
[ [ label>> lookup-label ] [ quot>> ] bi call ] bi ;
M: _branch generate-insn
label>> lookup-label %jump-label ;
M: _branch-f generate-insn
[ src>> ] [ label>> lookup-label ] bi %jump-f ;
M: _branch-t generate-insn
[ src>> ] [ label>> lookup-label ] bi %jump-t ;
M: ##dispatch-label generate-insn label>> %dispatch-label ;
M: ##dispatch generate-insn drop %dispatch ;
M: ##copy generate-insn %copy ;
M: ##copy-float generate-insn %copy-float ;
M: ##unbox-float generate-insn [ dst>> ] [ src>> ] bi %unbox-float ;
M: ##unbox-f generate-insn [ dst>> ] [ src>> ] bi %unbox-f ;
M: ##unbox-alien generate-insn [ dst>> ] [ src>> ] bi %unbox-alien ;
M: ##unbox-byte-array generate-insn [ dst>> ] [ src>> ] bi %unbox-byte-array ;
M: ##unbox-any-c-ptr generate-insn [ dst>> ] [ src>> ] bi %unbox-any-c-ptr ;
M: ##box-float generate-insn [ dst>> ] [ src>> ] bi %box-float ;
M: ##box-alien generate-insn [ dst>> ] [ src>> ] bi %box-alien ;
M: ##gc generate-insn drop %gc ;
! #alien-invoke
2008-09-10 23:11:03 -04:00
GENERIC: reg-size ( register-class -- n )
M: int-regs reg-size drop cell ;
M: single-float-regs reg-size drop 4 ;
M: double-float-regs reg-size drop 8 ;
GENERIC: reg-class-variable ( register-class -- symbol )
M: reg-class reg-class-variable ;
M: float-regs reg-class-variable drop float-regs ;
GENERIC: inc-reg-class ( register-class -- )
M: reg-class inc-reg-class
dup reg-class-variable inc
fp-shadows-int? [ reg-size stack-params +@ ] [ drop ] if ;
M: float-regs inc-reg-class
dup call-next-method
fp-shadows-int? [ reg-size cell /i int-regs +@ ] [ drop ] if ;
GENERIC: reg-class-full? ( class -- ? )
M: stack-params reg-class-full? drop t ;
M: object reg-class-full?
[ reg-class-variable get ] [ param-regs length ] bi >= ;
: spill-param ( reg-class -- n reg-class )
stack-params get
>r reg-size stack-params +@ r>
stack-params ;
: fastcall-param ( reg-class -- n reg-class )
[ reg-class-variable get ] [ inc-reg-class ] [ ] tri ;
: alloc-parameter ( parameter -- reg reg-class )
c-type-reg-class dup reg-class-full?
[ spill-param ] [ fastcall-param ] if
[ param-reg ] keep ;
2008-09-17 01:46:38 -04:00
: (flatten-int-type) ( size -- seq )
cell /i "void*" c-type <repetition> ;
2008-09-10 23:11:03 -04:00
2008-09-17 01:46:38 -04:00
GENERIC: flatten-value-type ( type -- types )
2008-09-10 23:11:03 -04:00
2008-09-17 01:46:38 -04:00
M: object flatten-value-type 1array ;
2008-09-10 23:11:03 -04:00
2008-09-17 01:46:38 -04:00
M: struct-type flatten-value-type ( type -- types )
2008-09-10 23:11:03 -04:00
stack-size cell align (flatten-int-type) ;
2008-09-17 01:46:38 -04:00
M: long-long-type flatten-value-type ( type -- types )
2008-09-10 23:11:03 -04:00
stack-size cell align (flatten-int-type) ;
: flatten-value-types ( params -- params )
#! Convert value type structs to consecutive void*s.
[
0 [
c-type
2008-09-17 01:46:38 -04:00
[ parameter-align (flatten-int-type) % ] keep
2008-09-10 23:11:03 -04:00
[ stack-size cell align + ] keep
2008-09-17 01:46:38 -04:00
flatten-value-type %
2008-09-10 23:11:03 -04:00
] reduce drop
] { } make ;
: each-parameter ( parameters quot -- )
>r [ parameter-sizes nip ] keep r> 2each ; inline
: reverse-each-parameter ( parameters quot -- )
>r [ parameter-sizes nip ] keep r> 2reverse-each ; inline
: reset-freg-counts ( -- )
{ int-regs float-regs stack-params } [ 0 swap set ] each ;
: with-param-regs ( quot -- )
#! In quot you can call alloc-parameter
[ reset-freg-counts call ] with-scope ; inline
: move-parameters ( node word -- )
#! Moves values from C stack to registers (if word is
#! %load-param-reg) and registers to C stack (if word is
#! %save-param-reg).
>r
alien-parameters
flatten-value-types
r> [ >r alloc-parameter r> execute ] curry each-parameter ;
inline
: unbox-parameters ( offset node -- )
parameters>> [
%prepare-unbox >r over + r> unbox-parameter
] reverse-each-parameter drop ;
: prepare-box-struct ( node -- offset )
#! Return offset on C stack where to store unboxed
#! parameters. If the C function is returning a structure,
#! the first parameter is an implicit target area pointer,
#! so we need to use a different offset.
return>> dup large-struct?
[ heap-size %prepare-box-struct cell ] [ drop 0 ] if ;
: objects>registers ( params -- )
#! Generate code for unboxing a list of C types, then
#! generate code for moving these parameters to register on
#! architectures where parameters are passed in registers.
[
[ prepare-box-struct ] keep
[ unbox-parameters ] keep
\ %load-param-reg move-parameters
] with-param-regs ;
: box-return* ( node -- )
return>> [ ] [ box-return ] if-void ;
TUPLE: no-such-library name ;
M: no-such-library summary
drop "Library not found" ;
M: no-such-library compiler-error-type
drop +linkage+ ;
: no-such-library ( name -- )
\ no-such-library boa
compiling-word get compiler-error ;
TUPLE: no-such-symbol name ;
M: no-such-symbol summary
drop "Symbol not found" ;
M: no-such-symbol compiler-error-type
drop +linkage+ ;
: no-such-symbol ( name -- )
\ no-such-symbol boa
compiling-word get compiler-error ;
: check-dlsym ( symbols dll -- )
dup dll-valid? [
dupd [ dlsym ] curry contains?
[ drop ] [ no-such-symbol ] if
] [
dll-path no-such-library drop
] if ;
: stdcall-mangle ( symbol node -- symbol )
"@"
swap parameters>> parameter-sizes drop
number>string 3append ;
: alien-invoke-dlsym ( params -- symbols dll )
dup function>> dup pick stdcall-mangle 2array
swap library>> library dup [ dll>> ] when
2dup check-dlsym ;
2008-09-17 01:46:38 -04:00
M: ##alien-invoke generate-insn
2008-09-10 23:11:03 -04:00
params>>
2008-09-17 01:46:38 -04:00
! Save registers for GC
%prepare-alien-invoke
! Unbox parameters
dup objects>registers
%prepare-var-args
! Call function
dup alien-invoke-dlsym %alien-invoke
! Box return value
dup %cleanup
box-return* ;
! ##alien-indirect
M: ##alien-indirect generate-insn
2008-09-10 23:11:03 -04:00
params>>
2008-09-17 01:46:38 -04:00
! Save registers for GC
%prepare-alien-invoke
! Save alien at top of stack to temporary storage
%prepare-alien-indirect
! Unbox parameters
dup objects>registers
%prepare-var-args
! Call alien in temporary storage
%alien-indirect
! Box return value
dup %cleanup
box-return* ;
! ##alien-callback
2008-09-10 23:11:03 -04:00
: box-parameters ( params -- )
alien-parameters [ box-parameter ] each-parameter ;
: registers>objects ( node -- )
[
dup \ %save-param-reg move-parameters
"nest_stacks" f %alien-invoke
box-parameters
] with-param-regs ;
TUPLE: callback-context ;
: current-callback 2 getenv ;
: wait-to-return ( token -- )
dup current-callback eq? [
drop
] [
yield wait-to-return
] if ;
: do-callback ( quot token -- )
init-catchstack
dup 2 setenv
slip
wait-to-return ; inline
: callback-return-quot ( ctype -- quot )
return>> {
{ [ dup "void" = ] [ drop [ ] ] }
{ [ dup large-struct? ] [ heap-size [ memcpy ] curry ] }
[ c-type c-type-unboxer-quot ]
} cond ;
: callback-prep-quot ( params -- quot )
parameters>> [ c-type c-type-boxer-quot ] map spread>quot ;
: wrap-callback-quot ( params -- quot )
[
[ callback-prep-quot ]
[ quot>> ]
[ callback-return-quot ] tri 3append ,
[ callback-context new do-callback ] %
] [ ] make ;
: %unnest-stacks ( -- ) "unnest_stacks" f %alien-invoke ;
: callback-unwind ( params -- n )
{
{ [ dup abi>> "stdcall" = ] [ alien-stack-frame ] }
{ [ dup return>> large-struct? ] [ drop 4 ] }
[ drop 0 ]
} cond ;
: %callback-return ( params -- )
#! All the extra book-keeping for %unwind is only for x86.
#! On other platforms its an alias for %return.
dup alien-return
[ %unnest-stacks ] [ %callback-value ] if-void
callback-unwind %unwind ;
2008-09-17 01:46:38 -04:00
M: ##alien-callback generate-insn
params>>
[ registers>objects ]
[ wrap-callback-quot %alien-callback ]
[ %callback-return ]
tri ;