Paste: register allocator
Author: | slava |
Mode: | factor |
Date: | Mon, 15 Sep 2008 06:51:41 |
Plain Text |
USING: namespaces sequences math math.order kernel assocs
accessors vectors fry heaps
compiler.cfg.linear-scan.live-intervals
compiler.backend ;
IN: compiler.cfg.linear-scan.allocation
SYMBOL: retired-intervals
: retire-interval ( live-interval -- )
retired-intervals get push ;
: retire-intervals ( live-intervals -- )
retired-intervals get push-all ;
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 ;
SYMBOL: active-intervals
: add-active ( live-interval -- )
active-intervals get push ;
: delete-active ( live-interval -- )
active-intervals get delete ;
: expire-old-intervals ( n -- )
active-intervals get
swap '[ end>> _ < ] partition
active-intervals set
[ [ retire-interval ] [ deallocate-register ] bi ] each ;
: expire-old-uses ( n -- )
active-intervals get
swap '[ uses>> dup peek _ < [ pop* ] [ drop ] if ] each ;
: update-state ( live-interval -- )
start>> [ expire-old-intervals ] [ expire-old-uses ] bi ;
SYMBOL: unhandled-intervals
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 ;
: assign-free-register ( live-interval registers -- )
over uses>> empty?
[ peek >>reg drop ] [ pop >>reg add-active ] if ;
SYMBOL: spill-counter
: next-spill-location ( -- n )
spill-counter [ dup 1+ ] change ;
: interval-to-spill ( -- live-interval )
active-intervals get 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 )
[ 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 ;
: assign-spill ( before after -- before after )
over reload-from>> [ 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 ;
: reuse-register ( new existing -- )
reg>> >>reg
dup uses>> empty? [
[ retire-interval ] [ deallocate-register ] bi
] [ add-active ] if ;
: spill-existing ( new existing -- )
[ reuse-register ]
[ delete-active ]
[
split-and-spill
[ retire-interval ]
[ add-unhandled ]
bi*
] tri ;
: spill-new ( new existing -- )
[ split-and-spill add-unhandled ] dip spill-existing ;
: spill-existing? ( new existing -- ? )
over uses>> empty? [ 2drop t ] [ [ uses>> peek ] bi@ < ] if ;
: assign-blocked-register ( live-interval -- )
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 ;
: slurp-heap ( heap quot: ( elt -- ) -- )
over heap-empty? [ 2drop ] [
[ [ heap-pop drop ] dip call ] [ slurp-heap ] 2bi
] if ; inline recursive
: init-allocator ( registers -- )
V{ } clone retired-intervals set
V{ } clone active-intervals set
<min-heap> unhandled-intervals set
[ >vector ] assoc-map free-registers set
0 spill-counter set
-1 progress set ;
: handle-interval ( live-interval -- )
[ start>> progress set ] [ update-state ] [ assign-register ] tri ;
: (allocate-registers) ( -- )
unhandled-intervals get [ handle-interval ] slurp-heap ;
: finish-allocator ( -- live-intervals )
active-intervals get retire-intervals
retired-intervals get ;
: allocate-registers ( live-intervals machine-registers -- live-intervals' )
[
init-allocator
init-unhandled
(allocate-registers)
finish-allocator
] with-scope ;
New Annotation