diff --git a/basis/compiler/cfg/alias-analysis/alias-analysis.factor b/basis/compiler/cfg/alias-analysis/alias-analysis.factor index 78e271c1f6..f6834c131d 100644 --- a/basis/compiler/cfg/alias-analysis/alias-analysis.factor +++ b/basis/compiler/cfg/alias-analysis/alias-analysis.factor @@ -3,7 +3,7 @@ USING: kernel math namespaces assocs hashtables sequences arrays accessors vectors combinators sets classes compiler.cfg compiler.cfg.registers compiler.cfg.instructions -compiler.cfg.copy-prop compiler.cfg.rpo compiler.cfg.def-use ; +compiler.cfg.copy-prop compiler.cfg.rpo compiler.cfg.liveness ; IN: compiler.cfg.alias-analysis ! We try to eliminate redundant slot operations using some simple heuristics. @@ -196,9 +196,6 @@ M: ##set-slot insn-object obj>> resolve ; M: ##set-slot-imm insn-object obj>> resolve ; M: ##alien-global insn-object drop \ ##alien-global ; -: inputs ( insns -- seq ) - [ [ ##phi? not ] filter gen-set ] [ kill-set ] bi assoc-diff keys ; - : init-alias-analysis ( insns -- insns' ) H{ } clone histories set H{ } clone vregs>acs set @@ -210,7 +207,7 @@ M: ##alien-global insn-object drop \ ##alien-global ; 0 ac-counter set next-ac heap-ac set - dup inputs [ set-heap-ac ] each ; + dup local-live-in [ set-heap-ac ] each ; GENERIC: analyze-aliases* ( insn -- insn' ) diff --git a/basis/compiler/cfg/dominance/dominance-tests.factor b/basis/compiler/cfg/dominance/dominance-tests.factor index 210d5614c2..e884e32d78 100644 --- a/basis/compiler/cfg/dominance/dominance-tests.factor +++ b/basis/compiler/cfg/dominance/dominance-tests.factor @@ -6,8 +6,7 @@ compiler.cfg.predecessors ; : test-dominance ( -- ) cfg new 0 get >>entry compute-predecessors - compute-dominance - drop ; + compute-dominance ; ! Example with no back edges V{ } 0 test-bb @@ -74,3 +73,25 @@ V{ } 5 test-bb [ ] [ test-dominance ] unit-test [ t ] [ 0 5 [a,b] [ get dom-parent 0 get eq? ] all? ] unit-test + +V{ } 0 test-bb +V{ } 1 test-bb +V{ } 2 test-bb +V{ } 3 test-bb +V{ } 4 test-bb +V{ } 5 test-bb +V{ } 6 test-bb + +0 get 1 get 5 get V{ } 2sequence >>successors drop +1 get 2 get 3 get V{ } 2sequence >>successors drop +2 get 4 get 1vector >>successors drop +3 get 4 get 1vector >>successors drop +4 get 6 get 1vector >>successors drop +5 get 6 get 1vector >>successors drop + +[ ] [ test-dominance ] unit-test + +[ t ] [ + 2 get 3 get 2array iterated-dom-frontier + 4 get 6 get 2array set= +] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/dominance/dominance.factor b/basis/compiler/cfg/dominance/dominance.factor index 9c8fc79619..73d9f58eec 100644 --- a/basis/compiler/cfg/dominance/dominance.factor +++ b/basis/compiler/cfg/dominance/dominance.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs combinators sets math fry kernel math.order -namespaces sequences sorting compiler.cfg.rpo ; +dlists deques namespaces sequences sorting compiler.cfg.rpo ; IN: compiler.cfg.dominance ! Reference: @@ -85,8 +85,31 @@ PRIVATE> PRIVATE> -: compute-dominance ( cfg -- cfg' ) +: compute-dominance ( cfg -- ) [ compute-dom-parents compute-dom-children ] [ compute-dom-frontiers ] - [ ] - tri ; + bi ; + + + +: iterated-dom-frontier ( bbs -- bbs' ) + [ + work-list set + H{ } clone visited set + [ add-to-work-list ] each + work-list get [ iterated-dom-frontier-step ] slurp-deque + visited get keys + ] with-scope ; \ No newline at end of file diff --git a/basis/compiler/cfg/linear-scan/assignment/assignment.factor b/basis/compiler/cfg/linear-scan/assignment/assignment.factor index 952feb5919..8e21e7e3fb 100644 --- a/basis/compiler/cfg/linear-scan/assignment/assignment.factor +++ b/basis/compiler/cfg/linear-scan/assignment/assignment.factor @@ -6,13 +6,13 @@ cpu.architecture compiler.cfg compiler.cfg.rpo compiler.cfg.def-use +compiler.cfg.liveness compiler.cfg.registers compiler.cfg.instructions compiler.cfg.linear-scan.mapping compiler.cfg.linear-scan.allocation compiler.cfg.linear-scan.allocation.state -compiler.cfg.linear-scan.live-intervals -compiler.cfg.linear-scan.liveness ; +compiler.cfg.linear-scan.live-intervals ; IN: compiler.cfg.linear-scan.assignment ! This contains both active and inactive intervals; any interval diff --git a/basis/compiler/cfg/linear-scan/linear-scan.factor b/basis/compiler/cfg/linear-scan/linear-scan.factor index 186a773355..b081f2ca6e 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan.factor @@ -4,9 +4,9 @@ USING: kernel accessors namespaces make locals cpu.architecture compiler.cfg compiler.cfg.rpo +compiler.cfg.liveness compiler.cfg.instructions compiler.cfg.linear-scan.numbering -compiler.cfg.linear-scan.liveness compiler.cfg.linear-scan.live-intervals compiler.cfg.linear-scan.allocation compiler.cfg.linear-scan.allocation.state diff --git a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor index 244f2bc069..8813a4e94e 100644 --- a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor +++ b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: namespaces kernel assocs accessors sequences math math.order fry combinators binary-search compiler.cfg.instructions compiler.cfg.registers -compiler.cfg.def-use compiler.cfg.linear-scan.liveness compiler.cfg.rpo +compiler.cfg.def-use compiler.cfg.liveness compiler.cfg.rpo compiler.cfg ; IN: compiler.cfg.linear-scan.live-intervals diff --git a/basis/compiler/cfg/linear-scan/liveness/liveness.factor b/basis/compiler/cfg/linear-scan/liveness/liveness.factor deleted file mode 100644 index ac36fca9c7..0000000000 --- a/basis/compiler/cfg/linear-scan/liveness/liveness.factor +++ /dev/null @@ -1,17 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: kernel accessors assocs compiler.cfg.def-use -compiler.cfg.dataflow-analysis ; -IN: compiler.cfg.linear-scan.liveness - -! See http://en.wikipedia.org/wiki/Liveness_analysis - -BACKWARD-ANALYSIS: live - -M: live-analysis transfer-set - drop instructions>> - [ gen-set assoc-union ] keep - kill-set assoc-diff ; - -M: live-analysis join-sets - drop assoc-combine ; \ No newline at end of file diff --git a/basis/compiler/cfg/linear-scan/resolve/resolve.factor b/basis/compiler/cfg/linear-scan/resolve/resolve.factor index 5bab261ea8..56beaa5379 100644 --- a/basis/compiler/cfg/linear-scan/resolve/resolve.factor +++ b/basis/compiler/cfg/linear-scan/resolve/resolve.factor @@ -4,11 +4,11 @@ USING: accessors arrays assocs combinators combinators.short-circuit fry kernel locals make math sequences compiler.cfg.rpo +compiler.cfg.liveness compiler.cfg.utilities compiler.cfg.instructions compiler.cfg.linear-scan.assignment -compiler.cfg.linear-scan.mapping -compiler.cfg.linear-scan.liveness ; +compiler.cfg.linear-scan.mapping ; IN: compiler.cfg.linear-scan.resolve : add-mapping ( from to reg-class -- ) diff --git a/basis/compiler/cfg/liveness/liveness-tests.factor b/basis/compiler/cfg/liveness/liveness-tests.factor new file mode 100644 index 0000000000..697a1f8a7b --- /dev/null +++ b/basis/compiler/cfg/liveness/liveness-tests.factor @@ -0,0 +1,38 @@ +USING: compiler.cfg.liveness compiler.cfg.debugger +compiler.cfg.instructions compiler.cfg.predecessors +compiler.cfg.registers compiler.cfg cpu.architecture +accessors namespaces sequences kernel tools.test ; +IN: compiler.cfg.liveness.tests + +! Sanity check... + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 1 D 1 } + T{ ##peek f V int-regs 1 D 1 } +} 1 test-bb + +V{ + T{ ##replace f V int-regs 2 D 0 } +} 2 test-bb + +V{ + T{ ##replace f V int-regs 3 D 0 } +} 3 test-bb + +1 get 2 get 3 get V{ } 2sequence >>successors drop + +cfg new 1 get >>entry +compute-predecessors +compute-live-sets + +[ + H{ + { V int-regs 1 V int-regs 1 } + { V int-regs 2 V int-regs 2 } + { V int-regs 3 V int-regs 3 } + } +] +[ 1 get live-in ] +unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/liveness/liveness.factor b/basis/compiler/cfg/liveness/liveness.factor new file mode 100644 index 0000000000..c1793842a2 --- /dev/null +++ b/basis/compiler/cfg/liveness/liveness.factor @@ -0,0 +1,26 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: kernel accessors assocs sequences sets +compiler.cfg.def-use compiler.cfg.dataflow-analysis +compiler.cfg.instructions ; +IN: compiler.cfg.liveness + +! See http://en.wikipedia.org/wiki/Liveness_analysis +! Do not run after SSA construction + +BACKWARD-ANALYSIS: live + +: transfer-liveness ( live-set instructions -- live-set' ) + [ clone ] [ ] bi* [ + [ uses-vregs [ over conjoin ] each ] + [ defs-vregs [ over delete-at ] each ] bi + ] each ; + +: local-live-in ( instructions -- live-set ) + [ ##phi? not ] filter [ H{ } ] dip transfer-liveness keys ; + +M: live-analysis transfer-set + drop instructions>> transfer-liveness ; + +M: live-analysis join-sets + drop assoc-combine ; \ No newline at end of file diff --git a/basis/compiler/cfg/ssa/ssa-tests.factor b/basis/compiler/cfg/ssa/ssa-tests.factor index c53d30af5d..6a3a014f78 100644 --- a/basis/compiler/cfg/ssa/ssa-tests.factor +++ b/basis/compiler/cfg/ssa/ssa-tests.factor @@ -5,9 +5,12 @@ compiler.cfg.registers cpu.architecture kernel namespaces sequences tools.test vectors ; IN: compiler.cfg.ssa.tests -! Reset counters so that results are deterministic w.r.t. hash order -0 vreg-counter set-global -0 basic-block set-global +: reset-counters ( -- ) + ! Reset counters so that results are deterministic w.r.t. hash order + 0 vreg-counter set-global + 0 basic-block set-global ; + +reset-counters V{ T{ ##load-immediate f V int-regs 1 100 } @@ -38,7 +41,6 @@ V{ : test-ssa ( -- ) cfg new 0 get >>entry compute-predecessors - compute-dominance construct-ssa drop ; @@ -67,6 +69,9 @@ V{ } ] [ 2 get instructions>> ] unit-test +: clean-up-phis ( insns -- insns' ) + [ dup ##phi? [ [ [ [ number>> ] dip ] assoc-map ] change-inputs ] when ] map ; + [ V{ T{ ##phi f V int-regs 6 H{ { 1 V int-regs 4 } { 2 V int-regs 5 } } } @@ -75,5 +80,34 @@ V{ } ] [ 3 get instructions>> - [ dup ##phi? [ [ [ [ number>> ] dip ] assoc-map ] change-inputs ] when ] map + clean-up-phis +] unit-test + +reset-counters + +V{ } 0 test-bb +V{ } 1 test-bb +V{ T{ ##peek f V int-regs 0 D 0 } } 2 test-bb +V{ T{ ##peek f V int-regs 0 D 0 } } 3 test-bb +V{ T{ ##replace f V int-regs 0 D 0 } } 4 test-bb +V{ } 5 test-bb +V{ } 6 test-bb + +0 get 1 get 5 get V{ } 2sequence >>successors drop +1 get 2 get 3 get V{ } 2sequence >>successors drop +2 get 4 get 1vector >>successors drop +3 get 4 get 1vector >>successors drop +4 get 6 get 1vector >>successors drop +5 get 6 get 1vector >>successors drop + +[ ] [ test-ssa ] unit-test + +[ + V{ + T{ ##phi f V int-regs 3 H{ { 2 V int-regs 1 } { 3 V int-regs 2 } } } + T{ ##replace f V int-regs 3 D 0 } + } +] [ + 4 get instructions>> + clean-up-phis ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/ssa/ssa.factor b/basis/compiler/cfg/ssa/ssa.factor index e11701965b..2e76ba35a1 100644 --- a/basis/compiler/cfg/ssa/ssa.factor +++ b/basis/compiler/cfg/ssa/ssa.factor @@ -1,19 +1,21 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: namespaces kernel accessors sequences fry dlists -deques assocs sets math combinators sorting +USING: namespaces kernel accessors sequences fry assocs +sets math combinators compiler.cfg compiler.cfg.rpo compiler.cfg.def-use compiler.cfg.renaming +compiler.cfg.liveness compiler.cfg.registers compiler.cfg.dominance compiler.cfg.instructions ; IN: compiler.cfg.ssa -! SSA construction. Predecessors and dominance must be computed first. +! SSA construction. Predecessors must be computed first. -! This is the classical algorithm based on dominance frontiers: +! This is the classical algorithm based on dominance frontiers, except +! we consult liveness information to build pruned SSA: ! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.8240 ! Eventually might be worth trying something fancier: @@ -32,45 +34,22 @@ SYMBOL: inserting-phi-nodes '[ dup instructions>> [ defs-vregs [ - _ push-at + _ conjoin-at ] with each ] with each ] each-basic-block ; -SYMBOLS: has-already ever-on-work-list work-list ; - -: init-insert-phi-nodes ( bbs -- ) - H{ } clone has-already set - [ unique ever-on-work-list set ] - [ [ push-all-front ] keep work-list set ] bi ; - -: add-to-work-list ( bb -- ) - dup ever-on-work-list get key? [ drop ] [ - [ ever-on-work-list get conjoin ] - [ work-list get push-front ] - bi - ] if ; - : insert-phi-node-later ( vreg bb -- ) - [ predecessors>> over '[ _ ] H{ } map>assoc \ ##phi new-insn ] keep - inserting-phi-nodes get push-at ; - -: compute-phi-node-in ( vreg bb -- ) - dup has-already get key? [ 2drop ] [ - [ insert-phi-node-later ] - [ has-already get conjoin ] - [ add-to-work-list ] - tri - ] if ; + 2dup live-in key? [ + [ predecessors>> over '[ _ ] H{ } map>assoc \ ##phi new-insn ] keep + inserting-phi-nodes get push-at + ] [ 2drop ] if ; : compute-phi-nodes-for ( vreg bbs -- ) - dup length 2 >= [ - init-insert-phi-nodes - work-list get [ - dom-frontier [ - compute-phi-node-in - ] with each - ] with slurp-deque + keys dup length 2 >= [ + iterated-dom-frontier [ + insert-phi-node-later + ] with each ] [ 2drop ] if ; : compute-phi-nodes ( -- ) @@ -143,4 +122,10 @@ M: ##phi rename-insn PRIVATE> : construct-ssa ( cfg -- cfg' ) - dup [ compute-defs compute-phi-nodes insert-phi-nodes ] [ rename ] bi ; \ No newline at end of file + { + [ ] + [ compute-live-sets ] + [ compute-dominance ] + [ compute-defs compute-phi-nodes insert-phi-nodes ] + [ rename ] + } cleave ; \ No newline at end of file