--- /dev/null
+! Copyright (C) 2004, 2005 Slava Pestov.
+! See http://factor.sf.net/license.txt for BSD license.
+IN: compiler-backend
+USING: generic inference kernel lists math namespaces
+prettyprint strings words ;
+
+! A peephole optimizer operating on the linear IR.
+
+! The linear IR being simplified is stored in this variable.
+SYMBOL: simplifying
+
+GENERIC: simplify-node ( linear vop -- linear ? )
+
+! The next node following this node in terms of control flow, or
+! f if this is a conditional.
+GENERIC: next-logical ( linear vop -- linear )
+
+! No delegation.
+M: tuple simplify-node drop f ;
+
+: simplify-1 ( list -- list ? )
+ #! Return a new linear IR.
+ dup [
+ dup car simplify-node
+ [ uncons simplify-1 drop cons t ]
+ [ uncons simplify-1 >r cons r> ] ifte
+ ] [
+ f
+ ] ifte ;
+
+: simplify ( linear -- linear )
+ #! Keep simplifying until simplify-1 returns f.
+ [
+ dup simplifying set simplify-1
+ ] with-scope [ simplify ] when ;
+
+: label-called? ( label -- ? )
+ simplifying get [ calls-label? ] some-with? ;
+
+M: %label simplify-node ( linear vop -- linear ? )
+ vop-label label-called? [ f ] [ cdr t ] ifte ;
+
+: next-physical? ( linear class -- vop ? )
+ #! If the following op has given class, remove it and
+ #! return it.
+ over cdr dup [
+ car class = [ cdr car t ] [ f ] ifte
+ ] [
+ 3drop f f
+ ] ifte ;
+
+M: %inc-d simplify-node ( linear vop -- linear ? )
+ #! %inc-d cancels a following %inc-d.
+ >r dup \ %inc-d next-physical? [
+ vop-literal r> vop-literal + dup 0 = [
+ drop cdr cdr f
+ ] [
+ %inc-d >r cdr cdr r> swons t
+ ] ifte
+ ] [
+ r> 2drop f
+ ] ifte ;
+
+: dead-load? ( linear vop -- ? )
+ #! Is the %replace-d followed by a %peek-d of the same
+ #! stack slot and vreg?
+ swap cdr car dup %peek-d? [
+ over vop-source over vop-dest = >r
+ swap vop-literal swap vop-literal = r> and
+ ] [
+ 2drop f
+ ] ifte ;
+
+: dead-store? ( linear n -- ? )
+ #! Is the %replace-d followed by a %dec-d, so the stored
+ #! value is lost?
+ swap \ %inc-d next-physical? [
+ vop-literal + 0 <
+ ] [
+ 2drop f
+ ] ifte ;
+
+M: %replace-d simplify-node ( linear vop -- linear ? )
+ 2dup dead-load? [
+ drop uncons cdr cons t
+ ] [
+ 2dup vop-literal dead-store? [
+ drop cdr t
+ ] [
+ drop f
+ ] ifte
+ ] ifte ;
+
+M: %immediate-d simplify-node ( linear vop -- linear ? )
+ over 0 dead-store? [ drop cdr t ] [ drop f ] ifte ;
+
+: pop? ( vop -- ? ) dup %inc-d? swap vop-literal -1 = and ;
+
+: can-fast-branch? ( linear -- ? )
+ unswons class fast-branch [
+ unswons pop? [ car %jump-t? ] [ drop f ] ifte
+ ] [
+ drop f
+ ] ifte ;
+
+: fast-branch-params ( linear -- src dest label linear )
+ uncons >r dup vop-source swap vop-dest r> cdr
+ uncons >r vop-label r> ;
+
+M: %fixnum<= simplify-node ( linear vop -- linear ? )
+ drop dup can-fast-branch? [
+ fast-branch-params >r
+ %jump-fixnum<= >r -1 %inc-d r>
+ r> cons cons t
+ ] [
+ f
+ ] ifte ;
+
+M: %eq? simplify-node ( linear vop -- linear ? )
+ drop dup can-fast-branch? [
+ fast-branch-params >r
+ %jump-eq? >r -1 %inc-d r>
+ r> cons cons t
+ ] [
+ f
+ ] ifte ;
+
+: find-label ( label -- rest )
+ simplifying get [
+ dup %label? [ vop-label = ] [ 2drop f ] ifte
+ ] some-with? ;
+
+M: %label next-logical ( linear vop -- linear )
+ drop cdr dup car next-logical ;
+
+M: %jump-label next-logical ( linear vop -- linear )
+ nip vop-label find-label cdr ;
+
+M: %target-label next-logical ( linear vop -- linear )
+ nip vop-label find-label cdr ;
+
+M: object next-logical ( linear vop -- linear )
+ drop ;
+
+: next-logical? ( op linear -- ? )
+ dup car next-logical dup [ car class = ] [ 2drop f ] ifte ;
+
+: reduce ( linear op new -- linear ? )
+ >r over cdr next-logical? [
+ dup car vop-label
+ r> execute swap cdr cons t
+ ] [
+ r> drop f
+ ] ifte ; inline
+
+M: %call simplify-node ( linear vop -- ? )
+ #! Tail call optimization.
+ drop \ %return \ %jump reduce ;
+
+M: %call-label simplify-node ( linear vop -- ? )
+ #! Tail call optimization.
+ drop \ %return \ %jump-label reduce ;
+
+: double-jump ( linear op2 op1 -- linear ? )
+ #! A jump to a jump is just a jump. If the next logical node
+ #! is a jump of type op1, replace the jump at the car of the
+ #! list with a jump of type op2.
+ pick next-logical? [
+ >r dup dup car next-logical car vop-label
+ r> execute swap cdr cons t
+ ] [
+ drop f
+ ] ifte ; inline
+
+: useless-jump ( linear -- linear ? )
+ #! A jump to a label immediately following is not needed.
+ dup car cdr find-label over cdr eq? [ cdr t ] [ f ] ifte ;
+
+: (dead-code) ( linear -- linear ? )
+ #! Remove all nodes until the next #label.
+ dup [
+ dup car %label? [
+ f
+ ] [
+ cdr (dead-code) t or
+ ] ifte
+ ] [
+ f
+ ] ifte ;
+
+: dead-code ( linear -- linear ? )
+ uncons (dead-code) >r cons r> ;
+
+M: %jump-label simplify-node ( linear vop -- linear ? )
+ drop
+ \ %return dup double-jump [
+ t
+ ] [
+ \ %jump-label dup double-jump [
+ t
+ ] [
+ \ %jump dup double-jump
+ ! [
+ ! t
+ ! ] [
+ ! useless-jump [
+ ! t
+ ! ] [
+ ! dead-code
+ ! ] ifte
+ ! ] ifte
+ ] ifte
+ ] ifte ;
+!
+! #jump-label [
+! [ #return #return double-jump ]
+! [ #jump-label #jump-label double-jump ]
+! [ #jump #jump double-jump ]
+! [ useless-jump ]
+! [ dead-code ]
+! ] "simplifiers" set-word-prop
+!
+! #target-label [
+! [ #target-label #jump-label double-jump ]
+! ! [ #target #jump double-jump ]
+! ] "simplifiers" set-word-prop
+!
+! #jump [ [ dead-code ] ] "simplifiers" set-word-prop
+! #return [ [ dead-code ] ] "simplifiers" set-word-prop
+! #end-dispatch [ [ dead-code ] ] "simplifiers" set-word-prop