2008-04-19 03:11:55 -04:00
|
|
|
! Copyright (C) 2004, 2008 Slava Pestov.
|
2007-09-20 18:09:08 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
|
|
USING: namespaces assocs sequences inference.dataflow
|
2008-04-19 03:11:55 -04:00
|
|
|
inference.backend kernel generic assocs classes vectors
|
|
|
|
accessors combinators ;
|
|
|
|
IN: optimizer.def-use
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
SYMBOL: def-use
|
|
|
|
|
|
|
|
: used-by ( value -- seq ) def-use get at ;
|
|
|
|
|
|
|
|
: unused? ( value -- ? )
|
|
|
|
used-by empty? ;
|
|
|
|
|
|
|
|
: uses-values ( node seq -- )
|
2008-06-13 03:09:16 -04:00
|
|
|
[ def-use get push-at ] with each ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: defs-values ( seq -- )
|
|
|
|
#! If there is no value, set it to a new empty vector,
|
|
|
|
#! otherwise do nothing.
|
|
|
|
[ def-use get [ V{ } like ] change-at ] each ;
|
|
|
|
|
|
|
|
GENERIC: node-def-use ( node -- )
|
|
|
|
|
2008-04-19 03:11:55 -04:00
|
|
|
: compute-def-use ( node -- node )
|
|
|
|
H{ } clone def-use set
|
|
|
|
dup [ node-def-use ] each-node ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: nest-def-use ( node -- def-use )
|
2008-04-19 03:11:55 -04:00
|
|
|
[ compute-def-use drop def-use get ] with-scope ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: (node-def-use) ( node -- )
|
2008-04-19 03:11:55 -04:00
|
|
|
{
|
|
|
|
[ dup in-d>> uses-values ]
|
|
|
|
[ dup in-r>> uses-values ]
|
|
|
|
[ out-d>> defs-values ]
|
|
|
|
[ out-r>> defs-values ]
|
|
|
|
} cleave ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: object node-def-use (node-def-use) ;
|
|
|
|
|
|
|
|
! nodes that don't use their values directly
|
|
|
|
UNION: #passthru
|
|
|
|
#shuffle #>r #r> #call-label #merge #values #entry #declare ;
|
|
|
|
|
|
|
|
M: #passthru node-def-use drop ;
|
|
|
|
|
|
|
|
M: #return node-def-use
|
|
|
|
#! Values returned by local labels can be killed.
|
2008-04-19 03:11:55 -04:00
|
|
|
dup param>> [ drop ] [ (node-def-use) ] if ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
! nodes that don't use their values directly
|
|
|
|
UNION: #killable
|
|
|
|
#push #passthru ;
|
|
|
|
|
|
|
|
: purge-invariants ( stacks -- seq )
|
|
|
|
#! Output a sequence of values which are not present in the
|
|
|
|
#! same position in each sequence of the stacks sequence.
|
2008-04-26 00:12:44 -04:00
|
|
|
unify-lengths flip [ all-eq? not ] filter concat ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
M: #label node-def-use
|
|
|
|
[
|
2008-04-19 03:11:55 -04:00
|
|
|
dup in-d>> ,
|
|
|
|
dup node-child out-d>> ,
|
|
|
|
dup calls>> [ in-d>> , ] each
|
2007-09-20 18:09:08 -04:00
|
|
|
] { } make purge-invariants uses-values ;
|
|
|
|
|
|
|
|
: branch-def-use ( #branch -- )
|
2008-04-19 03:11:55 -04:00
|
|
|
active-children [ in-d>> ] map
|
2007-09-20 18:09:08 -04:00
|
|
|
purge-invariants t swap uses-values ;
|
|
|
|
|
|
|
|
M: #branch node-def-use
|
|
|
|
#! This assumes that the last element of each branch is a
|
|
|
|
#! #values node.
|
|
|
|
dup branch-def-use (node-def-use) ;
|
|
|
|
|
2008-02-10 21:32:48 -05:00
|
|
|
: compute-dead-literals ( -- values )
|
2008-04-26 00:12:44 -04:00
|
|
|
def-use get [ >r value? r> empty? and ] assoc-filter ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-02-10 21:32:48 -05:00
|
|
|
DEFER: kill-nodes
|
|
|
|
SYMBOL: dead-literals
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-02-10 21:32:48 -05:00
|
|
|
GENERIC: kill-node* ( node -- node/t )
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-02-10 21:32:48 -05:00
|
|
|
M: node kill-node* drop t ;
|
|
|
|
|
|
|
|
: prune-if ( node quot -- successor/t )
|
|
|
|
over >r call [ r> node-successor ] [ r> drop t ] if ;
|
|
|
|
inline
|
|
|
|
|
|
|
|
M: #shuffle kill-node*
|
2008-04-19 03:11:55 -04:00
|
|
|
[ [ in-d>> empty? ] [ out-d>> empty? ] bi and ] prune-if ;
|
2008-02-10 21:32:48 -05:00
|
|
|
|
|
|
|
M: #push kill-node*
|
2008-04-19 03:11:55 -04:00
|
|
|
[ out-d>> empty? ] prune-if ;
|
2008-02-10 21:32:48 -05:00
|
|
|
|
2008-04-19 03:11:55 -04:00
|
|
|
M: #>r kill-node*
|
|
|
|
[ in-d>> empty? ] prune-if ;
|
2008-02-10 21:32:48 -05:00
|
|
|
|
2008-04-19 03:11:55 -04:00
|
|
|
M: #r> kill-node*
|
|
|
|
[ in-r>> empty? ] prune-if ;
|
2008-02-10 21:32:48 -05:00
|
|
|
|
|
|
|
: kill-node ( node -- node )
|
|
|
|
dup [
|
|
|
|
dup [ dead-literals get swap remove-all ] modify-values
|
|
|
|
dup kill-node* dup t eq? [
|
2008-04-04 01:33:06 -04:00
|
|
|
drop dup [ kill-nodes ] map-children
|
2008-02-10 21:32:48 -05:00
|
|
|
] [
|
|
|
|
nip kill-node
|
|
|
|
] if
|
|
|
|
] when ;
|
|
|
|
|
|
|
|
: kill-nodes ( node -- newnode )
|
|
|
|
[ kill-node ] transform-nodes ;
|
|
|
|
|
|
|
|
: kill-values ( node -- new-node )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! Remove literals which are not actually used anywhere.
|
2008-02-10 21:32:48 -05:00
|
|
|
compute-dead-literals dup assoc-empty? [ drop ] [
|
|
|
|
dead-literals [ kill-nodes ] with-variable
|
|
|
|
] if ;
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: sole-consumer ( #call -- node/f )
|
2008-04-19 03:11:55 -04:00
|
|
|
out-d>> first used-by
|
2007-09-20 18:09:08 -04:00
|
|
|
dup length 1 = [ first ] [ drop f ] if ;
|
2008-02-13 19:42:55 -05:00
|
|
|
|
|
|
|
: splice-def-use ( node -- )
|
|
|
|
#! As a first approximation, we take all the values used
|
|
|
|
#! by the set of new nodes, and push a 't' on their
|
|
|
|
#! def-use list here. We could perform a full graph
|
|
|
|
#! substitution, but we don't need to, because the next
|
|
|
|
#! optimizer iteration will do that. We just need a minimal
|
|
|
|
#! degree of accuracy; the new values should be marked as
|
|
|
|
#! having _some_ usage, so that flushing doesn't erronously
|
|
|
|
#! flush them away.
|
2008-06-13 03:09:16 -04:00
|
|
|
nest-def-use keys def-use get [ t -rot push-at ] curry each ;
|