1 ;; address after which memory is allocated by the user, therefore not used for
3 ;; in programs, located in the SIXPIC_MEMORY_DIVIDE variable
4 (define memory-divide #f)
6 ;; the vector equivalent to all-byte-cells
8 (define (id->byte-cell id) (vector-ref byte-cells id))
10 (define (interference-graph cfg)
12 (define (analyze-liveness cfg)
14 (define (instr-analyze-liveness instr live-after)
19 (let ((def-proc (call-instr-def-proc instr)))
20 (if (and (not (bitset-empty? live-after))
22 (def-procedure-live-after-calls def-proc)
26 (bitset-union! (def-procedure-live-after-calls def-proc)
35 (map (lambda (x) (byte-cell-id x))
37 (def-procedure-value def-proc)))))
38 ,(bb-live-before (def-procedure-entry def-proc))
39 ,@(map (lambda (def-var)
42 (map (lambda (x) (byte-cell-id x))
44 (def-variable-value def-var)))))
45 (def-procedure-params def-proc))))))
46 (if (bb? (def-procedure-entry def-proc))
48 (bb-live-before (def-procedure-entry def-proc))
52 ((return-instr? instr)
53 (let* ((def-proc (return-instr-def-proc instr))
55 (if (def-procedure? def-proc)
56 (def-procedure-live-after-calls def-proc)
57 (list->bitset byte-cell-counter
58 (map (lambda (x) (byte-cell-id x))
59 (value-bytes def-proc))))))
60 (set! live-after live)
64 (let* ((src1 (instr-src1 instr))
65 (src2 (instr-src2 instr))
66 (dst (instr-dst instr))
67 (s (bitset-copy live-after)))
68 (define (add-if-byte-cell c)
70 (bitset-add! s (byte-cell-id c))))
71 (define (remove-if-byte-cell c)
73 (bitset-remove! s (byte-cell-id c))))
74 (add-if-byte-cell src1)
75 (add-if-byte-cell src2)
76 (remove-if-byte-cell dst)
79 (instr-live-before-set! instr live-before)
80 (instr-live-after-set! instr live-after)
82 (define (bb-analyze-liveness bb)
83 (let loop ((rev-instrs (bb-rev-instrs bb))
84 (live-after (bitset-union-multi
86 (map bb-live-before (bb-succs bb)))))
87 (if (null? rev-instrs)
88 (if (not (equal? live-after (bb-live-before bb)))
89 (begin (set! changed? #t)
90 (bb-live-before-set! bb live-after)))
91 (let* ((instr (car rev-instrs))
92 (live-before (instr-analyze-liveness instr live-after)))
93 (loop (cdr rev-instrs)
96 ;; build a vector with all the byte-cells and initialise the bitsets
97 (set! byte-cells (make-vector byte-cell-counter #f))
98 (table-for-each (lambda (id cell)
99 (byte-cell-interferes-with-set!
100 cell (make-bitset byte-cell-counter))
101 (vector-set! byte-cells id cell))
103 ;; create the bitsets for each bb, instr and def-procedure
104 (for-each (lambda (bb)
105 (bb-live-before-set! bb (make-bitset byte-cell-counter))
106 (for-each (lambda (instr)
107 (instr-live-before-set!
108 instr (make-bitset byte-cell-counter))
109 (instr-live-after-set!
110 instr (make-bitset byte-cell-counter)))
113 (table-for-each (lambda (key s) (def-procedure-live-after-calls-set!
114 s (make-bitset byte-cell-counter)))
119 (begin (set! changed? #f)
120 (for-each bb-analyze-liveness (cfg-bbs cfg))
123 ;;-----------------------------------------------------------------------------
125 (define all-live (new-empty-set))
127 (define (bb-interference-graph bb)
128 (define (interfere x y)
129 (bitset-add! (byte-cell-interferes-with x) (byte-cell-id y))
130 (bitset-add! (byte-cell-interferes-with y) (byte-cell-id x)))
131 (define (make-coalesceable-with x y)
132 (set-add! (byte-cell-coalesceable-with x) y)
133 (set-add! (byte-cell-coalesceable-with y) x))
135 (define (interfere-pairwise live)
136 (set-union! all-live (list->set live))
142 (bitset-add! (byte-cell-interferes-with x) (byte-cell-id y))))
146 (define (instr-interference-graph instr)
147 (define (bitset->cells bs) (map id->byte-cell (bitset->list bs)))
148 (let ((dst (instr-dst instr))
149 (src1 (instr-src1 instr))
150 (src2 (instr-src2 instr)))
153 (if (and (byte-cell? src1) (not (eq? dst src1)))
154 (make-coalesceable-with src1 dst))
155 (if (and (byte-cell? src2) (not (eq? dst src2)))
156 (make-coalesceable-with src2 dst))))
157 (if (call-instr? instr)
158 (let* ((before (instr-live-before instr))
159 (after (instr-live-after instr))
160 (diff (bitset->cells (bitset-diff before after)))
161 (diff2 (bitset-diff after before)))
162 (interfere-pairwise diff)
167 (if (and (not (eq? x y))
168 (not (bitset-member? diff2 (byte-cell-id y))))
170 (bitset->cells after)))
173 (begin (set-add! all-live dst)
174 (for-each (lambda (x)
175 (set-add! all-live x)
176 (if (not (eq? dst x))
178 (bitset->cells (instr-live-after instr))))))))
180 (for-each instr-interference-graph (bb-rev-instrs bb)))
182 (pp analyse-liveness:)
183 (time (analyze-liveness cfg))
185 (pp interference-graph:)
186 (time (for-each bb-interference-graph (cfg-bbs cfg)))
188 ;; change the bitsets to sets, to speed up graph coloring
191 (let loop ((l (- (vector-length byte-cells) 1)))
193 (let* ((cell (id->byte-cell l)))
195 (byte-cell-interferes-with-set!
197 (let* ((bs (byte-cell-interferes-with cell))
198 (n (fxarithmetic-shift-left (u8vector-length bs) 3))
199 (set (new-empty-set)))
200 (let loop ((i (- n 1)))
202 (begin (if (bitset-member? bs i)
203 (set-add! set (id->byte-cell i)))
210 ;;-----------------------------------------------------------------------------
212 (define (delete byte-cell1 neighbours)
213 (set-for-each (lambda (byte-cell2)
214 (set-remove! (byte-cell-interferes-with byte-cell2)
216 (byte-cell-nb-neighbours-set!
217 byte-cell2 (- (byte-cell-nb-neighbours byte-cell2) 1)))
219 (define (undelete byte-cell1 neighbours)
220 (set-for-each (lambda (byte-cell2)
221 (set-add! (byte-cell-interferes-with byte-cell2)
223 (byte-cell-nb-neighbours-set!
224 byte-cell2 (+ (byte-cell-nb-neighbours byte-cell2) 1)))
227 (define (coalesce graph)
233 (let* ((coalesceable-with (byte-cell-coalesceable-with byte-cell))
234 (neighbours (byte-cell-interferes-with byte-cell))
235 (coalesce-candidates (set-diff coalesceable-with
237 (if (or (byte-cell-adr byte-cell) ; in a special register
238 (set-empty? coalesce-candidates))
240 ;; coalesce byte-cell with another cell
241 (let loop ((l (set->list coalesce-candidates)))
243 #t ; can't coalesce, keep
245 ;; don't coalesce with a special register
246 (if (byte-cell-adr c)
249 (byte-cell-interferes-with c))
251 (byte-cell-coalesceable-with c))
253 (byte-cell-coalesced-with c)))
254 ;; remove all references to byte-cell and replace
255 ;; them with references to c
256 (set-union! c-neighbours neighbours)
257 (undelete c neighbours)
258 (delete byte-cell neighbours)
259 (set-union! c-coalesced
260 (byte-cell-coalesced-with byte-cell))
263 (let ((s (byte-cell-coalesceable-with cell)))
264 (set-remove! s byte-cell)
265 #;(set-add! s c) ;; TODO does not work, register allocation fails with that
266 #;(set-add! c-coalesceable-with cell)))
268 (byte-cell-coalesceable-with-set! byte-cell
270 (byte-cell-interferes-with-set! byte-cell
272 (set-add! c-coalesced byte-cell)
277 ;;-----------------------------------------------------------------------------
279 (define register-table (make-table))
280 (define reverse-register-table (make-table))
281 (define (allocate-registers cfg)
282 (let ((all-live (coalesce (set->list (interference-graph cfg))))
283 (max-adr 0)) ; to know how much ram we need
285 (define (color byte-cell)
286 (define (set-register-table cell adr)
287 (if #f (not (string=? (byte-cell-name cell) "__tmp"))
288 (let* ((adr (if (and (> adr #x5F) (< adr #xF60)) ; not in bank 0 ;; TODO have a function for that
291 (name (byte-cell-name cell))
292 (full-name (cons (if name name "__tmp")
293 (byte-cell-id cell))))
294 (table-set! register-table
296 (cons (cons (byte-cell-bb cell)
298 (table-ref register-table adr '())))
299 (table-set! reverse-register-table name adr))))
300 (let ((neighbours (set->list (byte-cell-interferes-with byte-cell))))
302 (if (and memory-divide ; the user wants his own zone
303 (>= adr memory-divide)) ; and we'd use it
304 (error "register allocation would cross the memory divide") ;; TODO fallback ?
305 (let loop2 ((lst neighbours)) ;; TODO keep using sets, but not urgent, it's not a bottleneck
307 (begin (byte-cell-adr-set! byte-cell adr)
308 (set-register-table byte-cell adr)
311 (byte-cell-adr-set! cell adr)
312 (set-register-table cell adr))
313 (byte-cell-coalesced-with byte-cell)))
314 (if (= adr (byte-cell-adr (car lst)))
316 (loop2 (cdr lst))))))
317 (set! max-adr (max max-adr adr)))))
319 (define (find-min-neighbours graph)
320 (let loop ((lst graph) (m #f) (byte-cell #f))
324 (n (byte-cell-nb-neighbours x)))
325 (if (or (not m) (< n m))
327 (loop (cdr lst) m byte-cell))))))
329 (define (alloc-reg graph)
330 (if (not (null? graph))
331 (let* ((byte-cell (find-min-neighbours graph))
332 (neighbours (byte-cell-interferes-with byte-cell)))
333 (let ((new-graph (remove byte-cell graph)))
334 (delete byte-cell neighbours)
335 (alloc-reg new-graph)
336 (undelete byte-cell neighbours))
337 (if (not (byte-cell-adr byte-cell))
338 (color byte-cell)))))
340 ;; cache the number of neighbours
341 (for-each (lambda (cell)
342 (byte-cell-nb-neighbours-set!
343 cell (set-length (byte-cell-interferes-with cell))))
346 (pp register-allocation:)
347 (time (alloc-reg all-live))
348 (display (string-append (number->string (+ max-adr 1)) " RAM bytes\n"))))