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 (define (interference-graph cfg)
8 (define (analyze-liveness cfg)
10 (define (instr-analyze-liveness instr live-after)
15 (let ((def-proc (call-instr-def-proc instr)))
16 (if (and (not (set-empty? live-after))
19 (def-procedure-live-after-calls def-proc)
24 (set-union! (def-procedure-live-after-calls def-proc)
29 (map (lambda (def-var)
31 (value-bytes (def-variable-value def-var))))
32 (def-procedure-params def-proc)))
36 (value-bytes (def-procedure-value def-proc)))))))
37 (if (bb? (def-procedure-entry def-proc))
38 (set-intersection ;; TODO disabling this branch saves around 12 bytes
39 (bb-live-before (def-procedure-entry def-proc))
43 ((return-instr? instr)
44 (let ((def-proc (return-instr-def-proc instr)))
46 (if (def-procedure? def-proc)
47 (def-procedure-live-after-calls def-proc)
48 (list->set (value-bytes def-proc)))))
49 (set! live-after live)
53 (let* ((src1 (instr-src1 instr))
54 (src2 (instr-src2 instr))
55 (dst (instr-dst instr))
56 (use (if (byte-cell? src1)
58 (set-add (new-set src1) src2)
63 (def (if (byte-cell? dst)
67 ;; (and (byte-cell? dst) ; dead instruction?
68 ;; (not (set-member? live-after dst))
69 ;; (not (and (byte-cell? dst) (byte-cell-adr dst))))
72 (set-diff live-after def))))))))
74 (instr-live-before-set! instr live-before)
75 (instr-live-after-set! instr live-after)
77 (define (bb-analyze-liveness bb)
78 (let loop ((rev-instrs (bb-rev-instrs bb))
79 (live-after (set-union-multi
80 (map bb-live-before (bb-succs bb)))))
81 (if (null? rev-instrs)
82 (if (not (set-equal? live-after (bb-live-before bb)))
83 (begin (set! changed? #t)
84 (bb-live-before-set! bb live-after)))
85 (let* ((instr (car rev-instrs))
86 (live-before (instr-analyze-liveness instr live-after)))
87 (loop (cdr rev-instrs)
91 (begin (set! changed? #f)
92 (for-each bb-analyze-liveness (cfg-bbs cfg))
95 ;;-----------------------------------------------------------------------------
97 (define all-live (new-empty-set))
99 (define (bb-interference-graph bb)
101 (define (interfere x y)
102 (if (not (set-member? (byte-cell-interferes-with y) x)) ;; TODO is this check worth it ?
103 (begin (set-add! (byte-cell-interferes-with x) y)
104 (set-add! (byte-cell-interferes-with y) x))))
106 (define (interfere-pairwise live)
107 (set-union! all-live live)
108 (set-for-each (lambda (x)
109 (set-for-each (lambda (y)
110 (if (not (eq? x y)) (interfere x y)))
114 (define (instr-interference-graph instr)
115 (let ((dst (instr-dst instr)))
117 (let ((src1 (instr-src1 instr))
118 (src2 (instr-src2 instr)))
119 (if (and (byte-cell? src1) (not (eq? dst src1))) ;; FOO not sure this fixes anything, but if I remove it, loops infinitely in shl16 (which does no shifting) problem is probably elsewhere, though
120 (begin (set-add! (byte-cell-coalesceable-with dst) src1)
121 (set-add! (byte-cell-coalesceable-with src1) dst)))
122 (if (and (byte-cell? src2) (not (eq? dst src2)))
123 (begin (set-add! (byte-cell-coalesceable-with dst) src2)
124 (set-add! (byte-cell-coalesceable-with src2) dst)))
125 (interfere-pairwise (set-add (instr-live-after instr) dst)))))
126 (interfere-pairwise (instr-live-before instr)))
127 (for-each instr-interference-graph (bb-rev-instrs bb)))
129 (pp analyse-liveness:)
130 (time (analyze-liveness cfg))
132 (pp interference-graph:)
133 (time (for-each bb-interference-graph (cfg-bbs cfg)))
137 ;;-----------------------------------------------------------------------------
139 (define (delete byte-cell1 neighbours)
140 (set-for-each (lambda (byte-cell2)
141 (set-remove! (byte-cell-interferes-with byte-cell2)
144 (define (undelete byte-cell1 neighbours)
145 (set-for-each (lambda (byte-cell2)
146 (set-add! (byte-cell-interferes-with byte-cell2)
150 (define (coalesce graph) ;; FOO pc gets clobbered, it seems... (everything gets clobbered)
154 (let* ((coalesceable-with (byte-cell-coalesceable-with byte-cell))
155 (old-neighbours (byte-cell-interferes-with byte-cell))
156 (coalesce-candidates (set-diff coalesceable-with
158 (if (or (byte-cell-adr byte-cell) ; in a special register
159 (set-empty? coalesce-candidates))
161 ;; coalesce byte-cell with another cell
162 (let ((c (let loop ((l (set->list coalesce-candidates)))
166 (if (byte-cell-adr c)
171 (let ((c-neighbours (byte-cell-interferes-with c)))
172 ;; remove all references to byte-cell and add references
174 (set-union! c-neighbours old-neighbours)
175 (undelete c old-neighbours)
176 (delete byte-cell old-neighbours)
179 (let ((s (byte-cell-coalesceable-with cell)))
180 (set-remove! s byte-cell)
181 ;; (if (not (eq? cell c)) (set-add! s c)) ;; FOO disabled for now
184 (byte-cell-interferes-with-set! byte-cell
186 (byte-cell-coalesceable-with-set! byte-cell
188 (set-add! (byte-cell-coalesced-with c) byte-cell)
193 ;;-----------------------------------------------------------------------------
195 (define register-table (make-table))
196 (define (allocate-registers cfg)
197 (let ((all-live (coalesce (set->list (interference-graph cfg))))
198 (max-adr 0)) ; to know how much ram we need
200 (define (color byte-cell)
201 (define (set-register-table cell adr)
202 (if #f (not (string=? (byte-cell-name cell) "__tmp")) ;; TODO DEBUG
203 (table-set! register-table
204 (if (and (> adr #x5F) (< adr #xF60))
208 (cons (cons (byte-cell-bb cell)
209 (byte-cell-name cell))
210 (table-ref register-table adr '())))))
211 (let ((neighbours (byte-cell-interferes-with byte-cell)))
213 (if (and memory-divide ; the user wants his own zone
214 (>= adr memory-divide)) ; and we'd use it
215 (error "register allocation would cross the memory divide") ;; TODO fallback ?
216 (let loop2 ((lst (set->list neighbours))) ;; TODO keep using sets, but not urgent, it's not a bottleneck
218 (begin (byte-cell-adr-set! byte-cell adr)
219 (set-register-table byte-cell adr)
222 (byte-cell-adr-set! cell adr)
223 (set-register-table cell adr))
224 (byte-cell-coalesced-with byte-cell)))
225 (if (= adr (byte-cell-adr (car lst)))
227 (loop2 (cdr lst))))))
228 (set! max-adr (max max-adr adr)))))
230 (define (find-min-neighbours graph)
231 (let loop ((lst graph) (m #f) (byte-cell #f))
235 (n (set-length (byte-cell-interferes-with x))))
236 (if (or (not m) (< n m))
238 (loop (cdr lst) m byte-cell))))))
240 (define (alloc-reg graph)
241 (if (not (null? graph))
242 (let* ((byte-cell (find-min-neighbours graph))
243 (neighbours (byte-cell-interferes-with byte-cell)))
244 (let ((new-graph (remove byte-cell graph)))
245 (delete byte-cell neighbours)
246 (alloc-reg new-graph)
247 (undelete byte-cell neighbours))
248 (if (not (byte-cell-adr byte-cell))
249 (color byte-cell)))))
251 (let loop ((l all-live)) ;; FOO DEBUG might be nice to know which bb these temporaries come from, really have a way to know where each byte cell is used
253 (let ((head (car l)))
254 (if (or (string=? (byte-cell-name head) "env0$86")
255 (string=? (byte-cell-name head) "env1$85"))
256 (begin (pp (byte-cell-name head))
257 (for-each (lambda (x) (pp (list (byte-cell-name x) (byte-cell-bb x)))) ;; FOO does it report the right one ?
258 (set->list (byte-cell-coalesced-with head)))
259 ;; (let loop ((l all-live))
260 ;; (if (not (null? l))
261 ;; (let ((h (car l)))
262 ;; (if (not (set-member? (byte-cell-interferes-with head) h))
263 ;; (pp (list N-I: (byte-cell-name h) (byte-cell-bb h)))) ;; FOO commit all changes but register-allocation.scm ALSO, I don't think it reports the right conflicts, since the reportes coalesced cells do not seem to be allocated in the same place
266 ;; (if (not (set-empty? (set-filter (lambda (cell)
267 ;; (or (string=? (byte-cell-name cell) "env0$86")
268 ;; (string=? (byte-cell-name cell) "env1$85")))
269 ;; (byte-cell-coalesced-with head))))
270 ;; (pp (list OPP: (byte-cell-name head) I: (map (lambda (x) (byte-cell-name x)) (set->list (byte-cell-coalesced-with head))))))
273 (pp register-allocation:)
274 (time (alloc-reg all-live)) ;; TODO convert find-min-neighbours and alloc-reg to use tables, not urgent since it's not a bottleneck
275 (display (string-append (number->string (+ max-adr 1)) " RAM bytes\n"))))