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)
10 (define (interfere x y)
11 (if (not (memq x (byte-cell-interferes-with y)))
13 (byte-cell-interferes-with-set!
15 (cons y (byte-cell-interferes-with x)))
16 (byte-cell-interferes-with-set!
18 (cons x (byte-cell-interferes-with y))))))
20 (define (interfere-pairwise live)
21 (set! all-live (union all-live live))
29 (define (instr-interference-graph instr)
30 (let ((dst (instr-dst instr)))
32 (let ((src1 (instr-src1 instr))
33 (src2 (instr-src2 instr)))
36 (byte-cell-coalesceable-with-set!
38 (union (byte-cell-coalesceable-with dst)
40 (byte-cell-coalesceable-with-set!
42 (union (byte-cell-coalesceable-with src1)
46 (byte-cell-coalesceable-with-set!
48 (union (byte-cell-coalesceable-with dst)
50 (byte-cell-coalesceable-with-set!
52 (union (byte-cell-coalesceable-with src2)
54 (let ((live-before (instr-live-before instr)))
55 (interfere-pairwise live-before)))
57 (define (bb-interference-graph bb)
58 (for-each instr-interference-graph (bb-rev-instrs bb)))
60 (analyze-liveness cfg)
62 (for-each bb-interference-graph (cfg-bbs cfg))
66 (define (allocate-registers cfg)
67 (let ((all-live (interference-graph cfg)))
69 (define (color byte-cell)
70 (let ((coalesce-candidates ; TODO right now, no coalescing is done
72 (diff (byte-cell-coalesceable-with byte-cell)
73 (byte-cell-interferes-with byte-cell)))))
75 (pp (list byte-cell: byte-cell;;;;;;;;;;;;;;;
77 ; interferes-with: (byte-cell-interferes-with byte-cell)
78 ; coalesceable-with: (byte-cell-coalesceable-with byte-cell)
81 (if #f #;(not (null? coalesce-candidates))
82 (let ((adr (byte-cell-adr (car coalesce-candidates))))
83 (byte-cell-adr-set! byte-cell adr))
84 (let ((neighbours (byte-cell-interferes-with byte-cell)))
86 (if (and memory-divide ; the user wants his own zone
87 (>= adr memory-divide)) ; and we'd use it
88 (error "register allocation would cross the memory divide") ;; TODO fallback ?
89 (let loop2 ((lst neighbours))
91 (byte-cell-adr-set! byte-cell adr)
93 (if (= adr (byte-cell-adr x))
95 (loop2 (cdr lst))))))))))))
97 (define (delete byte-cell1 neighbours)
98 (for-each (lambda (byte-cell2)
99 (let ((lst (byte-cell-interferes-with byte-cell2)))
100 (byte-cell-interferes-with-set!
102 (remove byte-cell1 lst))))
105 (define (undelete byte-cell1 neighbours)
106 (for-each (lambda (byte-cell2)
107 (let ((lst (byte-cell-interferes-with byte-cell2)))
108 (byte-cell-interferes-with-set!
110 (cons byte-cell1 lst))))
113 (define (find-min-neighbours graph)
114 (let loop ((lst graph) (m #f) (byte-cell #f))
118 (n (length (byte-cell-interferes-with x))))
119 (if (or (not m) (< n m))
121 (loop (cdr lst) m byte-cell))))))
123 (define (alloc-reg graph)
124 (if (not (null? graph))
125 (let* ((byte-cell (find-min-neighbours graph))
126 (neighbours (byte-cell-interferes-with byte-cell)))
127 (let ((new-graph (remove byte-cell graph)))
128 (delete byte-cell neighbours)
129 (alloc-reg new-graph)
130 (undelete byte-cell neighbours))
131 (if (not (byte-cell-adr byte-cell))
132 (color byte-cell)))))
134 (alloc-reg all-live)))
137 (define (linearize-and-cleanup cfg)
139 (define bbs-vector (cfg->vector cfg))
143 (define (add-todo bb)
144 (set! todo (cons bb todo)))
146 (define rev-code '())
149 (set! rev-code (cons instr rev-code)))
152 (emit (list 'movlw val)))
154 (emit (list 'movwf adr)))
156 (emit (list 'movfw adr)))
157 (define (movff src dst)
158 (emit (list 'movff src dst)))
161 (emit (list 'clrf adr)))
163 (emit (list 'setf adr)))
166 (emit (list 'incf adr)))
168 (emit (list 'decf adr)))
171 (emit (list 'addwf adr)))
173 (emit (list 'addwfc adr)))
176 (emit (list 'subwf adr)))
178 (emit (list 'subwfb adr)))
181 (emit (list 'mullw adr)))
183 (emit (list 'mulwf adr)))
186 (emit (list 'andwf adr)))
188 (emit (list 'iorwf adr)))
190 (emit (list 'xorwf adr)))
193 (emit (list 'cpfseq adr)))
195 (emit (list 'cpfslt adr)))
197 (emit (list 'cpfsgt adr)))
200 (emit (list 'bra label)))
202 (define (rcall label)
203 (emit (list 'rcall label)))
206 (if (and #f (and (not (null? rev-code)) ; TODO probably here for eventual inlining
207 (eq? (caar rev-code) 'rcall)))
208 (let ((label (cadar rev-code)))
209 (set! rev-code (cdr rev-code))
211 (emit (list 'return))))
214 (if (and #f (and (not (null? rev-code)) ; TODO would probably be useful to eliminate things like : bra $2, $2:
215 (eq? (caar rev-code) 'bra)
216 (eq? (cadar rev-code) lab)))
218 (set! rev-code (cdr rev-code))
220 (emit (list 'label lab))))
223 (emit (list 'sleep)))
225 (define (move-reg src dst)
234 ;; takes 2 cycles (as much as movfw src ; movwf dst), but takes
235 ;; only 1 instruction
238 (define (bb-linearize bb)
239 (let ((label-num (bb-label-num bb)))
240 (let ((bb (vector-ref bbs-vector label-num)))
242 (define (move-lit n adr)
251 (define (dump-instr instr)
252 (cond ((call-instr? instr)
253 (let* ((def-proc (call-instr-def-proc instr))
254 (entry (def-procedure-entry def-proc)))
258 (let ((label (bb-label entry)))
261 ((return-instr? instr)
264 (let ((src1 (instr-src1 instr))
265 (src2 (instr-src2 instr))
266 (dst (instr-dst instr)))
267 (if (and (or (not (byte-cell? dst))
269 (or (not (byte-cell? src1))
270 (byte-cell-adr src1))
271 (or (not (byte-cell? src2))
272 (byte-cell-adr src2)))
274 (case (instr-id instr)
278 (let ((n (byte-lit-val src1))
279 (z (byte-cell-adr dst)))
281 (let ((x (byte-cell-adr src1))
282 (z (byte-cell-adr dst)))
287 (let ((n (byte-lit-val src2))
288 (z (byte-cell-adr dst)))
290 (move-lit (byte-lit-val src1) z)
291 (move-reg (byte-cell-adr src1) z))
292 (case (instr-id instr)
293 ((add) (cond ((= n 1) (incf z))
294 ((= n #xff) (decf z))
297 ((addc) (movlw n) (addwfc z))
298 ((sub) (cond ((= n 1) (decf z))
299 ((= n #xff) (incf z))
302 ((subb) (movlw n) (subwfb z))))
303 (let ((x (byte-cell-adr src1))
304 (y (byte-cell-adr src2))
305 (z (byte-cell-adr dst)))
306 (cond ((and (not (= x y))
308 (memq (instr-id instr)
310 ;; since this basically swaps the
311 ;; arguments, it can't be used for
316 ;; for subtraction, preserves argument
319 ;; this NEEDS to be done with movff, or
320 ;; else wreg will get clobbered and this
323 (else ;; TODO check if it could be merged with the previous case
326 (case (instr-id instr)
331 (else (error "..."))))))
333 ((mul) ; 8 by 8 multiplication
335 ;; since multiplication is commutative, the
336 ;; arguments are set up so the second one will
337 ;; be a literal if the operator is applied on a
338 ;; literal and a variable
339 (let ((n (byte-lit-val src2)))
340 (if (byte-lit? src1) ;; TODO will probably never be called with literals, since it's always inside a function
341 (movlw (byte-lit-val src1))
342 (movereg (byte-cell-adr src1) WREG))
343 ;; literal multiplication
345 (let ((x (byte-cell-adr src1))
346 (y (byte-cell-adr src2)))
350 ((and ior xor) ;; TODO similar to add sub and co, except that I removed the literal part
351 ;; no instructions for bitwise operations involving
352 ;; literals exist on the PIC18
353 (let ((x (if (byte-lit? src1)
355 (byte-cell-adr src1)))
356 (y (if (byte-lit? src2)
358 (byte-cell-adr src2)))
359 (z (byte-cell-adr dst)))
360 (cond ((byte-lit? src1)
364 (movlw x)) ;; TODO not sure it will work
365 ((and (not (= x y)) (= y z))
370 (case (instr-id instr)
374 (else (error "...")))))
377 (if (null? (bb-succs bb))
378 ;; TODO happens more often than I'd like to admit
379 (error "I think you might have given me an empty source file."))
380 (let* ((succs (bb-succs bb))
382 (bra (bb-label dest))
385 (let* ((succs (bb-succs bb))
386 (dest-true (car succs))
387 (dest-false (cadr succs)))
389 (define (compare flip adr)
390 (case (instr-id instr)
391 ((x<y) (if flip (cpfsgt adr) (cpfslt adr)))
392 ((x>y) (if flip (cpfslt adr) (cpfsgt adr)))
394 (bra (bb-label dest-false))
395 (bra (bb-label dest-true))
396 (add-todo dest-false)
397 (add-todo dest-true))
399 (cond ((byte-lit? src1)
400 (let ((n (byte-lit-val src1))
401 (y (byte-cell-adr src2)))
402 (if #f #;(and (or (= n 0) (= n 1) (= n #xff))
403 (eq? (instr-id instr) 'x==y))
404 (special-compare-eq-lit n x)
409 (let ((x (byte-cell-adr src1))
410 (n (byte-lit-val src2)))
411 (if #f #;(and (or (= n 0) (= n 1) (= n #xff))
412 (eq? (instr-id instr) 'x==y))
413 (special-compare-eq-lit n x) ;; TODO does not exist. the only way apart from cpfseq I see would be to load w, do a subtraction, then conditional branch, but would be larger and would take 1-2 cycles more
418 (let ((x (byte-cell-adr src1))
419 (y (byte-cell-adr src2)))
424 (emit (list (instr-id instr))))))))))
428 (vector-set! bbs-vector label-num #f)
429 (label (bb-label bb))
430 (for-each dump-instr (reverse (bb-rev-instrs bb)))
431 (for-each add-todo (bb-succs bb)))))))
433 (let ((prog-label (asm-make-label 'PROG)))
438 (add-todo (vector-ref bbs-vector 0))
443 (let ((bb (car todo)))
444 (set! todo (cdr todo))
449 (define (assembler-gen filename cfg)
454 (movlw (cadr instr)))
456 (movwf (cadr instr)))
458 (movf (cadr instr) 'w))
460 (movff (cadr instr) (caddr instr)))
470 (addwf (cadr instr)))
472 (addwfc (cadr instr)))
474 (subwf (cadr instr)))
476 (subwfb (cadr instr)))
478 (mullw (cadr instr)))
480 (mulwf (cadr instr)))
482 (andwf (cadr instr)))
484 (iorwf (cadr instr)))
486 (xorwf (cadr instr)))
488 (cpfseq (cadr instr)))
490 (cpfslt (cadr instr)))
492 (cpfsgt (cadr instr)))
496 (rcall (cadr instr)))
501 (string-append (symbol->string (asm-label-id (cadr instr))) ":"))
502 (asm-label (cadr instr)))
506 (error "unknown instruction" instr))))
512 (let ((code (linearize-and-cleanup cfg)))
513 ; (pretty-print code)
514 (for-each gen code)))
516 (define (code-gen filename cfg)
517 (allocate-registers cfg)
518 (assembler-gen filename cfg)
520 ; (pretty-print (reverse (bb-rev-instrs bb))) ;; TODO what ? there are no bbs here...