| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | ! Copyright (C) 2004, 2008 Slava Pestov. | 
					
						
							| 
									
										
										
										
											2008-02-12 21:35:25 -05:00
										 |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | USING: arrays generic assocs inference inference.class | 
					
						
							|  |  |  | inference.dataflow inference.backend inference.state io kernel | 
					
						
							|  |  |  | math namespaces sequences vectors words quotations hashtables | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | combinators classes classes.algebra generic.math continuations | 
					
						
							|  |  |  | optimizer.def-use optimizer.backend generic.standard ;
 | 
					
						
							| 
									
										
										
										
											2008-02-12 21:35:25 -05:00
										 |  |  | IN: optimizer.control | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | ! ! ! Rudimentary CFA | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | ! A LOOP | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !          #label A | 
					
						
							|  |  |  | !             | | 
					
						
							|  |  |  | !            #if ----> #merge ----> #return | 
					
						
							|  |  |  | !             | | 
					
						
							|  |  |  | !       ------------- | 
					
						
							|  |  |  | !       |           | | 
					
						
							|  |  |  | ! #call-label A     | | 
					
						
							|  |  |  | !       |          ... | 
					
						
							|  |  |  | !    #values | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | ! NOT A LOOP (call to A not in tail position): | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !          #label A | 
					
						
							|  |  |  | !             | | 
					
						
							|  |  |  | !            #if ----> ... ----> #merge ----> #return | 
					
						
							|  |  |  | !             | | 
					
						
							|  |  |  | !       ------------- | 
					
						
							|  |  |  | !       |           | | 
					
						
							|  |  |  | ! #call-label A     | | 
					
						
							|  |  |  | !       |          ... | 
					
						
							|  |  |  | !      ... | 
					
						
							|  |  |  | !       | | 
					
						
							|  |  |  | !    #values | 
					
						
							|  |  |  | !
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | ! NOT A LOOP (call to A nested inside another label which is | 
					
						
							|  |  |  | ! not a loop): | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | !
 | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !          #label A | 
					
						
							|  |  |  | !             | | 
					
						
							|  |  |  | !            #if ----> #merge ----> ... ----> #return | 
					
						
							|  |  |  | !             | | 
					
						
							|  |  |  | !       ------------- | 
					
						
							|  |  |  | !       |           | | 
					
						
							|  |  |  | !      ...      #label B | 
					
						
							|  |  |  | !                   | | 
					
						
							|  |  |  | !                  #if -> ... | 
					
						
							|  |  |  | !                   | | 
					
						
							|  |  |  | !               --------- | 
					
						
							|  |  |  | !               |       | | 
					
						
							|  |  |  | !         #call-label A | | 
					
						
							|  |  |  | !               |       | | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | !           #values     | | 
					
						
							|  |  |  | !                 #call-label B | 
					
						
							|  |  |  | !                       | | 
					
						
							|  |  |  | !                      ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! Mapping word => { node { nesting tail? }+ height } | 
					
						
							|  |  |  | ! We record all calls to a label, their control nesting and | 
					
						
							|  |  |  | ! whether it is a tail call or not | 
					
						
							|  |  |  | SYMBOL: label-info | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GENERIC: collect-label-info* ( node -- )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: #label collect-label-info* | 
					
						
							|  |  |  |     [ V{ } clone node-stack get length 3array ] keep
 | 
					
						
							|  |  |  |     node-param label-info get set-at ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: #call-label collect-label-info* | 
					
						
							|  |  |  |     node-param label-info get at
 | 
					
						
							|  |  |  |     node-stack get over third tail
 | 
					
						
							| 
									
										
										
										
											2008-04-26 00:12:44 -04:00
										 |  |  |     [ [ #label? ] filter [ node-param ] map ] keep
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  |     [ node-successor #tail? ] all? 2array
 | 
					
						
							|  |  |  |     swap second push ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: node collect-label-info* | 
					
						
							|  |  |  |     drop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : collect-label-info ( node -- )
 | 
					
						
							|  |  |  |     H{ } clone label-info set
 | 
					
						
							|  |  |  |     [ collect-label-info* ] each-node ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! Mapping word => label | 
					
						
							|  |  |  | SYMBOL: potential-loops | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : remove-non-tail-calls ( -- )
 | 
					
						
							|  |  |  |     label-info get
 | 
					
						
							| 
									
										
										
										
											2008-04-26 00:12:44 -04:00
										 |  |  |     [ nip second [ second ] all? ] assoc-filter
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  |     [ first ] assoc-map
 | 
					
						
							|  |  |  |     potential-loops set ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : remove-non-loop-calls ( -- )
 | 
					
						
							|  |  |  |     ! Boolean is set to t if something changed. | 
					
						
							|  |  |  |     !  We recurse until a fixed point is reached. | 
					
						
							|  |  |  |     f label-info get [ | 
					
						
							|  |  |  |         ! If label X is called from within a label Y that is | 
					
						
							|  |  |  |         ! no longer a potential loop, then X is no longer a | 
					
						
							|  |  |  |         ! potential loop either. | 
					
						
							|  |  |  |         over potential-loops get key? [ | 
					
						
							|  |  |  |             second [ first ] map concat
 | 
					
						
							|  |  |  |             potential-loops get [ key? ] curry all?
 | 
					
						
							|  |  |  |             [ drop ] [ potential-loops get delete-at t or ] if
 | 
					
						
							|  |  |  |         ] [ 2drop ] if
 | 
					
						
							|  |  |  |     ] assoc-each [ remove-non-loop-calls ] when ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-19 03:11:55 -04:00
										 |  |  | : detect-loops ( node -- node )
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  |     [ | 
					
						
							| 
									
										
										
										
											2008-04-19 03:11:55 -04:00
										 |  |  |         dup
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  |         collect-label-info | 
					
						
							|  |  |  |         remove-non-tail-calls | 
					
						
							|  |  |  |         remove-non-loop-calls | 
					
						
							|  |  |  |         potential-loops get [ | 
					
						
							|  |  |  |             nip t swap set-#label-loop? | 
					
						
							|  |  |  |         ] assoc-each
 | 
					
						
							|  |  |  |     ] with-scope ;
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | ! ! ! Constant branch folding | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | ! BEFORE | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !      #if ----> #merge ----> C | 
					
						
							|  |  |  | !       | | 
					
						
							|  |  |  | !   --------- | 
					
						
							|  |  |  | !   |       | | 
					
						
							|  |  |  | !   A       B | 
					
						
							|  |  |  | !   |       | | 
					
						
							|  |  |  | ! #values   | | 
					
						
							|  |  |  | !        #values | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | ! AFTER | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !       | | 
					
						
							|  |  |  | !       A | 
					
						
							|  |  |  | !       | | 
					
						
							|  |  |  | !    #values | 
					
						
							|  |  |  | !       | | 
					
						
							|  |  |  | !    #merge | 
					
						
							|  |  |  | !       | | 
					
						
							|  |  |  | !       C | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : fold-branch ( node branch# -- node )
 | 
					
						
							|  |  |  |     over node-children nth
 | 
					
						
							|  |  |  |     swap node-successor over splice-node ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! #if | 
					
						
							|  |  |  | : known-boolean-value? ( node value -- value ? )
 | 
					
						
							|  |  |  |     2dup node-literal? [ | 
					
						
							|  |  |  |         node-literal t
 | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         node-class { | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |             { [ dup null class<= ] [ drop f f ] } | 
					
						
							|  |  |  |             { [ dup \ f class-not class<= ] [ drop t t ] } | 
					
						
							|  |  |  |             { [ dup \ f class<= ] [ drop f t ] } | 
					
						
							| 
									
										
										
										
											2008-04-11 13:53:22 -04:00
										 |  |  |             [ drop f f ] | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  |         } cond
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-08 16:32:55 -04:00
										 |  |  | : fold-if-branch? ( node -- value ? )
 | 
					
						
							|  |  |  |     dup node-in-d first known-boolean-value? ;
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : fold-if-branch ( node value -- node' )
 | 
					
						
							|  |  |  |     over drop-inputs >r | 
					
						
							|  |  |  |     0 1 ? fold-branch | 
					
						
							|  |  |  |     r> [ set-node-successor ] keep ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! ! ! Lifting code after a conditional if one branch throws | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! BEFORE | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !         #if ----> #merge ----> B ----> #return/#values | 
					
						
							|  |  |  | !          | | 
					
						
							|  |  |  | !          | | 
					
						
							|  |  |  | !      --------- | 
					
						
							|  |  |  | !      |       | | 
					
						
							|  |  |  | !      |       A | 
					
						
							|  |  |  | ! #terminate   | | 
					
						
							|  |  |  | !           #values | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | ! AFTER | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | !         #if ----> #merge (*) ----> #return/#values (**) | 
					
						
							|  |  |  | !          | | 
					
						
							|  |  |  | !          | | 
					
						
							|  |  |  | !      --------- | 
					
						
							|  |  |  | !      |       | | 
					
						
							|  |  |  | !      |       A | 
					
						
							|  |  |  | ! #terminate   | | 
					
						
							|  |  |  | !           #values | 
					
						
							|  |  |  | !              | | 
					
						
							|  |  |  | !           #merge (***) | 
					
						
							|  |  |  | !              | | 
					
						
							|  |  |  | !              B | 
					
						
							|  |  |  | !              | | 
					
						
							|  |  |  | !        #return/#values | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | ! (*) has the same outputs as the inputs of (**), and it is not | 
					
						
							|  |  |  | ! the same node as (***) | 
					
						
							|  |  |  | !
 | 
					
						
							|  |  |  | ! Note: if (**) is #return is is sound to put #terminate there, | 
					
						
							| 
									
										
										
										
											2008-02-14 16:17:01 -05:00
										 |  |  | ! but not if (**) is # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : only-one ( seq -- elt/f )
 | 
					
						
							|  |  |  |     dup length 1 = [ first ] [ drop f ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : lift-throw-tail? ( #if -- tail/? )
 | 
					
						
							|  |  |  |     dup node-successor #tail? | 
					
						
							|  |  |  |     [ drop f ] [ active-children only-one ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : clone-node ( node -- newnode )
 | 
					
						
							|  |  |  |     clone dup [ clone ] modify-values ;
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-08 16:32:55 -04:00
										 |  |  | : lift-branch ( node tail -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  |     over
 | 
					
						
							|  |  |  |     last-node clone-node | 
					
						
							|  |  |  |     dup node-in-d \ #merge out-node | 
					
						
							|  |  |  |     [ set-node-successor ] keep -rot
 | 
					
						
							|  |  |  |     >r dup node-successor r> splice-node | 
					
						
							|  |  |  |     set-node-successor ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: #if optimize-node* | 
					
						
							|  |  |  |     dup fold-if-branch? [ fold-if-branch t ] [ | 
					
						
							|  |  |  |         drop dup lift-throw-tail? dup [ | 
					
						
							|  |  |  |             dupd lift-branch t
 | 
					
						
							|  |  |  |         ] [ | 
					
						
							|  |  |  |             2drop t f
 | 
					
						
							|  |  |  |         ] if
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! Loop tail hoising: code after a loop can sometimes go in the | 
					
						
							|  |  |  | ! non-recursive branch of the loop | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! BEFORE: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | !   #label -> C -> #return 1 | 
					
						
							|  |  |  | !     | | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | !     -> #if -> #merge (*) -> #return 2 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | !         | | 
					
						
							|  |  |  | !     -------- | 
					
						
							|  |  |  | !     |      | | 
					
						
							|  |  |  | !     A      B | 
					
						
							|  |  |  | !     |      | | 
					
						
							|  |  |  | !  #values   | | 
					
						
							|  |  |  | !        #call-label | 
					
						
							|  |  |  | !            | | 
					
						
							|  |  |  | !            | | 
					
						
							|  |  |  | !         #values | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! AFTER: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | !        #label -> #return 1 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | !         | | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | !         -> #if -------> #merge (*) -> #return 2 | 
					
						
							|  |  |  | !             |           \-------------------/ | 
					
						
							|  |  |  | !     ----------------              | | 
					
						
							|  |  |  | !     |              |              | | 
					
						
							|  |  |  | !     A              B     unreacachable code needed to | 
					
						
							|  |  |  | !     |              |         preserve invariants | 
					
						
							|  |  |  | !  #values           | | 
					
						
							|  |  |  | !     |          #call-label | 
					
						
							|  |  |  | !  #merge (*)        | | 
					
						
							|  |  |  | !     |              | | 
					
						
							|  |  |  | !     C           #values | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | !     | | 
					
						
							|  |  |  | !  #return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 21:27:18 -05:00
										 |  |  | : find-tail ( node -- tail )
 | 
					
						
							|  |  |  |     dup #terminate? [ | 
					
						
							|  |  |  |         dup node-successor #tail? [ | 
					
						
							|  |  |  |             node-successor find-tail | 
					
						
							|  |  |  |         ] unless
 | 
					
						
							|  |  |  |     ] unless ;
 | 
					
						
							| 
									
										
										
										
											2008-02-14 16:17:01 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : child-tails ( node -- seq )
 | 
					
						
							|  |  |  |     node-children [ find-tail ] map ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GENERIC: add-loop-exit* ( label node -- )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: #branch add-loop-exit* | 
					
						
							|  |  |  |     child-tails [ add-loop-exit* ] with each ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 21:27:18 -05:00
										 |  |  | M: #call-label add-loop-exit* | 
					
						
							|  |  |  |     tuck node-param eq? [ drop ] [ node-successor , ] if ;
 | 
					
						
							| 
									
										
										
										
											2008-02-14 16:17:01 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-14 21:27:18 -05:00
										 |  |  | M: #terminate add-loop-exit* | 
					
						
							|  |  |  |     2drop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: node add-loop-exit* | 
					
						
							|  |  |  |     nip node-successor dup #terminate? [ drop ] [ , ] if ;
 | 
					
						
							| 
									
										
										
										
											2008-02-14 16:17:01 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : find-loop-exits ( label node -- seq )
 | 
					
						
							|  |  |  |     [ add-loop-exit* ] { } make ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | : find-final-if ( node -- #if/f )
 | 
					
						
							|  |  |  |     dup [ | 
					
						
							|  |  |  |         dup #if? [ | 
					
						
							|  |  |  |             dup node-successor #tail? [ | 
					
						
							|  |  |  |                 node-successor find-final-if | 
					
						
							|  |  |  |             ] unless
 | 
					
						
							|  |  |  |         ] [ | 
					
						
							|  |  |  |             node-successor find-final-if | 
					
						
							|  |  |  |         ] if
 | 
					
						
							|  |  |  |     ] when ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:14:48 -05:00
										 |  |  | : detach-node-successor ( node -- successor )
 | 
					
						
							|  |  |  |     dup node-successor #terminate rot set-node-successor ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  | : lift-loop-tail? ( #label -- tail/f )
 | 
					
						
							|  |  |  |     dup node-successor node-successor [ | 
					
						
							|  |  |  |         dup node-param swap node-child find-final-if dup [ | 
					
						
							| 
									
										
										
										
											2008-02-14 16:17:01 -05:00
										 |  |  |             find-loop-exits only-one | 
					
						
							| 
									
										
										
										
											2008-02-13 21:07:08 -05:00
										 |  |  |         ] [ 2drop f ] if
 | 
					
						
							|  |  |  |     ] [ drop f ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:07:56 -05:00
										 |  |  | M: #loop optimize-node* | 
					
						
							|  |  |  |     dup lift-loop-tail? dup [ | 
					
						
							|  |  |  |         last-node "values" set
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dup node-successor "tail" set
 | 
					
						
							|  |  |  |         dup node-successor last-node "return" set
 | 
					
						
							|  |  |  |         dup node-child find-final-if node-successor "merge" set
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ! #label -> #return | 
					
						
							|  |  |  |         "return" get clone-node over set-node-successor | 
					
						
							|  |  |  |         ! #merge -> C | 
					
						
							|  |  |  |         "merge" get clone-node "tail" get over set-node-successor | 
					
						
							|  |  |  |         ! #values -> #merge ->C | 
					
						
							|  |  |  |         "values" get set-node-successor | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         t
 | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         2drop t f
 | 
					
						
							|  |  |  |     ] if ;
 |