2005-02-22 23:07:47 -05:00
|
|
|
! Copyright (C) 2004, 2005 Slava Pestov.
|
|
|
|
! See http://factor.sf.net/license.txt for BSD license.
|
2004-12-02 22:44:36 -05:00
|
|
|
IN: compiler
|
2005-02-22 23:07:47 -05:00
|
|
|
USING: inference kernel lists math namespaces words strings
|
|
|
|
errors prettyprint kernel-internals ;
|
2004-12-01 19:48:08 -05:00
|
|
|
|
2004-12-05 21:17:09 -05:00
|
|
|
! The linear IR is close to assembly language. It also resembles
|
|
|
|
! Forth code in some sense. It exists so that pattern matching
|
|
|
|
! optimization can be performed against it.
|
|
|
|
|
2004-12-01 19:48:08 -05:00
|
|
|
! Linear IR nodes. This is in addition to the symbols already
|
2004-12-05 23:00:52 -05:00
|
|
|
! defined in inference vocab.
|
2004-12-01 19:48:08 -05:00
|
|
|
|
2004-12-10 17:27:07 -05:00
|
|
|
SYMBOL: #push-immediate
|
|
|
|
SYMBOL: #push-indirect
|
2004-12-18 20:24:46 -05:00
|
|
|
SYMBOL: #replace-immediate
|
|
|
|
SYMBOL: #replace-indirect
|
2004-12-13 18:40:21 -05:00
|
|
|
SYMBOL: #jump-t ( branch if top of stack is true )
|
2005-02-22 23:07:47 -05:00
|
|
|
SYMBOL: #jump-t-label ( branch if top of stack is true )
|
|
|
|
SYMBOL: #jump-f ( branch if top of stack is false )
|
|
|
|
SYMBOL: #jump-f-label ( branch if top of stack is false )
|
2004-12-01 19:48:08 -05:00
|
|
|
SYMBOL: #jump ( tail-call )
|
2004-12-16 19:57:03 -05:00
|
|
|
SYMBOL: #jump-label ( tail-call )
|
2004-12-05 23:00:52 -05:00
|
|
|
SYMBOL: #return-to ( push addr on C stack )
|
2004-12-01 19:48:08 -05:00
|
|
|
|
2005-01-17 15:33:12 -05:00
|
|
|
! dispatch is linearized as dispatch followed by a #target or
|
|
|
|
! #target-label for each dispatch table entry. The dispatch
|
|
|
|
! table terminates with #end-dispatch. The linearizer ensures
|
|
|
|
! the correct number of #targets is emitted.
|
2004-12-13 16:28:28 -05:00
|
|
|
SYMBOL: #target ( part of jump table )
|
2005-01-17 15:33:12 -05:00
|
|
|
SYMBOL: #target-label
|
|
|
|
SYMBOL: #end-dispatch
|
2004-12-13 16:28:28 -05:00
|
|
|
|
2005-03-15 18:18:33 -05:00
|
|
|
! on PowerPC, compiled definitions that make subroutine calls
|
|
|
|
! must have a prologue and epilogue to set up and tear down the
|
|
|
|
! link register.
|
|
|
|
SYMBOL: #prologue
|
|
|
|
SYMBOL: #epilogue
|
|
|
|
|
2004-12-03 22:12:58 -05:00
|
|
|
: linear, ( node -- )
|
|
|
|
#! Add a node to the linear IR.
|
|
|
|
[ node-op get node-param get ] bind cons , ;
|
2004-12-01 19:48:08 -05:00
|
|
|
|
|
|
|
: >linear ( node -- )
|
|
|
|
#! Dataflow OPs have a linearizer word property. This
|
|
|
|
#! quotation is executed to convert the node into linear
|
|
|
|
#! form.
|
2004-12-03 22:12:58 -05:00
|
|
|
"linearizer" [ linear, ] apply-dataflow ;
|
2004-12-01 19:48:08 -05:00
|
|
|
|
|
|
|
: (linearize) ( dataflow -- )
|
|
|
|
[ >linear ] each ;
|
|
|
|
|
|
|
|
: linearize ( dataflow -- linear )
|
|
|
|
#! Transform dataflow IR into linear IR. This strips out
|
|
|
|
#! stack flow information, flattens conditionals into
|
|
|
|
#! jumps and labels, and turns dataflow IR nodes into
|
|
|
|
#! lists where the first element is an operation, and the
|
|
|
|
#! rest is arguments.
|
2005-03-15 18:18:33 -05:00
|
|
|
[ [ #prologue ] , (linearize) ] make-list ;
|
2004-12-01 19:48:08 -05:00
|
|
|
|
2004-12-10 17:27:07 -05:00
|
|
|
: immediate? ( obj -- ? )
|
|
|
|
#! fixnums and f have a pointerless representation, and
|
|
|
|
#! are compiled immediately. Everything else can be moved
|
|
|
|
#! by GC, and is indexed through a table.
|
|
|
|
dup fixnum? swap f eq? or ;
|
|
|
|
|
|
|
|
#push [
|
|
|
|
[ node-param get ] bind
|
|
|
|
dup immediate? #push-immediate #push-indirect ?
|
|
|
|
swons ,
|
2005-03-05 14:45:23 -05:00
|
|
|
] "linearizer" set-word-prop
|
2004-12-10 17:27:07 -05:00
|
|
|
|
2004-12-01 19:48:08 -05:00
|
|
|
: <label> ( -- label )
|
2005-03-05 14:45:23 -05:00
|
|
|
gensym dup t "label" set-word-prop ;
|
2004-12-14 02:57:40 -05:00
|
|
|
|
|
|
|
: label? ( obj -- ? )
|
2005-03-05 14:45:23 -05:00
|
|
|
dup word? [ "label" word-prop ] [ drop f ] ifte ;
|
2004-12-01 19:48:08 -05:00
|
|
|
|
|
|
|
: label, ( label -- )
|
2004-12-03 22:12:58 -05:00
|
|
|
#label swons , ;
|
2004-12-01 19:48:08 -05:00
|
|
|
|
2004-12-11 18:18:43 -05:00
|
|
|
: linearize-simple-label ( node -- )
|
|
|
|
#! Some labels become simple labels after the optimization
|
|
|
|
#! stage.
|
2004-12-05 23:00:52 -05:00
|
|
|
dup [ node-label get ] bind label,
|
|
|
|
[ node-param get ] bind (linearize) ;
|
|
|
|
|
2004-12-11 18:18:43 -05:00
|
|
|
#simple-label [
|
|
|
|
linearize-simple-label
|
2005-03-05 14:45:23 -05:00
|
|
|
] "linearizer" set-word-prop
|
2004-12-11 18:18:43 -05:00
|
|
|
|
2005-03-15 18:18:33 -05:00
|
|
|
: return, [ #epilogue ] , [ #return ] , ;
|
|
|
|
|
2004-12-05 23:00:52 -05:00
|
|
|
: linearize-label ( node -- )
|
|
|
|
#! Labels are tricky, because they might contain non-tail
|
|
|
|
#! calls. So we push the address of the location right after
|
|
|
|
#! the label, then linearize the label, then add a #return
|
|
|
|
#! node to the linear IR. The simplifier will take care of
|
|
|
|
#! this in the common case where the labelled block does
|
|
|
|
#! not contain non-tail recursive calls to itself.
|
|
|
|
<label> dup #return-to swons , >r
|
2004-12-11 18:18:43 -05:00
|
|
|
linearize-simple-label
|
2005-03-15 18:18:33 -05:00
|
|
|
return,
|
2004-12-05 23:00:52 -05:00
|
|
|
r> label, ;
|
|
|
|
|
2004-12-11 18:18:43 -05:00
|
|
|
#label [
|
|
|
|
linearize-label
|
2005-03-05 14:45:23 -05:00
|
|
|
] "linearizer" set-word-prop
|
2004-12-05 23:00:52 -05:00
|
|
|
|
2004-12-01 19:48:08 -05:00
|
|
|
: linearize-ifte ( param -- )
|
|
|
|
#! The parameter is a list of two lists, each one a dataflow
|
|
|
|
#! IR.
|
2005-01-14 14:56:19 -05:00
|
|
|
2unlist <label> [
|
2005-02-22 23:07:47 -05:00
|
|
|
#jump-t-label swons ,
|
2004-12-01 19:48:08 -05:00
|
|
|
(linearize) ( false branch )
|
2004-12-17 19:27:42 -05:00
|
|
|
<label> dup #jump-label swons ,
|
2004-12-01 19:48:08 -05:00
|
|
|
] keep label, ( branch target of BRANCH-T )
|
|
|
|
swap (linearize) ( true branch )
|
|
|
|
label, ( branch target of false branch end ) ;
|
|
|
|
|
2005-01-14 14:56:19 -05:00
|
|
|
\ ifte [
|
2004-12-05 23:00:52 -05:00
|
|
|
[ node-param get ] bind linearize-ifte
|
2005-03-05 14:45:23 -05:00
|
|
|
] "linearizer" set-word-prop
|
2004-12-05 23:00:52 -05:00
|
|
|
|
2004-12-13 16:28:28 -05:00
|
|
|
: dispatch-head ( vtable -- end label/code )
|
2004-12-05 21:17:09 -05:00
|
|
|
#! Output the jump table insn and return a list of
|
|
|
|
#! label/branch pairs.
|
2005-01-14 14:56:19 -05:00
|
|
|
[ dispatch ] ,
|
2004-12-05 21:17:09 -05:00
|
|
|
<label> ( end label ) swap
|
2005-01-17 15:33:12 -05:00
|
|
|
[ <label> dup #target-label swons , cons ] map
|
|
|
|
[ #end-dispatch ] , ;
|
2004-12-05 21:17:09 -05:00
|
|
|
|
2004-12-13 16:28:28 -05:00
|
|
|
: dispatch-body ( end label/param -- )
|
2004-12-05 21:17:09 -05:00
|
|
|
#! Output each branch, with a jump to the end label.
|
2005-02-17 19:01:11 -05:00
|
|
|
[ uncons label, (linearize) #jump-label swons , ] each-with ;
|
2004-12-13 16:28:28 -05:00
|
|
|
|
|
|
|
: linearize-dispatch ( vtable -- )
|
2004-12-05 21:17:09 -05:00
|
|
|
#! The parameter is a list of lists, each one is a branch to
|
|
|
|
#! take in case the top of stack has that type.
|
2005-02-17 19:01:11 -05:00
|
|
|
dispatch-head dupd dispatch-body label, ;
|
2004-12-05 21:17:09 -05:00
|
|
|
|
2005-01-14 14:56:19 -05:00
|
|
|
\ dispatch [
|
2004-12-13 16:28:28 -05:00
|
|
|
[ node-param get ] bind linearize-dispatch
|
2005-03-05 14:45:23 -05:00
|
|
|
] "linearizer" set-word-prop
|
2004-12-08 18:39:36 -05:00
|
|
|
|
2005-03-05 14:45:23 -05:00
|
|
|
#values [ drop ] "linearizer" set-word-prop
|
2005-03-15 18:18:33 -05:00
|
|
|
|
|
|
|
#return [ drop return, ] "linearizer" set-word-prop
|