1 ! Copyright (C) 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays accessors assocs combinators cpu.architecture fry
4 heaps kernel math math.order namespaces sequences vectors
5 linked-assocs compiler.cfg compiler.cfg.registers
6 compiler.cfg.instructions
7 compiler.cfg.linear-scan.live-intervals ;
8 IN: compiler.cfg.linear-scan.allocation.state
10 ! Start index of current live interval. We ensure that all
11 ! live intervals added to the unhandled set have a start index
12 ! strictly greater than this one. This ensures that we can catch
13 ! infinite loop situations. We also ensure that all live
14 ! intervals added to the handled set have an end index strictly
15 ! smaller than this one. This helps catch bugs.
18 : check-unhandled ( live-interval -- )
19 start>> progress get <= [ "check-unhandled" throw ] when ; inline
21 : check-handled ( live-interval -- )
22 end>> progress get > [ "check-handled" throw ] when ; inline
24 ! Mapping from register classes to sequences of machine registers
27 ! Vector of active live intervals
28 SYMBOL: active-intervals
30 : active-intervals-for ( live-interval -- seq )
31 reg-class>> active-intervals get at ;
33 : add-active ( live-interval -- )
34 dup active-intervals-for push ;
36 : delete-active ( live-interval -- )
37 dup active-intervals-for remove-eq! drop ;
39 : assign-free-register ( new registers -- )
40 pop >>reg add-active ;
42 ! Vector of inactive live intervals
43 SYMBOL: inactive-intervals
45 : inactive-intervals-for ( live-interval -- seq )
46 reg-class>> inactive-intervals get at ;
48 : add-inactive ( live-interval -- )
49 dup inactive-intervals-for push ;
51 : delete-inactive ( live-interval -- )
52 dup inactive-intervals-for remove-eq! drop ;
54 ! Vector of handled live intervals
55 SYMBOL: handled-intervals
57 : add-handled ( live-interval -- )
58 [ check-handled ] [ handled-intervals get push ] bi ;
60 : finished? ( n live-interval -- ? ) end>> swap < ;
62 : finish ( n live-interval -- keep? )
65 SYMBOL: check-allocation?
67 ERROR: register-already-used live-interval ;
69 : check-activate ( live-interval -- )
70 check-allocation? get [
71 dup [ reg>> ] [ active-intervals-for [ reg>> ] map ] bi member?
72 [ register-already-used ] [ drop ] if
75 : activate ( n live-interval -- keep? )
79 : deactivate ( n live-interval -- keep? )
82 : don't-change ( n live-interval -- keep? ) 2drop t ;
84 ! Moving intervals between active and inactive sets
85 : process-intervals ( n symbol quots -- )
86 ! symbol stores an alist mapping register classes to vectors
87 [ get values ] dip '[ [ _ cond ] with filter! drop ] with each ; inline
89 : deactivate-intervals ( n -- )
90 ! Any active intervals which have ended are moved to handled
91 ! Any active intervals which cover the current position
92 ! are moved to inactive
94 { [ 2dup finished? ] [ finish ] }
95 { [ 2dup covers? not ] [ deactivate ] }
99 : activate-intervals ( n -- )
100 ! Any inactive intervals which have ended are moved to handled
101 ! Any inactive intervals which do not cover the current position
102 ! are moved to active
104 { [ 2dup finished? ] [ finish ] }
105 { [ 2dup covers? ] [ activate ] }
107 } process-intervals ;
109 ! Minheap of live intervals which still need a register allocation
110 SYMBOL: unhandled-intervals
112 : add-unhandled ( live-interval -- )
114 [ dup start>> unhandled-intervals get heap-push ]
117 : reg-class-assoc ( quot -- assoc )
118 [ reg-classes ] dip { } map>assoc ; inline
120 : next-spill-slot ( size -- n )
122 [ swap [ align dup ] [ + ] bi ] change-spill-area-size drop
125 ! Minheap of sync points which still need to be processed
126 SYMBOL: unhandled-sync-points
128 ! Mapping from vregs to spill slots
131 : assign-spill-slot ( coalesced-vreg rep -- spill-slot )
132 rep-size spill-slots get [ nip next-spill-slot ] 2cache ;
134 : lookup-spill-slot ( coalesced-vreg rep -- spill-slot )
135 rep-size 2array spill-slots get ?at [ ] [ bad-vreg ] if ;
137 : init-allocator ( registers -- )
139 <min-heap> unhandled-intervals set
140 <min-heap> unhandled-sync-points set
141 [ V{ } clone ] reg-class-assoc active-intervals set
142 [ V{ } clone ] reg-class-assoc inactive-intervals set
143 V{ } clone handled-intervals set
144 cfg get 0 >>spill-area-size drop
145 H{ } clone spill-slots set
148 : init-unhandled ( live-intervals sync-points -- )
149 [ [ [ start>> ] keep ] { } map>assoc unhandled-intervals get heap-push-all ]
150 [ [ [ n>> ] keep ] { } map>assoc unhandled-sync-points get heap-push-all ]
153 ! A utility used by register-status and spill-status words
154 : free-positions ( new -- assoc )
155 reg-class>> registers get at
156 [ 1/0. ] H{ } <linked-assoc> map>assoc ;
158 : add-use-position ( n reg assoc -- ) [ [ min ] when* ] change-at ;
160 : register-available? ( new result -- ? )
161 [ end>> ] [ second ] bi* < ; inline
163 : register-available ( new result -- )
164 first >>reg add-active ;