1 ! Copyright (C) 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs combinators cpu.architecture fry heaps
4 kernel math math.order namespaces sequences vectors
5 linked-assocs compiler.cfg compiler.cfg.registers
6 compiler.cfg.instructions compiler.cfg.linear-scan.live-intervals ;
7 IN: compiler.cfg.linear-scan.allocation.state
9 ! Start index of current live interval. We ensure that all
10 ! live intervals added to the unhandled set have a start index
11 ! strictly greater than this one. This ensures that we can catch
12 ! infinite loop situations. We also ensure that all live
13 ! intervals added to the handled set have an end index strictly
14 ! smaller than this one. This helps catch bugs.
17 : check-unhandled ( live-interval -- )
18 start>> progress get <= [ "check-unhandled" throw ] when ; inline
20 : check-handled ( live-interval -- )
21 end>> progress get > [ "check-handled" throw ] when ; inline
23 ! Mapping from register classes to sequences of machine registers
26 ! Vector of active live intervals
27 SYMBOL: active-intervals
29 : active-intervals-for ( vreg -- seq )
30 rep-of reg-class-of active-intervals get at ;
32 : add-active ( live-interval -- )
33 dup vreg>> active-intervals-for push ;
35 : delete-active ( live-interval -- )
36 dup vreg>> active-intervals-for delq ;
38 : assign-free-register ( new registers -- )
39 pop >>reg add-active ;
41 ! Vector of inactive live intervals
42 SYMBOL: inactive-intervals
44 : inactive-intervals-for ( vreg -- seq )
45 rep-of reg-class-of inactive-intervals get at ;
47 : add-inactive ( live-interval -- )
48 dup vreg>> inactive-intervals-for push ;
50 : delete-inactive ( live-interval -- )
51 dup vreg>> inactive-intervals-for delq ;
53 ! Vector of handled live intervals
54 SYMBOL: handled-intervals
56 : add-handled ( live-interval -- )
57 [ check-handled ] [ handled-intervals get push ] bi ;
59 : finished? ( n live-interval -- ? ) end>> swap < ;
61 : finish ( n live-interval -- keep? )
64 SYMBOL: check-allocation?
66 ERROR: register-already-used live-interval ;
68 : check-activate ( live-interval -- )
69 check-allocation? get [
70 dup [ reg>> ] [ vreg>> active-intervals-for [ reg>> ] map ] bi member?
71 [ register-already-used ] [ drop ] if
74 : activate ( n live-interval -- keep? )
78 : deactivate ( n live-interval -- keep? )
81 : don't-change ( n live-interval -- keep? ) 2drop t ;
83 ! Moving intervals between active and inactive sets
84 : process-intervals ( n symbol quots -- )
85 ! symbol stores an alist mapping register classes to vectors
86 [ get values ] dip '[ [ _ cond ] with filter-here ] with each ; inline
88 : deactivate-intervals ( n -- )
89 ! Any active intervals which have ended are moved to handled
90 ! Any active intervals which cover the current position
91 ! are moved to inactive
93 { [ 2dup finished? ] [ finish ] }
94 { [ 2dup covers? not ] [ deactivate ] }
98 : activate-intervals ( n -- )
99 ! Any inactive intervals which have ended are moved to handled
100 ! Any inactive intervals which do not cover the current position
101 ! are moved to active
103 { [ 2dup finished? ] [ finish ] }
104 { [ 2dup covers? ] [ activate ] }
106 } process-intervals ;
108 ! Minheap of live intervals which still need a register allocation
109 SYMBOL: unhandled-intervals
111 : add-unhandled ( live-interval -- )
113 [ dup start>> unhandled-intervals get heap-push ]
116 : reg-class-assoc ( quot -- assoc )
117 [ reg-classes ] dip { } map>assoc ; inline
119 : next-spill-slot ( rep -- n )
121 [ swap [ align dup ] [ + ] bi ] change-spill-area-size drop
124 ! Minheap of sync points which still need to be processed
125 SYMBOL: unhandled-sync-points
127 ! Mapping from vregs to spill slots
130 : vreg-spill-slot ( vreg -- spill-slot )
131 spill-slots get [ rep-of next-spill-slot ] cache ;
133 : init-allocator ( registers -- )
135 <min-heap> unhandled-intervals set
136 <min-heap> unhandled-sync-points set
137 [ V{ } clone ] reg-class-assoc active-intervals set
138 [ V{ } clone ] reg-class-assoc inactive-intervals set
139 V{ } clone handled-intervals set
140 cfg get 0 >>spill-area-size drop
141 H{ } clone spill-slots set
144 : init-unhandled ( live-intervals sync-points -- )
145 [ [ [ start>> ] keep ] { } map>assoc unhandled-intervals get heap-push-all ]
146 [ [ [ n>> ] keep ] { } map>assoc unhandled-sync-points get heap-push-all ]
149 ! A utility used by register-status and spill-status words
150 : free-positions ( new -- assoc )
151 vreg>> rep-of reg-class-of registers get at
152 [ 1/0. ] H{ } <linked-assoc> map>assoc ;
154 : add-use-position ( n reg assoc -- ) [ [ min ] when* ] change-at ;
156 : register-available? ( new result -- ? )
157 [ end>> ] [ second ] bi* < ; inline
159 : register-available ( new result -- )
160 first >>reg add-active ;