]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor into s3
authorDaniel Ehrenberg <littledan@pool-224-36.res.carleton.edu>
Sat, 17 Apr 2010 19:05:40 +0000 (14:05 -0500)
committerDaniel Ehrenberg <littledan@pool-224-36.res.carleton.edu>
Sat, 17 Apr 2010 19:05:40 +0000 (14:05 -0500)
basis/compiler/cfg/dependence/dependence.factor [new file with mode: 0644]
basis/compiler/cfg/height/height.factor [new file with mode: 0644]
basis/compiler/cfg/height/summary.txt [new file with mode: 0644]
basis/compiler/cfg/optimizer/optimizer.factor
basis/compiler/cfg/scheduling/scheduling-tests.factor [new file with mode: 0644]
basis/compiler/cfg/scheduling/scheduling.factor [new file with mode: 0644]

diff --git a/basis/compiler/cfg/dependence/dependence.factor b/basis/compiler/cfg/dependence/dependence.factor
new file mode 100644 (file)
index 0000000..d25f29c
--- /dev/null
@@ -0,0 +1,181 @@
+! Copyright (C) 2009, 2010 Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators compiler.cfg.def-use
+compiler.cfg.instructions compiler.cfg.registers fry kernel
+locals namespaces sequences sets sorting math.vectors
+make math combinators.short-circuit vectors ;
+FROM: namespaces => set ;
+IN: compiler.cfg.dependence
+
+! Dependence graph construction
+
+SYMBOL: roots
+SYMBOL: node-number
+SYMBOL: nodes
+
+SYMBOL: +data+
+SYMBOL: +control+
+
+! Nodes in the dependency graph
+! These need to be numbered so that the same instruction
+! will get distinct nodes if it occurs multiple times
+TUPLE: node
+    number insn precedes follows
+    children parent
+    registers parent-index ;
+
+M: node equal?  [ number>> ] bi@ = ;
+
+M: node hashcode* nip number>> ;
+
+: <node> ( insn -- node )
+    node new
+        node-number counter >>number
+        swap >>insn
+        H{ } clone >>precedes
+        V{ } clone >>follows ;
+
+: ready? ( node -- ? ) precedes>> assoc-empty? ;
+
+:: precedes ( first second how -- )
+    how second first precedes>> set-at ;
+
+:: add-data-edges ( nodes -- )
+    ! This builds up def-use information on the fly, since
+    ! we only care about local def-use
+    H{ } clone :> definers
+    nodes [| node |
+        node insn>> defs-vreg [ node swap definers set-at ] when*
+        node insn>> uses-vregs [ definers at [ node +data+ precedes ] when* ] each
+    ] each ;
+
+UNION: stack-read-write ##peek ##replace ;
+
+UNION: ##alien-read
+    ##alien-double ##alien-float ##alien-cell ##alien-vector
+    ##alien-signed-1 ##alien-signed-2 ##alien-signed-4
+    ##alien-unsigned-1 ##alien-unsigned-2 ##alien-unsigned-4 ;
+
+UNION: ##alien-write
+    ##set-alien-double ##set-alien-float ##set-alien-cell ##set-alien-vector
+    ##set-alien-integer-1 ##set-alien-integer-2 ##set-alien-integer-4 ;
+
+UNION: slot-memory-insn
+    ##read ##write ;
+
+UNION: alien-memory-insn
+    ##alien-read ##alien-write ;
+
+UNION: string-memory-insn
+    ##string-nth ##set-string-nth-fast ;
+
+UNION: alien-call-insn
+    ##save-context ##alien-invoke ##alien-indirect ##alien-callback ;
+
+: chain ( node var -- )
+    dup get [
+        pick +control+ precedes
+    ] when*
+    set ;
+
+GENERIC: add-control-edge ( node insn -- )
+
+M: stack-read-write add-control-edge
+    loc>> chain ;
+
+M: alien-memory-insn add-control-edge
+    drop alien-memory-insn chain ;
+
+M: slot-memory-insn add-control-edge
+    drop slot-memory-insn chain ;
+
+M: string-memory-insn add-control-edge
+    drop string-memory-insn chain ;
+
+M: alien-call-insn add-control-edge
+    drop alien-call-insn chain ;
+
+M: object add-control-edge 2drop ;
+
+: add-control-edges ( nodes -- )
+    [
+        [ dup insn>> add-control-edge ] each
+    ] with-scope ;
+
+: set-follows ( nodes -- )
+    [
+        dup precedes>> keys [
+            follows>> push
+        ] with each
+    ] each ;
+
+: set-roots ( nodes -- )
+    [ ready? ] V{ } filter-as roots set ;
+
+: build-dependence-graph ( instructions -- )
+    [ <node> ] map {
+        [ add-control-edges ]
+        [ add-data-edges ]
+        [ set-follows ]
+        [ set-roots ]
+        [ nodes set ]
+    } cleave ;
+
+! Sethi-Ulmann numbering
+:: calculate-registers ( node -- registers )
+    node children>> [ 0 ] [
+        [ [ calculate-registers ] map natural-sort ]
+        [ length iota ]
+        bi v+ supremum
+    ] if-empty
+    node insn>> temp-vregs length +
+    dup node (>>registers) ;
+
+! Constructing fan-in trees
+
+: attach-parent ( node parent -- )
+    [ >>parent drop ]
+    [ [ ?push ] change-children drop ] 2bi ;
+
+: keys-for ( assoc value -- keys )
+    '[ nip _ = ] assoc-filter keys ;
+
+: choose-parent ( node -- )
+    ! If a node has control dependences, it has to be a root
+    ! Otherwise, choose one of the data dependences for a parent
+    dup precedes>> +control+ keys-for empty? [
+        dup precedes>> +data+ keys-for [ drop ] [
+            first attach-parent
+        ] if-empty
+    ] [ drop ] if ;
+
+: make-trees ( -- trees )
+    nodes get
+    [ [ choose-parent ] each ]
+    [ [ parent>> not ] filter ] bi ;
+
+ERROR: node-missing-parent trees nodes ;
+ERROR: node-missing-children trees nodes ;
+
+: flatten-tree ( node -- nodes )
+    [ children>> [ flatten-tree ] map concat ] keep
+    suffix ;
+
+: verify-parents ( trees -- trees )
+    nodes get over '[ [ parent>> ] [ _ member? ] bi or ] all?
+    [ nodes get node-missing-parent ] unless ;
+
+: verify-children ( trees -- trees )
+    dup [ flatten-tree ] map concat
+    nodes get
+    { [ [ length ] bi@ = ] [ set= ] } 2&&
+    [ nodes get node-missing-children ] unless ;
+
+: verify-trees ( trees -- trees )
+    verify-parents verify-children ;
+
+: build-fan-in-trees ( -- )
+    make-trees verify-trees [
+        -1/0. >>parent-index 
+        calculate-registers drop
+    ] each ;
diff --git a/basis/compiler/cfg/height/height.factor b/basis/compiler/cfg/height/height.factor
new file mode 100644 (file)
index 0000000..a782d2d
--- /dev/null
@@ -0,0 +1,55 @@
+! Copyright (C) 2008, 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors math namespaces sequences kernel fry
+compiler.cfg compiler.cfg.registers compiler.cfg.instructions
+compiler.cfg.rpo ;
+IN: compiler.cfg.height
+
+! Combine multiple stack height changes into one at the
+! start of the basic block.
+
+SYMBOL: ds-height
+SYMBOL: rs-height
+
+GENERIC: compute-heights ( insn -- )
+
+M: ##inc-d compute-heights n>> ds-height [ + ] change ;
+M: ##inc-r compute-heights n>> rs-height [ + ] change ;
+M: insn compute-heights drop ;
+
+GENERIC: normalize-height* ( insn -- insn' )
+
+: normalize-inc-d/r ( insn stack -- insn' )
+    swap n>> '[ _ - ] change f ; inline
+
+M: ##inc-d normalize-height* ds-height normalize-inc-d/r ;
+M: ##inc-r normalize-height* rs-height normalize-inc-d/r ;
+
+GENERIC: loc-stack ( loc -- stack )
+
+M: ds-loc loc-stack drop ds-height ;
+M: rs-loc loc-stack drop rs-height ;
+
+GENERIC: <loc> ( n stack -- loc )
+
+M: ds-loc <loc> drop <ds-loc> ;
+M: rs-loc <loc> drop <rs-loc> ;
+
+: normalize-peek/replace ( insn -- insn' )
+    [ [ [ n>> ] [ loc-stack get ] bi + ] keep <loc> ] change-loc ; inline
+
+M: ##peek normalize-height* normalize-peek/replace ;
+M: ##replace normalize-height* normalize-peek/replace ;
+
+M: insn normalize-height* ;
+
+: height-step ( insns -- insns' )
+    0 ds-height set
+    0 rs-height set
+    [ [ compute-heights ] each ]
+    [ [ [ normalize-height* ] map sift ] with-scope ] bi
+    ds-height get dup 0 = [ drop ] [ \ ##inc-d new-insn prefix ] if
+    rs-height get dup 0 = [ drop ] [ \ ##inc-r new-insn prefix ] if ;
+
+: normalize-height ( cfg -- cfg' )
+    [ height-step ] local-optimization ;
diff --git a/basis/compiler/cfg/height/summary.txt b/basis/compiler/cfg/height/summary.txt
new file mode 100644 (file)
index 0000000..ce1974a
--- /dev/null
@@ -0,0 +1 @@
+Stack height normalization coalesces height changes at start of basic block
index 84726a9b99de44d52f876780a53975ff3ac3945e..d43e4adcc83f3814d3884143f1a87781127d01bc 100644 (file)
@@ -5,12 +5,14 @@ compiler.cfg.tco
 compiler.cfg.useless-conditionals
 compiler.cfg.branch-splitting
 compiler.cfg.block-joining
+compiler.cfg.height
 compiler.cfg.ssa.construction
 compiler.cfg.alias-analysis
 compiler.cfg.value-numbering
 compiler.cfg.copy-prop
 compiler.cfg.dce
 compiler.cfg.write-barrier
+compiler.cfg.scheduling
 compiler.cfg.representations
 compiler.cfg.ssa.destruction
 compiler.cfg.empty-blocks
@@ -29,6 +31,7 @@ SYMBOL: check-optimizer?
     delete-useless-conditionals
     split-branches
     join-blocks
+    normalize-height
     construct-ssa
     alias-analysis
     value-numbering
@@ -36,6 +39,7 @@ SYMBOL: check-optimizer?
     eliminate-dead-code
     eliminate-write-barriers
     select-representations
+    schedule-instructions
     destruct-ssa
     delete-empty-blocks
     ?check ;
diff --git a/basis/compiler/cfg/scheduling/scheduling-tests.factor b/basis/compiler/cfg/scheduling/scheduling-tests.factor
new file mode 100644 (file)
index 0000000..fd61790
--- /dev/null
@@ -0,0 +1,11 @@
+USING: compiler.cfg.scheduling vocabs.loader namespaces tools.test ;
+IN: compiler.cfg.scheduling.tests
+
+! Recompile compiler.cfg.scheduling with extra tests,
+! and see if any errors come up. Back when there were
+! errors of this kind, they always surfaced this way.
+
+t check-scheduling? [
+    [ ] [ "compiler.cfg.scheduling" reload ] unit-test
+    [ ] [ "compiler.cfg.dependence" reload ] unit-test
+] with-variable
diff --git a/basis/compiler/cfg/scheduling/scheduling.factor b/basis/compiler/cfg/scheduling/scheduling.factor
new file mode 100644 (file)
index 0000000..1c6c698
--- /dev/null
@@ -0,0 +1,134 @@
+! Copyright (C) 2009, 2010 Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs compiler.cfg.def-use
+compiler.cfg.dependence compiler.cfg.instructions
+compiler.cfg.liveness compiler.cfg.rpo cpu.architecture fry
+kernel locals make math namespaces sequences sets ;
+IN: compiler.cfg.scheduling
+
+! Instruction scheduling to reduce register pressure, from:
+! "Register-sensitive selection, duplication, and
+!  sequencing of instructions"
+! by Vivek Sarkar, et al.
+! http://portal.acm.org/citation.cfm?id=377849
+
+ERROR: bad-delete-at key assoc ;
+
+: check-delete-at ( key assoc -- )
+    2dup key? [ delete-at ] [ bad-delete-at ] if ;
+
+: set-parent-indices ( node -- )
+    children>> building get length
+    '[ _ >>parent-index drop ] each ;
+
+: remove-node ( node -- )
+    [ follows>> members ] keep
+    '[ [ precedes>> _ swap check-delete-at ] each ]
+    [ [ ready? ] filter roots get push-all ] bi ;
+
+: score ( insn -- n )
+    [ parent-index>> ] [ registers>> neg ] [ insn>> insn#>> ] tri 3array ;
+
+: pull-out-nth ( n seq -- elt )
+    [ nth ] [ remove-nth! drop ] 2bi ;
+
+: select ( vector quot -- elt )
+    ! This could be sped up by a constant factor
+    [ dup <enum> ] dip '[ _ call( insn -- score ) ] assoc-map
+    dup values supremum '[ nip _ = ] assoc-find
+    2drop swap pull-out-nth ; inline
+
+: select-instruction ( -- insn/f )
+    roots get [ f ] [
+        [ score ] select 
+        [ insn>> ]
+        [ set-parent-indices ]
+        [ remove-node ] tri
+    ] if-empty ;
+
+: (reorder) ( -- )
+    select-instruction [
+        , (reorder)
+    ] when* ;
+
+: cut-by ( seq quot -- before after )
+    dupd find drop [ cut ] [ f ] if* ; inline
+
+UNION: initial-insn
+    ##phi ##inc-d ##inc-r ;
+
+: split-3-ways ( insns -- first middle last )
+    [ initial-insn? not ] cut-by unclip-last ;
+
+: reorder ( insns -- insns' )
+    split-3-ways [
+        build-dependence-graph
+        build-fan-in-trees
+        [ (reorder) ] V{ } make reverse
+    ] dip suffix append ;
+
+ERROR: not-all-instructions-were-scheduled old-bb new-bb ;
+
+SYMBOL: check-scheduling?
+f check-scheduling? set-global
+
+:: check-instructions ( new-bb old-bb -- )
+    new-bb old-bb [ instructions>> ] bi@
+    [ [ length ] bi@ = ] [ [ unique ] bi@ = ] 2bi and
+    [ old-bb new-bb not-all-instructions-were-scheduled ] unless ;
+
+ERROR: definition-after-usage vreg old-bb new-bb ;
+
+:: check-usages ( new-bb old-bb -- )
+    HS{ } clone :> useds
+    new-bb instructions>> split-3-ways drop nip
+    [| insn |
+        insn uses-vregs [ useds adjoin ] each
+        insn defs-vreg :> def-reg
+        def-reg useds in?
+        [ def-reg old-bb new-bb definition-after-usage ] when
+    ] each ;
+
+: check-scheduling ( new-bb old-bb -- )
+    [ check-instructions ] [ check-usages ] 2bi ;
+
+: with-scheduling-check ( bb quot: ( bb -- ) -- )
+    check-scheduling? get [
+        over dup clone
+        [ call( bb -- ) ] 2dip
+        check-scheduling
+    ] [
+        call( bb -- )
+    ] if ; inline
+
+: number-insns ( insns -- )
+    [ >>insn# drop ] each-index ;
+
+: clear-numbers ( insns -- )
+    [ f >>insn# drop ] each ;
+
+: schedule-block ( bb -- )
+    [
+        [
+            [ number-insns ]
+            [ reorder ]
+            [ clear-numbers ] tri
+        ] change-instructions drop
+    ] with-scheduling-check ;
+
+! Really, instruction scheduling should be aware that there are
+! multiple types of registers, but this number is just used
+! to decide whether to schedule instructions
+: num-registers ( -- x ) int-regs machine-registers at length ;
+
+: might-spill? ( bb -- ? )
+    [ live-in assoc-size ]
+    [ instructions>> [ defs-vreg ] count ] bi
+    + num-registers >= ;
+
+: schedule-instructions ( cfg -- cfg' )
+    dup [
+        dup might-spill?
+        [ schedule-block ]
+        [ drop ] if
+    ] each-basic-block ;