more work on optimizer
parent
d45d4803d3
commit
736c4b8b64
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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 -- )
|
||||||
|
|
|
@ -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 , ,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue