factor/library/compiler/vops.factor

340 lines
8.5 KiB
Factor
Raw Normal View History

2006-04-01 19:50:33 -05:00
! Copyright (C) 2004, 2006 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler
2005-12-04 22:06:12 -05:00
USING: arrays errors generic hashtables kernel kernel-internals
lists math memory 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 -- ? )
2005-09-24 15:21:17 -04:00
dup word? [ "label" word-prop ] [ drop f ] if ;
2005-05-09 02:34:15 -04:00
2005-05-06 18:33:40 -04:00
! A virtual register
TUPLE: vreg n ;
! Register classes
TUPLE: int-regs ;
2005-06-14 20:54:11 -04:00
TUPLE: float-regs size ;
2006-02-21 18:12:00 -05:00
! A pseudo-register class for parameters spilled on the stack
TUPLE: stack-params ;
2005-12-24 16:08:15 -05:00
GENERIC: return-reg ( register-class -- reg )
2006-01-24 20:20:20 -05:00
GENERIC: fastcall-regs ( register-class -- regs )
2006-02-21 18:12:00 -05:00
M: stack-params fastcall-regs drop 0 ;
2005-12-25 01:27:34 -05:00
GENERIC: reg-size ( register-class -- n )
GENERIC: inc-reg-class ( register-class -- )
M: int-regs reg-size drop cell ;
2005-12-24 16:08:15 -05:00
2006-02-20 17:49:44 -05:00
: (inc-reg-class)
dup class inc
macosx? [ reg-size stack-params +@ ] [ drop ] if ;
2006-02-20 17:49:44 -05:00
M: int-regs inc-reg-class
(inc-reg-class) ;
2005-12-25 01:27:34 -05:00
M: float-regs reg-size float-regs-size ;
M: float-regs inc-reg-class
2006-02-20 17:49:44 -05:00
dup (inc-reg-class)
macosx? [ reg-size 4 / int-regs +@ ] [ drop ] if ;
2005-12-04 19:56:42 -05:00
GENERIC: v>operand
M: integer v>operand tag-bits shift ;
2005-12-04 22:06:12 -05:00
M: vreg v>operand vreg-n vregs nth ;
2005-12-04 19:56:42 -05:00
M: f v>operand address ;
2005-05-06 18:33:40 -04:00
! A virtual operation
2005-05-16 17:01:39 -04:00
TUPLE: vop inputs outputs label ;
2005-12-04 22:06:12 -05:00
: (scratch)
vop get dup vop-inputs swap vop-outputs append
[ vreg? ] subset [ v>operand ] map vregs diff ;
: scratch ( n -- reg )
#! Output a scratch register that is not used by the
#! current VOP.
\ scratch get nth ;
: with-vop ( vop quot -- )
2006-03-07 19:53:58 -05:00
swap vop set (scratch) \ scratch set call ; inline
2005-12-04 22:06:12 -05:00
2005-12-04 19:56:42 -05:00
: input ( n -- obj ) vop get vop-inputs nth ;
: input-operand ( n -- n ) input v>operand ;
: output ( n -- obj ) vop get vop-outputs nth ;
: output-operand ( n -- n ) output v>operand ;
: label ( -- label ) vop get 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 ;
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) 1array swap f swap ;
: src-vop ( src) 1array f f ;
: dest-vop ( dest) 1array dup f ;
: src/dest-vop ( src dest) >r 1array r> 1array f ;
: 2-in-vop ( in1 in2) 2array f f ;
: 3-in-vop ( in1 in2 in3) 3array f f ;
: 2-in/label-vop ( in1 in2 label) >r 2array f r> ;
: 2-vop ( in dest) [ 2array ] keep 1array f ;
: 3-vop ( in1 in2 dest) >r 2array r> 1array f ;
2005-05-06 18:33:40 -04:00
! miscellanea
TUPLE: %prologue ;
C: %prologue make-vop ;
2006-03-07 19:53:58 -05:00
: %prologue src-vop <%prologue> ;
2005-05-16 17:01:39 -04:00
TUPLE: %label ;
C: %label make-vop ;
2005-05-06 18:33:40 -04:00
: %label label-vop <%label> ;
2005-05-09 02:34:15 -04:00
! Return vops take a label that is ignored, to have the
! same stack effect as jumps. This is needed for the
! simplifier.
TUPLE: %return ;
C: %return make-vop ;
2005-09-10 00:55:46 -04:00
: %return empty-vop <%return> ;
2005-05-09 02:34:15 -04:00
TUPLE: %jump ;
C: %jump make-vop ;
2005-05-06 18:33:40 -04:00
: %jump label-vop <%jump> ;
2005-05-16 17:01:39 -04:00
2006-02-28 00:26:45 -05:00
TUPLE: %jump-label ;
C: %jump-label make-vop ;
: %jump-label label-vop <%jump-label> ;
TUPLE: %call ;
C: %call make-vop ;
2005-05-06 18:33:40 -04:00
: %call label-vop <%call> ;
2005-05-16 17:01:39 -04:00
TUPLE: %jump-t ;
C: %jump-t make-vop ;
2006-04-01 19:50:33 -05:00
: %jump-t label/src-vop <%jump-t> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
! dispatch tables
TUPLE: %dispatch ;
C: %dispatch make-vop ;
2006-04-01 19:50:33 -05:00
: %dispatch src-vop <%dispatch> ;
2005-05-16 17:01:39 -04:00
TUPLE: %target-label ;
C: %target-label make-vop ;
2005-05-06 18:33:40 -04:00
: %target-label label-vop <%target-label> ;
2005-05-16 17:01:39 -04:00
2005-05-06 18:33:40 -04:00
! stack operations
TUPLE: %peek ;
C: %peek make-vop ;
: %peek swap src/dest-vop <%peek> ;
2005-09-08 22:23:54 -04:00
TUPLE: %replace ;
C: %replace make-vop ;
: %replace ( vreg loc -- vop ) src/dest-vop <%replace> ;
2005-05-16 17:01:39 -04:00
TUPLE: %inc-d ;
C: %inc-d make-vop ;
2005-09-04 17:07:59 -04:00
: %inc-d ( n -- node ) src-vop <%inc-d> ;
TUPLE: %inc-r ;
C: %inc-r make-vop ;
2005-05-16 17:01:39 -04:00
: %inc-r ( n -- ) src-vop <%inc-r> ;
TUPLE: %immediate ;
C: %immediate make-vop ;
: %immediate ( obj vreg -- vop )
src/dest-vop <%immediate> ;
2005-05-06 18:33:40 -04:00
! indirect load of a literal through a table
TUPLE: %indirect ;
C: %indirect make-vop ;
: %indirect ( obj vreg -- )
src/dest-vop <%indirect> ;
2005-05-06 18:33:40 -04:00
! object slot accessors
TUPLE: %untag ;
C: %untag make-vop ;
2006-04-01 19:50:33 -05:00
: %untag dest-vop <%untag> ;
2005-05-16 17:01:39 -04:00
TUPLE: %slot ;
C: %slot make-vop ;
2006-04-01 19:50:33 -05:00
: %slot ( n vreg ) 2-vop <%slot> ;
2005-05-06 18:33:40 -04:00
: set-slot-vop
2006-04-01 19:50:33 -05:00
[ 3array ] keep 1array f ;
TUPLE: %set-slot ;
C: %set-slot make-vop ;
2005-09-09 00:17:19 -04:00
2005-05-16 17:01:39 -04:00
: %set-slot ( value obj n )
2005-09-09 00:17:19 -04:00
#! %set-slot writes to vreg obj.
set-slot-vop <%set-slot> ;
2005-09-09 00:17:19 -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
TUPLE: %fast-slot ;
C: %fast-slot make-vop ;
2006-04-01 19:50:33 -05:00
: %fast-slot ( n vreg )
2-vop <%fast-slot> ;
2005-05-16 17:01:39 -04:00
TUPLE: %fast-set-slot ;
C: %fast-set-slot make-vop ;
2005-05-16 17:01:39 -04:00
: %fast-set-slot ( value obj n )
#! %fast-set-slot writes to vreg obj.
2006-04-01 19:50:33 -05:00
over >r 3array r> 1array f <%fast-set-slot> ;
! Char readers and writers
TUPLE: %char-slot ;
C: %char-slot make-vop ;
2006-04-01 19:50:33 -05:00
: %char-slot ( n vreg ) 2-vop <%char-slot> ;
TUPLE: %set-char-slot ;
C: %set-char-slot make-vop ;
: %set-char-slot ( value ch n )
#! %set-char-slot writes to vreg obj.
set-slot-vop <%set-char-slot> ;
TUPLE: %write-barrier ;
C: %write-barrier make-vop ;
2006-04-01 19:50:33 -05:00
: %write-barrier ( ptr ) dest-vop <%write-barrier> ;
! fixnum intrinsics
TUPLE: %fixnum+ ;
C: %fixnum+ make-vop ; : %fixnum+ 3-vop <%fixnum+> ;
TUPLE: %fixnum- ;
C: %fixnum- make-vop ; : %fixnum- 3-vop <%fixnum-> ;
TUPLE: %fixnum* ;
C: %fixnum* make-vop ; : %fixnum* 3-vop <%fixnum*> ;
TUPLE: %fixnum-mod ;
C: %fixnum-mod make-vop ; : %fixnum-mod 3-vop <%fixnum-mod> ;
TUPLE: %fixnum/i ;
C: %fixnum/i make-vop ; : %fixnum/i 3-vop <%fixnum/i> ;
TUPLE: %fixnum/mod ;
C: %fixnum/mod make-vop ; : %fixnum/mod f <%fixnum/mod> ;
2005-09-08 22:23:54 -04:00
TUPLE: %fixnum-bitand ;
C: %fixnum-bitand make-vop ; : %fixnum-bitand 3-vop <%fixnum-bitand> ;
2005-09-08 22:23:54 -04:00
TUPLE: %fixnum-bitor ;
C: %fixnum-bitor make-vop ; : %fixnum-bitor 3-vop <%fixnum-bitor> ;
2005-09-08 22:23:54 -04:00
TUPLE: %fixnum-bitxor ;
C: %fixnum-bitxor make-vop ; : %fixnum-bitxor 3-vop <%fixnum-bitxor> ;
2005-09-08 22:23:54 -04:00
TUPLE: %fixnum-bitnot ;
C: %fixnum-bitnot make-vop ; : %fixnum-bitnot 2-vop <%fixnum-bitnot> ;
! At the VOP level, the 'shift' operation is split into four
2005-05-09 22:34:47 -04:00
! distinct operations:
! - shifts with a positive count: calls runtime to make
2005-05-09 22:34:47 -04:00
! a bignum
! - shifts with a small negative count: %fixnum>>
! - shifts with a small negative count: %fixnum>>
! - shifts with a large negative count: %fixnum-sgn
TUPLE: %fixnum>> ;
C: %fixnum>> make-vop ; : %fixnum>> 3-vop <%fixnum>>> ;
2005-09-08 22:23:54 -04:00
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).
TUPLE: %fixnum-sgn ;
C: %fixnum-sgn make-vop ; : %fixnum-sgn src/dest-vop <%fixnum-sgn> ;
2005-09-08 22:23:54 -04:00
2005-05-09 22:34:47 -04:00
! Integer comparison followed by a conditional branch is
! optimized
TUPLE: %jump-fixnum<= ;
C: %jump-fixnum<= make-vop ;
2005-05-16 17:01:39 -04:00
: %jump-fixnum<= 2-in/label-vop <%jump-fixnum<=> ;
TUPLE: %jump-fixnum< ;
C: %jump-fixnum< make-vop ;
2005-05-16 17:01:39 -04:00
: %jump-fixnum< 2-in/label-vop <%jump-fixnum<> ;
TUPLE: %jump-fixnum>= ;
C: %jump-fixnum>= make-vop ;
2005-05-16 17:01:39 -04:00
: %jump-fixnum>= 2-in/label-vop <%jump-fixnum>=> ;
TUPLE: %jump-fixnum> ;
C: %jump-fixnum> make-vop ;
2005-05-16 17:01:39 -04:00
: %jump-fixnum> 2-in/label-vop <%jump-fixnum>> ;
TUPLE: %jump-eq? ;
C: %jump-eq? make-vop ;
2005-05-16 17:01:39 -04:00
: %jump-eq? 2-in/label-vop <%jump-eq?> ;
2005-05-09 02:34:15 -04:00
! some slightly optimized inline assembly
TUPLE: %type ;
C: %type make-vop ;
2006-04-01 19:50:33 -05:00
: %type ( vreg ) dest-vop <%type> ;
TUPLE: %tag ;
C: %tag make-vop ;
2006-04-01 19:50:33 -05:00
: %tag ( vreg ) dest-vop <%tag> ;
TUPLE: %getenv ;
C: %getenv make-vop ;
: %getenv src/dest-vop <%getenv> ;
TUPLE: %setenv ;
C: %setenv make-vop ;
2005-05-16 17:01:39 -04:00
: %setenv 2-in-vop <%setenv> ;
2006-02-13 22:20:39 -05:00
TUPLE: %stack>freg ;
C: %stack>freg make-vop ;
: %stack>freg ( n reg reg-class -- vop ) 3-in-vop <%stack>freg> ;
TUPLE: %freg>stack ;
C: %freg>stack make-vop ;
: %freg>stack ( n reg reg-class -- vop ) 3-in-vop <%freg>stack> ;
2005-05-08 20:30:38 -04:00
TUPLE: %cleanup ;
C: %cleanup make-vop ;
2005-05-16 17:01:39 -04:00
: %cleanup ( n -- vop ) src-vop <%cleanup> ;
2005-05-08 20:30:38 -04:00
TUPLE: %unbox ;
C: %unbox make-vop ;
: %unbox ( n reg-class func -- vop ) 3-in-vop <%unbox> ;
TUPLE: %unbox-struct ;
C: %unbox-struct make-vop ;
: %unbox-struct ( n reg-class size -- vop )
3-in-vop <%unbox-struct> ;
2005-05-08 20:30:38 -04:00
TUPLE: %box ;
C: %box make-vop ;
2006-02-13 22:20:39 -05:00
: %box ( n reg-class func -- vop ) 3-in-vop <%box> ;
2005-05-08 20:30:38 -04:00
2006-03-10 22:16:46 -05:00
TUPLE: %box-struct ;
C: %box-struct make-vop ;
: %box-struct ( n reg-class size -- vop )
3-in-vop <%box-struct> ;
TUPLE: %alien-invoke ;
C: %alien-invoke make-vop ;
: %alien-invoke ( func lib -- vop ) 2-in-vop <%alien-invoke> ;
2006-02-13 17:16:34 -05:00
TUPLE: %alien-callback ;
C: %alien-callback make-vop ;
: %alien-callback ( quot -- vop ) src-vop <%alien-callback> ;
TUPLE: %callback-value ;
C: %callback-value make-vop ;
: %callback-value ( reg-class func -- vop )
2-in-vop <%callback-value> ;