From: Slava Pestov Date: Thu, 21 May 2009 21:49:28 +0000 (-0500) Subject: CFG optimizer work in progress - adding phi nodes X-Git-Tag: 0.97~6168^2~43 X-Git-Url: https://gitweb.factorcode.org/gitweb.cgi?p=factor.git;a=commitdiff_plain;h=6af61656f3b6d3d35a090fed720f7aedbbc93c6a CFG optimizer work in progress - adding phi nodes --- diff --git a/basis/compiler/cfg/def-use/def-use.factor b/basis/compiler/cfg/def-use/def-use.factor index 6275ae2003..97047a7c3e 100644 --- a/basis/compiler/cfg/def-use/def-use.factor +++ b/basis/compiler/cfg/def-use/def-use.factor @@ -39,6 +39,7 @@ M: ##dispatch uses-vregs src>> 1array ; M: ##alien-getter uses-vregs src>> 1array ; M: ##alien-setter uses-vregs [ src>> ] [ value>> ] bi 2array ; M: ##fixnum-overflow uses-vregs [ src1>> ] [ src2>> ] bi 2array ; +M: ##phi uses-vregs inputs>> ; M: _conditional-branch uses-vregs [ src1>> ] [ src2>> ] bi 2array ; M: _compare-imm-branch uses-vregs src1>> 1array ; M: insn uses-vregs drop f ; diff --git a/basis/compiler/cfg/hats/hats.factor b/basis/compiler/cfg/hats/hats.factor index 817c0f4680..b61f091fad 100644 --- a/basis/compiler/cfg/hats/hats.factor +++ b/basis/compiler/cfg/hats/hats.factor @@ -73,3 +73,5 @@ IN: compiler.cfg.hats : ^^offset>slot ( vreg -- vreg' ) cell 4 = [ 1 ^^shr-imm ] when ; inline : ^^tag-fixnum ( src -- dst ) ^^i1 ##tag-fixnum ; inline : ^^untag-fixnum ( src -- dst ) ^^i1 ##untag-fixnum ; inline + +: ^^phi ( inputs -- dst ) ^^i1 ##phi ; inline \ No newline at end of file diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index 359e7188b0..6ebf064a94 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -178,6 +178,8 @@ INSN: ##branch ; INSN: ##loop-entry ; +INSN: ##phi < ##pure inputs ; + ! Condition codes SYMBOL: cc< SYMBOL: cc<= diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis.factor b/basis/compiler/cfg/stack-analysis/stack-analysis.factor index 682d2ac092..cbe46d7dd4 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis.factor @@ -1,9 +1,9 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs kernel namespaces math sequences fry deques +USING: accessors assocs kernel namespaces math sequences fry deques grouping search-deques dlists sets make combinators compiler.cfg.copy-prop compiler.cfg.def-use compiler.cfg.instructions compiler.cfg.registers -compiler.cfg.rpo ; +compiler.cfg.rpo compiler.cfg.hats ; IN: compiler.cfg.stack-analysis ! Convert stack operations to register operations @@ -67,10 +67,11 @@ M: state clone [ vregs>locs>> clear-assoc ] } cleave ; +ERROR: poisoned-state state ; + : sync-state ( -- ) - ! also: update height - ! but first, sync outputs state get { + [ dup poisoned?>> [ poisoned-state ] [ drop ] if ] [ save-changed-locs ] [ d-height>> dup 0 = [ drop ] [ ##inc-d ] if ] [ r-height>> dup 0 = [ drop ] [ ##inc-r ] if ] @@ -181,11 +182,72 @@ SYMBOL: work-list ! Maps basic-blocks to states SYMBOLS: state-in state-out ; -: merge-states ( seq -- state ) - [ ] [ first ] if-empty ; +: sync-unpoisoned-states ( predecessors states -- ) + [ + dup poisoned?>> [ 2drop ] [ + state [ + instructions>> building set + sync-state + ] with-variable + ] if + ] 2each ; + +ERROR: must-equal-failed seq ; + +: must-equal ( seq -- elt ) + dup all-equal? [ first ] [ must-equal-failed ] if ; + +: merge-heights ( state predecessors states -- state ) + nip + [ [ d-height>> ] map must-equal >>d-height ] + [ [ r-height>> ] map must-equal >>r-height ] bi ; + +ERROR: inconsistent-vreg>loc states ; + +: check-vreg>loc ( states -- ) + ! The same vreg should not store different locs in + ! different branches + dup + [ vregs>locs>> ] map + [ [ keys ] map concat prune ] keep + '[ _ [ at ] with map sift all-equal? ] all? + [ drop ] [ inconsistent-vreg>loc ] if ; + +: insert-peek ( predecessor loc -- vreg ) + ! XXX critical edges + [ instructions>> building ] dip '[ _ ^^peek ] with-variable ; + +: merge-loc ( predecessors locs>vregs loc -- vreg ) + ! Insert a ##phi in the current block where the input + ! is the vreg storing loc from each predecessor block + [ '[ [ _ ] dip at ] map ] keep + '[ [ ] [ _ insert-peek ] if ] 2map + ^^phi ; + +: merge-locs ( state predecessors states -- state ) + [ locs>vregs>> ] map dup [ keys ] map prune + [ + [ 2nip ] [ merge-loc ] 3bi + ] with with H{ } map>assoc + >>locs>vregs ; + +: merge-states ( predecessors states -- state ) + ! If any states are poisoned, save all registers + ! to the stack in each branch + [ drop ] [ + dup [ poisoned?>> ] any? [ + sync-unpoisoned-states + ] [ + dup check-vreg>loc + [ state new ] 2dip + [ merge-heights ] + [ merge-locs ] 2bi + ! what about vregs>locs + ] if + ] if-empty ; : block-in-state ( bb -- states ) - predecessors>> state-out get '[ _ at ] map merge-states ; + predecessors>> dup state-out get '[ _ at ] map merge-states ; : maybe-set-at ( value key assoc -- changed? ) 3dup at* [ = [ 3drop f ] [ set-at t ] if ] [ 2drop set-at t ] if ; @@ -201,14 +263,19 @@ SYMBOLS: state-in state-out ; [ successors>> [ add-to-work-list ] each ] [ drop ] if ; : visit-block ( bb -- ) - dup block-in-state - [ swap set-block-in-state ] [ - state [ - [ [ [ [ visit ] each ] V{ } make ] change-instructions drop ] - [ state get finish-block ] - bi - ] with-variable - ] 2bi ; + ! block-in-state may add phi nodes at the start of the basic block + ! so we wrap the whole thing with a 'make' + [ + dup block-in-state + [ swap set-block-in-state ] [ + state [ + [ instructions>> [ visit ] each ] + [ state get finish-block ] + [ ] + tri + ] with-variable + ] 2bi + ] V{ } make >>instructions drop ; : visit-blocks ( bb -- ) reverse-post-order work-list get @@ -223,16 +290,8 @@ SYMBOLS: state-in state-out ; dup entry>> visit-blocks ] with-scope ; -! To do: -! - implement merge-states -! - insert loads to convert partially available values into available values - -! if any state is poisoned, then we need to sync in every predecessor that didn't sync -! and begin with a new state. - -! if heights differ, throw an error. - -! changed-locs is the union of the changed-locs of all predecessors -! locs>vregs: take the union, then for each predecessor, diff its locs>vregs against the union. -! those are the ones that need to be loaded in. -! think about phi insertion. \ No newline at end of file +! XXX: what if our height doesn't match +! a future block we're merging with? +! - we should only poison tail calls +! - non-tail poisoning nodes: ##alien-callback, ##call of a non-tail dispatch +! do we need a distinction between height changes in code and height changes done by the callee \ No newline at end of file