factor/library/compiler/optimizer.factor

222 lines
5.1 KiB
Factor
Raw Normal View History

2005-04-02 02:39:33 -05:00
! Copyright (C) 2004, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
2005-05-09 02:34:15 -04:00
IN: compiler-frontend
2005-05-22 02:35:38 -04:00
USING: hashtables inference kernel lists namespaces sequences ;
2004-12-02 22:44:36 -05:00
! The optimizer transforms dataflow IR to dataflow IR. Currently
! it removes literals that are eventually dropped, and never
! arise as inputs to any other type of function. Such 'dead'
! literals arise when combinators are inlined and quotations are
2005-05-22 02:35:38 -04:00
! lifted to their call sites.
2004-12-02 22:44:36 -05:00
2005-05-22 02:35:38 -04:00
GENERIC: literals* ( node -- )
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
: literals, ( node -- )
[ dup literals* node-successor literals, ] when* ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
: literals ( node -- list )
[ literals, ] make-list ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
GENERIC: can-kill* ( literal node -- ? )
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
: can-kill? ( literal node -- ? )
2005-05-21 16:05:39 -04:00
#! Return false if the literal appears in any node in the
#! list.
2005-05-22 02:35:38 -04:00
dup [
2dup can-kill* [
node-successor can-kill?
] [
2drop f
] ifte
] [
2drop t
] ifte ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
: kill-set ( node -- list )
2005-05-21 16:05:39 -04:00
#! Push a list of literals that may be killed in the IR.
2005-05-22 02:35:38 -04:00
dup literals [ swap can-kill? ] subset-with ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
GENERIC: kill-node* ( literals node -- )
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
DEFER: kill-node
: kill-children ( literals node -- )
node-children [ kill-node ] each-with ;
2005-05-21 16:05:39 -04:00
: kill-node ( literals node -- )
2005-05-22 02:35:38 -04:00
dup [
2dup kill-children
2dup kill-node* node-successor kill-node
] [
2drop
] ifte ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
GENERIC: useless-node? ( node -- ? )
2005-05-21 16:05:39 -04:00
2005-05-22 21:07:24 -04:00
DEFER: prune-nodes
: prune-children ( node -- )
[ node-children [ prune-nodes ] map ] keep
set-node-children ;
2005-05-22 02:35:38 -04:00
: (prune-nodes) ( node -- )
[
2005-05-22 21:07:24 -04:00
dup prune-children
2005-05-22 02:35:38 -04:00
dup node-successor dup useless-node? [
node-successor over set-node-successor
] [
nip
] ifte (prune-nodes)
] when* ;
: prune-nodes ( node -- node )
dup useless-node? [
node-successor prune-nodes
] [
[ (prune-nodes) ] keep
] ifte ;
2005-05-21 16:05:39 -04:00
: optimize ( dataflow -- dataflow )
#! Remove redundant literals from the IR. The original IR
#! is destructively modified.
2005-05-22 02:35:38 -04:00
dup kill-set over kill-node prune-nodes ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! Generic nodes
M: node literals* ( node -- )
node-children [ literals, ] each ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: f can-kill* ( literal node -- ? )
2drop t ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: node can-kill* ( literal node -- ? )
2dup consumes-literal? >r produces-literal? r> or not ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: node kill-node* ( literals node -- )
2drop ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: f useless-node? ( node -- ? )
drop f ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: node useless-node? ( node -- ? )
drop f ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #push
M: #push literals* ( node -- )
node-out-d % ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #push can-kill* ( literal node -- ? )
2drop t ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #push kill-node* ( literals node -- )
[ node-out-d diffq ] keep set-node-out-d ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #push useless-node? ( node -- ? )
node-out-d empty? ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #drop
M: #drop can-kill* ( literal node -- ? )
2drop t ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #drop kill-node* ( literals node -- )
[ node-in-d diffq ] keep set-node-in-d ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #drop useless-node? ( node -- ? )
node-in-d empty? ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #call
M: #call can-kill* ( literal node -- ? )
nip node-param {{
[[ dup t ]]
[[ drop t ]]
[[ swap t ]]
[[ over t ]]
[[ pick t ]]
[[ >r t ]]
[[ r> t ]]
}} hash ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
: kill-mask ( killing inputs -- mask )
[ swap memq? ] map-with ;
2005-05-21 16:05:39 -04:00
2005-05-22 21:07:24 -04:00
: (kill-shuffle) ( word -- map )
2005-05-22 02:35:38 -04:00
{{
2005-05-22 21:07:24 -04:00
[[ over
{{
[[ [ f t ] dup ]]
}}
]]
[[ pick
{{
[[ [ f f t ] over ]]
[[ [ f t f ] over ]]
[[ [ f t t ] dup ]]
}}
]]
[[ swap {{ }} ]]
[[ dup {{ }} ]]
[[ >r {{ }} ]]
[[ r> {{ }} ]]
2005-05-22 02:35:38 -04:00
}} hash ;
2005-05-21 16:05:39 -04:00
2005-05-22 21:07:24 -04:00
: lookup-mask ( mask word -- word )
over [ not ] all? [ nip ] [ (kill-shuffle) hash ] ifte ;
2005-05-22 02:35:38 -04:00
: kill-shuffle ( literals node -- )
#! If certain values passing through a stack op are being
#! killed, the stack op can be reduced, in extreme cases
#! to a no-op.
2005-05-22 21:07:24 -04:00
[ [ node-in-d kill-mask ] keep node-param lookup-mask ] keep
set-node-param ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #call kill-node* ( literals node -- )
2005-05-22 21:07:24 -04:00
dup node-param (kill-shuffle)
2005-05-22 02:35:38 -04:00
[ kill-shuffle ] [ 2drop ] ifte ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #call useless-node? ( node -- ? )
node-param not ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #call-label
M: #call-label can-kill* ( literal node -- ? )
2drop t ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #label
M: #label can-kill* ( literal node -- ? )
node-children car can-kill? ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #values
SYMBOL: branch-returns
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
M: #values can-kill* ( literal node -- ? )
dupd consumes-literal? [
2005-05-22 21:07:24 -04:00
branch-returns get
[ memq? ] subset-with
[ [ eq? ] fiber? ] all?
2005-05-22 02:35:38 -04:00
] [
drop t
] ifte ;
2005-05-21 16:05:39 -04:00
2005-05-22 21:07:24 -04:00
: branch-values ( branches -- )
[ last-node node-in-d >list ] map
2005-05-23 00:25:52 -04:00
unify-lengths dual branch-returns set ;
2005-05-22 21:07:24 -04:00
2005-05-22 02:35:38 -04:00
: can-kill-branches? ( literal node -- ? )
#! Check if the literal appears in either branch. This
#! assumes that the last element of each branch is a #values
#! node.
2dup consumes-literal? [
2drop f
] [
2005-05-22 21:07:24 -04:00
[
node-children dup branch-values
2005-05-22 02:35:38 -04:00
[ can-kill? ] all-with?
] with-scope
] ifte ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #ifte
M: #ifte can-kill* ( literal node -- ? )
can-kill-branches? ;
2005-05-21 16:05:39 -04:00
2005-05-22 02:35:38 -04:00
! #dispatch
M: #dispatch can-kill* ( literal node -- ? )
can-kill-branches? ;