more work on optimizer

cvs
Slava Pestov 2004-12-04 03:12:58 +00:00
parent d45d4803d3
commit 736c4b8b64
8 changed files with 146 additions and 59 deletions

View File

@ -10,8 +10,12 @@
- type inference - type inference
- handle odd base cases, with code after ifte - handle odd base cases, with code after ifte
- handle recursion with when, when* etc - handle recursion with when, when* etc
- lifting - optimizer rewrite stack ops
- stack ops and alien-call need special nodes - optimizer nested ifte
- optimizer recursive call
- dataflow make block nodes for inlined words
- dataflow recursive calls marked as so
- alien-call need special nodes
+ linearizer/generator: + linearizer/generator:

View File

@ -36,19 +36,19 @@ USE: combinators
! Linear IR nodes. This is in addition to the symbols already ! Linear IR nodes. This is in addition to the symbols already
! defined in dataflow vocab. ! defined in dataflow vocab.
SYMBOL: #branch-t ( branch if top of stack is true ) SYMBOL: #jump-label-t ( branch if top of stack is true )
SYMBOL: #branch ( unconditional branch ) SYMBOL: #jump-label ( unconditional branch )
SYMBOL: #label ( branch target )
SYMBOL: #jump ( tail-call ) SYMBOL: #jump ( tail-call )
: linear, ( param op -- ) : linear, ( node -- )
swons , ; #! Add a node to the linear IR.
[ node-op get node-param get ] bind cons , ;
: >linear ( node -- ) : >linear ( node -- )
#! Dataflow OPs have a linearizer word property. This #! Dataflow OPs have a linearizer word property. This
#! quotation is executed to convert the node into linear #! quotation is executed to convert the node into linear
#! form. #! form.
"linearizer" [ drop linear, ] apply-dataflow ; "linearizer" [ linear, ] apply-dataflow ;
: (linearize) ( dataflow -- ) : (linearize) ( dataflow -- )
[ >linear ] each ; [ >linear ] each ;
@ -59,24 +59,31 @@ SYMBOL: #jump ( tail-call )
#! jumps and labels, and turns dataflow IR nodes into #! jumps and labels, and turns dataflow IR nodes into
#! lists where the first element is an operation, and the #! lists where the first element is an operation, and the
#! rest is arguments. #! rest is arguments.
[ (linearize) f #return linear, ] make-list ; [ (linearize) ] make-list ;
: <label> ( -- label ) : <label> ( -- label )
gensym ; gensym ;
: label, ( label -- ) : label, ( label -- )
#label linear, ; #label swons , ;
: linearize-ifte ( param -- ) : linearize-ifte ( param -- )
#! The parameter is a list of two lists, each one a dataflow #! The parameter is a list of two lists, each one a dataflow
#! IR. #! IR.
uncons car uncons car
<label> [ <label> [
#branch-t linear, #jump-label-t swons ,
(linearize) ( false branch ) (linearize) ( false branch )
<label> dup #branch linear, <label> dup #jump-label swons ,
] keep label, ( branch target of BRANCH-T ) ] keep label, ( branch target of BRANCH-T )
swap (linearize) ( true branch ) swap (linearize) ( true branch )
label, ( branch target of false branch end ) ; label, ( branch target of false branch end ) ;
#ifte [ linearize-ifte ] "linearizer" set-word-property #label [
dup [ node-label get ] bind label,
[ node-param get ] bind (linearize)
] "linearizer" set-word-property
#ifte [
[ node-param get ] bind linearize-ifte
] "linearizer" set-word-property

View File

@ -43,39 +43,47 @@ USE: logic
! quotations are lifted to their call sites. ! quotations are lifted to their call sites.
: scan-literal ( node -- ) : scan-literal ( node -- )
"scan-literal" [ 2drop ] apply-dataflow ; #! If the node represents a literal push, add the literal to
#! the list being constructed.
"scan-literal" [ drop ] apply-dataflow ;
: (scan-literals) ( dataflow -- )
[ scan-literal ] each ;
: scan-literals ( dataflow -- list ) : scan-literals ( dataflow -- list )
[ [ scan-literal ] each ] make-list ; [ (scan-literals) ] make-list ;
: scan-branches ( branches -- ) : scan-branches ( branches -- )
[ [ scan-literal ] each ] each ; #! Collect all literals from all branches.
[ node-param get ] bind [ [ scan-literal ] each ] each ;
: mentions-literal? ( literal list -- ) : mentions-literal? ( literal list -- )
#! Does the given list of result objects refer to this #! Does the given list of result objects refer to this
#! literal? #! literal?
[ dup cons? [ car over = ] [ drop f ] ifte ] some? ; [ dup cons? [ car over = ] [ drop f ] ifte ] some? ;
: default-kill? ( literal node -- ? ) : consumes-literal? ( literal node -- ? )
#! Does the dataflow node consume the literal?
[ [
node-consume-d get mentions-literal? swap node-consume-d get mentions-literal? swap
node-consume-r get mentions-literal? nip or not node-consume-r get mentions-literal? nip or
] bind ;
: produces-literal? ( literal node -- ? )
#! Does the dataflow node produce the literal?
[
node-produce-d get mentions-literal? swap
node-produce-r get mentions-literal? nip or
] bind ; ] bind ;
: (can-kill?) ( literal node -- ? ) : (can-kill?) ( literal node -- ? )
#! Return false if the literal appears as input to this #! Return false if the literal appears as input to this
#! node, and this node is not a stack operation. #! node, and this node is not a stack operation.
dup [ node-op get ] bind dup "shuffle" word-property [ "can-kill" [ consumes-literal? not ] apply-dataflow ;
3drop t
] [
"can-kill" word-property dup [
call
] [
drop default-kill?
] ifte
] ifte ;
: can-kill? ( literal dataflow -- ? ) : can-kill? ( literal dataflow -- ? )
#! Return false if the literal appears in any node in the
#! list.
[ dupd (can-kill?) ] all? nip ; [ dupd (can-kill?) ] all? nip ;
: kill-set ( dataflow -- list ) : kill-set ( dataflow -- list )
@ -83,12 +91,54 @@ USE: logic
dup scan-literals [ over can-kill? ] subset nip ; dup scan-literals [ over can-kill? ] subset nip ;
: can-kill-branches? ( literal node -- ? ) : can-kill-branches? ( literal node -- ? )
#! Check if the literal appears in either branch.
[ node-param get ] bind [ dupd can-kill? ] all? nip ; [ node-param get ] bind [ dupd can-kill? ] all? nip ;
#push [ , ] "scan-literal" set-word-property : kill-literal ( literals node -- )
#! Remove the literals from the node and , it if it is not a
#! NOP.
swap [
over 2dup consumes-literal? >r produces-literal? r> or
] some?
[ drop ] [ , ] ifte ;
: kill-literals ( literals dataflow -- )
#! Remove literals and construct a list.
[ dupd kill-literal ] each drop ;
: optimize ( dataflow -- )
[ dup kill-set swap kill-literals ] make-list ;
#push [
[ node-param get ] bind ,
] "scan-literal" set-word-property
#label [
[ node-param get ] bind (scan-literals)
] "scan-literal" set-word-property
#label [
[ node-param get ] bind can-kill?
] "can-kill" set-word-property
#ifte [ scan-branches ] "scan-literal" set-word-property #ifte [ scan-branches ] "scan-literal" set-word-property
#ifte [ can-kill-branches? ] "can-kill" set-word-property #ifte [ can-kill-branches? ] "can-kill" set-word-property
#generic [ scan-branches ] "scan-literal" set-word-property #generic [ scan-branches ] "scan-literal" set-word-property
#generic [ can-kill-branches? ] "can-kill" set-word-property #generic [ can-kill-branches? ] "can-kill" set-word-property
#2generic [ scan-branches ] "scan-literal" set-word-property #2generic [ scan-branches ] "scan-literal" set-word-property
#2generic [ can-kill-branches? ] "can-kill" set-word-property #2generic [ can-kill-branches? ] "can-kill" set-word-property
! Don't care about inputs to recursive combinator calls
#call-label [ 2drop t ] "can-kill" set-word-property
#drop [ 2drop t ] "can-kill" set-word-property
#dup [ 2drop t ] "can-kill" set-word-property
#swap [ 2drop t ] "can-kill" set-word-property
#over [ 2drop t ] "can-kill" set-word-property
#pick [ 2drop t ] "can-kill" set-word-property
#nip [ 2drop t ] "can-kill" set-word-property
#tuck [ 2drop t ] "can-kill" set-word-property
#rot [ 2drop t ] "can-kill" set-word-property
#>r [ 2drop t ] "can-kill" set-word-property
#r> [ 2drop t ] "can-kill" set-word-property

View File

@ -38,7 +38,10 @@ USE: vectors
! We build a dataflow graph for the compiler. ! We build a dataflow graph for the compiler.
SYMBOL: dataflow-graph SYMBOL: dataflow-graph
SYMBOL: #label
SYMBOL: #call ( non-tail call ) SYMBOL: #call ( non-tail call )
SYMBOL: #call-label
SYMBOL: #push ( literal ) SYMBOL: #push ( literal )
SYMBOL: #ifte SYMBOL: #ifte
@ -64,6 +67,7 @@ SYMBOL: node-produce-d
SYMBOL: node-consume-r SYMBOL: node-consume-r
SYMBOL: node-produce-r SYMBOL: node-produce-r
SYMBOL: node-op SYMBOL: node-op
SYMBOL: node-label
! #push nodes have this field set to the value being pushed. ! #push nodes have this field set to the value being pushed.
! #call nodes have this as the word being called ! #call nodes have this as the word being called
@ -110,12 +114,10 @@ SYMBOL: node-param
: apply-dataflow ( dataflow name default -- ) : apply-dataflow ( dataflow name default -- )
#! For the dataflow node, look up named word property, #! For the dataflow node, look up named word property,
#! if its not defined, apply default quotation to #! if its not defined, apply default quotation to
#! ( param op ) otherwise apply property quotation to #! ( node ) otherwise apply property quotation to
#! ( param ). #! ( node ).
>r >r [ node-param get node-op get ] bind dup r> >r >r dup [ node-op get ] bind r> word-property dup [
word-property dup [ call r> drop
( param op property )
nip call r> drop
] [ ] [
drop r> call drop r> call
] ifte ; ] ifte ;

View File

@ -54,6 +54,10 @@ SYMBOL: recursive-state
! ... with keys: ! ... with keys:
SYMBOL: base-case SYMBOL: base-case
SYMBOL: entry-effect SYMBOL: entry-effect
! When a call to a combinator is compiled, recursion cannot
! simply jump to the definition of the combinator. Instead, it
! makes a local jump to this label.
SYMBOL: recursive-label
: gensym-vector ( n -- vector ) : gensym-vector ( n -- vector )
dup <vector> swap [ gensym over vector-push ] times ; dup <vector> swap [ gensym over vector-push ] times ;
@ -98,11 +102,6 @@ SYMBOL: entry-effect
recursive-state set recursive-state set
dataflow-graph off ; dataflow-graph off ;
: with-recursive-state ( word quot -- )
over <recursive-state> cons recursive-state cons@
call
recursive-state uncons@ drop ;
DEFER: apply-word DEFER: apply-word
: apply-literal ( obj -- ) : apply-literal ( obj -- )

View File

@ -38,19 +38,14 @@ USE: namespaces
[ 0 1 node-outputs ] bind [ 0 1 node-outputs ] bind
] "infer" set-word-property ] "infer" set-word-property
\ >r t "shuffle" set-word-property
\ r> [ \ r> [
f #r> dataflow, [ 0 1 node-inputs ] extend f #r> dataflow, [ 0 1 node-inputs ] extend
pop-r push-d pop-r push-d
[ 1 0 node-outputs ] bind [ 1 0 node-outputs ] bind
] "infer" set-word-property ] "infer" set-word-property
\ r> t "shuffle" set-word-property
: meta-infer ( word op -- ) : meta-infer ( word op -- )
#! Mark a word as being partially evaluated. #! Mark a word as being partially evaluated.
dup t "shuffle" set-word-property
dupd [ dupd [
over unit , \ car , over unit , \ car ,
f , , f , ,

View File

@ -49,10 +49,13 @@ USE: prettyprint
[ pick swap dataflow-inputs ] keep [ pick swap dataflow-inputs ] keep
pick 2slip swap dataflow-outputs ; inline pick 2slip swap dataflow-outputs ; inline
: (consume/produce) ( param op effect -- )
[ unswons consume-d produce-d ] with-dataflow ;
: consume/produce ( word [ in | out ] -- ) : consume/produce ( word [ in | out ] -- )
#! Add a node to the dataflow graph that consumes and #! Add a node to the dataflow graph that consumes and
#! produces a number of values. #! produces a number of values.
#call swap [ unswons consume-d produce-d ] with-dataflow ; #call swap (consume/produce) ;
: apply-effect ( word [ in | out ] -- ) : apply-effect ( word [ in | out ] -- )
#! If a word does not have special inference behavior, we #! If a word does not have special inference behavior, we
@ -68,10 +71,33 @@ USE: prettyprint
: no-effect ( word -- ) : no-effect ( word -- )
"Unknown stack effect: " swap word-name cat2 throw ; "Unknown stack effect: " swap word-name cat2 throw ;
: with-recursive-state ( word label quot -- )
>r
<recursive-state> [ recursive-label set ] extend dupd cons
recursive-state cons@
r> call
( recursive-state uncons@ drop ) ;
: (with-block) ( label quot -- )
#! Call a quotation in a new namespace, and transfer
#! inference state from the outer scope.
swap >r [
dataflow-graph off
call
d-in get meta-d get meta-r get get-dataflow
] with-scope
r> swap #label dataflow, [ node-label set ] bind
meta-r set meta-d set d-in set ;
: with-block ( word label quot -- )
#! Execute a quotation with the word on the stack, and add
#! its dataflow contribution to a new block node in the IR.
over [ with-recursive-state ] (with-block) ;
: inline-compound ( word -- effect ) : inline-compound ( word -- effect )
#! Infer the stack effect of a compound word in the current #! Infer the stack effect of a compound word in the current
#! inferencer instance. #! inferencer instance.
[ word-parameter infer-quot effect ] with-recursive-state ; gensym [ word-parameter infer-quot effect ] with-block ;
: (infer-compound) ( word -- effect ) : (infer-compound) ( word -- effect )
#! Infer a word's stack effect in a separate inferencer #! Infer a word's stack effect in a separate inferencer
@ -118,9 +144,15 @@ USE: prettyprint
: recursive-word ( word state -- ) : recursive-word ( word state -- )
#! Handle a recursive call, by either applying a previously #! Handle a recursive call, by either applying a previously
#! inferred base case, or raising an error. #! inferred base case, or raising an error. If the recursive
base-case swap hash dup [ #! call is to a local block, emit a label call node.
consume/produce base-case over hash dup [
swap [ recursive-label get ] bind ( word effect label )
dup [
rot drop #call-label rot
] [
drop #call swap
] ifte (consume/produce)
] [ ] [
drop no-base-case drop no-base-case
] ifte ; ] ifte ;
@ -147,13 +179,11 @@ USE: prettyprint
] ifte ; ] ifte ;
: infer-call ( [ rstate | quot ] -- ) : infer-call ( [ rstate | quot ] -- )
\ drop #call dataflow, drop 1 ensure-d
[ dataflow-drop,
dataflow-graph off gensym dup [
pop-d uncons recursive-state set infer-quot drop pop-d uncons recursive-state set infer-quot
d-in get meta-d get get-dataflow ] with-block ;
] with-scope
[ dataflow-graph cons@ ] each meta-d set d-in set ;
\ call [ infer-call ] "infer" set-word-property \ call [ infer-call ] "infer" set-word-property

View File

@ -71,14 +71,14 @@ SYMBOL: #test
{{ {{
[ node-op | #test ] [ node-op | #test ]
[ node-param | 5 ] [ node-param | 5 ]
}} "foobar" [ drop succ ] apply-dataflow }} "foobar" [ [ node-param get ] bind succ ] apply-dataflow
] unit-test ] unit-test
#test [ sq ] "foobar" set-word-property #test [ [ node-param get ] bind sq ] "foobar" set-word-property
[ 25 ] [ [ 25 ] [
{{ {{
[ node-op | #test ] [ node-op | #test ]
[ node-param | 5 ] [ node-param | 5 ]
}} "foobar" [ drop succ ] apply-dataflow }} "foobar" [ [ node-param get ] bind succ ] apply-dataflow
] unit-test ] unit-test