! Copyright (C) 2004, 2006 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. IN: inference USING: arrays generic hashtables interpreter kernel math namespaces parser sequences words ; ! The dataflow IR is the first of the two intermediate ! representations used by Factor. It annotates concatenative ! code with stack flow information and types. TUPLE: node param shuffle classes literals history successor children ; M: node = eq? ; : make-node ( param in-d out-d in-r out-r node -- node ) [ >r swapd f f f f f r> set-delegate ] keep ; : node-in-d node-shuffle shuffle-in-d ; : node-in-r node-shuffle shuffle-in-r ; : node-out-d node-shuffle shuffle-out-d ; : node-out-r node-shuffle shuffle-out-r ; : set-node-in-d node-shuffle set-shuffle-in-d ; : set-node-in-r node-shuffle set-shuffle-in-r ; : set-node-out-d node-shuffle set-shuffle-out-d ; : set-node-out-r node-shuffle set-shuffle-out-r ; : empty-node f { } { } { } { } ; : param-node ( label) { } { } { } { } ; : in-node ( inputs) >r f r> { } { } { } ; : out-node ( outputs) >r f { } r> { } { } ; : meta-d-node meta-d get clone in-node ; : d-tail ( n -- list ) meta-d get tail* ; : r-tail ( n -- list ) meta-r get tail* ; : node-child node-children first ; TUPLE: #label ; C: #label make-node ; : #label ( label -- node ) param-node <#label> ; TUPLE: #entry ; C: #entry make-node ; : #entry ( -- node ) meta-d-node <#entry> ; TUPLE: #call ; C: #call make-node ; : #call ( word -- node ) param-node <#call> ; TUPLE: #call-label ; C: #call-label make-node ; : #call-label ( label -- node ) param-node <#call-label> ; TUPLE: #push ; C: #push make-node ; : #push ( -- node ) peek-d 1array out-node <#push> ; : >#push< ( node -- seq ) node-out-d [ value-literal ] map ; TUPLE: #shuffle ; C: #shuffle make-node ; : #shuffle ( -- node ) empty-node <#shuffle> ; TUPLE: #values ; C: #values make-node ; : #values ( -- node ) meta-d-node <#values> ; TUPLE: #return ; C: #return make-node ; : #return ( label -- node ) #! The parameter is the label we are returning from, or if #! f, this is a top-level return. meta-d-node <#return> [ set-node-param ] keep ; TUPLE: #if ; C: #if make-node ; : #if ( in -- node ) peek-d 1array in-node <#if> ; TUPLE: #dispatch ; C: #dispatch make-node ; : #dispatch ( in -- node ) peek-d 1array in-node <#dispatch> ; TUPLE: #merge ; C: #merge make-node ; : #merge ( -- node ) meta-d get clone out-node <#merge> ; TUPLE: #terminate ; C: #terminate make-node ; : #terminate ( -- node ) empty-node <#terminate> ; TUPLE: #declare ; C: #declare make-node ; : #declare ( classes -- node ) param-node <#declare> ; : node-inputs ( d-count r-count node -- ) tuck >r r-tail r> set-node-in-r >r d-tail r> set-node-in-d ; : node-outputs ( d-count r-count node -- ) tuck >r r-tail r> set-node-out-r >r d-tail r> set-node-out-d ; ! Variable holding dataflow graph being built. SYMBOL: dataflow-graph ! The most recently added node. SYMBOL: current-node : node, ( node -- ) dataflow-graph get [ dup current-node [ set-node-successor ] change ] [ ! first node dup dataflow-graph set current-node set ] if ; : node-values ( node -- values ) [ dup node-in-d % dup node-out-d % dup node-in-r % node-out-r % ] { } make ; : last-node ( node -- last ) dup node-successor [ last-node ] [ ] ?if ; : penultimate-node ( node -- penultimate ) dup node-successor dup [ dup node-successor [ nip penultimate-node ] [ drop ] if ] [ 2drop f ] if ; : drop-inputs ( node -- #shuffle ) node-in-d clone in-node <#shuffle> ; : #drop ( n -- #shuffle ) d-tail in-node <#shuffle> ; : each-node ( node quot -- | quot: node -- ) over [ [ call ] 2keep swap [ node-children [ swap each-node ] each-with ] 2keep node-successor swap each-node ] [ 2drop ] if ; inline : each-node-with ( obj node quot -- | quot: obj node -- ) swap [ with ] each-node 2drop ; inline : all-nodes? ( node quot -- ? | quot: node -- ? ) over [ [ call ] 2keep rot [ [ swap node-children [ swap all-nodes? ] all-with? ] 2keep rot [ >r node-successor r> all-nodes? ] [ 2drop f ] if ] [ 2drop f ] if ] [ 2drop t ] if ; inline : all-nodes-with? ( obj node quot -- ? | quot: obj node -- ? ) swap [ with rot ] all-nodes? 2nip ; inline : remember-node ( word node -- ) #! Annotate each node with the fact it was inlined from #! 'word'. [ dup #call? [ [ node-history ?push ] keep set-node-history ] [ 2drop ] if ] each-node-with ; GENERIC: calls-label* ( label node -- ? ) M: node calls-label* 2drop f ; M: #call-label calls-label* node-param eq? ; : calls-label? ( label node -- ? ) [ calls-label* not ] all-nodes-with? not ; : recursive-label? ( node -- ? ) dup node-param swap calls-label? ; SYMBOL: node-stack : >node node-stack get push ; : node> node-stack get pop ; : node@ node-stack get peek ; DEFER: iterate-nodes : iterate-children ( quot -- ) node@ node-children [ swap iterate-nodes ] each-with ; inline : iterate-next ( -- node ) node@ node-successor ; : iterate-nodes ( node quot -- ) over [ [ swap >node call node> drop ] keep over [ iterate-nodes ] [ 2drop ] if ] [ 2drop ] if ; inline : ?set-node-successor ( next prev -- ) [ set-node-successor ] [ drop ] if* ; : map-node ( prev quot -- ) swap >r node@ swap call dup r> ?set-node-successor node> drop >node ; inline DEFER: map-children DEFER: (map-nodes) : map-next ( quot -- ) node@ [ swap [ map-children ] keep node> node-successor >node (map-nodes) ] [ drop ] if* ; inline : (map-nodes) ( prev quot -- | quot: node -- node ) node@ [ [ map-node ] keep map-next ] [ drop f swap ?set-node-successor ] if ; inline : map-first ( node quot -- node | quot: node -- node ) call node> drop dup >node ; inline : map-nodes ( node quot -- node | quot: node -- node ) over [ over >node [ map-first ] keep map-next node> ] when drop ; inline : map-children ( quot -- | quot: node -- node ) node@ [ node-children [ swap map-nodes ] map-with ] keep set-node-children ; inline : with-node-iterator ( quot -- ) [ V{ } clone node-stack set call ] with-scope ; inline : (subst-values) ( new old node -- ) [ [ node-in-d subst ] 3keep [ node-in-r subst ] 3keep [ node-out-d subst ] 3keep [ node-out-r subst ] 3keep drop ] each-node 2drop ; : subst-values ( new old node -- ) #! Mutates nodes. 1 node-stack get head* swap add [ >r 2dup r> node-successor (subst-values) ] each 2drop ;