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 (analyze-liveness cfg)
8 (define (instr-analyze-liveness instr live-after)
12 (let ((def-proc (call-instr-def-proc instr)))
13 (if (not (set-empty? live-after))
14 (begin (set! changed #t)
15 (union! (def-procedure-live-after-calls def-proc)
20 (map (lambda (def-var)
21 (list->set (value-bytes
22 (def-variable-value def-var))))
23 (def-procedure-params def-proc)))
25 (list->set (value-bytes
26 (def-procedure-value def-proc)))))))
27 (if (bb? (def-procedure-entry def-proc))
29 (bb-live-before (def-procedure-entry def-proc))
32 ((return-instr? instr)
33 (let ((def-proc (return-instr-def-proc instr)))
35 (if (def-procedure? def-proc)
36 (def-procedure-live-after-calls def-proc)
37 (list->set (value-bytes def-proc)))))
38 (let ((live (set-filter byte-cell? live)))
39 (set! live-after live)
42 (let* ((src1 (instr-src1 instr))
43 (src2 (instr-src2 instr))
44 (dst (instr-dst instr))
45 (use (if (byte-cell? src1)
47 (set-add (new-set src1) src2)
52 (def (if (byte-cell? dst)
56 ;; (and (byte-cell? dst) ; dead instruction?
57 ;; (not (memq dst live-after))
58 ;; (not (and (byte-cell? dst) (byte-cell-adr dst))))
60 (union use (diff live-after def))))))))
61 (instr-live-before-set! instr live-before)
62 (instr-live-after-set! instr live-after)
64 (define (bb-analyze-liveness bb)
65 (let loop ((rev-instrs (bb-rev-instrs bb))
66 (live-after (union-multi (map bb-live-before (bb-succs bb)))))
67 (if (null? rev-instrs)
68 (if (not (set-equal? live-after (bb-live-before bb)))
69 (begin (set! changed? #t)
70 (bb-live-before-set! bb live-after)))
71 (let* ((instr (car rev-instrs))
72 (live-before (instr-analyze-liveness instr live-after)))
73 (loop (cdr rev-instrs)
77 (begin (set! changed? #f)
78 (for-each bb-analyze-liveness (cfg-bbs cfg))
81 (define (interference-graph cfg)
82 (define all-live (new-empty-set))
83 (define (interfere x y)
84 (if (not (set-member? (byte-cell-interferes-with y) x))
85 (begin (set-add! (byte-cell-interferes-with x) y)
86 (set-add! (byte-cell-interferes-with y) x))))
87 (define (interfere-pairwise live)
88 (union! all-live live)
89 (set-for-each (lambda (x)
90 (set-for-each (lambda (y)
91 (if (not (eq? x y)) (interfere x y)))
94 (define (instr-interference-graph instr)
95 (let ((dst (instr-dst instr)))
97 (let ((src1 (instr-src1 instr))
98 (src2 (instr-src2 instr)))
100 (begin (set-add! (byte-cell-coalesceable-with dst) src1)
101 (set-add! (byte-cell-coalesceable-with src1) dst)))
102 (if (byte-cell? src2)
103 (begin (set-add! (byte-cell-coalesceable-with dst) src2)
104 (set-add! (byte-cell-coalesceable-with src2) dst))))))
105 (let ((live-before (instr-live-before instr)))
106 (interfere-pairwise live-before)))
107 (define (bb-interference-graph bb)
108 (for-each instr-interference-graph (bb-rev-instrs bb))
109 ;; (map instr-interference-graph (bb-rev-instrs bb)) ;; TODO for better profiling
112 (pp analyse-liveness:)
113 (time (analyze-liveness cfg))
115 (pp interference-graph:)
116 (time (for-each bb-interference-graph (cfg-bbs cfg)))
120 ;;-----------------------------------------------------------------------------
122 (define (allocate-registers cfg)
123 (let ((all-live (interference-graph cfg)))
125 (define (color byte-cell)
126 (let ((coalesce-candidates ; TODO right now, no coalescing is done
127 (set-filter byte-cell-adr
128 (diff (byte-cell-coalesceable-with byte-cell)
129 (byte-cell-interferes-with byte-cell)))))
131 (pp (list byte-cell: byte-cell;;;;;;;;;;;;;;;
133 ; interferes-with: (byte-cell-interferes-with byte-cell)
134 ; coalesceable-with: (byte-cell-coalesceable-with byte-cell)
137 (if #f #;(not (null? coalesce-candidates))
138 (let ((adr (byte-cell-adr (car (set->list coalesce-candidates))))) ;; TODO have as a set all along
139 (byte-cell-adr-set! byte-cell adr))
140 (let ((neighbours (byte-cell-interferes-with byte-cell)))
142 (if (and memory-divide ; the user wants his own zone
143 (>= adr memory-divide)) ; and we'd use it
144 (error "register allocation would cross the memory divide") ;; TODO fallback ?
145 (let loop2 ((lst (set->list neighbours))) ;; TODO keep using sets, but not urgent, it's not a bottleneck
147 (byte-cell-adr-set! byte-cell adr)
149 (if (= adr (byte-cell-adr x))
151 (loop2 (cdr lst))))))))))))
153 (define (delete byte-cell1 neighbours)
154 (set-for-each (lambda (byte-cell2)
155 (set-remove! (byte-cell-interferes-with byte-cell2)
159 (define (undelete byte-cell1 neighbours)
160 (set-for-each (lambda (byte-cell2)
161 (set-add! (byte-cell-interferes-with byte-cell2)
165 (define (find-min-neighbours graph)
166 (let loop ((lst graph) (m #f) (byte-cell #f))
170 (n (table-length (byte-cell-interferes-with x))))
171 (if (or (not m) (< n m))
173 (loop (cdr lst) m byte-cell))))))
175 (define (alloc-reg graph)
176 (if (not (null? graph))
177 (let* ((byte-cell (find-min-neighbours graph))
178 (neighbours (byte-cell-interferes-with byte-cell)))
179 (let ((new-graph (remove byte-cell graph)))
180 (delete byte-cell neighbours)
181 (alloc-reg new-graph)
182 (undelete byte-cell neighbours))
183 (if (not (byte-cell-adr byte-cell))
184 (color byte-cell)))))
186 (pp register-allocation:)
187 (time (alloc-reg (set->list all-live)))
188 )) ;; TODO convert find-min-neighbors and alloc-reg to use tables, not urgent since it's not a bottleneck