diff --git a/basis/compiler/cfg/optimizer/optimizer.factor b/basis/compiler/cfg/optimizer/optimizer.factor index faaaccff61..ac6dcbc503 100644 --- a/basis/compiler/cfg/optimizer/optimizer.factor +++ b/basis/compiler/cfg/optimizer/optimizer.factor @@ -4,7 +4,6 @@ USING: kernel sequences accessors combinators namespaces compiler.cfg.tco compiler.cfg.predecessors compiler.cfg.useless-conditionals -compiler.cfg.stack-analysis compiler.cfg.dcn compiler.cfg.dominance compiler.cfg.ssa @@ -27,24 +26,19 @@ SYMBOL: check-optimizer? dup check-cfg ] when ; -SYMBOL: new-optimizer? - : optimize-cfg ( cfg -- cfg' ) ! Note that compute-predecessors has to be called several times. ! The passes that need this document it. [ optimize-tail-calls - new-optimizer? get [ delete-useless-conditionals ] unless + delete-useless-conditionals compute-predecessors - new-optimizer? get [ split-branches ] unless - new-optimizer? get [ - deconcatenatize - compute-dominance - construct-ssa - ] when + split-branches join-blocks compute-predecessors - new-optimizer? get [ stack-analysis ] unless + deconcatenatize + compute-dominance + construct-ssa compute-liveness alias-analysis value-numbering diff --git a/basis/compiler/cfg/stack-analysis/authors.txt b/basis/compiler/cfg/stack-analysis/authors.txt deleted file mode 100644 index d4f5d6b3ae..0000000000 --- a/basis/compiler/cfg/stack-analysis/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Slava Pestov \ No newline at end of file diff --git a/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor b/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor deleted file mode 100644 index 5883777861..0000000000 --- a/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor +++ /dev/null @@ -1,104 +0,0 @@ -IN: compiler.cfg.stack-analysis.merge.tests -USING: compiler.cfg.stack-analysis.merge tools.test arrays accessors - compiler.cfg.instructions compiler.cfg.stack-analysis.state -compiler.cfg.utilities compiler.cfg compiler.cfg.registers -compiler.cfg.debugger cpu.architecture make assocs namespaces -sequences kernel classes ; - -[ - { D 0 } - { V int-regs 0 V int-regs 1 } -] [ - - - V{ T{ ##branch } } >>instructions dup 1 set - V{ T{ ##branch } } >>instructions dup 2 set 2array - - H{ { D 0 V int-regs 0 } } >>locs>vregs - H{ { D 0 V int-regs 1 } } >>locs>vregs 2array - - H{ } clone added-instructions set - V{ } clone added-phis set - merge-locs locs>vregs>> keys added-phis get values first -] unit-test - -[ - { D 0 } - ##peek -] [ - - - V{ T{ ##branch } } >>instructions dup 1 set - V{ T{ ##branch } } >>instructions dup 2 set 2array - - - H{ { D 0 V int-regs 1 } } >>locs>vregs 2array - - H{ } clone added-instructions set - V{ } clone added-phis set - [ merge-locs locs>vregs>> keys ] { } make drop - 1 get added-instructions get at first class -] unit-test - -[ - 0 ##inc-d -] [ - - - V{ T{ ##branch } } >>instructions dup 1 set - V{ T{ ##branch } } >>instructions dup 2 set 2array - - H{ } clone added-instructions set - V{ } clone added-phis set - - -1 >>ds-height - 2array - - [ merge-ds-heights ds-height>> ] { } make drop - 1 get added-instructions get at first class -] unit-test - -[ - 0 - { D 0 } - { 1 1 } -] [ - - - V{ T{ ##branch } } >>instructions - V{ T{ ##branch } } >>instructions 2array - - H{ } clone added-instructions set - V{ } clone added-phis set - - [ - -1 >>ds-height H{ { D 1 V int-regs 0 } } >>locs>vregs - H{ { D 0 V int-regs 1 } } >>locs>vregs 2array - - [ merge-locs [ ds-height>> ] [ locs>vregs>> keys ] bi ] { } make drop - ] keep - [ instructions>> length ] map -] unit-test - -[ - -1 - { D -1 } - { 1 1 } -] [ - - - V{ T{ ##branch } } >>instructions - V{ T{ ##branch } } >>instructions 2array - - H{ } clone added-instructions set - V{ } clone added-phis set - - [ - -1 >>ds-height H{ { D -1 V int-regs 0 } } >>locs>vregs - -1 >>ds-height H{ { D -1 V int-regs 1 } } >>locs>vregs 2array - - [ [ merge-ds-heights ] [ merge-locs ] 2bi ] { } make drop - [ ds-height>> ] [ locs>vregs>> keys ] bi - ] keep - [ instructions>> length ] map -] unit-test diff --git a/basis/compiler/cfg/stack-analysis/merge/merge.factor b/basis/compiler/cfg/stack-analysis/merge/merge.factor deleted file mode 100644 index a53fd7494e..0000000000 --- a/basis/compiler/cfg/stack-analysis/merge/merge.factor +++ /dev/null @@ -1,117 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: kernel assocs sequences accessors fry combinators grouping sets -arrays vectors locals namespaces make compiler.cfg compiler.cfg.hats -compiler.cfg.instructions compiler.cfg.stack-analysis.state -compiler.cfg.registers compiler.cfg.utilities cpu.architecture ; -IN: compiler.cfg.stack-analysis.merge - -: initial-state ( bb states -- state ) 2drop ; - -: single-predecessor ( bb states -- state ) nip first clone ; - -: save-ds-height ( n -- ) - dup 0 = [ drop ] [ ##inc-d ] if ; - -: merge-ds-heights ( state predecessors states -- state ) - [ ds-height>> ] map dup all-equal? - [ nip first >>ds-height ] - [ [ '[ _ save-ds-height ] add-instructions ] 2each ] if ; - -: save-rs-height ( n -- ) - dup 0 = [ drop ] [ ##inc-r ] if ; - -: merge-rs-heights ( state predecessors states -- state ) - [ rs-height>> ] map dup all-equal? - [ nip first >>rs-height ] - [ [ '[ _ save-rs-height ] add-instructions ] 2each ] if ; - -: assoc-map-keys ( assoc quot -- assoc' ) - '[ _ dip ] assoc-map ; inline - -: translate-locs ( assoc state -- assoc' ) - '[ _ translate-loc ] assoc-map-keys ; - -: untranslate-locs ( assoc state -- assoc' ) - '[ _ untranslate-loc ] assoc-map-keys ; - -: collect-locs ( loc-maps states -- assoc ) - ! assoc maps locs to sequences - [ untranslate-locs ] 2map - [ [ keys ] map concat prune ] keep - '[ dup _ [ at ] with map ] H{ } map>assoc ; - -: insert-peek ( predecessor loc state -- vreg ) - '[ _ _ translate-loc ^^peek ] add-instructions ; - -SYMBOL: added-phis - -: add-phi-later ( inputs -- vreg ) - [ int-regs next-vreg dup ] dip 2array added-phis get push ; - -: merge-loc ( predecessors vregs loc state -- vreg ) - ! Insert a ##phi in the current block where the input - ! is the vreg storing loc from each predecessor block - '[ [ ] [ _ _ insert-peek ] ?if ] 2map - dup all-equal? [ first ] [ add-phi-later ] if ; - -:: merge-locs ( state predecessors states -- state ) - states [ locs>vregs>> ] map states collect-locs - [| key value | - key - predecessors value key state merge-loc - ] assoc-map - state translate-locs - state (>>locs>vregs) - state ; - -: merge-actual-loc ( vregs -- vreg/f ) - dup all-equal? [ first ] [ drop f ] if ; - -:: merge-actual-locs ( state states -- state ) - states [ actual-locs>vregs>> ] map states collect-locs - [ merge-actual-loc ] assoc-map [ nip ] assoc-filter - state translate-locs - state (>>actual-locs>vregs) - state ; - -: merge-changed-locs ( state states -- state ) - [ [ changed-locs>> ] keep untranslate-locs ] map assoc-combine - over translate-locs - >>changed-locs ; - -:: insert-phis ( bb -- ) - bb predecessors>> :> predecessors - [ - added-phis get [| dst inputs | - dst predecessors inputs zip ##phi - ] assoc-each - ] V{ } make bb instructions>> over push-all - bb (>>instructions) ; - -:: multiple-predecessors ( bb states -- state ) - states [ not ] any? [ - - bb add-to-work-list - ] [ - [ - H{ } clone added-instructions set - V{ } clone added-phis set - bb predecessors>> :> predecessors - state new - predecessors states merge-ds-heights - predecessors states merge-rs-heights - predecessors states merge-locs - states merge-actual-locs - states merge-changed-locs - bb insert-basic-blocks - bb insert-phis - ] with-scope - ] if ; - -: merge-states ( bb states -- state ) - dup length { - { 0 [ initial-state ] } - { 1 [ single-predecessor ] } - [ drop multiple-predecessors ] - } case ; diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor b/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor deleted file mode 100644 index 9fbf7acf78..0000000000 --- a/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor +++ /dev/null @@ -1,204 +0,0 @@ -USING: prettyprint compiler.cfg.debugger compiler.cfg.linearization -compiler.cfg.predecessors compiler.cfg.stack-analysis -compiler.cfg.instructions sequences kernel tools.test accessors -sequences.private alien math combinators.private compiler.cfg -compiler.cfg.checker compiler.cfg.rpo -compiler.cfg.dce compiler.cfg.registers -sets namespaces arrays cpu.architecture ; -IN: compiler.cfg.stack-analysis.tests - -! Fundamental invariant: a basic block should not load or store a value more than once -: test-stack-analysis ( quot -- cfg ) - dup cfg? [ test-cfg first ] unless - compute-predecessors - stack-analysis - dup check-cfg ; - -: linearize ( cfg -- mr ) - flatten-cfg instructions>> ; - -[ ] [ [ ] test-stack-analysis drop ] unit-test - -! Only peek once -[ 1 ] [ [ dup drop dup ] test-stack-analysis linearize [ ##peek? ] count ] unit-test - -! Redundant replace is redundant -[ f ] [ [ dup drop ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test -[ f ] [ [ swap swap ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test - -! Replace required here -[ t ] [ [ dup ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test -[ t ] [ [ [ drop 1 ] when ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test - -! Only one replace, at the end -[ 1 ] [ [ [ 1 ] [ 2 ] if ] test-stack-analysis linearize [ ##replace? ] count ] unit-test - -! Do we support the full language? -[ ] [ [ { [ ] [ ] } dispatch ] test-stack-analysis drop ] unit-test -[ ] [ [ { [ ] [ ] } dispatch dup ] test-stack-analysis drop ] unit-test -[ ] [ - [ "int" { "int" "int" } "cdecl" [ + ] alien-callback ] - test-cfg second test-stack-analysis drop -] unit-test - -! Test loops -[ ] [ [ [ t ] loop ] test-stack-analysis drop ] unit-test -[ ] [ [ [ dup ] loop ] test-stack-analysis drop ] unit-test - -! Make sure that peeks are inserted in the right place -[ ] [ [ [ drop 1 ] when ] test-stack-analysis drop ] unit-test - -! This should be a total no-op -[ f ] [ [ [ ] dip ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test - -! Don't insert inc-d/inc-r; that's wrong! -[ 1 ] [ [ dup ] test-stack-analysis linearize [ ##inc-d? ] count ] unit-test - -! Bug in height tracking -[ ] [ [ dup [ ] [ reverse ] if ] test-stack-analysis drop ] unit-test -[ ] [ [ dup [ ] [ dup reverse drop ] if ] test-stack-analysis drop ] unit-test -[ ] [ [ [ drop dup 4.0 > ] find-last-integer ] test-stack-analysis drop ] unit-test - -! Bugs with code that throws -[ ] [ [ [ "Oops" throw ] unless ] test-stack-analysis drop ] unit-test -[ ] [ [ [ ] (( -- * )) call-effect-unsafe ] test-stack-analysis drop ] unit-test -[ ] [ [ dup [ "Oops" throw ] when dup ] test-stack-analysis drop ] unit-test -[ ] [ [ B{ 1 2 3 4 } over [ "Oops" throw ] when swap ] test-stack-analysis drop ] unit-test - -! Make sure the replace stores a value with the right height -[ ] [ - [ [ . ] [ 2drop 1 ] if ] test-stack-analysis eliminate-dead-code linearize - [ ##replace? ] filter [ length 1 assert= ] [ first loc>> D 0 assert= ] bi -] unit-test - -! translate-loc was the wrong way round -[ ] [ - [ 1 2 rot ] test-stack-analysis eliminate-dead-code linearize - [ [ ##load-immediate? ] count 2 assert= ] - [ [ ##peek? ] count 1 assert= ] - [ [ ##replace? ] count 3 assert= ] - tri -] unit-test - -[ ] [ - [ 1 2 ? ] test-stack-analysis eliminate-dead-code linearize - [ [ ##load-immediate? ] count 2 assert= ] - [ [ ##peek? ] count 1 assert= ] - [ [ ##replace? ] count 1 assert= ] - tri -] unit-test - -! Sync before a back-edge, not after -! ##peeks should be inserted before a ##loop-entry -! Don't optimize out the constants -[ t ] [ - [ 1000 [ ] times ] test-stack-analysis eliminate-dead-code linearize - [ ##load-immediate? ] any? -] unit-test - -! Correct height tracking -[ t ] [ - [ pick [ ] [ drop ] if swap ] test-stack-analysis eliminate-dead-code - reverse-post-order 4 swap nth - instructions>> [ ##peek? ] filter first2 [ loc>> ] [ loc>> ] bi* - 2array { D 1 D 0 } set= -] unit-test - -[ D 1 ] [ - V{ T{ ##branch } } 0 test-bb - - V{ T{ ##peek f V int-regs 0 D 2 } T{ ##branch } } 1 test-bb - - V{ - T{ ##peek f V int-regs 1 D 2 } - T{ ##inc-d f -1 } - T{ ##branch } - } 2 test-bb - - V{ T{ ##call f \ + -1 } T{ ##branch } } 3 test-bb - - V{ T{ ##return } } 4 test-bb - - test-diamond - - cfg new 0 get >>entry - compute-predecessors - stack-analysis - drop - - 3 get successors>> first instructions>> first loc>> -] unit-test - -! Do inserted ##peeks reference the correct stack location if -! an ##inc-d/r was also inserted? -[ D 0 ] [ - V{ T{ ##branch } } 0 test-bb - - V{ T{ ##branch } } 1 test-bb - - V{ - T{ ##peek f V int-regs 1 D 0 } - T{ ##branch } - } 2 test-bb - - V{ - T{ ##call f \ + -1 } - T{ ##inc-d f 1 } - T{ ##branch } - } 3 test-bb - - V{ T{ ##return } } 4 test-bb - - test-diamond - - cfg new 0 get >>entry - compute-predecessors - stack-analysis - drop - - 3 get successors>> first instructions>> [ ##peek? ] find nip loc>> -] unit-test - -! Missing ##replace -[ t ] [ - [ [ "B" ] 2dip dup [ [ /mod ] dip ] when ] test-stack-analysis - reverse-post-order last - instructions>> [ ##replace? ] filter [ loc>> ] map - { D 0 D 1 D 2 } set= -] unit-test - -! Inserted ##peeks reference the wrong stack location -[ t ] [ - [ [ "B" ] 2dip dup [ [ /mod ] dip ] when ] test-stack-analysis - eliminate-dead-code reverse-post-order 4 swap nth - instructions>> [ ##peek? ] filter [ loc>> ] map - { D 0 D 1 } set= -] unit-test - -[ D 0 ] [ - V{ T{ ##branch } } 0 test-bb - - V{ T{ ##branch } } 1 test-bb - - V{ - T{ ##peek f V int-regs 1 D 0 } - T{ ##inc-d f 1 } - T{ ##branch } - } 2 test-bb - - V{ - T{ ##inc-d f 1 } - T{ ##branch } - } 3 test-bb - - V{ T{ ##return } } 4 test-bb - - test-diamond - - cfg new 0 get >>entry - compute-predecessors - stack-analysis - drop - - 3 get successors>> first instructions>> [ ##peek? ] find nip loc>> -] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis.factor b/basis/compiler/cfg/stack-analysis/stack-analysis.factor deleted file mode 100644 index ec34c96a24..0000000000 --- a/basis/compiler/cfg/stack-analysis/stack-analysis.factor +++ /dev/null @@ -1,124 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs kernel namespaces math sequences fry grouping -sets make combinators dlists deques -compiler.cfg -compiler.cfg.copy-prop -compiler.cfg.def-use -compiler.cfg.instructions -compiler.cfg.registers -compiler.cfg.rpo -compiler.cfg.hats -compiler.cfg.stack-analysis.state -compiler.cfg.stack-analysis.merge -compiler.cfg.utilities ; -IN: compiler.cfg.stack-analysis - -SYMBOL: global-optimization? - -: redundant-replace? ( vreg loc -- ? ) - dup state get untranslate-loc n>> 0 < - [ 2drop t ] [ state get actual-locs>vregs>> at = ] if ; - -: save-changed-locs ( state -- ) - [ changed-locs>> keys ] [ locs>vregs>> ] bi '[ - dup _ at swap 2dup redundant-replace? - [ 2drop ] [ state get untranslate-loc ##replace ] if - ] each ; - -: sync-state ( -- ) - state get { - [ ds-height>> save-ds-height ] - [ rs-height>> save-rs-height ] - [ save-changed-locs ] - [ clear-state ] - } cleave ; - -! Abstract interpretation -GENERIC: visit ( insn -- ) - -M: ##inc-d visit - n>> state get [ + ] change-ds-height drop ; - -M: ##inc-r visit - n>> state get [ + ] change-rs-height drop ; - -! Instructions which don't have any effect on the stack -UNION: neutral-insn - ##effect - ##flushable - ##no-tco ; - -M: neutral-insn visit , ; - -UNION: sync-if-back-edge - ##branch - ##conditional-branch - ##compare-imm-branch - ##dispatch - ##loop-entry - ##fixnum-overflow ; - -: sync-state? ( -- ? ) - basic-block get successors>> - [ [ predecessors>> ] keep '[ _ back-edge? ] any? ] any? ; - -M: sync-if-back-edge visit - global-optimization? get [ sync-state? [ sync-state ] when ] unless - , ; - -: eliminate-peek ( dst src -- ) - ! the requested stack location is already in 'src' - [ ##copy ] [ swap copies get set-at ] 2bi ; - -M: ##peek visit - [ dst>> ] [ loc>> state get translate-loc ] bi dup loc>vreg - [ eliminate-peek ] [ [ record-peek ] [ ##peek ] 2bi ] ?if ; - -M: ##replace visit - [ src>> resolve ] [ loc>> state get translate-loc ] bi - record-replace ; - -M: ##copy visit - [ call-next-method ] [ record-copy ] bi ; - -M: ##jump visit sync-state , ; - -M: ##return visit sync-state , ; - -M: ##callback-return visit sync-state , ; - -M: kill-vreg-insn visit sync-state , ; - -! Maps basic-blocks to states -SYMBOL: state-out - -: block-in-state ( bb -- states ) - dup predecessors>> state-out get '[ _ at ] map merge-states ; - -: set-block-out-state ( state bb -- ) - [ clone ] dip state-out get set-at ; - -: visit-block ( bb -- ) - ! block-in-state may add phi nodes at the start of the basic block - ! so we wrap the whole thing with a 'make' - [ - dup basic-block set - dup block-in-state - state [ - [ instructions>> [ visit ] each ] - [ [ state get ] dip set-block-out-state ] - [ ] - tri - ] with-variable - ] V{ } make >>instructions drop ; - -: stack-analysis ( cfg -- cfg' ) - [ - work-list set - H{ } clone copies set - H{ } clone state-out set - dup [ visit-block ] each-basic-block - global-optimization? get [ work-list get [ visit-block ] slurp-deque ] when - cfg-changed - ] with-scope ; diff --git a/basis/compiler/cfg/stack-analysis/state/state.factor b/basis/compiler/cfg/stack-analysis/state/state.factor deleted file mode 100644 index 25fa249853..0000000000 --- a/basis/compiler/cfg/stack-analysis/state/state.factor +++ /dev/null @@ -1,53 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: kernel accessors namespaces assocs sets math deques -compiler.cfg.registers ; -IN: compiler.cfg.stack-analysis.state - -TUPLE: state -locs>vregs actual-locs>vregs changed-locs -{ ds-height integer } -{ rs-height integer } -poisoned? ; - -: ( -- state ) - state new - H{ } clone >>locs>vregs - H{ } clone >>actual-locs>vregs - H{ } clone >>changed-locs - 0 >>ds-height - 0 >>rs-height ; - -M: state clone - call-next-method - [ clone ] change-locs>vregs - [ clone ] change-actual-locs>vregs - [ clone ] change-changed-locs ; - -: loc>vreg ( loc -- vreg ) state get locs>vregs>> at ; - -: record-peek ( dst loc -- ) - state get [ locs>vregs>> set-at ] [ actual-locs>vregs>> set-at ] 3bi ; - -: changed-loc ( loc -- ) - state get changed-locs>> conjoin ; - -: record-replace ( src loc -- ) - dup changed-loc state get locs>vregs>> set-at ; - -: clear-state ( state -- ) - 0 >>ds-height 0 >>rs-height - [ locs>vregs>> ] [ actual-locs>vregs>> ] [ changed-locs>> ] tri - [ clear-assoc ] tri@ ; - -GENERIC# translate-loc 1 ( loc state -- loc' ) -M: ds-loc translate-loc [ n>> ] [ ds-height>> ] bi* - ; -M: rs-loc translate-loc [ n>> ] [ rs-height>> ] bi* - ; - -GENERIC# untranslate-loc 1 ( loc state -- loc' ) -M: ds-loc untranslate-loc [ n>> ] [ ds-height>> ] bi* + ; -M: rs-loc untranslate-loc [ n>> ] [ rs-height>> ] bi* + ; - -SYMBOL: work-list - -: add-to-work-list ( bb -- ) work-list get push-front ;