]> gitweb.factorcode.org Git - factor.git/commitdiff
Split up compiler.cfg.linear-scan.allocation into a number of sub-vocabularies; start...
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Thu, 11 Jun 2009 22:55:14 +0000 (17:55 -0500)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Thu, 11 Jun 2009 22:55:14 +0000 (17:55 -0500)
14 files changed:
basis/compiler/cfg/instructions/instructions.factor
basis/compiler/cfg/linear-scan/allocation/allocation.factor
basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor [new file with mode: 0644]
basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor [new file with mode: 0644]
basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor [new file with mode: 0644]
basis/compiler/cfg/linear-scan/allocation/state/state.factor [new file with mode: 0644]
basis/compiler/cfg/linear-scan/assignment/assignment-tests.factor [deleted file]
basis/compiler/cfg/linear-scan/assignment/assignment.factor
basis/compiler/cfg/linear-scan/linear-scan-tests.factor
basis/compiler/cfg/linear-scan/linear-scan.factor
basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor
basis/compiler/cfg/linear-scan/resolve/resolve.factor [new file with mode: 0644]
basis/compiler/cfg/predecessors/predecessors.factor
basis/compiler/codegen/codegen.factor

index fe853cf490ec6b1e2849e87a3d7d0fb789dce06e..1bf94985a6574faebc686c2ccdad19e7bcab45ff 100644 (file)
@@ -245,4 +245,5 @@ INSN: _gc { temp1 vreg } { temp2 vreg } gc-roots gc-root-count gc-root-size ;
 ! virtual registers
 INSN: _spill src class n ;
 INSN: _reload dst class n ;
+INSN: _copy dst src class ;
 INSN: _spill-counts counts ;
index 7b56bd61503e789c8de4e8a847fd1f2c92c1d13e..a99fea1d2476d79f09fc658a026a5d04a0dcbf17 100644 (file)
 ! Copyright (C) 2008, 2009 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces sequences math math.order kernel assocs
-accessors vectors fry heaps cpu.architecture sorting locals
-combinators compiler.cfg.registers
-compiler.cfg.linear-scan.live-intervals hints ;
+USING: accessors assocs heaps kernel namespaces sequences
+compiler.cfg.linear-scan.allocation.coalescing
+compiler.cfg.linear-scan.allocation.spilling
+compiler.cfg.linear-scan.allocation.splitting
+compiler.cfg.linear-scan.allocation.state ;
 IN: compiler.cfg.linear-scan.allocation
 
-! Mapping from register classes to sequences of machine registers
-SYMBOL: free-registers
-
-: free-registers-for ( vreg -- seq )
-    reg-class>> free-registers get at ;
-
-: deallocate-register ( live-interval -- )
-    [ reg>> ] [ vreg>> ] bi free-registers-for push ;
-
-! Vector of active live intervals
-SYMBOL: active-intervals
-
-: active-intervals-for ( vreg -- seq )
-    reg-class>> active-intervals get at ;
-
-: add-active ( live-interval -- )
-    dup vreg>> active-intervals-for push ;
-
-: delete-active ( live-interval -- )
-    dup vreg>> active-intervals-for delq ;
-
-! Vector of inactive live intervals
-SYMBOL: inactive-intervals
-
-: inactive-intervals-for ( vreg -- seq )
-    reg-class>> inactive-intervals get at ;
-
-: add-inactive ( live-interval -- )
-    dup vreg>> inactive-intervals-for push ;
-
-! Vector of handled live intervals
-SYMBOL: handled-intervals
-
-: add-handled ( live-interval -- )
-    handled-intervals get push ;
-
-: finished? ( n live-interval -- ? ) end>> swap < ;
-
-: finish ( n live-interval -- keep? )
-    nip [ deallocate-register ] [ add-handled ] bi f ;
-
-: activate ( n live-interval -- keep? )
-    nip add-active f ;
-
-: deactivate ( n live-interval -- keep? )
-    nip add-inactive f ;
-
-: don't-change ( n live-interval -- keep? ) 2drop t ;
-
-! Moving intervals between active and inactive sets
-: process-intervals ( n symbol quots -- )
-    ! symbol stores an alist mapping register classes to vectors
-    [ get values ] dip '[ [ _ cond ] with filter-here ] with each ; inline
-
-: covers? ( insn# live-interval -- ? )
-    ranges>> [ [ from>> ] [ to>> ] bi between? ] with any? ;
-
-: deactivate-intervals ( n -- )
-    ! Any active intervals which have ended are moved to handled
-    ! Any active intervals which cover the current position
-    ! are moved to inactive
-    active-intervals {
-        { [ 2dup finished? ] [ finish ] }
-        { [ 2dup covers? not ] [ deactivate ] }
-        [ don't-change ]
-    } process-intervals ;
-
-: activate-intervals ( n -- )
-    ! Any inactive intervals which have ended are moved to handled
-    ! Any inactive intervals which do not cover the current position
-    ! are moved to active
-    inactive-intervals {
-        { [ 2dup finished? ] [ finish ] }
-        { [ 2dup covers? ] [ activate ] }
-        [ don't-change ]
-    } process-intervals ;
-
-! Minheap of live intervals which still need a register allocation
-SYMBOL: unhandled-intervals
-
-! Start index of current live interval. We ensure that all
-! live intervals added to the unhandled set have a start index
-! strictly greater than ths one. This ensures that we can catch
-! infinite loop situations.
-SYMBOL: progress
-
-: check-progress ( live-interval -- )
-    start>> progress get <= [ "No progress" throw ] when ; inline
-
-: add-unhandled ( live-interval -- )
-    [ check-progress ]
-    [ dup start>> unhandled-intervals get heap-push ]
-    bi ;
-
-: init-unhandled ( live-intervals -- )
-    [ [ start>> ] keep ] { } map>assoc
-    unhandled-intervals get heap-push-all ;
-
-! Coalescing
-: active-interval ( vreg -- live-interval )
-    dup [ dup active-intervals-for [ vreg>> = ] with find nip ] when ;
-
-: coalesce? ( live-interval -- ? )
-    [ start>> ] [ copy-from>> active-interval ] bi
-    dup [ end>> = ] [ 2drop f ] if ;
-
-: coalesce ( live-interval -- )
-    dup copy-from>> active-interval
-    [ [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ]
-    [ reg>> >>reg drop ]
-    2bi ;
-
-! Splitting
-: split-range ( live-range n -- before after )
-    [ [ from>> ] dip <live-range> ]
-    [ 1 + swap to>> <live-range> ]
-    2bi ;
-
-: split-last-range? ( last n -- ? )
-    swap to>> <= ;
-
-: split-last-range ( before after last n -- before' after' )
-    split-range [ [ but-last ] dip suffix ] [ prefix ] bi-curry* bi* ;
-
-: split-ranges ( live-ranges n -- before after )
-    [ '[ from>> _ <= ] partition ]
-    [
-        pick empty? [ drop ] [
-            [ over last ] dip 2dup split-last-range?
-            [ split-last-range ] [ 2drop ] if
-        ] if
-    ] bi ;
-
-: split-uses ( uses n -- before after )
-    '[ _ <= ] partition ;
-
-: record-split ( live-interval before after -- )
-    [ >>split-before ] [ >>split-after ] bi* drop ; inline
-
-: check-split ( live-interval -- )
-    [ end>> ] [ start>> ] bi - 0 =
-    [ "BUG: splitting atomic interval" throw ] when ; inline
-
-: split-before ( before -- before' )
-    [ [ ranges>> last ] [ uses>> last ] bi >>to drop ]
-    [ compute-start/end ]
-    [ ]
-    tri ; inline
-
-: split-after ( after -- after' )
-    [ [ ranges>> first ] [ uses>> first ] bi >>from drop ]
-    [ compute-start/end ]
-    [ ]
-    tri ; inline
-
-:: split-interval ( live-interval n -- before after )
-    live-interval check-split
-    live-interval clone :> before
-    live-interval clone f >>copy-from f >>reg :> after
-    live-interval uses>> n split-uses before after [ (>>uses) ] bi-curry@ bi*
-    live-interval ranges>> n split-ranges before after [ (>>ranges) ] bi-curry@ bi*
-    live-interval before after record-split
-    before split-before
-    after split-after ;
-
-HINTS: split-interval live-interval object ;
-
-! Spilling
-SYMBOL: spill-counts
-
-: next-spill-location ( reg-class -- n )
-    spill-counts get [ dup 1+ ] change-at ;
-
-: find-use ( live-interval n quot -- i elt )
-    [ uses>> ] 2dip curry find ; inline
-
-: interval-to-spill ( active-intervals current -- live-interval )
-    #! We spill the interval with the most distant use location.
-    start>> '[ dup _ [ >= ] find-use nip ] { } map>assoc
-    [ ] [ [ [ second ] bi@ > ] most ] map-reduce first ;
-
-: assign-spill ( before after -- before after )
-    #! If it has been spilled already, reuse spill location.
-    over reload-from>>
-    [ over vreg>> reg-class>> next-spill-location ] unless*
-    [ >>spill-to ] [ >>reload-from ] bi-curry bi* ;
-
-: split-and-spill ( new existing -- before after )
-    swap start>> split-interval assign-spill ;
-
-: reuse-register ( new existing -- )
-    reg>> >>reg add-active ;
-
-: spill-existing ( new existing -- )
-    #! Our new interval will be used before the active interval
-    #! with the most distant use location. Spill the existing
-    #! interval, then process the new interval and the tail end
-    #! of the existing interval again.
-    [ reuse-register ]
-    [ nip delete-active ]
-    [ split-and-spill [ add-handled ] [ add-unhandled ] bi* ] 2tri ;
-
-: spill-new ( new existing -- )
-    #! Our new interval will be used after the active interval
-    #! with the most distant use location. Split the new
-    #! interval, then process both parts of the new interval
-    #! again.
-    [ dup split-and-spill add-unhandled ] dip spill-existing ;
-
-: spill-existing? ( new existing -- ? )
-    #! Test if 'new' will be used before 'existing'.
-    over start>> '[ _ [ > ] find-use nip -1 or ] bi@ < ;
-
-: assign-blocked-register ( new -- )
-    [ dup vreg>> active-intervals-for ] keep interval-to-spill
-    2dup spill-existing? [ spill-existing ] [ spill-new ] if ;
-
-: assign-free-register ( new registers -- )
-    pop >>reg add-active ;
-
-: relevant-ranges ( new inactive -- new' inactive' )
-    ! Slice off all ranges of 'inactive' that precede the start of 'new'
-    [ [ ranges>> ] bi@ ] [ nip start>> ] 2bi '[ to>> _ >= ] filter ;
-
-: intersect-live-range ( range1 range2 -- n/f )
-    2dup [ from>> ] bi@ > [ swap ] when
-    2dup [ to>> ] [ from>> ] bi* >= [ nip from>> ] [ 2drop f ] if ;
-
-: intersect-live-ranges ( ranges1 ranges2 -- n )
-    {
-        { [ over empty? ] [ 2drop 1/0. ] }
-        { [ dup empty? ] [ 2drop 1/0. ] }
-        [
-            2dup [ first ] bi@ intersect-live-range dup [ 2nip ] [
-                drop
-                2dup [ first from>> ] bi@ <
-                [ [ rest-slice ] dip ] [ rest-slice ] if
-                intersect-live-ranges
-            ] if
-        ]
-    } cond ;
-
-: intersect-inactive ( new inactive -- n )
-    relevant-ranges intersect-live-ranges ;
-
-: intersecting-inactive ( new -- live-intervals )
-    dup vreg>> inactive-intervals-for
-    [ tuck intersect-inactive ] with { } map>assoc ;
-
-: fits-in-hole ( new pair -- )
-    first reuse-register ;
-
-: split-before-use ( new pair -- before after )
-    ! Find optimal split position
-    ! Insert move instruction
-    second split-interval ;
-
-: assign-inactive-register ( new live-intervals -- )
-    ! If there is an interval which is inactive for the entire lifetime
-    ! if the new interval, reuse its vreg. Otherwise, split new so that
-    ! the first half fits.
-    sort-values last
-    2dup [ end>> ] [ second ] bi* < [
-        fits-in-hole
-    ] [
-        [ split-before-use ] keep
-       '[ _ fits-in-hole ] [ add-unhandled ] bi*
-    ] if ;
-
 : assign-register ( new -- )
     dup coalesce? [ coalesce ] [
         dup vreg>> free-registers-for [
@@ -286,21 +18,6 @@ SYMBOL: spill-counts
         if-empty
     ] if ;
 
-! Main loop
-CONSTANT: reg-classes { int-regs double-float-regs }
-
-: reg-class-assoc ( quot -- assoc )
-    [ reg-classes ] dip { } map>assoc ; inline
-
-: init-allocator ( registers -- )
-    [ reverse >vector ] assoc-map free-registers set
-    [ 0 ] reg-class-assoc spill-counts set
-    <min-heap> unhandled-intervals set
-    [ V{ } clone ] reg-class-assoc active-intervals set
-    [ V{ } clone ] reg-class-assoc inactive-intervals set
-    V{ } clone handled-intervals set
-    -1 progress set ;
-
 : handle-interval ( live-interval -- )
     [
         start>>
@@ -313,12 +30,10 @@ CONSTANT: reg-classes { int-regs double-float-regs }
     unhandled-intervals get [ handle-interval ] slurp-heap ;
 
 : finish-allocation ( -- )
-    ! Sanity check: all live intervals should've been processed
     active-intervals inactive-intervals
     [ get values [ handled-intervals get push-all ] each ] bi@ ;
 
 : allocate-registers ( live-intervals machine-registers -- live-intervals )
-    #! This modifies the input live-intervals.
     init-allocator
     init-unhandled
     (allocate-registers)
diff --git a/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor b/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor
new file mode 100644 (file)
index 0000000..99ed75d
--- /dev/null
@@ -0,0 +1,18 @@
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel sequences
+compiler.cfg.linear-scan.allocation.state ;
+IN: compiler.cfg.linear-scan.allocation.coalescing
+
+: active-interval ( vreg -- live-interval )
+    dup [ dup active-intervals-for [ vreg>> = ] with find nip ] when ;
+
+: coalesce? ( live-interval -- ? )
+    [ start>> ] [ copy-from>> active-interval ] bi
+    dup [ end>> = ] [ 2drop f ] if ;
+
+: coalesce ( live-interval -- )
+    dup copy-from>> active-interval
+    [ [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ]
+    [ reg>> >>reg drop ]
+    2bi ;
diff --git a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor
new file mode 100644 (file)
index 0000000..4981a22
--- /dev/null
@@ -0,0 +1,60 @@
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators fry hints kernel locals
+math sequences sets sorting splitting
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.allocation.splitting
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.allocation.spilling
+
+: split-for-spill ( live-interval n -- before after )
+    split-interval
+    [
+        [ [ ranges>> last ] [ uses>> last ] bi >>to drop ]
+        [ [ ranges>> first ] [ uses>> first ] bi >>from drop ] bi*
+    ]
+    [ [ compute-start/end ] bi@ ]
+    [ ]
+    2tri ;
+
+: find-use ( live-interval n quot -- i elt )
+    [ uses>> ] 2dip curry find ; inline
+
+: interval-to-spill ( active-intervals current -- live-interval )
+    #! We spill the interval with the most distant use location.
+    start>> '[ dup _ [ >= ] find-use nip ] { } map>assoc
+    [ ] [ [ [ second ] bi@ > ] most ] map-reduce first ;
+
+: assign-spill ( before after -- before after )
+    #! If it has been spilled already, reuse spill location.
+    over reload-from>>
+    [ over vreg>> reg-class>> next-spill-location ] unless*
+    [ >>spill-to ] [ >>reload-from ] bi-curry bi* ;
+
+: split-and-spill ( new existing -- before after )
+    swap start>> split-for-spill assign-spill ;
+
+: spill-existing ( new existing -- )
+    #! Our new interval will be used before the active interval
+    #! with the most distant use location. Spill the existing
+    #! interval, then process the new interval and the tail end
+    #! of the existing interval again.
+    [ reuse-register ]
+    [ nip delete-active ]
+    [ split-and-spill [ add-handled ] [ add-unhandled ] bi* ] 2tri ;
+
+: spill-new ( new existing -- )
+    #! Our new interval will be used after the active interval
+    #! with the most distant use location. Split the new
+    #! interval, then process both parts of the new interval
+    #! again.
+    [ dup split-and-spill add-unhandled ] dip spill-existing ;
+
+: spill-existing? ( new existing -- ? )
+    #! Test if 'new' will be used before 'existing'.
+    over start>> '[ _ [ > ] find-use nip -1 or ] bi@ < ;
+
+: assign-blocked-register ( new -- )
+    [ dup vreg>> active-intervals-for ] keep interval-to-spill
+    2dup spill-existing? [ spill-existing ] [ spill-new ] if ;
+
diff --git a/basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor b/basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor
new file mode 100644 (file)
index 0000000..31c9332
--- /dev/null
@@ -0,0 +1,119 @@
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators fry hints kernel locals
+math sequences sets sorting splitting
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.allocation.splitting
+
+: split-range ( live-range n -- before after )
+    [ [ from>> ] dip <live-range> ]
+    [ 1 + swap to>> <live-range> ]
+    2bi ;
+
+: split-last-range? ( last n -- ? )
+    swap to>> <= ;
+
+: split-last-range ( before after last n -- before' after' )
+    split-range [ [ but-last ] dip suffix ] [ prefix ] bi-curry* bi* ;
+
+: split-ranges ( live-ranges n -- before after )
+    [ '[ from>> _ <= ] partition ]
+    [
+        pick empty? [ drop ] [
+            [ over last ] dip 2dup split-last-range?
+            [ split-last-range ] [ 2drop ] if
+        ] if
+    ] bi ;
+
+: split-uses ( uses n -- before after )
+    '[ _ <= ] partition ;
+
+: record-split ( live-interval before after -- )
+    [ >>split-next drop ]
+    [ [ >>split-before ] [ >>split-after ] bi* drop ]
+    2bi ; inline
+
+ERROR: splitting-atomic-interval ;
+
+: check-split ( live-interval -- )
+    [ end>> ] [ start>> ] bi - 0 =
+    [ splitting-atomic-interval ] when ; inline
+
+: split-before ( before -- before' )
+    f >>spill-to ; inline
+
+: split-after ( after -- after' )
+    f >>copy-from f >>reg f >>reload-from ; inline
+
+:: split-interval ( live-interval n -- before after )
+    live-interval check-split
+    live-interval clone :> before
+    live-interval clone :> after
+    live-interval uses>> n split-uses before after [ (>>uses) ] bi-curry@ bi*
+    live-interval ranges>> n split-ranges before after [ (>>ranges) ] bi-curry@ bi*
+    live-interval before after record-split
+    before split-before
+    after split-after ;
+
+HINTS: split-interval live-interval object ;
+
+: reuse-register ( new existing -- )
+    reg>> >>reg add-active ;
+
+: relevant-ranges ( new inactive -- new' inactive' )
+    ! Slice off all ranges of 'inactive' that precede the start of 'new'
+    [ [ ranges>> ] bi@ ] [ nip start>> ] 2bi '[ to>> _ >= ] filter ;
+
+: intersect-live-range ( range1 range2 -- n/f )
+    2dup [ from>> ] bi@ > [ swap ] when
+    2dup [ to>> ] [ from>> ] bi* >= [ nip from>> ] [ 2drop f ] if ;
+
+: intersect-live-ranges ( ranges1 ranges2 -- n )
+    {
+        { [ over empty? ] [ 2drop 1/0. ] }
+        { [ dup empty? ] [ 2drop 1/0. ] }
+        [
+            2dup [ first ] bi@ intersect-live-range dup [ 2nip ] [
+                drop
+                2dup [ first from>> ] bi@ <
+                [ [ rest-slice ] dip ] [ rest-slice ] if
+                intersect-live-ranges
+            ] if
+        ]
+    } cond ;
+
+: intersect-inactive ( new inactive active-regs -- n )
+    2dup [ reg>> ] dip key? [
+        2drop start>>
+    ] [
+        drop relevant-ranges intersect-live-ranges
+    ] if ;
+
+: intersecting-inactive ( new -- live-intervals )
+    dup vreg>>
+    [ inactive-intervals-for ]
+    [ active-intervals-for [ reg>> ] map unique ] bi
+    '[ tuck _ intersect-inactive ] with { } map>assoc ;
+
+: insert-use-for-copy ( seq n -- seq' )
+    [ 1array split1 ] keep [ 1 - ] keep 2array glue ;
+
+: split-before-use ( new n -- before after )
+    ! Find optimal split position
+    ! Insert move instruction
+    [ '[ _ insert-use-for-copy ] change-uses ] keep
+    1 - split-interval
+    2dup [ compute-start/end ] bi@ ;
+
+: assign-inactive-register ( new live-intervals -- )
+    ! If there is an interval which is inactive for the entire lifetime
+    ! if the new interval, reuse its vreg. Otherwise, split new so that
+    ! the first half fits.
+    sort-values last
+    2dup [ end>> ] [ second ] bi* < [
+        first reuse-register
+    ] [
+        [ second split-before-use ] keep
+       '[ _ first reuse-register ] [ add-unhandled ] bi*
+    ] if ;
\ No newline at end of file
diff --git a/basis/compiler/cfg/linear-scan/allocation/state/state.factor b/basis/compiler/cfg/linear-scan/allocation/state/state.factor
new file mode 100644 (file)
index 0000000..2a1e87d
--- /dev/null
@@ -0,0 +1,134 @@
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators cpu.architecture fry heaps
+kernel math namespaces sequences vectors
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.allocation.state
+
+! Mapping from register classes to sequences of machine registers
+SYMBOL: free-registers
+
+: free-registers-for ( vreg -- seq )
+    reg-class>> free-registers get at ;
+
+: deallocate-register ( live-interval -- )
+    [ reg>> ] [ vreg>> ] bi free-registers-for push ;
+
+! Vector of active live intervals
+SYMBOL: active-intervals
+
+: active-intervals-for ( vreg -- seq )
+    reg-class>> active-intervals get at ;
+
+: add-active ( live-interval -- )
+    dup vreg>> active-intervals-for push ;
+
+: delete-active ( live-interval -- )
+    dup vreg>> active-intervals-for delq ;
+
+: assign-free-register ( new registers -- )
+    pop >>reg add-active ;
+
+! Vector of inactive live intervals
+SYMBOL: inactive-intervals
+
+: inactive-intervals-for ( vreg -- seq )
+    reg-class>> inactive-intervals get at ;
+
+: add-inactive ( live-interval -- )
+    dup vreg>> inactive-intervals-for push ;
+
+! Vector of handled live intervals
+SYMBOL: handled-intervals
+
+: add-handled ( live-interval -- )
+    handled-intervals get push ;
+
+: finished? ( n live-interval -- ? ) end>> swap < ;
+
+: finish ( n live-interval -- keep? )
+    nip [ deallocate-register ] [ add-handled ] bi f ;
+
+SYMBOL: check-allocation?
+
+ERROR: register-already-used live-interval ;
+
+: check-activate ( live-interval -- )
+    check-allocation? get [
+        dup [ reg>> ] [ vreg>> active-intervals-for [ reg>> ] map ] bi member?
+        [ register-already-used ] [ drop ] if
+    ] [ drop ] if ;
+
+: activate ( n live-interval -- keep? )
+    dup check-activate
+    nip add-active f ;
+
+: deactivate ( n live-interval -- keep? )
+    nip add-inactive f ;
+
+: don't-change ( n live-interval -- keep? ) 2drop t ;
+
+! Moving intervals between active and inactive sets
+: process-intervals ( n symbol quots -- )
+    ! symbol stores an alist mapping register classes to vectors
+    [ get values ] dip '[ [ _ cond ] with filter-here ] with each ; inline
+
+: deactivate-intervals ( n -- )
+    ! Any active intervals which have ended are moved to handled
+    ! Any active intervals which cover the current position
+    ! are moved to inactive
+    active-intervals {
+        { [ 2dup finished? ] [ finish ] }
+        { [ 2dup covers? not ] [ deactivate ] }
+        [ don't-change ]
+    } process-intervals ;
+
+: activate-intervals ( n -- )
+    ! Any inactive intervals which have ended are moved to handled
+    ! Any inactive intervals which do not cover the current position
+    ! are moved to active
+    inactive-intervals {
+        { [ 2dup finished? ] [ finish ] }
+        { [ 2dup covers? ] [ activate ] }
+        [ don't-change ]
+    } process-intervals ;
+
+! Minheap of live intervals which still need a register allocation
+SYMBOL: unhandled-intervals
+
+! Start index of current live interval. We ensure that all
+! live intervals added to the unhandled set have a start index
+! strictly greater than ths one. This ensures that we can catch
+! infinite loop situations.
+SYMBOL: progress
+
+: check-progress ( live-interval -- )
+    start>> progress get <= [ "No progress" throw ] when ; inline
+
+: add-unhandled ( live-interval -- )
+    [ check-progress ]
+    [ dup start>> unhandled-intervals get heap-push ]
+    bi ;
+
+CONSTANT: reg-classes { int-regs double-float-regs }
+
+: reg-class-assoc ( quot -- assoc )
+    [ reg-classes ] dip { } map>assoc ; inline
+
+SYMBOL: spill-counts
+
+: next-spill-location ( reg-class -- n )
+    spill-counts get [ dup 1 + ] change-at ;
+
+: init-allocator ( registers -- )
+    [ reverse >vector ] assoc-map free-registers set
+    [ 0 ] reg-class-assoc spill-counts set
+    <min-heap> unhandled-intervals set
+    [ V{ } clone ] reg-class-assoc active-intervals set
+    [ V{ } clone ] reg-class-assoc inactive-intervals set
+    V{ } clone handled-intervals set
+    -1 progress set ;
+
+: init-unhandled ( live-intervals -- )
+    [ [ start>> ] keep ] { } map>assoc
+    unhandled-intervals get heap-push-all ;
\ No newline at end of file
diff --git a/basis/compiler/cfg/linear-scan/assignment/assignment-tests.factor b/basis/compiler/cfg/linear-scan/assignment/assignment-tests.factor
deleted file mode 100644 (file)
index 13c1783..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-USING: compiler.cfg.linear-scan.assignment tools.test ;
-IN: compiler.cfg.linear-scan.assignment.tests
-
-
index 6fcd6e757071f08dda0a468b8524abf99982593a..ff06fbfa9b57a867e37485cb6b8af33da94cb201 100644 (file)
@@ -7,20 +7,16 @@ compiler.cfg.def-use
 compiler.cfg.registers
 compiler.cfg.instructions
 compiler.cfg.linear-scan.allocation
+compiler.cfg.linear-scan.allocation.state
 compiler.cfg.linear-scan.live-intervals ;
 IN: compiler.cfg.linear-scan.assignment
 
-! A vector of live intervals. There is linear searching involved
-! but since we never have too many machine registers (around 30
-! at most) and we probably won't have that many live at any one
-! time anyway, it is not a problem to check each element.
-TUPLE: active-intervals seq ;
+! This contains both active and inactive intervals; any interval
+! such that start <= insn# <= end is in this set.
+SYMBOL: pending-intervals
 
 : add-active ( live-interval -- )
-    active-intervals get seq>> push ;
-
-: lookup-register ( vreg -- reg )
-    active-intervals get seq>> [ vreg>> = ] with find nip reg>> ;
+    pending-intervals get push ;
 
 ! Minheap of live intervals which still need a register allocation
 SYMBOL: unhandled-intervals
@@ -37,9 +33,11 @@ SYMBOL: spill-slots
 : spill-slots-for ( vreg -- assoc )
     reg-class>> spill-slots get at ;
 
+ERROR: already-spilled ;
+
 : record-spill ( live-interval -- )
     [ dup spill-to>> ] [ vreg>> spill-slots-for ] bi
-    2dup key? [ "BUG: Already spilled" throw ] [ set-at ] if ;
+    2dup key? [ already-spilled ] [ set-at ] if ;
 
 : insert-spill ( live-interval -- )
     [ reg>> ] [ vreg>> reg-class>> ] [ spill-to>> ] tri _spill ;
@@ -47,14 +45,27 @@ SYMBOL: spill-slots
 : handle-spill ( live-interval -- )
     dup spill-to>> [ [ record-spill ] [ insert-spill ] bi ] [ drop ] if ;
 
+: insert-copy ( live-interval -- )
+    [ split-next>> reg>> ]
+    [ reg>> ]
+    [ vreg>> reg-class>> ]
+    tri _copy ;
+
+: handle-copy ( live-interval -- )
+    dup [ spill-to>> not ] [ split-next>> ] bi and
+    [ insert-copy ] [ drop ] if ;
+
 : expire-old-intervals ( n -- )
-    active-intervals get
-    [ swap '[ end>> _ = ] partition ] change-seq drop
-    [ handle-spill ] each ;
+    [ pending-intervals get ] dip '[
+        dup end>> _ <
+        [ [ handle-spill ] [ handle-copy ] bi f ] [ drop t ] if
+    ] filter-here ;
+
+ERROR: already-reloaded ;
 
 : record-reload ( live-interval -- )
     [ reload-from>> ] [ vreg>> spill-slots-for ] bi
-    2dup key? [ delete-at ] [ "BUG: Already reloaded" throw ] if ;
+    2dup key? [ delete-at ] [ already-reloaded ] if ;
 
 : insert-reload ( live-interval -- )
     [ reg>> ] [ vreg>> reg-class>> ] [ reload-from>> ] tri _reload ;
@@ -73,39 +84,40 @@ SYMBOL: spill-slots
         ] [ 2drop ] if
     ] if ;
 
-GENERIC: assign-before ( insn -- )
+GENERIC: assign-registers-in-insn ( insn -- )
 
-GENERIC: assign-after ( insn -- )
+: register-mapping ( live-intervals -- alist )
+    [ [ vreg>> ] [ reg>> ] bi ] { } map>assoc ;
 
 : all-vregs ( insn -- vregs )
     [ defs-vregs ] [ temp-vregs ] [ uses-vregs ] tri 3append ;
 
-M: vreg-insn assign-before
-    active-intervals get seq>> over all-vregs '[ vreg>> _ member? ] filter
-    [ [ vreg>> ] [ reg>> ] bi ] { } map>assoc
-    >>regs drop ;
+: active-intervals ( insn -- intervals )
+    insn#>> pending-intervals get [ covers? ] with filter ;
 
-M: insn assign-before drop ;
+M: vreg-insn assign-registers-in-insn
+    dup [ active-intervals ] [ all-vregs ] bi
+    '[ vreg>> _ member? ] filter
+    register-mapping
+    >>regs drop ;
 
-: compute-live-registers ( -- regs )
-    active-intervals get seq>> [ [ vreg>> ] [ reg>> ] bi ] { } map>assoc ;
+: compute-live-registers ( insn -- regs )
+    active-intervals register-mapping ;
 
 : compute-live-spill-slots ( -- spill-slots )
     spill-slots get values [ values ] map concat
     [ [ vreg>> ] [ reload-from>> ] bi ] { } map>assoc ;
 
-M: ##gc assign-after
-    compute-live-registers >>live-registers
+M: ##gc assign-registers-in-insn
+    dup call-next-method
+    dup compute-live-registers >>live-registers
     compute-live-spill-slots >>live-spill-slots
     drop ;
 
-M: insn assign-after drop ;
-
-: <active-intervals> ( -- obj )
-    V{ } clone active-intervals boa ;
+M: insn assign-registers-in-insn drop ;
 
 : init-assignment ( live-intervals -- )
-    <active-intervals> active-intervals set
+    V{ } clone pending-intervals set
     <min-heap> unhandled-intervals set
     [ H{ } clone ] reg-class-assoc spill-slots set 
     init-unhandled ;
@@ -114,13 +126,15 @@ M: insn assign-after drop ;
     [
         [
             [
-                {
-                    [ insn#>> activate-new-intervals ]
-                    [ assign-before ]
-                    [ , ]
-                    [ insn#>> expire-old-intervals ]
-                    [ assign-after ]
-                } cleave
+                [
+                    insn#>>
+                    [ activate-new-intervals ]
+                    [ expire-old-intervals ]
+                    bi
+                ]
+                [ assign-registers-in-insn ]
+                [ , ]
+                tri
             ] each
         ] V{ } make
     ] change-instructions drop ;
index ccfc4a1ff76690bd32c441f3905594b06fff0e13..d851b67fc0109d0083eb8a42b6f541cee0702605 100644 (file)
@@ -1,17 +1,26 @@
 IN: compiler.cfg.linear-scan.tests
 USING: tools.test random sorting sequences sets hashtables assocs
-kernel fry arrays splitting namespaces math accessors vectors
+kernel fry arrays splitting namespaces math accessors vectors locals
 math.order grouping
 cpu.architecture
 compiler.cfg
 compiler.cfg.optimizer
 compiler.cfg.instructions
 compiler.cfg.registers
+compiler.cfg.liveness
+compiler.cfg.predecessors
+compiler.cfg.rpo
 compiler.cfg.linear-scan
 compiler.cfg.linear-scan.live-intervals
 compiler.cfg.linear-scan.allocation
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.allocation.splitting
+compiler.cfg.linear-scan.allocation.spilling
+compiler.cfg.linear-scan.assignment
 compiler.cfg.linear-scan.debugger ;
 
+check-allocation? on
+
 [
     { T{ live-range f 1 10 } T{ live-range f 15 15 } }
     { T{ live-range f 16 20 } }
@@ -118,32 +127,57 @@ compiler.cfg.linear-scan.debugger ;
        { end 5 }
        { uses V{ 0 1 5 } }
        { ranges V{ T{ live-range f 0 5 } } }
-    } 2 split-interval
+    } 2 split-for-spill [ f >>split-next ] bi@
+] unit-test
+
+[
+    T{ live-interval
+       { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+       { start 0 }
+       { end 0 }
+       { uses V{ 0 } }
+       { ranges V{ T{ live-range f 0 0 } } }
+    }
+    T{ live-interval
+       { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+       { start 1 }
+       { end 5 }
+       { uses V{ 1 5 } }
+       { ranges V{ T{ live-range f 1 5 } } }
+    }
+] [
+    T{ live-interval
+       { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+       { start 0 }
+       { end 5 }
+       { uses V{ 0 1 5 } }
+       { ranges V{ T{ live-range f 0 5 } } }
+    } 0 split-for-spill [ f >>split-next ] bi@
 ] unit-test
 
 [
     T{ live-interval
         { vreg T{ vreg { reg-class int-regs } { n 1 } } }
         { start 0 }
-        { end 0 }
-        { uses V{ 0 } }
-        { ranges V{ T{ live-range f 0 0 } } }
+        { end 4 }
+        { uses V{ 0 1 4 } }
+        { ranges V{ T{ live-range f 0 4 } } }
     }
     T{ live-interval
         { vreg T{ vreg { reg-class int-regs } { n 1 } } }
-        { start 1 }
+        { start 5 }
         { end 5 }
-        { uses V{ 5 } }
-        { ranges V{ T{ live-range f 1 5 } } }
+        { uses V{ 5 } }
+        { ranges V{ T{ live-range f 5 5 } } }
     }
 ] [
     T{ live-interval
-        { vreg T{ vreg { reg-class int-regs } { n 1 } } }
-        { start 0 }
-        { end 5 }
-        { uses V{ 0 1 5 } }
-         { ranges V{ T{ live-range f 0 5 } } }
-    } 0 split-interval
+       { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+       { start 0 }
+       { end 5 }
+       { uses V{ 0 1 5 } }
+       { ranges V{ T{ live-range f 0 5 } } }
+    } 5 split-before-use [ f >>split-next ] bi@
 ] unit-test
 
 [
@@ -1294,26 +1328,32 @@ USING: math.private compiler.cfg.debugger ;
 ! Spill slot liveness was computed incorrectly, leading to a FEP
 ! early in bootstrap on x86-32
 [ t ] [
-    T{ basic-block
-       { instructions
-         V{
-             T{ ##gc f V int-regs 6 V int-regs 7 }
-             T{ ##peek f V int-regs 0 D 0 }
-             T{ ##peek f V int-regs 1 D 1 }
-             T{ ##peek f V int-regs 2 D 2 }
-             T{ ##peek f V int-regs 3 D 3 }
-             T{ ##peek f V int-regs 4 D 4 }
-             T{ ##peek f V int-regs 5 D 5 }
-             T{ ##replace f V int-regs 0 D 1 }
-             T{ ##replace f V int-regs 1 D 2 }
-             T{ ##replace f V int-regs 2 D 3 }
-             T{ ##replace f V int-regs 3 D 4 }
-             T{ ##replace f V int-regs 4 D 5 }
-             T{ ##replace f V int-regs 5 D 0 }
-         }
-       }
-    } dup 1array { { int-regs V{ 0 1 2 3 } } } (linear-scan)
-    instructions>> first live-spill-slots>> empty?
+    [
+        H{ } clone live-ins set
+        H{ } clone live-outs set
+        H{ } clone phi-live-ins set
+        T{ basic-block
+           { id 12345 }
+           { instructions
+             V{
+                 T{ ##gc f V int-regs 6 V int-regs 7 }
+                 T{ ##peek f V int-regs 0 D 0 }
+                 T{ ##peek f V int-regs 1 D 1 }
+                 T{ ##peek f V int-regs 2 D 2 }
+                 T{ ##peek f V int-regs 3 D 3 }
+                 T{ ##peek f V int-regs 4 D 4 }
+                 T{ ##peek f V int-regs 5 D 5 }
+                 T{ ##replace f V int-regs 0 D 1 }
+                 T{ ##replace f V int-regs 1 D 2 }
+                 T{ ##replace f V int-regs 2 D 3 }
+                 T{ ##replace f V int-regs 3 D 4 }
+                 T{ ##replace f V int-regs 4 D 5 }
+                 T{ ##replace f V int-regs 5 D 0 }
+             }
+           }
+        } dup 1array { { int-regs V{ 0 1 2 3 } } } (linear-scan)
+        instructions>> first live-spill-slots>> empty?
+    ] with-scope
 ] unit-test
 
 [ f ] [
@@ -1373,5 +1413,388 @@ USING: math.private compiler.cfg.debugger ;
        { uses { 5 10 } }
        { ranges V{ T{ live-range f 5 10 } } }
     }
+    H{ }
     intersect-inactive
-] unit-test
\ No newline at end of file
+] unit-test
+
+! Bug in live spill slots calculation
+
+T{ basic-block
+   { id 205651 }
+   { number 0 }
+   { instructions V{ T{ ##prologue } T{ ##branch } } }
+} 0 set
+
+T{ basic-block
+   { id 205652 }
+   { number 1 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 703128 }
+            { loc D 1 }
+         }
+         T{ ##peek
+            { dst V int-regs 703129 }
+            { loc D 0 }
+         }
+         T{ ##copy
+            { dst V int-regs 703134 }
+            { src V int-regs 703128 }
+         }
+         T{ ##copy
+            { dst V int-regs 703135 }
+            { src V int-regs 703129 }
+         }
+         T{ ##compare-imm-branch
+            { src1 V int-regs 703128 }
+            { src2 5 }
+            { cc cc/= }
+         }
+     }
+   }
+} 1 set
+
+T{ basic-block
+   { id 205653 }
+   { number 2 }
+   { instructions
+     V{
+         T{ ##copy
+            { dst V int-regs 703134 }
+            { src V int-regs 703129 }
+         }
+         T{ ##copy
+            { dst V int-regs 703135 }
+            { src V int-regs 703128 }
+         }
+         T{ ##branch }
+     }
+   }
+} 2 set
+
+T{ basic-block
+   { id 205655 }
+   { number 3 }
+   { instructions
+     V{
+         T{ ##replace
+            { src V int-regs 703134 }
+            { loc D 0 }
+         }
+         T{ ##replace
+            { src V int-regs 703135 }
+            { loc D 1 }
+         }
+         T{ ##epilogue }
+         T{ ##return }
+     }
+   }
+} 3 set
+
+1 get 1vector 0 get (>>successors)
+2 get 3 get V{ } 2sequence 1 get (>>successors)
+3 get 1vector 2 get (>>successors)
+
+:: test-linear-scan-on-cfg ( regs -- )
+    [ ] [
+        cfg new 0 get >>entry
+        compute-predecessors
+        compute-liveness
+        reverse-post-order
+        { { int-regs regs } } (linear-scan)
+    ] unit-test ;
+
+{ 1 2 } test-linear-scan-on-cfg
+
+! Bug in inactive interval handling
+! [ rot dup [ -rot ] when ]
+T{ basic-block
+   { id 201486 }
+   { number 0 }
+   { instructions V{ T{ ##prologue } T{ ##branch } } }
+} 0 set
+    
+T{ basic-block
+   { id 201487 }
+   { number 1 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 689473 }
+            { loc D 2 }
+         }
+         T{ ##peek
+            { dst V int-regs 689474 }
+            { loc D 1 }
+         }
+         T{ ##peek
+            { dst V int-regs 689475 }
+            { loc D 0 }
+         }
+         T{ ##compare-imm-branch
+            { src1 V int-regs 689473 }
+            { src2 5 }
+            { cc cc/= }
+         }
+     }
+   }
+} 1 set
+
+T{ basic-block
+   { id 201488 }
+   { number 2 }
+   { instructions
+     V{
+         T{ ##copy
+            { dst V int-regs 689481 }
+            { src V int-regs 689475 }
+         }
+         T{ ##copy
+            { dst V int-regs 689482 }
+            { src V int-regs 689474 }
+         }
+         T{ ##copy
+            { dst V int-regs 689483 }
+            { src V int-regs 689473 }
+         }
+         T{ ##branch }
+     }
+   }
+} 2 set
+
+T{ basic-block
+   { id 201489 }
+   { number 3 }
+   { instructions
+     V{
+         T{ ##copy
+            { dst V int-regs 689481 }
+            { src V int-regs 689473 }
+         }
+         T{ ##copy
+            { dst V int-regs 689482 }
+            { src V int-regs 689475 }
+         }
+         T{ ##copy
+            { dst V int-regs 689483 }
+            { src V int-regs 689474 }
+         }
+         T{ ##branch }
+     }
+   }
+} 3 set
+
+T{ basic-block
+   { id 201490 }
+   { number 4 }
+   { instructions
+     V{
+         T{ ##replace
+            { src V int-regs 689481 }
+            { loc D 0 }
+         }
+         T{ ##replace
+            { src V int-regs 689482 }
+            { loc D 1 }
+         }
+         T{ ##replace
+            { src V int-regs 689483 }
+            { loc D 2 }
+         }
+         T{ ##epilogue }
+         T{ ##return }
+     }
+   }
+} 4 set
+
+: test-diamond ( -- )
+    1 get 1vector 0 get (>>successors)
+    2 get 3 get V{ } 2sequence 1 get (>>successors)
+    4 get 1vector 2 get (>>successors)
+    4 get 1vector 3 get (>>successors) ;
+
+test-diamond
+
+{ 1 2 3 4 } test-linear-scan-on-cfg
+
+! Similar to the above
+! [ swap dup [ rot ] when ]
+
+T{ basic-block
+   { id 201537 }
+   { number 0 }
+   { instructions V{ T{ ##prologue } T{ ##branch } } }
+} 0 set
+    
+T{ basic-block
+   { id 201538 }
+   { number 1 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 689600 }
+            { loc D 1 }
+         }
+         T{ ##peek
+            { dst V int-regs 689601 }
+            { loc D 0 }
+         }
+         T{ ##compare-imm-branch
+            { src1 V int-regs 689600 }
+            { src2 5 }
+            { cc cc/= }
+         }
+     }
+   }
+} 1 set
+    
+T{ basic-block
+   { id 201539 }
+   { number 2 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 689604 }
+            { loc D 2 }
+         }
+         T{ ##copy
+            { dst V int-regs 689607 }
+            { src V int-regs 689604 }
+         }
+         T{ ##copy
+            { dst V int-regs 689608 }
+            { src V int-regs 689600 }
+         }
+         T{ ##copy
+            { dst V int-regs 689610 }
+            { src V int-regs 689601 }
+         }
+         T{ ##branch }
+     }
+   }
+} 2 set
+    
+T{ basic-block
+   { id 201540 }
+   { number 3 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 689609 }
+            { loc D 2 }
+         }
+         T{ ##copy
+            { dst V int-regs 689607 }
+            { src V int-regs 689600 }
+         }
+         T{ ##copy
+            { dst V int-regs 689608 }
+            { src V int-regs 689601 }
+         }
+         T{ ##copy
+            { dst V int-regs 689610 }
+            { src V int-regs 689609 }
+         }
+         T{ ##branch }
+     }
+   }
+} 3 set
+    
+T{ basic-block
+   { id 201541 }
+   { number 4 }
+   { instructions
+     V{
+         T{ ##replace
+            { src V int-regs 689607 }
+            { loc D 0 }
+         }
+         T{ ##replace
+            { src V int-regs 689608 }
+            { loc D 1 }
+         }
+         T{ ##replace
+            { src V int-regs 689610 }
+            { loc D 2 }
+         }
+         T{ ##epilogue }
+         T{ ##return }
+     }
+   }
+} 4 set
+
+test-diamond
+
+{ 1 2 3 4 } test-linear-scan-on-cfg
+
+! compute-live-registers was inaccurate since it didn't take
+! lifetime holes into account
+
+T{ basic-block
+   { id 0 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 0 }
+            { loc D 0 }
+         }
+         T{ ##compare-imm-branch
+            { src1 V int-regs 0 }
+            { src2 5 }
+            { cc cc/= }
+         }
+     }
+   }
+} 0 set
+
+T{ basic-block
+   { id 1 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 1 }
+            { loc D 1 }
+         }
+         T{ ##copy
+            { dst V int-regs 2 }
+            { src V int-regs 1 }
+         }
+         T{ ##branch }
+     }
+   }
+} 1 set
+
+T{ basic-block
+   { id 2 }
+   { instructions
+     V{
+         T{ ##peek
+            { dst V int-regs 3 }
+            { loc D 2 }
+         }
+         T{ ##copy
+            { dst V int-regs 2 }
+            { src V int-regs 3 }
+         }
+         T{ ##branch }
+     }
+   }
+} 2 set
+
+T{ basic-block
+   { id 3 }
+   { instructions
+     V{
+         T{ ##replace
+            { src V int-regs 2 }
+            { loc D 0 }
+         }
+         T{ ##return }
+     }
+   }
+} 3 set
+
+test-diamond
+
+{ 1 2 3 4 } test-linear-scan-on-cfg
\ No newline at end of file
index ffa356bfc2687da311abea750f4244f79d399be4..3a0a7f877002d19ba3fc6d32e833ca928a368dab 100644 (file)
@@ -8,6 +8,7 @@ compiler.cfg.instructions
 compiler.cfg.linear-scan.numbering
 compiler.cfg.linear-scan.live-intervals
 compiler.cfg.linear-scan.allocation
+compiler.cfg.linear-scan.allocation.state
 compiler.cfg.linear-scan.assignment ;
 IN: compiler.cfg.linear-scan
 
index 546443b289c62cb86e7a55320e96bfd5b6b6a0da..b631834d79cc5472f8e259f946cdc7bb57d6597d 100644 (file)
@@ -11,10 +11,21 @@ C: <live-range> live-range
 
 TUPLE: live-interval
 vreg
-reg spill-to reload-from split-before split-after
+reg spill-to reload-from
+split-before split-after split-next
 start end ranges uses
 copy-from ;
 
+: covers? ( insn# live-interval -- ? )
+    ranges>> [ [ from>> ] [ to>> ] bi between? ] with any? ;
+
+: child-interval-at ( insn# interval -- interval' )
+    dup split-after>> [
+        2dup split-after>> start>> <
+        [ split-before>> ] [ split-after>> ] if
+        child-interval-at
+    ] [ nip ] if ;
+
 ERROR: dead-value-error vreg ;
 
 : shorten-range ( n live-interval -- )
@@ -46,11 +57,9 @@ ERROR: dead-value-error vreg ;
         V{ } clone >>ranges
         swap >>vreg ;
 
-: block-from ( -- n )
-    basic-block get instructions>> first insn#>> ;
+: block-from ( bb -- n ) instructions>> first insn#>> ;
 
-: block-to ( -- n )
-    basic-block get instructions>> last insn#>> ;
+: block-to ( bb -- n ) instructions>> last insn#>> ;
 
 M: live-interval hashcode*
     nip [ start>> ] [ end>> 1000 * ] bi + ;
@@ -74,7 +83,7 @@ M: insn compute-live-intervals* drop ;
 
 : handle-input ( n vreg live-intervals -- )
     live-interval
-    [ [ block-from ] 2dip add-range ] [ add-use ] 2bi ;
+    [ [ basic-block get block-from ] 2dip add-range ] [ add-use ] 2bi ;
 
 : handle-temp ( n vreg live-intervals -- )
     live-interval
@@ -98,7 +107,9 @@ M: ##copy-float compute-live-intervals*
     [ call-next-method ] [ record-copy ] bi ;
 
 : handle-live-out ( bb -- )
-    live-out keys block-from block-to live-intervals get '[
+    live-out keys
+    basic-block get [ block-from ] [ block-to ] bi
+    live-intervals get '[
         [ _ _ ] dip _ live-interval add-range
     ] each ;
 
diff --git a/basis/compiler/cfg/linear-scan/resolve/resolve.factor b/basis/compiler/cfg/linear-scan/resolve/resolve.factor
new file mode 100644 (file)
index 0000000..8996327
--- /dev/null
@@ -0,0 +1,34 @@
+! Copyright (C) 2009 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel math namespaces sequences
+compiler.cfg.linear-scan.live-intervals compiler.cfg.liveness ;
+IN: compiler.cfg.linear-scan.resolve
+
+: add-mapping ( from to -- )
+    2drop
+    ;
+
+: resolve-value-data-flow ( bb to vreg -- )
+    live-intervals get at
+    [ [ block-to ] dip child-interval-at ]
+    [ [ block-from ] dip child-interval-at ]
+    bi-curry bi* 2dup = [ 2drop ] [
+        add-mapping
+    ] if ;
+
+: resolve-mappings ( bb to -- )
+    2drop
+    ;
+
+: resolve-edge-data-flow ( bb to -- )
+    [ 2dup live-in [ resolve-value-data-flow ] with with each ]
+    [ resolve-mappings ]
+    2bi ; 
+
+: resolve-block-data-flow ( bb -- )
+    dup successors>> [
+        resolve-edge-data-flow
+    ] with each ;
+
+: resolve-data-flow ( rpo -- )
+    [ resolve-block-data-flow ] each ;
\ No newline at end of file
index 5be085ba5a19ea13462cbc6ad65aa84ef155b70b..54efc53bc424e0d055aaaf5501219a132c1c95cf 100644 (file)
@@ -7,4 +7,7 @@ IN: compiler.cfg.predecessors
     dup successors>> [ predecessors>> push ] with each ;
 
 : compute-predecessors ( cfg -- cfg' )
-    dup [ predecessors-step ] each-basic-block ;
+    [ [ V{ } clone >>predecessors drop ] each-basic-block ]
+    [ [ predecessors-step ] each-basic-block ]
+    [ ]
+    tri ;
index 7602295284cd98adb33474ff0a71d09e08fdbff7..a1583d2a5d6bd8488c6613fbc4212a7c515738c6 100755 (executable)
@@ -531,4 +531,10 @@ M: _reload generate-insn
         { double-float-regs [ %reload-float ] }
     } case ;
 
+M: _copy generate-insn
+    [ dst>> ] [ src>> ] [ class>> ] tri {
+        { int-regs [ %copy ] }
+        { double-float-regs [ %copy-float ] }
+    } case ;
+
 M: _spill-counts generate-insn drop ;