| 
									
										
										
										
											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 ;
 |