]> gitweb.factorcode.org Git - factor.git/commitdiff
new dataflow IR
authorSlava Pestov <slava@factorcode.org>
Tue, 17 May 2005 20:13:08 +0000 (20:13 +0000)
committerSlava Pestov <slava@factorcode.org>
Tue, 17 May 2005 20:13:08 +0000 (20:13 +0000)
13 files changed:
TODO.FACTOR.txt
library/alien/compiler.factor
library/combinators.factor
library/compiler/intrinsics.factor
library/compiler/linearizer.factor
library/compiler/optimizer.factor
library/inference/branches.factor
library/inference/dataflow.factor
library/inference/inference.factor
library/inference/partial-eval.factor
library/inference/stack.factor
library/inference/words.factor
library/test/tuple.factor

index f404851bd1d0620ad2c1159a8c428faedbaa1a4e..e3aed42f91038269323a45ad4a1d2bd000f5f67f 100644 (file)
@@ -6,8 +6,9 @@
 <magnus--> http://www.caddr.com/macho/archives/sbcl-devel/2005-3/4764.html\r
 <magnus--> http://clozure.com/cgi-bin/viewcvs.cgi/ccl/lisp-kernel/lisp-exceptions.c?rev=1.9&content-type=text/vnd.viewcvs-markup\r
 \r
+- single-stepper and variable access: wrong namespace?\r
+- [ over ] generics no-method\r
 - investigate if COPYING_GEN needs a fix\r
-- alien-global type wrong\r
 - simplifier:\r
   - dead loads not optimized out\r
   - kill tag-fixnum/untag-fixnum\r
index 8e58366f217dc6d89c33c5b6b708de25d2c77ddb..467bcf51ed5b1efcc9e2035bbcd0918eae23997c 100644 (file)
@@ -1,9 +1,9 @@
 ! Copyright (C) 2004, 2005 Slava Pestov.
 ! See http://factor.sf.net/license.txt for BSD license.
 IN: alien
-USING: assembler compiler compiler-backend errors generic
-inference kernel lists math namespaces sequences stdio strings
-unparser words ;
+USING: assembler compiler compiler-frontend compiler-backend
+errors generic inference kernel lists math namespaces sequences
+stdio strings unparser words ;
 
 ! ! ! WARNING ! ! !
 ! Reloading this file into a running Factor instance on Win32
@@ -42,48 +42,42 @@ M: alien-error error. ( error -- )
         " symbol." %
     ] make-string print ;
 
-: alien-invoke ( ... returns library function parameters -- ... )
+: alien-invoke ( ... return library function parameters -- ... )
     #! Call a C library function.
-    #! 'returns' is a type spec, and 'parameters' is a list of
+    #! 'return' is a type spec, and 'parameters' is a list of
     #! type specs. 'library' is an entry in the "libraries"
     #! namespace.
     drop <alien-error> throw ;
 
-! These are set in the alien-invoke dataflow IR node.
-SYMBOL: alien-returns
-SYMBOL: alien-parameters
+TUPLE: alien-node return parameters ;
+C: alien-node make-node ;
 
-: set-alien-returns ( returns node -- )
-    [ dup alien-returns set ] bind
-    "void" = [
-        [ object ] produce-d 1 0 node-outputs
-    ] unless ;
+: set-alien-return ( return node -- )
+    2dup set-alien-node-return
+    swap "void" = [
+        drop
+    ] [
+        [ object ] produce-d 1 0 rot node-outputs
+    ] ifte ;
 
 : set-alien-parameters ( parameters node -- )
-    [ dup alien-parameters set ] bind
-    [ drop object ] map dup dup ensure-d
-    length 0 node-inputs consume-d ;
+    2dup set-alien-node-parameters
+    >r [ drop object ] map dup dup ensure-d
+    length 0 r> node-inputs consume-d ;
 
 : ensure-dlsym ( symbol library -- ) load-library dlsym drop ;
 
-: alien-invoke-node ( returns params function library -- )
+: alien-node ( return params function library -- )
     #! We should fail if the library does not exist, so that
     #! compilation does not keep trying to compile FFI words
     #! over and over again if the library is not loaded.
     2dup ensure-dlsym
-    cons \ alien-invoke dataflow,
+    cons param-node <alien-node>
     [ set-alien-parameters ] keep
-    set-alien-returns ;
+    [ set-alien-return ] keep
+    node, ;
 
-: infer-alien-invoke ( -- )
-    \ alien-invoke "infer-effect" word-prop car ensure-d
-    pop-literal nip
-    pop-literal nip >r
-    pop-literal nip
-    pop-literal nip -rot
-    r> swap alien-invoke-node ;
-
-: parameters [ alien-parameters get reverse ] bind ;
+: parameters alien-node-parameters reverse ;
 
 : stack-space ( parameters -- n )
     0 swap [ c-size cell align + ] each ;
@@ -101,57 +95,35 @@ SYMBOL: alien-parameters
     parameters
     dup stack-space
     dup %parameters , >r
-    dup dup length swap [ >r 1 - dup r> unbox-parameter ] each drop
+    dup dup length swap [
+        >r 1 - dup r> unbox-parameter
+    ] each drop
     length [ %parameter ] project % r> ;
 
-: linearize-returns ( returns -- )
-    [ alien-returns get ] bind dup "void" = [
+: linearize-return ( return -- )
+    alien-node-return dup "void" = [
         drop
     ] [
         c-type [ "boxer" get "box-op" get ] bind execute ,
     ] ifte ;
 
-: linearize-alien-invoke ( node -- )
+M: alien-node linearize-node* ( node -- )
     dup linearize-parameters >r
-    dup [ node-param get ] bind %alien-invoke ,
-    dup [ node-param get cdr library-abi "stdcall" = ] bind
+    dup node-param %alien-invoke ,
+    dup node-param cdr library-abi "stdcall" =
     r> swap [ drop ] [ %cleanup , ] ifte
-    linearize-returns ;
-
-\ alien-invoke [ linearize-alien-invoke ] "linearizer" set-word-prop
+    linearize-return ;
 
-\ alien-invoke [ [ string string string general-list ] [ ] ]
+\ alien-invoke [ [ string object string general-list ] [ ] ]
 "infer-effect" set-word-prop
 
-\ alien-invoke [ infer-alien-invoke ] "infer" set-word-prop
-
-: alien-global ( type library name -- value )
-    #! Fetch the value of C global variable.
-    #! 'type' is a type spec. 'library' is an entry in the
-    #! "libraries" namespace.
-    <alien-error> throw ;
-
-: alien-global-node ( type name library -- )
-    2dup ensure-dlsym
-    cons \ alien-global dataflow,
-    set-alien-returns ;
-
-: infer-alien-global ( -- )
-    \ alien-global "infer-effect" word-prop car ensure-d
+\ alien-invoke [
     pop-literal nip
+    pop-literal nip >r
     pop-literal nip
     pop-literal nip -rot
-    alien-global-node ;
-
-: linearize-alien-global ( node -- )
-    dup [ node-param get ] bind %alien-global ,
-    linearize-returns ;
-
-\ alien-global [ linearize-alien-global ] "linearizer" set-word-prop
-
-\ alien-global [ [ string string string ] [ object ] ] "infer-effect" set-word-prop
-
-\ alien-global [ infer-alien-global ] "infer" set-word-prop
+    r> swap alien-node
+] "infer" set-word-prop
 
 global [
     "libraries" get [ <namespace> "libraries" set ] unless
index afd71e8a7150c208e3dcf955d5bc2beaeecbc218..a030dee8449e0bca9d814e259010cff608e18651 100644 (file)
@@ -5,6 +5,9 @@ IN: kernel
 : slip ( quot x -- x | quot: -- )
     >r call r> ; inline
 
+: 2slip ( quot x y -- x y | quot: -- )
+    >r >r call r> r> ; inline
+
 : keep ( x quot -- x | quot: x -- )
     over >r call r> ; inline
 
index b93d5aabd7781056ffdaded9f86f221cf8be786b..a6083273bc8ce5534f06dd17942665533a39e68a 100644 (file)
@@ -5,55 +5,33 @@ USING: assembler compiler-backend generic hashtables inference
 kernel kernel-internals lists math math-internals namespaces
 sequences words ;
 
-: immediate? ( obj -- ? )
-    #! fixnums and f have a pointerless representation, and
-    #! are compiled immediately. Everything else can be moved
-    #! by GC, and is indexed through a table.
-    dup fixnum? swap f eq? or ;
-
-: push-1 ( obj -- )
-    0 swap literal-value dup
-    immediate? [ %immediate ] [ %indirect ] ifte , ;
-
-#push [
-    [ node-produce-d get ] bind
-    dup length dup %inc-d ,
-    1 - swap [
-        push-1 0 over %replace-d ,
-    ] each drop
-] "linearizer" set-word-prop
-
-#drop [
-    [ node-consume-d get length ] bind %dec-d ,
-] "linearizer" set-word-prop
-
 \ dup [
     drop
     in-1
     1 %inc-d ,
     out-1
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 \ swap [
     drop
     in-2
     0 0 %replace-d ,
     1 1 %replace-d ,
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 \ over [
     drop
     0 1 %peek-d ,
     1 %inc-d ,
     out-1
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 \ pick [
     drop
     0 2 %peek-d ,
     1 %inc-d ,
     out-1
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 \ >r [
     drop
@@ -61,7 +39,7 @@ sequences words ;
     1 %inc-r ,
     1 %dec-d ,
     0 0 %replace-r ,
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 \ r> [
     drop
@@ -69,20 +47,18 @@ sequences words ;
     1 %inc-d ,
     1 %dec-r ,
     out-1
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
-: node-peek ( node -- obj ) node-consume-d swap hash peek ;
+: node-peek ( node -- obj ) node-in-d peek ;
 
 : peek-2 dup length 2 - swap nth ;
-: node-peek-2 ( node -- obj ) node-consume-d swap hash peek-2 ;
+: node-peek-2 ( node -- obj ) node-in-d peek-2 ;
 
 : typed? ( value -- ? ) value-types length 1 = ;
 
-\ slot t "intrinsic" set-word-prop
-
 : slot@ ( node -- n )
     #! Compute slot offset.
-    node-consume-d swap hash
+    node-in-d
     dup peek literal-value cell *
     swap peek-2 value-types car type-tag - ;
 
@@ -103,9 +79,7 @@ sequences words ;
         0 %untag ,
         1 0 %slot ,
     ] ifte  out-1
-] "linearizer" set-word-prop
-
-\ set-slot t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ set-slot [
     dup typed-literal? [
@@ -120,9 +94,7 @@ sequences words ;
         1 %untag ,
         0 1 2 %set-slot ,
     ] ifte
-] "linearizer" set-word-prop
-
-\ type t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ type [
     drop
@@ -130,9 +102,7 @@ sequences words ;
     0 %type ,
     0 %tag-fixnum ,
     out-1
-] "linearizer" set-word-prop
-
-\ arithmetic-type t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ arithmetic-type [
     drop
@@ -141,25 +111,21 @@ sequences words ;
     0 %tag-fixnum ,
     1 %inc-d ,
     out-1
-] "linearizer" set-word-prop
-
-\ getenv t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ getenv [
     1 %dec-d ,
     node-peek literal-value 0 <vreg> swap %getenv ,
     1 %inc-d ,
     out-1
-] "linearizer" set-word-prop
-
-\ setenv t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ setenv [
     1 %dec-d ,
     in-1
     node-peek literal-value 0 <vreg> swap %setenv ,
     1 %dec-d ,
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 : binary-op-reg ( op out -- )
     >r in-2
@@ -194,13 +160,10 @@ sequences words ;
     [[ fixnum>       %fixnum>       ]]
     [[ eq?           %eq?           ]]
 ] [
-    uncons over t "intrinsic" set-word-prop
-    [ literal, 0 , \ binary-op , ] make-list
-    "linearizer" set-word-prop
+    uncons [ literal, 0 , \ binary-op , ] make-list
+    "intrinsic" set-word-prop
 ] each
 
-\ fixnum* t "intrinsic" set-word-prop
-
 : slow-fixnum* \ %fixnum* 0 binary-op-reg ;
 
 \ fixnum* [
@@ -217,24 +180,20 @@ sequences words ;
     ] [
         drop slow-fixnum*
     ] ifte
-] "linearizer" set-word-prop
-
-\ fixnum-mod t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ fixnum-mod [
     ! This is not clever. Because of x86, %fixnum-mod is
     ! hard-coded to put its output in vreg 2, which happends to
     ! be EDX there.
     drop \ %fixnum-mod 2 binary-op-reg
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 \ fixnum/i t "intrinsic" set-word-prop
 
 \ fixnum/i [
     drop \ %fixnum/i 0 binary-op-reg
-] "linearizer" set-word-prop
-
-\ fixnum/mod t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ fixnum/mod [
     ! See the remark on fixnum-mod for vreg usage
@@ -243,16 +202,14 @@ sequences words ;
     0 <vreg> 1 <vreg> %fixnum/mod ,
     2 0 %replace-d ,
     0 1 %replace-d ,
-] "linearizer" set-word-prop
-
-\ fixnum-bitnot t "intrinsic" set-word-prop
+] "intrinsic" set-word-prop
 
 \ fixnum-bitnot [
     drop
     in-1
     0 %fixnum-bitnot ,
     out-1
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
 
 : slow-shift ( -- ) \ fixnum-shift %call , ;
 
@@ -289,12 +246,10 @@ sequences words ;
         ] ifte
     ] ifte ;
 
-\ fixnum-shift t "intrinsic" set-word-prop
-
 \ fixnum-shift [
     node-peek dup literal? [
         literal-value fast-shift
     ] [
         drop slow-shift
     ] ifte
-] "linearizer" set-word-prop
+] "intrinsic" set-word-prop
index 97853d2fa95c81645f85a044602c4f0bdde9f3ef..a4e1d9aaeec7ddd285aee548222319866a509bb0 100644 (file)
@@ -4,66 +4,69 @@ IN: compiler-frontend
 USING: compiler-backend inference kernel kernel-internals lists
 math namespaces words strings errors prettyprint sequences ;
 
-: >linear ( node -- )
-    #! Dataflow OPs have a linearizer word property. This
-    #! quotation is executed to convert the node into linear
-    #! form.
-    "linearizer" [ "No linearizer" throw ] apply-dataflow ;
+GENERIC: linearize-node* ( node -- )
+M: f linearize-node* ( f -- ) drop ;
 
-: (linearize) ( dataflow -- )
-    [ >linear ] each ;
+: linearize-node ( node -- )
+    [
+        dup linearize-node* node-successor linearize-node
+    ] when* ;
 
 : linearize ( dataflow -- linear )
     #! Transform dataflow IR into linear IR. This strips out
-    #! stack flow information, flattens conditionals into
-    #! jumps and labels, and turns dataflow IR nodes into
-    #! lists where the first element is an operation, and the
-    #! rest is arguments.
-    [ %prologue , (linearize) ] make-list ;
-
-: linearize-label ( node -- )
-    #! Labels are tricky, because they might contain non-tail
-    #! calls. So we push the address of the location right after
-    #! the #label , then linearize the #label , then add a #return
-    #! node to the linear IR. The simplifier will take care of
-    #! this in the common case where the labelled block does
-    #! not contain non-tail recursive calls to itself.
+    #! stack flow information, and flattens conditionals into
+    #! jumps and labels.
+    [ %prologue , linearize-node ] make-list ;
+
+M: #label linearize-node* ( node -- )
     <label> dup %return-to , >r
-    dup [ node-label get ] bind %label ,
-    [ node-param get ] bind (linearize)
+    dup node-param %label ,
+    node-children car linearize-node
     f %return ,
     r> %label , ;
 
-#label [
-    linearize-label
-] "linearizer" set-word-prop
+M: #call linearize-node* ( node -- )
+    dup node-param
+    dup "intrinsic" word-prop [
+        call
+    ] [
+        %call , drop
+    ] ?ifte ;
+
+M: #call-label linearize-node* ( node -- )
+    node-param %call-label , ;
+
+: immediate? ( obj -- ? )
+    #! fixnums and f have a pointerless representation, and
+    #! are compiled immediately. Everything else can be moved
+    #! by GC, and is indexed through a table.
+    dup fixnum? swap f eq? or ;
 
-#call [
-    [ node-param get ] bind %call ,
-] "linearizer" set-word-prop
+: push-1 ( obj -- )
+    0 swap literal-value dup
+    immediate? [ %immediate ] [ %indirect ] ifte , ;
 
-#call-label [
-    [ node-param get ] bind %call-label ,
-] "linearizer" set-word-prop
+M: #push linearize-node* ( node -- )
+    node-out-d dup length dup %inc-d ,
+    1 - swap [ push-1 0 over %replace-d , ] each drop ;
+
+M: #drop linearize-node* ( node -- )
+    node-in-d length %dec-d , ;
 
 : ifte-head ( label -- )
     in-1  1 %dec-d , 0 %jump-t , ;
 
-: linearize-ifte ( param -- )
+M: #ifte linearize-node* ( node -- )
     #! The parameter is a list of two lists, each one a dataflow
     #! IR.
-    2unlist  <label> [
+    node-children 2unlist  <label> [
         ifte-head
-        (linearize) ( false branch )
+        linearize-node ( false branch )
         <label> dup %jump-label ,
     ] keep %label , ( branch target of BRANCH-T )
-    swap (linearize) ( true branch )
+    swap linearize-node ( true branch )
     %label , ( branch target of false branch end ) ;
 
-\ ifte [
-    [ node-param get ] bind linearize-ifte
-] "linearizer" set-word-prop
-
 : dispatch-head ( vtable -- end label/code )
     #! Output the jump table insn and return a list of
     #! label/branch pairs.
@@ -77,17 +80,15 @@ math namespaces words strings errors prettyprint sequences ;
 
 : dispatch-body ( end label/param -- )
     #! Output each branch, with a jump to the end label.
-    [ uncons %label , (linearize) %jump-label , ] each-with ;
+    [ uncons %label , linearize-node %jump-label , ] each-with ;
 
-: linearize-dispatch ( vtable -- )
+M: #dispatch linearize-node* ( vtable -- )
     #! The parameter is a list of lists, each one is a branch to
     #! take in case the top of stack has that type.
-    dispatch-head dupd dispatch-body %label , ;
-
-\ dispatch [
-    [ node-param get ] bind linearize-dispatch
-] "linearizer" set-word-prop
+    node-children dispatch-head dupd dispatch-body %label , ;
 
-#values [ drop ] "linearizer" set-word-prop
+M: #values linearize-node* ( node -- )
+    drop ;
 
-#return [ drop f %return , ] "linearizer" set-word-prop
+M: #return linearize-node* ( node -- )
+    drop  f %return , ;
index 3a5c98ce57cd6e62dd85df9fcf47def5e2e28479..07e10aea4b76c96838bd4f271a36a566d2e05ea4 100644 (file)
@@ -11,207 +11,209 @@ sequences vectors words words ;
 ! lifted to their call sites. Also, #label nodes are inlined if
 ! their children do not make a recursive call to the label.
 
-: scan-literal ( node -- )
-    #! If the node represents a literal push, add the literal to
-    #! the list being constructed.
-    "scan-literal" [ drop ] apply-dataflow ;
-
-: (scan-literals) ( dataflow -- )
-    [ scan-literal ] each ;
-
-: scan-literals ( dataflow -- list )
-    [ (scan-literals) ] make-list ;
-
-: scan-branches ( branches -- )
-    #! Collect all literals from all branches.
-    [ node-param get ] bind [ [ scan-literal ] each ] each ;
-
-: mentions-literal? ( literal list -- ? )
-    #! Does the given list of result objects refer to this
-    #! literal?
-    [ value= ] some-with? ;
-
-: consumes-literal? ( literal node -- ? )
-    #! Does the dataflow node consume the literal?
-    [
-        dup node-consume-d get mentions-literal? swap
-        dup node-consume-r get mentions-literal? nip or
-    ] bind ;
-
-: produces-literal? ( literal node -- ? )
-    #! Does the dataflow node produce the literal?
-    [
-        dup node-produce-d get mentions-literal? swap
-        dup node-produce-r get mentions-literal? nip or
-    ] bind ;
-
-: (can-kill?) ( literal node -- ? )
-    #! Return false if the literal appears as input to this
-    #! node, and this node is not a stack operation.
-    2dup consumes-literal? >r produces-literal? r> or not ;
-
-: can-kill? ( literal dataflow -- ? )
-    #! Return false if the literal appears in any node in the
-    #! list.
-    [ dupd "can-kill" [ (can-kill?) ] apply-dataflow ] all? nip ;
-
-: kill-set ( dataflow -- list )
-    #! Push a list of literals that may be killed in the IR.
-    dup scan-literals [ over can-kill? ] subset nip ;
-
-SYMBOL: branch-returns
-
-: 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
-    ] [
-        [ node-param get ] bind
-        [
-            dup [
-                peek [ node-consume-d get >vector ] bind
-            ] map
-            unify-stacks >list
-            branch-returns set
-            [ dupd can-kill? ] all? nip
-        ] with-scope
-    ] ifte ;
-
-: kill-node ( literals node -- )
-    swap [ over (can-kill?) ] all? [ , ] [ drop ] ifte ;
-
-: (kill-nodes) ( literals dataflow -- )
-    #! Append live nodes to currently constructing list.
-    [ "kill-node" [ nip , ] apply-dataflow ] each-with ;
-
-: kill-nodes ( literals dataflow -- dataflow )
-    #! Remove literals and construct a list.
-    [ (kill-nodes) ] make-list ;
-
-: optimize ( dataflow -- dataflow )
-    #! Remove redundant literals from the IR. The original IR
-    #! is destructively modified.
-    dup kill-set swap kill-nodes ;
-
-: kill-branches ( literals node -- )
-    [
-        node-param [ [ dupd kill-nodes ] map nip ] change
-    ] extend , ;
-
-: kill-literal ( literals values -- values )
-    [
-        swap [ swap value= ] some-with? not
-    ] subset-with ;
-
-#push [
-    [ node-produce-d get ] bind [ literal-value ] map %
-] "scan-literal" set-word-prop
-
-#push [ 2drop t ] "can-kill" set-word-prop
-
-#push [
-    [ node-produce-d [ kill-literal ] change ] extend ,
-] "kill-node" set-word-prop
-
-#drop [ 2drop t ] "can-kill" set-word-prop
-
-#drop [
-    [ node-consume-d [ kill-literal ] change ] extend ,
-] "kill-node" set-word-prop
-
-#label [
-    [ node-param get ] bind (scan-literals)
-] "scan-literal" set-word-prop
-
-#label [
-    [ node-param get ] bind can-kill?
-] "can-kill" set-word-prop
-
-#call-label [
-    [ node-param get ] bind =
-] "calls-label" set-word-prop
-
-: calls-label? ( label list -- ? )
-    [ "calls-label" [ 2drop f ] apply-dataflow ] some-with? ;
-
-#label [
-    [ node-param get ] bind calls-label?
-] "calls-label" set-word-prop
-
-: branches-call-label? ( label list -- ? )
-    [ calls-label? ] some-with? ;
-
-\ ifte [
-    [ node-param get ] bind branches-call-label?
-] "calls-label" set-word-prop
-
-\ dispatch [
-    [ node-param get ] bind branches-call-label?
-] "calls-label" set-word-prop
-
-#label [ ( literals node -- )
-    [ node-param [ kill-nodes ] change ] extend ,
-] "kill-node" set-word-prop
-
-#values [
-    dupd consumes-literal? [
-        branch-returns get mentions-literal?
-    ] [
-        drop t
-    ] ifte
-] "can-kill" set-word-prop
-
-\ ifte [ scan-branches ] "scan-literal" set-word-prop
-\ ifte [ can-kill-branches? ] "can-kill" set-word-prop
-\ ifte [ kill-branches ] "kill-node" set-word-prop
-
-\ dispatch [ scan-branches ] "scan-literal" set-word-prop
-\ dispatch [ can-kill-branches? ] "can-kill" set-word-prop
-\ dispatch [ kill-branches ] "kill-node" set-word-prop
-
-! Don't care about inputs to recursive combinator calls
-#call-label [ 2drop t ] "can-kill" set-word-prop
-
-\ drop [ 2drop t ] "can-kill" set-word-prop
-\ drop [ kill-node ] "kill-node" set-word-prop
-\ dup [ 2drop t ] "can-kill" set-word-prop
-\ dup [ kill-node ] "kill-node" set-word-prop
-\ swap [ 2drop t ] "can-kill" set-word-prop
-\ swap [ kill-node ] "kill-node" set-word-prop
-
-: kill-mask ( killing inputs -- mask )
-    [ over [ over value= ] some? >boolean nip ] map nip ;
-
-: reduce-stack-op ( literals node map -- )
-    #! If certain values passing through a stack op are being
-    #! killed, the stack op can be reduced, in extreme cases
-    #! to a no-op.
-    -rot [
-        [ node-consume-d get ] bind kill-mask swap assoc
-    ] keep
-    over [ [ node-op set ] extend , ] [ 2drop ] ifte ;
-
-\ over [ 2drop t ] "can-kill" set-word-prop
-\ over [
-    [
-        [[ [ f f ] over ]]
-        [[ [ f t ] dup  ]]
-    ] reduce-stack-op
-] "kill-node" set-word-prop
-
-\ pick [ 2drop t ] "can-kill" set-word-prop
-\ pick [
-    [
-        [[ [ f f f ] pick ]]
-        [[ [ f f t ] over ]]
-        [[ [ f t f ] over ]]
-        [[ [ f t t ] dup  ]]
-    ] reduce-stack-op
-] "kill-node" set-word-prop
-
-\ >r [ 2drop t ] "can-kill" set-word-prop
-\ >r [ kill-node ] "kill-node" set-word-prop
-\ r> [ 2drop t ] "can-kill" set-word-prop
-\ r> [ kill-node ] "kill-node" set-word-prop
+! : scan-literal ( node -- )
+!     #! If the node represents a literal push, add the literal to
+!     #! the list being constructed.
+!     "scan-literal" [ drop ] apply-dataflow ;
+! 
+! : (scan-literals) ( dataflow -- )
+!     [ scan-literal ] each ;
+! 
+! : scan-literals ( dataflow -- list )
+!     [ (scan-literals) ] make-list ;
+! 
+! : scan-branches ( branches -- )
+!     #! Collect all literals from all branches.
+!     [ node-param get ] bind [ [ scan-literal ] each ] each ;
+! 
+! : mentions-literal? ( literal list -- ? )
+!     #! Does the given list of result objects refer to this
+!     #! literal?
+!     [ value= ] some-with? ;
+! 
+! : consumes-literal? ( literal node -- ? )
+!     #! Does the dataflow node consume the literal?
+!     [
+!         dup node-consume-d get mentions-literal? swap
+!         dup node-consume-r get mentions-literal? nip or
+!     ] bind ;
+! 
+! : produces-literal? ( literal node -- ? )
+!     #! Does the dataflow node produce the literal?
+!     [
+!         dup node-produce-d get mentions-literal? swap
+!         dup node-produce-r get mentions-literal? nip or
+!     ] bind ;
+! 
+! : (can-kill?) ( literal node -- ? )
+!     #! Return false if the literal appears as input to this
+!     #! node, and this node is not a stack operation.
+!     2dup consumes-literal? >r produces-literal? r> or not ;
+! 
+! : can-kill? ( literal dataflow -- ? )
+!     #! Return false if the literal appears in any node in the
+!     #! list.
+!     [ dupd "can-kill" [ (can-kill?) ] apply-dataflow ] all? nip ;
+! 
+! : kill-set ( dataflow -- list )
+!     #! Push a list of literals that may be killed in the IR.
+!     dup scan-literals [ over can-kill? ] subset nip ;
+! 
+! SYMBOL: branch-returns
+! 
+! : 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
+!     ] [
+!         [ node-param get ] bind
+!         [
+!             dup [
+!                 peek [ node-consume-d get >vector ] bind
+!             ] map
+!             unify-stacks >list
+!             branch-returns set
+!             [ dupd can-kill? ] all? nip
+!         ] with-scope
+!     ] ifte ;
+! 
+! : kill-node ( literals node -- )
+!     swap [ over (can-kill?) ] all? [ , ] [ drop ] ifte ;
+! 
+! : (kill-nodes) ( literals dataflow -- )
+!     #! Append live nodes to currently constructing list.
+!     [ "kill-node" [ nip , ] apply-dataflow ] each-with ;
+! 
+! : kill-nodes ( literals dataflow -- dataflow )
+!     #! Remove literals and construct a list.
+!     [ (kill-nodes) ] make-list ;
+! 
+! : optimize ( dataflow -- dataflow )
+!     #! Remove redundant literals from the IR. The original IR
+!     #! is destructively modified.
+!     dup kill-set swap kill-nodes ;
+! 
+! : kill-branches ( literals node -- )
+!     [
+!         node-param [ [ dupd kill-nodes ] map nip ] change
+!     ] extend , ;
+! 
+! : kill-literal ( literals values -- values )
+!     [
+!         swap [ swap value= ] some-with? not
+!     ] subset-with ;
+! 
+! #push [
+!     [ node-produce-d get ] bind [ literal-value ] map %
+! ] "scan-literal" set-word-prop
+! 
+! #push [ 2drop t ] "can-kill" set-word-prop
+! 
+! #push [
+!     [ node-produce-d [ kill-literal ] change ] extend ,
+! ] "kill-node" set-word-prop
+! 
+! #drop [ 2drop t ] "can-kill" set-word-prop
+! 
+! #drop [
+!     [ node-consume-d [ kill-literal ] change ] extend ,
+! ] "kill-node" set-word-prop
+! 
+! #label [
+!     [ node-param get ] bind (scan-literals)
+! ] "scan-literal" set-word-prop
+! 
+! #label [
+!     [ node-param get ] bind can-kill?
+! ] "can-kill" set-word-prop
+! 
+! #call-label [
+!     [ node-param get ] bind =
+! ] "calls-label" set-word-prop
+! 
+! : calls-label? ( label list -- ? )
+!     [ "calls-label" [ 2drop f ] apply-dataflow ] some-with? ;
+! 
+! #label [
+!     [ node-param get ] bind calls-label?
+! ] "calls-label" set-word-prop
+! 
+! : branches-call-label? ( label list -- ? )
+!     [ calls-label? ] some-with? ;
+! 
+! \ ifte [
+!     [ node-param get ] bind branches-call-label?
+! ] "calls-label" set-word-prop
+! 
+! \ dispatch [
+!     [ node-param get ] bind branches-call-label?
+! ] "calls-label" set-word-prop
+! 
+! #label [ ( literals node -- )
+!     [ node-param [ kill-nodes ] change ] extend ,
+! ] "kill-node" set-word-prop
+! 
+! #values [
+!     dupd consumes-literal? [
+!         branch-returns get mentions-literal?
+!     ] [
+!         drop t
+!     ] ifte
+! ] "can-kill" set-word-prop
+! 
+! \ ifte [ scan-branches ] "scan-literal" set-word-prop
+! \ ifte [ can-kill-branches? ] "can-kill" set-word-prop
+! \ ifte [ kill-branches ] "kill-node" set-word-prop
+! 
+! \ dispatch [ scan-branches ] "scan-literal" set-word-prop
+! \ dispatch [ can-kill-branches? ] "can-kill" set-word-prop
+! \ dispatch [ kill-branches ] "kill-node" set-word-prop
+! 
+! ! Don't care about inputs to recursive combinator calls
+! #call-label [ 2drop t ] "can-kill" set-word-prop
+! 
+! \ drop [ 2drop t ] "can-kill" set-word-prop
+! \ drop [ kill-node ] "kill-node" set-word-prop
+! \ dup [ 2drop t ] "can-kill" set-word-prop
+! \ dup [ kill-node ] "kill-node" set-word-prop
+! \ swap [ 2drop t ] "can-kill" set-word-prop
+! \ swap [ kill-node ] "kill-node" set-word-prop
+! 
+! : kill-mask ( killing inputs -- mask )
+!     [ over [ over value= ] some? >boolean nip ] map nip ;
+! 
+! : reduce-stack-op ( literals node map -- )
+!     #! If certain values passing through a stack op are being
+!     #! killed, the stack op can be reduced, in extreme cases
+!     #! to a no-op.
+!     -rot [
+!         [ node-consume-d get ] bind kill-mask swap assoc
+!     ] keep
+!     over [ [ node-op set ] extend , ] [ 2drop ] ifte ;
+! 
+! \ over [ 2drop t ] "can-kill" set-word-prop
+! \ over [
+!     [
+!         [[ [ f f ] over ]]
+!         [[ [ f t ] dup  ]]
+!     ] reduce-stack-op
+! ] "kill-node" set-word-prop
+! 
+! \ pick [ 2drop t ] "can-kill" set-word-prop
+! \ pick [
+!     [
+!         [[ [ f f f ] pick ]]
+!         [[ [ f f t ] over ]]
+!         [[ [ f t f ] over ]]
+!         [[ [ f t t ] dup  ]]
+!     ] reduce-stack-op
+! ] "kill-node" set-word-prop
+! 
+! \ >r [ 2drop t ] "can-kill" set-word-prop
+! \ >r [ kill-node ] "kill-node" set-word-prop
+! \ r> [ 2drop t ] "can-kill" set-word-prop
+! \ r> [ kill-node ] "kill-node" set-word-prop
+
+: optimize ;
index 736e8d3167bbfec4eaf95a45fd8756ccc1b17479..737be2fdeee4e12e125ef0d504eb478f84926459 100644 (file)
@@ -73,6 +73,9 @@ sequences strings vectors words hashtables prettyprint ;
         terminate
     ] ifte* ;
 
+: unify-dataflow ( effects -- nodes )
+    [ [ dataflow-graph get ] bind ] map ;
+
 : deep-clone ( seq -- seq ) [ clone ] map ;
 
 : copy-inference ( -- )
@@ -81,7 +84,8 @@ sequences strings vectors words hashtables prettyprint ;
     meta-r [ deep-clone ] change
     meta-d [ deep-clone ] change
     d-in [ deep-clone ] change
-    dataflow-graph off ;
+    dataflow-graph off
+    current-node off ;
 
 : infer-branch ( value -- namespace )
     #! Return a namespace with inferencer variables:
@@ -92,7 +96,7 @@ sequences strings vectors words hashtables prettyprint ;
         dup value-recursion recursive-state set
         literal-value dup infer-quot
         active? [
-            #values values-node
+            #values node,
             handle-terminator
         ] [
             drop
@@ -110,23 +114,18 @@ sequences strings vectors words hashtables prettyprint ;
         ] each
     ] make-list ;
 
-: unify-dataflow ( input instruction effectlist -- )
-    [ [ get-dataflow ] bind ] map
-    swap dataflow, [ unit node-consume-d set ] bind ;
-
-: infer-branches ( input instruction branchlist -- )
+: infer-branches ( branches node -- )
     #! Recursive stack effect inference is done here. If one of
     #! the branches has an undecidable stack effect, we set the
     #! base case to this stack effect and try again.
-    (infer-branches) dup unify-effects unify-dataflow ;
-
-: infer-ifte ( true false -- )
-    #! If branch taken is computed, infer along both paths and
-    #! unify.
-    2list >r pop-d \ ifte r> infer-branches ;
+    [
+        >r (infer-branches) dup unify-effects unify-dataflow
+        r> set-node-children
+    ] keep node, ;
 
 \ ifte [
-    2 dataflow-drop, pop-d pop-d swap infer-ifte
+    2 #drop node, pop-d pop-d swap 2list
+    #ifte pop-d drop infer-branches
 ] "infer" set-word-prop
 
 : vtable>list ( rstate vtable -- list  )
@@ -134,9 +133,9 @@ sequences strings vectors words hashtables prettyprint ;
 
 USE: kernel-internals
 
-: infer-dispatch ( rstate vtable -- )
-    >r >r pop-d \ dispatch r> r> vtable>list infer-branches ;
-
-\ dispatch [ pop-literal infer-dispatch ] "infer" set-word-prop
+\ dispatch [
+    pop-literal vtable>list
+    #dispatch pop-d drop infer-branches
+] "infer" set-word-prop
 
 \ dispatch [ [ fixnum vector ] [ ] ] "infer-effect" set-word-prop
index c309d610ec6e885999bbc5244448a55a66a5c939..794ab8f2c9a5d32238d161f329d4a0dd1eda0b92 100644 (file)
@@ -1,87 +1,99 @@
 ! Copyright (C) 2004, 2005 Slava Pestov.
 ! See http://factor.sf.net/license.txt for BSD license.
 IN: inference
-USING: interpreter kernel lists namespaces sequences vectors
-words ;
+USING: generic interpreter kernel lists namespaces parser
+sequences vectors words ;
 
-! Recursive state. An alist, mapping words to labels.
-SYMBOL: recursive-state
+! 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 effect param in-d out-d in-r out-r
+       successor children ;
+
+: make-node ( effect param in-d out-d in-r out-r node -- node )
+    [ >r f <node> r> set-delegate ] keep ;
+
+: NODE:
+    #! Followed by a node name.
+    scan dup [ ] define-tuple
+    create-in [ make-node ] define-constructor ; parsing
+
+: empty-node f f f f f f f f f ;
+: param-node ( label) f swap f f f f f ;
+: in-d-node ( inputs) >r f f r> f f f f ;
+: out-d-node ( outputs) >r f f f r> f f f ;
+
+: d-tail ( n -- list ) meta-d get vector-tail* ;
+: r-tail ( n -- list ) meta-r get vector-tail* ;
+
+NODE: #label
+: #label ( label -- node ) param-node <#label> ;
+
+NODE: #call
+: #call ( word -- node ) param-node <#call> ;
+
+NODE: #call-label
+: #call-label ( label -- node ) param-node <#call> ;
+
+NODE: #push
+: #push ( outputs -- node ) d-tail out-d-node <#push> ;
+
+NODE: #drop
+: #drop ( inputs -- node ) d-tail in-d-node <#drop> ;
+
+NODE: #values
+: #values ( -- node ) meta-d get >list in-d-node <#values> ;
 
-! We build a dataflow graph for the compiler.
+NODE: #return
+: #return ( -- node ) meta-d get >list in-d-node <#return> ;
+
+NODE: #ifte
+: #ifte ( in -- node ) 1 d-tail in-d-node <#ifte> ;
+
+NODE: #dispatch
+: #dispatch ( in -- node ) 1 d-tail in-d-node <#dispatch> ;
+
+: 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
 
-! Label nodes have the node-label variable set.
-SYMBOL: #label
-
-SYMBOL: #call ( non-tail call )
-SYMBOL: #call-label
-SYMBOL: #push ( literal )
-SYMBOL: #drop
-
-! This is purely a marker for values we retain after a
-! conditional. It does not generate code, but merely alerts the
-! dataflow optimizer to the fact these values must be retained.
-SYMBOL: #values
-
-SYMBOL: #return
-
-SYMBOL: node-consume-d
-SYMBOL: node-produce-d
-SYMBOL: node-consume-r
-SYMBOL: node-produce-r
-SYMBOL: node-op
-SYMBOL: node-label
-
-! #push nodes have this field set to the value being pushed.
-! #call nodes have this as the word being called
-SYMBOL: node-param
-
-: <dataflow-node> ( param op -- node )
-    <namespace> [
-        node-op set
-        node-param set
-        [ ] node-consume-d set
-        [ ] node-produce-d set
-        [ ] node-consume-r set
-        [ ] node-produce-r set
-    ] extend ;
-
-: node-inputs ( d-count r-count -- )
-    #! Execute in the node's namespace.
-    meta-r get vector-tail* node-consume-r set
-    meta-d get vector-tail* node-consume-d set ;
-
-: dataflow-inputs ( in node -- )
-    [ length 0 node-inputs ] bind ;
-
-: node-outputs ( d-count r-count -- )
-    #! Execute in the node's namespace.
-    meta-r get vector-tail* node-produce-r set
-    meta-d get vector-tail* node-produce-d set ;
-
-: dataflow-outputs ( out node -- )
-    [ length 0 node-outputs ] bind ;
-
-: get-dataflow ( -- IR )
-    dataflow-graph get reverse ;
-
-: dataflow, ( param op -- node )
-    #! Add a node to the dataflow IR.
-    <dataflow-node> dup dataflow-graph [ cons ] change ;
-
-: dataflow-drop, ( n -- )
-    f #drop dataflow, [ 0 node-inputs ] bind ;
-
-: dataflow-push, ( n -- )
-    f #push dataflow, [ 0 node-outputs ] bind ;
-
-: apply-dataflow ( dataflow name default -- )
-    #! For the dataflow node, look up named word property,
-    #! if its not defined, apply default quotation to
-    #! ( node ) otherwise apply property quotation to
-    #! ( node ).
-    >r >r dup [ node-op get ] bind r> word-prop dup [
-        call r> drop
+: node, ( node -- )
+    dataflow-graph get [
+        dup current-node [ set-node-successor ] change
     ] [
-        drop r> call
+        ! first node
+        dup dataflow-graph set  current-node set
     ] ifte ;
+
+: nest-node ( -- dataflow current )
+    dataflow-graph get  dataflow-graph off
+    current-node get    current-node off ;
+
+: unnest-node ( new-node dataflow current -- new-node )
+    >r >r dataflow-graph get unit over set-node-children
+    r> dataflow-graph set
+    r> current-node set ;
+
+: with-nesting ( quot -- new-node | quot: -- new-node )
+    nest-node 2slip unnest-node ; inline
+
+: copy-effect ( from to -- )
+    over node-in-d over set-node-in-d
+    over node-in-r over set-node-in-r
+    over node-out-d over set-node-out-d
+    swap node-out-r swap set-node-out-r ;
+
+! Recursive state. An alist, mapping words to labels.
+SYMBOL: recursive-state
index 12032f9e9f163129d8c90ceb950560d79419b9cd..298c21b453de63ccd5f9e6e0defa5087f0fea65b 100644 (file)
@@ -18,7 +18,7 @@ SYMBOL: inferring-base-case
 SYMBOL: d-in
 
 : pop-literal ( -- rstate obj )
-    1 dataflow-drop, pop-d >literal< ;
+    1 #drop node, pop-d >literal< ;
 
 : (ensure-types) ( typelist n stack -- )
     pick [
@@ -48,6 +48,12 @@ SYMBOL: d-in
     meta-d [ append ] change
     d-in [ append ] change ;
 
+: hairy-node ( node effect quot -- )
+    over car ensure-d
+    -rot 2dup car length 0 rot node-inputs
+    2slip
+    cdr car length 0 rot node-outputs ; inline
+
 : (present-effect) ( vector -- list )
     >list [ value-class ] map ;
 
@@ -64,6 +70,7 @@ SYMBOL: d-in
     0 <vector> d-in set
     recursive-state set
     dataflow-graph off
+    current-node off
     inferring-base-case off ;
 
 GENERIC: apply-object
@@ -71,7 +78,7 @@ GENERIC: apply-object
 : apply-literal ( obj -- )
     #! Literals are annotated with the current recursive
     #! state.
-    recursive-state get <literal> push-d  1 dataflow-push, ;
+    recursive-state get <literal> push-d  1 #push node, ;
 
 M: object apply-object apply-literal ;
 
@@ -119,12 +126,6 @@ M: object apply-object apply-literal ;
         "Word leaves elements on return stack" inference-error
     ] unless ;
 
-: values-node ( op -- )
-    #! Add a #values or #return node to the graph.
-    f swap dataflow, [
-        meta-d get >list node-consume-d set
-    ] bind ;
-
 : with-infer ( quot -- )
     [
         f init-inference
@@ -133,10 +134,10 @@ M: object apply-object apply-literal ;
         check-return
     ] with-scope ;
 
-: infer ( quot -- [[ in out ]] )
+: infer ( quot -- effect )
     #! Stack effect of a quotation.
     [ infer-quot effect present-effect ] with-infer ;
 
 : dataflow ( quot -- dataflow )
     #! Data flow of a quotation.
-    [ infer-quot #return values-node get-dataflow ] with-infer ;
+    [ infer-quot #return node, dataflow-graph get ] with-infer ;
index 8ba729371064932b91f43034d9f11fcaaffec686..af49bed0449af0fd225be6e5dc526254c6d2c2d3 100644 (file)
@@ -6,7 +6,7 @@ sequences words ;
 
 : literal-inputs? ( in stack -- )
     tail-slice dup >list [ safe-literal? ] all? [
-        length dataflow-drop, t
+        length #drop node, t
     ] [
         drop f
     ] ifte ;
@@ -16,7 +16,7 @@ sequences words ;
 
 : literal-outputs ( out stack -- )
     tail-slice dup [ recursive-state get <literal> ] nmap
-    length dataflow-push, ;
+    length #push node, ;
 
 : partial-eval? ( word -- ? )
     "infer-effect" word-prop car length
index 6726b37bdbd919cf03c821c55d35e1eac6b378ff..5e57b565880185f6a0376b45c5394e9b0de29082 100644 (file)
@@ -4,24 +4,27 @@ IN: inference
 USING: interpreter kernel namespaces words ;
 
 \ >r [
-    f \ >r dataflow, [ 1 0 node-inputs ] extend
+    \ >r #call
+    1 0 pick node-inputs
     pop-d push-r
-    [ 0 1 node-outputs ] bind
+    0 1 pick node-outputs
+    node,
 ] "infer" set-word-prop
 
 \ r> [
-    f \ r> dataflow, [ 0 1 node-inputs ] extend
+    \ r> #call
+    0 1 pick node-inputs
     pop-r push-d
-    [ 1 0 node-outputs ] bind
+    1 0 pick node-outputs
+    node,
 ] "infer" set-word-prop
 
-: partial-eval ( word quot -- | quot: word -- )
-    >r f over dup "infer-effect" word-prop r> with-dataflow ;
-
 : infer-shuffle ( word -- )
-    [ host-word ] partial-eval ;
+    dup #call [
+        over "infer-effect" word-prop [ host-word ] hairy-node
+    ] keep node, ;
 
-\ drop [ 1 dataflow-drop, pop-d drop ] "infer" set-word-prop
+\ drop [ 1 #drop node, pop-d drop ] "infer" set-word-prop
 \ dup  [ \ dup  infer-shuffle ] "infer" set-word-prop
 \ swap [ \ swap infer-shuffle ] "infer" set-word-prop
 \ over [ \ over infer-shuffle ] "infer" set-word-prop
index 55b2dd5eedb3f284390883b6e333b826d9927273..2613fdf4dadb20129e02af3d04a1d0f5203a5032 100644 (file)
@@ -5,37 +5,24 @@ USING: errors generic interpreter kernel lists math
 math-internals namespaces sequences strings vectors words
 hashtables parser prettyprint ;
 
-: with-dataflow ( param op [[ in# out# ]] quot -- )
-    #! Take input parameters, execute quotation, take output
-    #! parameters, add node. The quotation is called with the
-    #! stack effect.
-    >r dup car ensure-d
-    >r dataflow, r> r> rot
-    [ pick car swap [ length 0 node-inputs ] bind ] keep
-    pick >r >r nip call r> r> cdr car swap
-    [ length 0 node-outputs ] bind ; inline
-
 : consume-d ( typelist -- )
     [ pop-d 2drop ] each ;
 
 : produce-d ( typelist -- )
     [ <computed> push-d ] each ;
 
-: (consume/produce) ( param op effect )
-    dup >r -rot r>
-    [ unswons consume-d car produce-d ] with-dataflow ;
-
-: consume/produce ( word [ in-types out-types ] -- )
+: consume/produce ( word effect -- )
     #! Add a node to the dataflow graph that consumes and
     #! produces a number of values.
-    over "intrinsic" word-prop [
-        f -rot
-    ] [
-        #call swap
-    ] ifte (consume/produce) ;
+    swap #call [
+        over [
+            2unlist swap consume-d produce-d
+        ] hairy-node
+    ] keep node, ;
 
 : no-effect ( word -- )
-    "Unknown stack effect: " swap word-name cat2 inference-error ;
+    "Unknown stack effect: " swap word-name append
+    inference-error ;
 
 : inhibit-parital ( -- )
     meta-d get [ f swap set-value-safe? ] each ;
@@ -43,31 +30,16 @@ hashtables parser prettyprint ;
 : recursive? ( word -- ? )
     f swap dup word-def [ = or ] tree-each-with ;
 
-: (with-block) ( [[ label quot ]] quot -- node )
-    #! Call a quotation in a new namespace, and transfer
-    #! inference state from the outer scope.
-    swap car >r [
-        dataflow-graph off
-        call
-        d-in get meta-d get meta-r get get-dataflow
-    ] with-scope
-    r> swap #label dataflow, [ node-label set ] extend >r
-    meta-r set meta-d set d-in set r> ;
-
-: with-block ( word [[ label quot ]] quot -- node )
+: with-block ( word [[ label quot ]] quot -- block-node )
     #! Execute a quotation with the word on the stack, and add
-    #! its dataflow contribution to a new block node in the IR.
-    over [
-        >r
-        dupd cons
-        recursive-state [ cons ] change
-        r> call
-    ] (with-block) ;
-
-: inline-block ( word -- effect node )
+    #! its dataflow contribution to a new #label node in the IR.
+    >r 2dup cons recursive-state [ cons ] change r>
+    [ swap car #label slip ] with-nesting
+    recursive-state [ cdr ] change ; inline
+
+: inline-block ( word -- node-block )
     gensym over word-def cons [
-        inhibit-parital
-        word-def infer-quot effect
+        inhibit-parital  word-def infer-quot
     ] with-block ;
 
 : inline-compound ( word -- )
@@ -75,7 +47,7 @@ hashtables parser prettyprint ;
     #! inferencer instance. If the word in question is recursive
     #! we infer its stack effect inside a new block.
     dup recursive? [
-        inline-block 2drop
+        inline-block node,
     ] [
         word-def infer-quot
     ] ifte ;
@@ -86,7 +58,7 @@ hashtables parser prettyprint ;
     [
         [
             recursive-state get init-inference
-            dup dup inline-block drop present-effect
+            dup dup inline-block drop effect present-effect
             [ "infer-effect" set-word-prop ] keep
         ] with-scope consume/produce
     ] [
@@ -153,16 +125,16 @@ M: compound apply-word ( word -- )
 
 : base-case ( word [ label quot ] -- )
     [
-        car over inline-block [
-            drop
-            [ #call-label ] [ #call ] ?ifte
-            node-op set
-            node-param set
-        ] bind
+        >r [ inline-block ] keep r> car [
+            #call-label
+        ] [
+            #call
+        ] ?ifte [ copy-effect ] keep node,
     ] with-recursion ;
 
 : no-base-case ( word -- )
-    word-name " does not have a base case." cat2 inference-error ;
+    word-name " does not have a base case." append
+    inference-error ;
 
 : recursive-word ( word [ label quot ] -- )
     #! Handle a recursive call, by either applying a previously
index 96796b1421aa898c5fa7eee787203cd6e8b87e15..61523e4e62d19b43123c8a8afba0a6a116103cdc 100644 (file)
@@ -70,3 +70,5 @@ TUPLE: circle radius ;
 M: circle area circle-radius sq pi * ;
 
 [ 200 ] [ << rect f 0 0 10 20 >> area ] unit-test
+
+[ ] [ "IN: temporary  SYMBOL: #x  TUPLE: #x ;" eval ] unit-test