factor/library/compiler/vops.factor

307 lines
8.3 KiB
Factor
Raw Normal View History

2005-05-06 18:33:40 -04:00
! Copyright (C) 2004, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
2005-05-09 02:34:15 -04:00
IN: compiler-backend
2005-05-16 17:01:39 -04:00
USING: errors generic hashtables kernel lists math namespaces
parser sequences words ;
2005-05-06 18:33:40 -04:00
! The linear IR is the second of the two intermediate
! representations used by Factor. It is basically a high-level
! assembly language. Linear IR operations are called VOPs.
2005-05-08 20:30:38 -04:00
! This file defines all the types of VOPs. A linear IR program
! is then just a list of VOPs.
2005-05-09 02:34:15 -04:00
: <label> ( -- label )
#! Make a label.
gensym dup t "label" set-word-prop ;
: label? ( obj -- ? )
dup word? [ "label" word-prop ] [ drop f ] ifte ;
2005-05-06 18:33:40 -04:00
! A virtual register
TUPLE: vreg n ;
! A virtual operation
2005-05-16 17:01:39 -04:00
TUPLE: vop inputs outputs label ;
: vop-in-1 ( vop -- input ) vop-inputs first ;
: vop-in-2 ( vop -- input ) vop-inputs second ;
: vop-in-3 ( vop -- input ) vop-inputs third ;
: vop-out-1 ( vop -- output ) vop-outputs first ;
: vop-out-2 ( vop -- output ) vop-outputs second ;
2005-05-06 18:33:40 -04:00
2005-05-16 17:01:39 -04:00
GENERIC: basic-block? ( vop -- ? )
M: vop basic-block? drop f ;
! simplifies some code
M: f basic-block? drop f ;
2005-05-09 02:34:15 -04:00
2005-05-16 17:01:39 -04:00
GENERIC: calls-label? ( label vop -- ? )
2005-05-09 02:34:15 -04:00
M: vop calls-label? vop-label = ;
2005-05-06 18:33:40 -04:00
2005-05-16 17:01:39 -04:00
: make-vop ( inputs outputs label vop -- vop )
2005-05-06 18:33:40 -04:00
[ >r <vop> r> set-delegate ] keep ;
: VOP:
#! Followed by a VOP name.
scan dup [ ] define-tuple
create-in [ make-vop ] define-constructor ; parsing
2005-05-16 17:01:39 -04:00
: empty-vop f f f ;
: label-vop ( label) >r f f r> ;
: label/src-vop ( label src) unit swap f swap ;
: src-vop ( src) unit f f ;
: dest-vop ( dest) unit dup f ;
: src/dest-vop ( src dest) >r unit r> unit f ;
: 2-in-vop ( in1 in2) 2list f f ;
: 2-in/label-vop ( in1 in2 label) >r 2list f r> ;
: 2-vop ( in dest) [ 2list ] keep unit f ;
: 3-vop ( in1 in2 dest) >r 2list r> unit f ;
2005-05-06 18:33:40 -04:00
! miscellanea
VOP: %prologue
: %prologue empty-vop <%prologue> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %label
: %label label-vop <%label> ;
2005-05-09 02:34:15 -04:00
M: %label calls-label? 2drop f ;
! Return vops take a label that is ignored, to have the
! same stack effect as jumps. This is needed for the
! simplifier.
2005-05-06 18:33:40 -04:00
VOP: %return
2005-05-09 02:34:15 -04:00
: %return ( label) label-vop <%return> ;
2005-05-06 18:33:40 -04:00
VOP: %return-to
: %return-to label-vop <%return-to> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %jump
: %jump label-vop <%jump> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %jump-label
: %jump-label label-vop <%jump-label> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %call
: %call label-vop <%call> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %call-label
: %call-label label-vop <%call-label> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %jump-t
: %jump-t <vreg> label/src-vop <%jump-t> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %jump-f
: %jump-f <vreg> label/src-vop <%jump-f> ;
! dispatch tables
VOP: %dispatch
: %dispatch <vreg> src-vop <%dispatch> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %target-label
: %target-label label-vop <%target-label> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %target
: %target label-vop <%target> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
VOP: %end-dispatch
: %end-dispatch empty-vop <%end-dispatch> ;
! stack operations
VOP: %peek-d
2005-05-16 17:01:39 -04:00
: %peek-d ( vreg n -- ) swap <vreg> src/dest-vop <%peek-d> ;
M: %peek-d basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %replace-d
2005-05-16 17:01:39 -04:00
: %replace-d ( vreg n -- ) swap <vreg> 2-in-vop <%replace-d> ;
M: %replace-d basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %inc-d
2005-05-16 17:01:39 -04:00
: %inc-d ( n -- ) src-vop <%inc-d> ;
2005-05-09 02:34:15 -04:00
: %dec-d ( n -- ) neg %inc-d ;
2005-05-16 17:01:39 -04:00
M: %inc-d basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %immediate
2005-05-15 21:17:56 -04:00
: %immediate ( vreg obj -- )
2005-05-16 17:01:39 -04:00
swap <vreg> src/dest-vop <%immediate> ;
M: %immediate basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %peek-r
2005-05-16 17:01:39 -04:00
: %peek-r ( vreg n -- ) swap <vreg> src/dest-vop <%peek-r> ;
2005-05-06 18:33:40 -04:00
VOP: %replace-r
2005-05-16 17:01:39 -04:00
: %replace-r ( vreg n -- ) swap <vreg> 2-in-vop <%replace-r> ;
2005-05-06 18:33:40 -04:00
VOP: %inc-r
2005-05-16 17:01:39 -04:00
: %inc-r ( n -- ) src-vop <%inc-r> ;
2005-05-09 02:34:15 -04:00
! this exists, unlike %dec-d which does not, due to x86 quirks
VOP: %dec-r
2005-05-16 17:01:39 -04:00
: %dec-r ( n -- ) src-vop <%dec-r> ;
2005-05-06 18:33:40 -04:00
: in-1 0 0 %peek-d , ;
: in-2 0 1 %peek-d , 1 0 %peek-d , ;
: in-3 0 2 %peek-d , 1 1 %peek-d , 2 0 %peek-d , ;
2005-05-06 18:33:40 -04:00
: out-1 0 0 %replace-d , ;
! indirect load of a literal through a table
VOP: %indirect
2005-05-16 17:01:39 -04:00
: %indirect ( vreg obj -- )
swap <vreg> src/dest-vop <%indirect> ;
M: %indirect basic-block? drop t ;
2005-05-06 18:33:40 -04:00
! object slot accessors
! mask off a tag (see also %untag-fixnum)
2005-05-06 18:33:40 -04:00
VOP: %untag
: %untag <vreg> dest-vop <%untag> ;
2005-05-16 17:01:39 -04:00
M: %untag basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %slot
: %slot ( n vreg ) >r <vreg> r> <vreg> 2-vop <%slot> ;
2005-05-16 17:01:39 -04:00
M: %slot basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %set-slot
2005-05-16 17:01:39 -04:00
: %set-slot ( value obj n )
#! %set-slot writes to vreg n.
>r >r <vreg> r> <vreg> r> <vreg> [ 3list ] keep unit f
<%set-slot> ;
M: %set-slot basic-block? drop t ;
2005-05-06 18:33:40 -04:00
! in the 'fast' versions, the object's type and slot number is
2005-05-06 18:33:40 -04:00
! known at compile time, so these become a single instruction
VOP: %fast-slot
2005-05-16 17:01:39 -04:00
: %fast-slot ( vreg n )
swap <vreg> 2-vop <%fast-slot> ;
2005-05-16 17:01:39 -04:00
M: %fast-slot basic-block? drop t ;
2005-05-06 18:33:40 -04:00
VOP: %fast-set-slot
2005-05-16 17:01:39 -04:00
: %fast-set-slot ( value obj n )
#! %fast-set-slot writes to vreg obj.
>r >r <vreg> r> <vreg> r> over >r 3list r> unit f
<%fast-set-slot> ;
M: %fast-set-slot basic-block? drop t ;
! fixnum intrinsics
VOP: %fixnum+ : %fixnum+ 3-vop <%fixnum+> ;
VOP: %fixnum- : %fixnum- 3-vop <%fixnum-> ;
VOP: %fixnum* : %fixnum* 3-vop <%fixnum*> ;
VOP: %fixnum-mod : %fixnum-mod 3-vop <%fixnum-mod> ;
VOP: %fixnum/i : %fixnum/i 3-vop <%fixnum/i> ;
VOP: %fixnum/mod : %fixnum/mod f <%fixnum/mod> ;
VOP: %fixnum-bitand : %fixnum-bitand 3-vop <%fixnum-bitand> ;
VOP: %fixnum-bitor : %fixnum-bitor 3-vop <%fixnum-bitor> ;
VOP: %fixnum-bitxor : %fixnum-bitxor 3-vop <%fixnum-bitxor> ;
VOP: %fixnum-bitnot : %fixnum-bitnot <vreg> dest-vop <%fixnum-bitnot> ;
2005-05-09 02:34:15 -04:00
VOP: %fixnum<= : %fixnum<= 3-vop <%fixnum<=> ;
VOP: %fixnum< : %fixnum< 3-vop <%fixnum<> ;
VOP: %fixnum>= : %fixnum>= 3-vop <%fixnum>=> ;
VOP: %fixnum> : %fixnum> 3-vop <%fixnum>> ;
VOP: %eq? : %eq? 3-vop <%eq?> ;
2005-05-09 22:34:47 -04:00
! At the VOP level, the 'shift' operation is split into five
! distinct operations:
! - shifts with a large positive count: calls runtime to make
! a bignum
! - shifts with a small positive count: %fixnum<<
! - shifts with a small negative count: %fixnum>>
! - shifts with a small negative count: %fixnum>>
! - shifts with a large negative count: %fixnum-sgn
VOP: %fixnum<< : %fixnum<< 3-vop <%fixnum<<> ;
VOP: %fixnum>> : %fixnum>> 3-vop <%fixnum>>> ;
2005-05-09 22:34:47 -04:00
! due to x86 limitations the destination of this VOP must be
! vreg 2 (EDX), and the source must be vreg 0 (EAX).
VOP: %fixnum-sgn : %fixnum-sgn 3-vop <%fixnum-sgn> ;
2005-05-09 22:34:47 -04:00
! Integer comparison followed by a conditional branch is
! optimized
2005-05-16 17:01:39 -04:00
VOP: %jump-fixnum<=
: %jump-fixnum<= 2-in/label-vop <%jump-fixnum<=> ;
VOP: %jump-fixnum<
: %jump-fixnum< 2-in/label-vop <%jump-fixnum<> ;
VOP: %jump-fixnum>=
: %jump-fixnum>= 2-in/label-vop <%jump-fixnum>=> ;
VOP: %jump-fixnum>
: %jump-fixnum> 2-in/label-vop <%jump-fixnum>> ;
VOP: %jump-eq?
: %jump-eq? 2-in/label-vop <%jump-eq?> ;
2005-05-09 02:34:15 -04:00
: fast-branch ( class -- class )
{{
[[ %fixnum<= %jump-fixnum<= ]]
[[ %fixnum< %jump-fixnum< ]]
[[ %fixnum>= %jump-fixnum>= ]]
[[ %fixnum> %jump-fixnum> ]]
[[ %eq? %jump-eq? ]]
}} hash ;
PREDICATE: tuple fast-branch
#! Class of VOPs whose class is a key in fast-branch
#! hashtable.
class fast-branch ;
! some slightly optimized inline assembly
VOP: %type
: %type ( vreg ) <vreg> dest-vop <%type> ;
2005-05-16 17:01:39 -04:00
M: %type basic-block? drop t ;
VOP: %arithmetic-type
: %arithmetic-type <vreg> dest-vop <%arithmetic-type> ;
VOP: %tag-fixnum
: %tag-fixnum <vreg> dest-vop <%tag-fixnum> ;
2005-05-16 17:01:39 -04:00
M: %tag-fixnum basic-block? drop t ;
VOP: %untag-fixnum
: %untag-fixnum <vreg> dest-vop <%untag-fixnum> ;
2005-05-16 17:01:39 -04:00
M: %untag-fixnum basic-block? drop t ;
: check-dest ( vop reg -- )
2005-05-30 03:37:22 -04:00
swap vop-out-1 = [ "bad VOP destination" throw ] unless ;
: check-src ( vop reg -- )
swap vop-out-1 = [ "bad VOP source" throw ] unless ;
2005-05-08 20:30:38 -04:00
VOP: %getenv
2005-05-16 17:01:39 -04:00
: %getenv swap src/dest-vop <%getenv> ;
M: %getenv basic-block? drop t ;
VOP: %setenv
2005-05-16 17:01:39 -04:00
: %setenv 2-in-vop <%setenv> ;
M: %setenv basic-block? drop t ;
2005-05-08 20:30:38 -04:00
! alien operations
VOP: %parameters
2005-05-16 17:01:39 -04:00
: %parameters ( n -- vop ) src-vop <%parameters> ;
2005-05-08 20:30:38 -04:00
VOP: %parameter
2005-05-16 17:01:39 -04:00
: %parameter ( n -- vop ) src-vop <%parameter> ;
2005-05-08 20:30:38 -04:00
VOP: %cleanup
2005-05-16 17:01:39 -04:00
: %cleanup ( n -- vop ) src-vop <%cleanup> ;
2005-05-08 20:30:38 -04:00
VOP: %unbox
2005-05-16 17:01:39 -04:00
: %unbox ( [[ n func ]] -- vop ) src-vop <%unbox> ;
2005-05-08 20:30:38 -04:00
VOP: %unbox-float
2005-05-16 17:01:39 -04:00
: %unbox-float ( [[ n func ]] -- vop ) src-vop <%unbox-float> ;
2005-05-08 20:30:38 -04:00
VOP: %unbox-double
2005-05-16 17:01:39 -04:00
: %unbox-double ( [[ n func ]] -- vop ) src-vop <%unbox-double> ;
2005-05-08 20:30:38 -04:00
VOP: %box
2005-05-16 17:01:39 -04:00
: %box ( func -- vop ) src-vop <%box> ;
2005-05-08 20:30:38 -04:00
VOP: %box-float
2005-05-16 17:01:39 -04:00
: %box-float ( func -- vop ) src-vop <%box-float> ;
2005-05-08 20:30:38 -04:00
VOP: %box-double
2005-05-16 17:01:39 -04:00
: %box-double ( [[ n func ]] -- vop ) src-vop <%box-double> ;
2005-05-08 20:30:38 -04:00
VOP: %alien-invoke
2005-05-16 17:01:39 -04:00
: %alien-invoke ( func -- vop ) src-vop <%alien-invoke> ;
VOP: %alien-global
2005-05-16 17:01:39 -04:00
: %alien-global ( global -- vop ) src-vop <%alien-global> ;