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
9 (define (interference-graph cfg)
11 (define (analyze-liveness cfg)
13 (define (instr-analyze-liveness instr live-after)
18 (let ((def-proc (call-instr-def-proc instr)))
19 (if (and (not (set-empty? live-after))
22 (def-procedure-live-after-calls def-proc)
27 (set-union! (def-procedure-live-after-calls def-proc)
32 (map (lambda (def-var)
34 (value-bytes (def-variable-value def-var))))
35 (def-procedure-params def-proc)))
40 (value-bytes (def-procedure-value def-proc))))
41 (bb-live-before (def-procedure-entry def-proc)))))) ;; FOO now the liveness analysis takes a whole minute
42 (if (bb? (def-procedure-entry def-proc))
43 (set-intersection ;; TODO disabling this branch saves around 12 bytes
44 (bb-live-before (def-procedure-entry def-proc))
48 ((return-instr? instr)
49 (let* ((def-proc (return-instr-def-proc instr))
51 (if (def-procedure? def-proc)
52 (def-procedure-live-after-calls def-proc)
53 (list->set (value-bytes def-proc)))))
54 (set! live-after live)
58 (let* ((src1 (instr-src1 instr))
59 (src2 (instr-src2 instr))
60 (dst (instr-dst instr))
61 (use (if (byte-cell? src1)
63 (set-add (new-set src1) src2)
68 (def (if (byte-cell? dst)
72 ;; (and (byte-cell? dst) ; dead instruction?
73 ;; (not (set-member? live-after dst))
74 ;; (not (and (byte-cell? dst) (byte-cell-adr dst))))
77 (set-diff live-after def))))))))
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 (set-union-multi
85 (map bb-live-before (bb-succs bb)))))
86 (if (null? rev-instrs)
87 (if (not (set-equal? live-after (bb-live-before bb)))
88 (begin (set! changed? #t)
89 (bb-live-before-set! bb live-after)))
90 (let* ((instr (car rev-instrs))
91 (live-before (instr-analyze-liveness instr live-after)))
92 (loop (cdr rev-instrs)
96 (begin (set! changed? #f)
97 (for-each bb-analyze-liveness (cfg-bbs cfg))
100 ;;-----------------------------------------------------------------------------
102 (define all-live (new-empty-set))
104 (define (bb-interference-graph bb)
105 ;; TODO maybe building them asymetric, and then having a pass to make them symetric could be faster. I tried, but it didn't work
106 (define (interfere x y)
107 (bitset-add! (byte-cell-interferes-with x) (byte-cell-id y))
108 (bitset-add! (byte-cell-interferes-with y) (byte-cell-id x)))
109 (define (make-coalesceable-with x y)
110 (set-add! (byte-cell-coalesceable-with x) y)
111 (set-add! (byte-cell-coalesceable-with y) x))
113 (define (interfere-pairwise live)
114 (set-union! all-live live)
120 (bitset-add! (byte-cell-interferes-with x) (byte-cell-id y))))
124 (define (instr-interference-graph instr)
125 (let ((dst (instr-dst instr))
126 (src1 (instr-src1 instr))
127 (src2 (instr-src2 instr)))
130 (if (and (byte-cell? src1) (not (eq? dst src1)))
131 (make-coalesceable-with src1 dst))
132 (if (and (byte-cell? src2) (not (eq? dst src2)))
133 (make-coalesceable-with src2 dst))))
134 (if (call-instr? instr)
135 (let* ((before (instr-live-before instr))
136 (after (instr-live-after instr))
137 (diff (set-diff before after))
138 (diff2 (set-diff after before)))
139 (interfere-pairwise diff)
144 (if (and (not (eq? x y)) (not (set-member? diff2 y)))
149 (begin (set-add! all-live dst)
150 (set-for-each (lambda (x)
151 (set-add! all-live x)
152 (if (not (eq? dst x))
154 (instr-live-after instr)))))))
156 (for-each instr-interference-graph (bb-rev-instrs bb)))
158 ;; build a vector with all the byte-cells and initialise the bit fields
159 (set! byte-cells (make-vector byte-cell-counter #f))
160 (table-for-each (lambda (id cell)
161 (byte-cell-interferes-with-set!
162 cell (make-bitset byte-cell-counter))
163 (vector-set! byte-cells id cell))
166 (pp analyse-liveness:)
167 (time (analyze-liveness cfg))
169 (pp interference-graph:)
170 (time (for-each bb-interference-graph (cfg-bbs cfg)))
172 ;; change the bitsets to sets, to speed up graph coloring
173 (let loop ((l (- (vector-length byte-cells) 1)))
175 (let* ((cell (vector-ref byte-cells l)))
177 (byte-cell-interferes-with-set!
179 (let* ((bs (byte-cell-interferes-with cell))
180 (n (fxarithmetic-shift-left (u8vector-length bs) 3))
181 (set (new-empty-set)))
182 (let loop ((i (- n 1)))
184 (begin (if (bitset-member? bs i)
185 (set-add! set (vector-ref byte-cells i)))
192 ;;-----------------------------------------------------------------------------
194 (define (delete byte-cell1 neighbours)
195 (set-for-each (lambda (byte-cell2)
196 (set-remove! (byte-cell-interferes-with byte-cell2)
198 (byte-cell-nb-neighbours-set!
199 byte-cell2 (- (byte-cell-nb-neighbours byte-cell2) 1)))
201 (define (undelete byte-cell1 neighbours)
202 (set-for-each (lambda (byte-cell2)
203 (set-add! (byte-cell-interferes-with byte-cell2)
205 (byte-cell-nb-neighbours-set!
206 byte-cell2 (+ (byte-cell-nb-neighbours byte-cell2) 1)))
209 (define (coalesce graph)
213 (let* ((coalesceable-with (byte-cell-coalesceable-with byte-cell))
214 (old-neighbours (byte-cell-interferes-with byte-cell))
215 (coalesce-candidates (set-diff coalesceable-with
217 (if (or (byte-cell-adr byte-cell) ; in a special register
218 (set-empty? coalesce-candidates))
220 ;; coalesce byte-cell with another cell
221 (let loop ((l (set->list coalesce-candidates)))
223 #t ; can't coalesce, keep
225 ;; don't coalesce with a special register
226 (if (byte-cell-adr c)
228 (let ((c-neighbours (byte-cell-interferes-with c))
229 (c-coalesced (byte-cell-coalesced-with c)))
230 ;; remove all references to byte-cell and replace
231 ;; them with references to c
232 (set-union! c-neighbours old-neighbours)
233 (undelete c old-neighbours)
234 (delete byte-cell old-neighbours)
235 (set-union! c-coalesced
236 (byte-cell-coalesced-with byte-cell))
239 (let ((s (byte-cell-coalesceable-with cell)))
240 (set-remove! s byte-cell)
241 #;(set-add! s c))) ;; FOO attempt (failed)
243 (byte-cell-coalesceable-with-set! byte-cell
245 (byte-cell-interferes-with-set! byte-cell
247 (set-add! c-coalesced byte-cell)
252 ;;-----------------------------------------------------------------------------
254 (define register-table (make-table))
255 (define reverse-register-table (make-table))
256 (define (allocate-registers cfg)
257 (let ((all-live (coalesce (set->list (interference-graph cfg))))
258 (max-adr 0)) ; to know how much ram we need
260 (define (color byte-cell)
261 (define (set-register-table cell adr)
262 (if #f (not (string=? (byte-cell-name cell) "__tmp"))
263 (let ((adr (if (and (> adr #x5F) (< adr #xF60)) ; not in bank 0 ;; TODO have a function for that
266 (table-set! register-table
268 (cons (cons (byte-cell-bb cell)
269 (byte-cell-name cell))
270 (table-ref register-table adr '())))
271 (table-set! reverse-register-table
272 (byte-cell-name cell) ;; TODO add the bb ?
274 (let ((neighbours (set->list (byte-cell-interferes-with byte-cell))))
276 (if (and memory-divide ; the user wants his own zone
277 (>= adr memory-divide)) ; and we'd use it
278 (error "register allocation would cross the memory divide") ;; TODO fallback ?
279 (let loop2 ((lst neighbours)) ;; TODO keep using sets, but not urgent, it's not a bottleneck
281 (begin (byte-cell-adr-set! byte-cell adr)
282 (set-register-table byte-cell adr)
285 (byte-cell-adr-set! cell adr)
286 (set-register-table cell adr))
287 (byte-cell-coalesced-with byte-cell)))
288 (if (= adr (byte-cell-adr (car lst)))
290 (loop2 (cdr lst))))))
291 (set! max-adr (max max-adr adr)))))
293 (define (find-min-neighbours graph)
294 (let loop ((lst graph) (m #f) (byte-cell #f))
298 (n (byte-cell-nb-neighbours x)))
299 (if (or (not m) (< n m))
301 (loop (cdr lst) m byte-cell))))))
303 (define (alloc-reg graph)
304 (if (not (null? graph))
305 (let* ((byte-cell (find-min-neighbours graph))
306 (neighbours (byte-cell-interferes-with byte-cell)))
307 (let ((new-graph (remove byte-cell graph)))
308 (delete byte-cell neighbours)
309 (alloc-reg new-graph)
310 (undelete byte-cell neighbours))
311 (if (not (byte-cell-adr byte-cell))
312 (color byte-cell)))))
314 ;; cache the number of neighbours
315 (for-each (lambda (cell)
316 (byte-cell-nb-neighbours-set!
317 cell (set-length (byte-cell-interferes-with cell))))
320 (pp register-allocation:)
321 (time (alloc-reg all-live))
322 (display (string-append (number->string (+ max-adr 1)) " RAM bytes\n"))))