Fixing register allocator prspilling

db4
Slava Pestov 2008-10-19 01:10:21 -05:00
parent b3f30fb807
commit c0d89b061e
17 changed files with 519 additions and 151 deletions

View File

@ -329,8 +329,7 @@ M: #terminate emit-node
stack-frame new
swap
[ return>> return-size >>return ]
[ alien-parameters parameter-sizes drop >>params ] bi
dup [ params>> ] [ return>> ] bi + >>size ;
[ alien-parameters parameter-sizes drop >>params ] bi ;
: alien-stack-frame ( params -- )
<alien-stack-frame> ##stack-frame ;

View File

@ -1,6 +1,6 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors namespaces assocs sequences sets fry ;
USING: kernel arrays accessors namespaces assocs sequences sets fry ;
IN: compiler.cfg
TUPLE: cfg entry word label ;
@ -19,7 +19,7 @@ successors ;
V{ } clone >>instructions
V{ } clone >>successors ;
TUPLE: mr instructions word label ;
TUPLE: mr { instructions array } word label spill-counts ;
: <mr> ( instructions word label -- mr )
mr new

View File

@ -4,7 +4,7 @@ USING: kernel words sequences quotations namespaces io
accessors prettyprint prettyprint.config
compiler.tree.builder compiler.tree.optimizer
compiler.cfg.builder compiler.cfg.linearization
compiler.cfg.stack-frame ;
compiler.cfg.stack-frame compiler.cfg.linear-scan ;
IN: compiler.cfg.debugger
GENERIC: test-cfg ( quot -- cfgs )
@ -16,7 +16,7 @@ M: word test-cfg
[ build-tree-from-word nip optimize-tree ] keep build-cfg ;
: test-mr ( quot -- mrs )
test-cfg [ build-mr build-stack-frame ] map ;
test-cfg [ build-mr ] map ;
: mr. ( mrs -- )
[

View File

@ -19,10 +19,10 @@ INSN: ##inc-r { n integer } ;
! Subroutine calls
TUPLE: stack-frame
{ size integer }
{ params integer }
{ return integer }
{ total-size integer } ;
{ total-size integer }
spill-counts ;
INSN: ##stack-frame stack-frame ;
: ##simple-stack-frame ( -- ) T{ stack-frame } ##stack-frame ;
@ -125,8 +125,8 @@ M: _cond-branch uses-vregs src>> 1array ;
M: _if-intrinsic defs-vregs intrinsic-defs-vregs ;
M: _if-intrinsic uses-vregs intrinsic-uses-vregs ;
INSN: _spill-integer { src vreg } n ;
INSN: _reload-integer { dst vreg } n ;
INSN: _spill-float { src vreg } n ;
INSN: _reload-float { dst vreg } n ;
! These instructions operate on machine registers and not
! virtual registers
INSN: _spill src class n ;
INSN: _reload dst class n ;
INSN: _spill-counts counts ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2008 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
accessors vectors fry heaps cpu.architecture combinators
compiler.cfg.registers
compiler.cfg.linear-scan.live-intervals ;
IN: compiler.cfg.linear-scan.allocation
@ -24,25 +24,11 @@ SYMBOL: active-intervals
: delete-active ( live-interval -- )
active-intervals get delete ;
: expired-interval? ( n interval -- ? )
[ end>> ] [ start>> ] bi or > ;
: expire-old-intervals ( n -- )
active-intervals get
[ expired-interval? ] with partition
[ end>> > ] with partition
[ [ deallocate-register ] each ] [ active-intervals set ] bi* ;
: expire-old-uses ( n -- )
active-intervals get
swap '[
uses>> [
dup peek _ < [ pop* ] [ drop ] if
] unless-empty
] each ;
: update-state ( live-interval -- )
start>> [ expire-old-intervals ] [ expire-old-uses ] bi ;
! Minheap of live intervals which still need a register allocation
SYMBOL: unhandled-intervals
@ -64,8 +50,25 @@ SYMBOL: progress
[ [ start>> ] keep ] { } map>assoc
unhandled-intervals get heap-push-all ;
: assign-free-register ( live-interval registers -- )
pop >>reg add-active ;
! Splitting
: find-use ( live-interval n quot -- i elt )
[ uses>> ] 2dip curry find ; inline
: split-before ( live-interval i -- before )
[ clone dup uses>> ] dip
[ head >>uses ] [ 1- swap nth >>end ] 2bi ;
: split-after ( live-interval i -- after )
[ clone dup uses>> ] dip
[ tail >>uses ] [ swap nth >>start ] 2bi
f >>reg ;
: split-interval ( live-interval n -- before after )
[ drop ] [ [ > ] find-use drop ] 2bi
[ split-before ] [ split-after ] 2bi ;
: record-split ( live-interval before after -- )
[ >>split-before ] [ >>split-after ] bi* drop ;
! Spilling
SYMBOL: spill-counts
@ -73,37 +76,20 @@ SYMBOL: spill-counts
: next-spill-location ( reg-class -- n )
spill-counts get [ dup 1+ ] change-at ;
: interval-to-spill ( -- live-interval )
: interval-to-spill ( active-intervals current -- live-interval )
#! We spill the interval with the most distant use location.
active-intervals get
[ uses>> empty? not ] filter
unclip-slice [
[ [ uses>> peek ] bi@ > ] most
] reduce ;
: check-split ( live-interval -- )
[ start>> ] [ end>> ] bi = [ "Cannot split any further" throw ] when ;
: split-interval ( live-interval -- before after )
#! Split the live interval at the location of its first use.
#! 'Before' now starts and ends on the same instruction.
[ check-split ]
[ clone [ uses>> delete-all ] [ dup start>> >>end ] bi ]
[ clone f >>reg dup uses>> peek >>start ]
tri ;
: record-split ( live-interval before after -- )
[ >>split-before ] [ >>split-after ] bi* drop ;
start>> '[ dup _ [ >= ] find-use nip ] { } map>assoc
unclip-slice [ [ [ second ] bi@ > ] most ] reduce first ;
: assign-spill ( before after -- before after )
#! If it has been spilled already, reuse spill location.
USE: cpu.architecture ! XXX
over reload-from>>
[ int-regs next-spill-location ] unless*
[ over vreg>> reg-class>> next-spill-location ] unless*
tuck [ >>spill-to ] [ >>reload-from ] 2bi* ;
: split-and-spill ( live-interval -- before after )
dup split-interval [ record-split ] [ assign-spill ] 2bi ;
: split-and-spill ( new existing -- before after )
dup rot start>> split-interval
[ record-split ] [ assign-spill ] 2bi ;
: reuse-register ( new existing -- )
reg>> >>reg add-active ;
@ -114,30 +100,30 @@ SYMBOL: spill-counts
#! interval, then process the new interval and the tail end
#! of the existing interval again.
[ reuse-register ]
[ delete-active ]
[ split-and-spill [ drop ] [ add-unhandled ] bi* ] tri ;
[ nip delete-active ]
[ split-and-spill [ drop ] [ 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.
[ split-and-spill add-unhandled ] dip spill-existing ;
[ dup split-and-spill add-unhandled ] dip spill-existing ;
: spill-existing? ( new existing -- ? )
over uses>> empty? [ 2drop t ] [ [ uses>> peek ] bi@ < ] if ;
#! Test if 'new' will be used before 'existing'.
over start>> '[ _ [ > ] find-use nip -1 or ] bi@ < ;
: assign-blocked-register ( live-interval -- )
interval-to-spill
2dup spill-existing?
[ spill-existing ] [ spill-new ] if ;
: assign-blocked-register ( new -- )
[ active-intervals get ] keep interval-to-spill
2dup spill-existing? [ spill-existing ] [ spill-new ] if ;
: assign-register ( live-interval -- )
dup vreg>> free-registers-for [
assign-blocked-register
] [
assign-free-register
] if-empty ;
: assign-free-register ( new registers -- )
pop >>reg add-active ;
: assign-register ( new -- )
dup vreg>> free-registers-for
[ assign-blocked-register ] [ assign-free-register ] if-empty ;
! Main loop
: init-allocator ( registers -- )
@ -148,7 +134,10 @@ SYMBOL: spill-counts
-1 progress set ;
: handle-interval ( live-interval -- )
[ start>> progress set ] [ update-state ] [ assign-register ] tri ;
[ start>> progress set ]
[ start>> expire-old-intervals ]
[ assign-register ]
tri ;
: (allocate-registers) ( -- )
unhandled-intervals get [ handle-interval ] slurp-heap ;

View File

@ -35,13 +35,8 @@ SYMBOL: unhandled-intervals
[ add-unhandled ] each ;
: insert-spill ( live-interval -- )
[ reg>> ] [ spill-to>> ] [ vreg>> reg-class>> ] tri
over [
{
{ int-regs [ _spill-integer ] }
{ double-float-regs [ _spill-float ] }
} case
] [ 3drop ] if ;
[ reg>> ] [ vreg>> reg-class>> ] [ spill-to>> ] tri
dup [ _spill ] [ 3drop ] if ;
: expire-old-intervals ( n -- )
active-intervals get
@ -50,13 +45,8 @@ SYMBOL: unhandled-intervals
[ insert-spill ] each ;
: insert-reload ( live-interval -- )
[ reg>> ] [ reload-from>> ] [ vreg>> reg-class>> ] tri
over [
{
{ int-regs [ _reload-integer ] }
{ double-float-regs [ _reload-float ] }
} case
] [ 3drop ] if ;
[ reg>> ] [ vreg>> reg-class>> ] [ reload-from>> ] tri
dup [ _reload ] [ 3drop ] if ;
: activate-new-intervals ( n -- )
#! Any live intervals which start on the current instruction

View File

@ -7,49 +7,209 @@ compiler.cfg.instructions
compiler.cfg.registers
compiler.cfg.linear-scan
compiler.cfg.linear-scan.live-intervals
compiler.cfg.linear-scan.allocation
compiler.cfg.linear-scan.debugger ;
[ 7 ] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 2 } } }
{ start 0 }
{ end 10 }
{ uses V{ 0 1 3 7 10 } }
}
4 [ >= ] find-use nip
] unit-test
[ 4 ] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 2 } } }
{ start 0 }
{ end 10 }
{ uses V{ 0 1 3 4 10 } }
}
4 [ >= ] find-use nip
] unit-test
[ f ] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 2 } } }
{ start 0 }
{ end 10 }
{ uses V{ 0 1 3 4 10 } }
}
100 [ >= ] find-use nip
] unit-test
[
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 0 }
{ end 1 }
{ uses V{ 0 1 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 5 }
{ end 5 }
{ uses V{ 5 } }
}
] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 0 }
{ end 5 }
{ uses V{ 0 1 5 } }
} 2 split-interval
] unit-test
[
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 0 }
{ end 0 }
{ uses V{ 0 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 1 }
{ end 5 }
{ uses V{ 1 5 } }
}
] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 0 }
{ end 5 }
{ uses V{ 0 1 5 } }
} 0 split-interval
] unit-test
[
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 3 }
{ end 10 }
{ uses V{ 3 10 } }
}
] [
{
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 1 }
{ end 15 }
{ uses V{ 1 3 7 10 15 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 3 }
{ end 8 }
{ uses V{ 3 4 8 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 3 }
{ end 10 }
{ uses V{ 3 10 } }
}
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 5 }
{ end 5 }
{ uses V{ 5 } }
}
interval-to-spill
] unit-test
[ t ] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 5 }
{ end 15 }
{ uses V{ 5 10 15 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 1 }
{ end 20 }
{ uses V{ 1 20 } }
}
spill-existing?
] unit-test
[ f ] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 5 }
{ end 15 }
{ uses V{ 5 10 15 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 1 }
{ end 20 }
{ uses V{ 1 7 20 } }
}
spill-existing?
] unit-test
[ t ] [
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 5 }
{ end 5 }
{ uses V{ 5 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 1 }
{ end 20 }
{ uses V{ 1 7 20 } }
}
spill-existing?
] unit-test
[ ] [
{
T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
T{ live-interval { vreg T{ vreg { n 1 } { reg-class int-regs } } } { start 0 } { end 100 } { uses V{ 0 100 } } }
}
H{ { f { "A" } } }
H{ { int-regs { "A" } } }
check-linear-scan
] unit-test
[ ] [
{
T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 10 } { uses V{ 10 } } }
T{ live-interval { vreg T{ vreg { n 2 } } } { start 11 } { end 20 } { uses V{ 20 } } }
T{ live-interval { vreg T{ vreg { n 1 } { reg-class int-regs } } } { start 0 } { end 10 } { uses V{ 0 10 } } }
T{ live-interval { vreg T{ vreg { n 2 } { reg-class int-regs } } } { start 11 } { end 20 } { uses V{ 11 20 } } }
}
H{ { f { "A" } } }
H{ { int-regs { "A" } } }
check-linear-scan
] unit-test
[ ] [
{
T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
T{ live-interval { vreg T{ vreg { n 2 } } } { start 30 } { end 60 } { uses V{ 60 } } }
T{ live-interval { vreg T{ vreg { n 1 } { reg-class int-regs } } } { start 0 } { end 100 } { uses V{ 0 100 } } }
T{ live-interval { vreg T{ vreg { n 2 } { reg-class int-regs } } } { start 30 } { end 60 } { uses V{ 30 60 } } }
}
H{ { f { "A" } } }
H{ { int-regs { "A" } } }
check-linear-scan
] unit-test
[ ] [
{
T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
T{ live-interval { vreg T{ vreg { n 2 } } } { start 30 } { end 200 } { uses V{ 200 } } }
T{ live-interval { vreg T{ vreg { n 1 } { reg-class int-regs } } } { start 0 } { end 100 } { uses V{ 0 100 } } }
T{ live-interval { vreg T{ vreg { n 2 } { reg-class int-regs } } } { start 30 } { end 200 } { uses V{ 30 200 } } }
}
H{ { f { "A" } } }
H{ { int-regs { "A" } } }
check-linear-scan
] unit-test
[
{
T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
T{ live-interval { vreg T{ vreg { n 2 } } } { start 30 } { end 100 } { uses V{ 100 } } }
T{ live-interval { vreg T{ vreg { n 1 } { reg-class int-regs } } } { start 0 } { end 100 } { uses V{ 0 100 } } }
T{ live-interval { vreg T{ vreg { n 2 } { reg-class int-regs } } } { start 30 } { end 100 } { uses V{ 30 100 } } }
}
H{ { f { "A" } } }
H{ { int-regs { "A" } } }
check-linear-scan
] must-fail
@ -81,15 +241,15 @@ SYMBOL: max-uses
max-insns get [ dup ] H{ } map>assoc available set
[
live-interval new
swap f swap vreg boa >>vreg
swap int-regs swap vreg boa >>vreg
max-uses get random 2 max [ not-taken ] replicate natural-sort
unclip [ >vector >>uses ] [ >>start ] bi*
dup uses>> first >>end
[ >>uses ] [ first >>start ] bi
dup uses>> peek >>end
] map
] with-scope ;
: random-test ( num-intervals max-uses max-registers max-insns -- )
over >r random-live-intervals r> f associate check-linear-scan ;
over >r random-live-intervals r> int-regs associate check-linear-scan ;
[ ] [ 30 2 1 60 random-test ] unit-test
[ ] [ 60 2 2 60 random-test ] unit-test
@ -118,3 +278,29 @@ USING: math.private compiler.cfg.debugger ;
} clone
1array (linear-scan) first regs>> values all-equal?
] unit-test
[ 0 1 ] [
{
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 1 } } }
{ start 0 }
{ end 5 }
{ uses V{ 0 1 5 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 2 } } }
{ start 3 }
{ end 4 }
{ uses V{ 3 4 } }
}
T{ live-interval
{ vreg T{ vreg { reg-class int-regs } { n 3 } } }
{ start 2 }
{ end 6 }
{ uses V{ 2 4 6 } }
}
} [ clone ] map
H{ { int-regs { "A" "B" } } }
allocate-registers
first split-before>> [ start>> ] [ end>> ] bi
] unit-test

View File

@ -1,8 +1,9 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors namespaces
USING: kernel accessors namespaces make
cpu.architecture
compiler.cfg
compiler.cfg.instructions
compiler.cfg.linear-scan.live-intervals
compiler.cfg.linear-scan.allocation
compiler.cfg.linear-scan.assignment ;
@ -28,6 +29,10 @@ IN: compiler.cfg.linear-scan
: linear-scan ( mr -- mr' )
[
[ (linear-scan) ] change-instructions
! spill-counts get >>spill-counts
[
[
(linear-scan) %
spill-counts get _spill-counts
] { } make
] change-instructions
] with-scope ;

View File

@ -4,16 +4,20 @@ USING: namespaces kernel assocs accessors sequences math fry
compiler.cfg.instructions compiler.cfg.registers ;
IN: compiler.cfg.linear-scan.live-intervals
TUPLE: live-interval < identity-tuple
TUPLE: live-interval
vreg
reg spill-to reload-from split-before split-after
start end uses ;
: add-use ( n live-interval -- )
[ (>>end) ] [ uses>> push ] 2bi ;
: <live-interval> ( start vreg -- live-interval )
live-interval new
V{ } clone >>uses
swap >>vreg
swap >>start
V{ } clone >>uses ;
over >>start
[ add-use ] keep ;
M: live-interval hashcode*
nip [ start>> ] [ end>> 1000 * ] bi + ;
@ -24,25 +28,18 @@ M: live-interval clone
! Mapping from vreg to live-interval
SYMBOL: live-intervals
: add-use ( n vreg live-intervals -- )
at [ (>>end) ] [ uses>> push ] 2bi ;
: new-live-interval ( n vreg live-intervals -- )
2dup key? [ "Multiple defs" throw ] when
[ [ <live-interval> ] keep ] dip set-at ;
: compute-live-intervals* ( insn n -- )
live-intervals get
[ [ uses-vregs ] 2dip '[ _ swap _ add-use ] each ]
[ [ uses-vregs ] 2dip '[ _ swap _ at add-use ] each ]
[ [ defs-vregs ] 2dip '[ _ swap _ new-live-interval ] each ]
3bi ;
: finalize-live-intervals ( assoc -- seq' )
#! Reverse uses lists so that we can pop values off.
values dup [ uses>> reverse-here ] each ;
: compute-live-intervals ( instructions -- live-intervals )
H{ } clone [
live-intervals set
[ compute-live-intervals* ] each-index
] keep finalize-live-intervals ;
] keep values ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces accessors math.order assocs kernel sequences
combinators make compiler.cfg.instructions
combinators make cpu.architecture compiler.cfg.instructions
compiler.cfg.instructions.syntax compiler.cfg.registers ;
IN: compiler.cfg.stack-frame
@ -9,35 +9,31 @@ SYMBOL: frame-required?
SYMBOL: spill-counts
: init-stack-frame-builder ( -- )
frame-required? off
T{ stack-frame } clone stack-frame set ;
GENERIC: compute-stack-frame* ( insn -- )
: max-stack-frame ( frame1 frame2 -- frame3 )
{
[ [ size>> ] bi@ max ]
[ [ params>> ] bi@ max ]
[ [ return>> ] bi@ max ]
[ [ total-size>> ] bi@ max ]
} 2cleave
stack-frame boa ;
[ stack-frame new ] 2dip
[ [ params>> ] bi@ max >>params ]
[ [ return>> ] bi@ max >>return ]
2bi ;
M: ##stack-frame compute-stack-frame*
frame-required? on
stack-frame>> stack-frame [ max-stack-frame ] change ;
M: _spill-integer compute-stack-frame*
M: _spill compute-stack-frame*
drop frame-required? on ;
M: _spill-float compute-stack-frame*
drop frame-required? on ;
M: _spill-counts compute-stack-frame*
counts>> stack-frame get (>>spill-counts) ;
M: insn compute-stack-frame* drop ;
: compute-stack-frame ( insns -- )
[ compute-stack-frame* ] each ;
frame-required? off
T{ stack-frame } clone stack-frame set
[ compute-stack-frame* ] each
stack-frame get dup stack-frame-size >>total-size drop ;
GENERIC: insert-pro/epilogues* ( insn -- )
@ -56,7 +52,6 @@ M: insn insert-pro/epilogues* , ;
: build-stack-frame ( mr -- mr )
[
init-stack-frame-builder
[
[ compute-stack-frame ]
[ insert-pro/epilogues ]

View File

@ -0,0 +1,23 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler.cfg.value-numbering.expressions
! Referentially-transparent expressions.
TUPLE: expr op ;
! op is always %peek
TUPLE: peek-expr < expr loc ;
TUPLE: unary-expr < expr in ;
TUPLE: load-literal-expr < expr obj ;
GENERIC: >expr ( insn -- expr )
M: ##peek >expr
[ class ] [ loc>> ] bi peek-expr boa ;
M: ##load-literal >expr
[ class ] [ obj>> ] bi load-literal-expr boa ;
M: ##unary >expr
[ class ] [ src>> vreg>vn ] bi unary-expr boa ;

View File

@ -0,0 +1,32 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler.cfg.value-numbering.graph
SYMBOL: vn-counter
: next-vn ( -- vn ) vn-counter [ dup 1 + ] change ;
! biassoc mapping expressions to value numbers
SYMBOL: exprs>vns
: expr>vn ( expr -- vn ) exprs>vns get [ drop next-vn ] cache ;
: vn>expr ( vn -- expr ) exprs>vns get value-at ;
! biassoc mapping vregs to value numbers
SYMBOL: vregs>vns
: vreg>vn ( vreg -- vn ) vregs>vns get at ;
: vn>vreg ( vn -- vreg ) vregs>vns get value-at ;
: set-vn ( vn vreg -- ) vregs>vns get set-at ;
: init-value-graph ( -- )
0 vn-counter set
<bihash> exprs>vns set
<bihash> vregs>vns set ;
: reset-value-graph ( -- )
exprs>vns get clear-assoc
vregs>vns get clear-assoc ;

View File

@ -0,0 +1,38 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler.cfg.value-numbering.liveness
! A set of VNs which are (transitively) used by side-effecting
! instructions.
SYMBOL: live-vns
GENERIC: live-expr ( expr -- )
: live-vn ( vn -- )
#! Mark a VN and all VNs used in its computation as live.
dup live-vns get key? [ drop ] [
[ live-vns get conjoin ] [ vn>expr live-expr ] bi
] if ;
M: peek-expr live-expr drop ;
M: unary-expr live-expr in>> live-vn ;
M: load-literal-expr live-expr in>> live-vn ;
: live-vreg ( vreg -- ) vreg>vn live-vn ;
: live? ( vreg -- ? )
dup vreg>vn tuck vn>vreg =
[ live-vns get key? ] [ drop f ] if ;
: init-liveness ( -- )
H{ } clone live-vns set ;
GENERIC: eliminate ( insn -- insn/f )
: (eliminate) ( insn -- insn/f )
dup dst>> >vreg live? [ drop f ] unless ;
M: ##peek eliminate (eliminate) ;
M: ##unary eliminate (eliminate) ;
M: ##load-literal eliminate (eliminate) ;
M: insn eliminate ;

View File

@ -0,0 +1,58 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler.cfg.value-numbering.propagate
! If two vregs compute the same value, replace references to
! the latter with the former.
: resolve ( vreg -- vreg' ) vreg>vn vn>vreg ;
GENERIC: propogate ( insn -- insn )
M: ##cond-branch propagate [ resolve ] change-src ;
M: ##unary propogate [ resolve ] change-src ;
M: ##nullary propagate ;
M: ##replace propagate [ resolve ] change-src ;
M: ##inc-d propagate ;
M: ##inc-r propagate ;
M: ##stack-frame propagate ;
M: ##call propagate ;
M: ##jump propagate ;
M: ##return propagate ;
M: ##intrinsic propagate
[ [ resolve ] assoc-map ] change-defs-vregs
[ [ resolve ] assoc-map ] change-uses-vregs ;
M: ##dispatch propagate [ resolve ] change-src ;
M: ##dispatch-label propagate ;
M: ##write-barrier propagate [ resolve ] change-src ;
M: ##alien-invoke propagate ;
M: ##alien-indirect propagate ;
M: ##alien-callback propagate ;
M: ##callback-return propagate ;
M: ##prologue propagate ;
M: ##epilogue propagate ;
M: ##branch propagate ;
M: ##if-intrinsic propagate
[ [ resolve ] assoc-map ] change-defs-vregs
[ [ resolve ] assoc-map ] change-uses-vregs ;

View File

@ -0,0 +1,46 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler.cfg.value-numbering
: insn>vn ( insn -- vn ) >expr simplify ; inline
GENERIC: make-value-node ( insn -- )
M: ##cond-branch make-value-node src>> live-vreg ;
M: ##unary make-value-node [ insn>vn ] [ dst>> ] bi set-vn ;
M: ##nullary make-value-node drop ;
M: ##load-literal make-value-node [ insn>vn ] [ dst>> ] bi set-vn ;
M: ##peek make-value-node [ insn>vn ] [ dst>> ] bi set-vn ;
M: ##replace make-value-node reset-value-graph ;
M: ##inc-d make-value-node reset-value-graph ;
M: ##inc-r make-value-node reset-value-graph ;
M: ##stack-frame make-value-node reset-value-graph ;
M: ##call make-value-node reset-value-graph ;
M: ##jump make-value-node reset-value-graph ;
M: ##return make-value-node reset-value-graph ;
M: ##intrinsic make-value-node uses-vregs [ live-vreg ] each ;
M: ##dispatch make-value-node reset-value-graph ;
M: ##dispatch-label make-value-node reset-value-graph ;
M: ##allot make-value-node drop ;
M: ##write-barrier make-value-node drop ;
M: ##gc make-value-node reset-value-graph ;
M: ##replace make-value-node reset-value-graph ;
M: ##alien-invoke make-value-node reset-value-graph ;
M: ##alien-indirect make-value-node reset-value-graph ;
M: ##alien-callback make-value-node reset-value-graph ;
M: ##callback-return make-value-node reset-value-graph ;
M: ##prologue make-value-node reset-value-graph ;
M: ##epilogue make-value-node reset-value-graph ;
M: ##branch make-value-node reset-value-graph ;
M: ##if-intrinsic make-value-node uses-vregs [ live-vreg ] each ;
: init-value-numbering ( -- )
init-value-graph
init-expressions
init-liveness ;
: value-numbering ( instructions -- instructions )
init-value-numbering
[ [ make-value-node ] [ propagate ] bi ] map
[ eliminate ] map
sift ;

View File

@ -72,11 +72,7 @@ M: _label generate-insn
id>> lookup-label , ;
M: _prologue generate-insn
stack-frame>>
[ stack-frame set ]
[ dup size>> stack-frame-size >>total-size drop ]
[ total-size>> %prologue ]
tri ;
stack-frame>> [ stack-frame set ] [ total-size>> %prologue ] bi ;
M: _epilogue generate-insn
stack-frame>> total-size>> %epilogue ;
@ -439,3 +435,17 @@ M: ##alien-callback generate-insn
[ wrap-callback-quot %alien-callback ]
[ alien-return [ %unnest-stacks ] [ %callback-value ] if-void ]
tri ;
M: _spill generate-insn
[ src>> ] [ n>> ] [ class>> ] tri {
{ int-regs [ %spill-integer ] }
{ double-float-regs [ %spill-float ] }
} case ;
M: _reload generate-insn
[ dst>> ] [ n>> ] [ class>> ] tri {
{ int-regs [ %reload-integer ] }
{ double-float-regs [ %reload-float ] }
} case ;
M: _spill-counts generate-insn drop ;

View File

@ -61,18 +61,6 @@ SYMBOL: +failed+
: frontend ( word -- effect nodes )
[ build-tree-from-word ] [ fail ] recover optimize-tree ;
: finish ( effect word -- )
[ swap save-effect ]
[ compiled-unxref ]
[
dup crossref?
[
dependencies get >alist
generic-dependencies get >alist
compiled-xref
] [ drop ] if
] tri ;
! Only switch this off for debugging.
SYMBOL: compile-dependencies?
@ -92,6 +80,18 @@ t compile-dependencies? set-global
save-asm
] each ;
: finish ( effect word -- )
[ swap save-effect ]
[ compiled-unxref ]
[
dup crossref?
[
dependencies get >alist
generic-dependencies get >alist
compiled-xref
] [ drop ] if
] tri ;
: (compile) ( word -- )
'[
_ {