Commit | Line | Data |
---|---|---|
f05517b2 AW |
1 | ;;; Continuation-passing style (CPS) intermediate language (IL) |
2 | ||
3 | ;; Copyright (C) 2014 Free Software Foundation, Inc. | |
4 | ||
5 | ;;;; This library is free software; you can redistribute it and/or | |
6 | ;;;; modify it under the terms of the GNU Lesser General Public | |
7 | ;;;; License as published by the Free Software Foundation; either | |
8 | ;;;; version 3 of the License, or (at your option) any later version. | |
9 | ;;;; | |
10 | ;;;; This library is distributed in the hope that it will be useful, | |
11 | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | ;;;; Lesser General Public License for more details. | |
14 | ;;;; | |
15 | ;;;; You should have received a copy of the GNU Lesser General Public | |
16 | ;;;; License along with this library; if not, write to the Free Software | |
17 | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ||
19 | ;;; Commentary: | |
20 | ;;; | |
21 | ;;; A pass to renumber variables and continuation labels so that they | |
09220d21 AW |
22 | ;;; are contiguous within each function and, in the case of labels, |
23 | ;;; topologically sorted. | |
f05517b2 AW |
24 | ;;; |
25 | ;;; Code: | |
26 | ||
27 | (define-module (language cps renumber) | |
28 | #:use-module (ice-9 match) | |
f9bceb77 | 29 | #:use-module (srfi srfi-1) |
f05517b2 AW |
30 | #:use-module (language cps) |
31 | #:export (renumber)) | |
32 | ||
09220d21 AW |
33 | ;; Topologically sort the continuation tree starting at k0, using |
34 | ;; reverse post-order numbering. | |
6d7b6a17 | 35 | (define (sort-conts k0 conts new-k0 path-lengths) |
09220d21 AW |
36 | (let ((next -1)) |
37 | (let visit ((k k0)) | |
6d7b6a17 AW |
38 | (define (maybe-visit k) |
39 | (let ((entry (vector-ref conts k))) | |
40 | ;; Visit the successor if it has not been | |
41 | ;; visited yet. | |
42 | (when (and entry (not (exact-integer? entry))) | |
43 | (visit k)))) | |
44 | ||
09220d21 AW |
45 | (let ((cont (vector-ref conts k))) |
46 | ;; Clear the cont table entry to mark this continuation as | |
47 | ;; visited. | |
48 | (vector-set! conts k #f) | |
6d7b6a17 AW |
49 | |
50 | (match cont | |
51 | (($ $kargs names syms body) | |
52 | (let lp ((body body)) | |
53 | (match body | |
54 | (($ $letk conts body) (lp body)) | |
55 | (($ $letrec names syms funs body) (lp body)) | |
56 | (($ $continue k src exp) | |
57 | (match exp | |
58 | (($ $prompt escape? tag handler) | |
59 | (maybe-visit handler) | |
60 | (maybe-visit k)) | |
61 | (($ $branch kt) | |
62 | ;; Visit the successor with the shortest path length | |
63 | ;; to the tail first, so that if the branches are | |
64 | ;; unsorted, the longer path length will appear | |
65 | ;; first. This will move a loop exit out of a loop. | |
66 | (let ((k-len (vector-ref path-lengths k)) | |
67 | (kt-len (vector-ref path-lengths kt))) | |
68 | (cond | |
69 | ((and k-len kt-len (< k-len kt-len)) | |
70 | (maybe-visit k) | |
71 | (maybe-visit kt)) | |
72 | (else | |
73 | (maybe-visit kt) | |
74 | (maybe-visit k))))) | |
75 | (_ | |
76 | (maybe-visit k))))))) | |
77 | (($ $kreceive arity k) (maybe-visit k)) | |
78 | (($ $kclause arity ($ $cont kbody) alt) | |
79 | (match alt | |
80 | (($ $cont kalt) (maybe-visit kalt)) | |
81 | (_ #f)) | |
82 | (maybe-visit kbody)) | |
83 | (($ $kfun src meta self tail clause) | |
84 | (match clause | |
85 | (($ $cont kclause) (maybe-visit kclause)) | |
86 | (_ #f))) | |
87 | (_ #f)) | |
88 | ||
09220d21 AW |
89 | ;; Chain this label to the label that will follow it in the sort |
90 | ;; order, and record this label as the new head of the order. | |
91 | (vector-set! conts k next) | |
92 | (set! next k))) | |
93 | ||
94 | ;; Finally traverse the label chain, giving each label its final | |
95 | ;; name. | |
96 | (let lp ((n new-k0) (head next)) | |
97 | (if (< head 0) | |
98 | n | |
99 | (let ((next (vector-ref conts head))) | |
100 | (vector-set! conts head n) | |
101 | (lp (1+ n) next)))))) | |
102 | ||
6d7b6a17 AW |
103 | (define (compute-tail-path-lengths preds ktail path-lengths) |
104 | (let visit ((k ktail) (length-in 0)) | |
105 | (let ((length (vector-ref path-lengths k))) | |
106 | (unless (and length (<= length length-in)) | |
107 | (vector-set! path-lengths k length-in) | |
108 | (let lp ((preds (vector-ref preds k))) | |
109 | (match preds | |
110 | (() #t) | |
111 | ((pred . preds) | |
112 | (visit pred (1+ length-in)) | |
113 | (lp preds)))))))) | |
114 | ||
f05517b2 | 115 | (define (compute-new-labels-and-vars fun) |
a0329d01 | 116 | (call-with-values (lambda () (compute-max-label-and-var fun)) |
f05517b2 | 117 | (lambda (max-label max-var) |
09220d21 | 118 | (let ((labels (make-vector (1+ max-label) #f)) |
f05517b2 | 119 | (next-label 0) |
09220d21 | 120 | (vars (make-vector (1+ max-var) #f)) |
6d7b6a17 AW |
121 | (next-var 0) |
122 | (preds (make-vector (1+ max-label) '())) | |
123 | (path-lengths (make-vector (1+ max-label) #f))) | |
124 | (define (add-predecessor! pred succ) | |
125 | (vector-set! preds succ (cons pred (vector-ref preds succ)))) | |
f05517b2 AW |
126 | (define (rename! var) |
127 | (vector-set! vars var next-var) | |
128 | (set! next-var (1+ next-var))) | |
09220d21 AW |
129 | |
130 | (define (collect-conts fun) | |
f05517b2 AW |
131 | (define (visit-cont cont) |
132 | (match cont | |
133 | (($ $cont label cont) | |
09220d21 | 134 | (vector-set! labels label cont) |
f05517b2 AW |
135 | (match cont |
136 | (($ $kargs names vars body) | |
6d7b6a17 | 137 | (visit-term body label)) |
8320f504 | 138 | (($ $kfun src meta self tail clause) |
f05517b2 | 139 | (visit-cont tail) |
6d7b6a17 AW |
140 | (match clause |
141 | (($ $cont kclause) | |
142 | (add-predecessor! label kclause) | |
143 | (visit-cont clause)) | |
144 | (#f #f))) | |
145 | (($ $kclause arity (and body ($ $cont kbody)) alternate) | |
146 | (add-predecessor! label kbody) | |
90dce16d | 147 | (visit-cont body) |
6d7b6a17 AW |
148 | (match alternate |
149 | (($ $cont kalt) | |
150 | (add-predecessor! label kalt) | |
151 | (visit-cont alternate)) | |
152 | (#f #f))) | |
153 | (($ $kreceive arity kargs) | |
154 | (add-predecessor! label kargs)) | |
155 | (($ $ktail) #f))))) | |
156 | (define (visit-term term label) | |
f05517b2 AW |
157 | (match term |
158 | (($ $letk conts body) | |
6d7b6a17 AW |
159 | (let lp ((conts conts)) |
160 | (unless (null? conts) | |
161 | (visit-cont (car conts)) | |
162 | (lp (cdr conts)))) | |
163 | (visit-term body label)) | |
f05517b2 | 164 | (($ $letrec names syms funs body) |
6d7b6a17 AW |
165 | (visit-term body label)) |
166 | (($ $continue k src exp) | |
167 | (add-predecessor! label k) | |
168 | (match exp | |
169 | (($ $branch kt) | |
170 | (add-predecessor! label kt)) | |
171 | (($ $prompt escape? tag handler) | |
172 | (add-predecessor! label handler)) | |
173 | (_ #f))))) | |
a0329d01 | 174 | (visit-cont fun)) |
f05517b2 | 175 | |
09220d21 | 176 | (define (compute-names-in-fun fun) |
f9bceb77 | 177 | (define queue '()) |
09220d21 AW |
178 | (define (visit-cont cont) |
179 | (match cont | |
180 | (($ $cont label cont) | |
181 | (let ((reachable? (exact-integer? (vector-ref labels label)))) | |
182 | ;; This cont is reachable if it was given a number. | |
183 | ;; Otherwise the cont table entry still contains the | |
184 | ;; cont itself; clear it out to indicate that the cont | |
185 | ;; should not be residualized. | |
186 | (unless reachable? | |
187 | (vector-set! labels label #f)) | |
188 | (match cont | |
189 | (($ $kargs names vars body) | |
190 | (when reachable? | |
191 | (for-each rename! vars)) | |
192 | (visit-term body reachable?)) | |
8320f504 | 193 | (($ $kfun src meta self tail clause) |
f9bceb77 AW |
194 | (unless reachable? (error "entry should be reachable")) |
195 | (rename! self) | |
09220d21 AW |
196 | (visit-cont tail) |
197 | (when clause | |
198 | (visit-cont clause))) | |
199 | (($ $kclause arity body alternate) | |
f9bceb77 | 200 | (unless reachable? (error "clause should be reachable")) |
09220d21 AW |
201 | (visit-cont body) |
202 | (when alternate | |
203 | (visit-cont alternate))) | |
204 | (($ $ktail) | |
205 | (unless reachable? | |
206 | ;; It's possible for the tail to be unreachable, | |
207 | ;; if all paths contify to infinite loops. Make | |
208 | ;; sure we mark as reachable. | |
209 | (vector-set! labels label next-label) | |
210 | (set! next-label (1+ next-label)))) | |
59258f7c | 211 | (($ $kreceive) |
09220d21 AW |
212 | #f)))))) |
213 | (define (visit-term term reachable?) | |
214 | (match term | |
215 | (($ $letk conts body) | |
216 | (for-each visit-cont conts) | |
217 | (visit-term body reachable?)) | |
218 | (($ $letrec names syms funs body) | |
219 | (when reachable? | |
f9bceb77 | 220 | (for-each rename! syms) |
a0329d01 AW |
221 | (set! queue (fold (lambda (fun queue) |
222 | (match fun | |
223 | (($ $fun free body) | |
224 | (cons body queue)))) | |
225 | queue | |
226 | funs))) | |
09220d21 | 227 | (visit-term body reachable?)) |
a0329d01 | 228 | (($ $continue k src ($ $fun free body)) |
f9bceb77 | 229 | (when reachable? |
a0329d01 | 230 | (set! queue (cons body queue)))) |
f9bceb77 | 231 | (($ $continue) #f))) |
09220d21 | 232 | |
09220d21 | 233 | (match fun |
6d7b6a17 | 234 | (($ $cont kfun ($ $kfun src meta self ($ $cont ktail))) |
cf8bb037 | 235 | (collect-conts fun) |
6d7b6a17 AW |
236 | (compute-tail-path-lengths preds ktail path-lengths) |
237 | (set! next-label (sort-conts kfun labels next-label path-lengths)) | |
a0329d01 | 238 | (visit-cont fun) |
cf8bb037 AW |
239 | (for-each compute-names-in-fun (reverse queue))) |
240 | (($ $program conts) | |
241 | (for-each compute-names-in-fun conts)))) | |
09220d21 | 242 | |
f9bceb77 | 243 | (compute-names-in-fun fun) |
cc8eb195 | 244 | (values labels vars next-label next-var))))) |
f05517b2 | 245 | |
cf8bb037 AW |
246 | (define (apply-renumbering term labels vars) |
247 | (define (relabel label) (vector-ref labels label)) | |
248 | (define (rename var) (vector-ref vars var)) | |
249 | (define (rename-kw-arity arity) | |
250 | (match arity | |
251 | (($ $arity req opt rest kw aok?) | |
252 | (make-$arity req opt rest | |
253 | (map (match-lambda | |
254 | ((kw kw-name kw-var) | |
255 | (list kw kw-name (rename kw-var)))) | |
256 | kw) | |
257 | aok?)))) | |
258 | (define (must-visit-cont cont) | |
259 | (or (visit-cont cont) | |
260 | (error "internal error -- failed to visit cont"))) | |
261 | (define (visit-conts conts) | |
262 | (match conts | |
263 | (() '()) | |
264 | ((cont . conts) | |
265 | (cond | |
266 | ((visit-cont cont) | |
267 | => (lambda (cont) | |
268 | (cons cont (visit-conts conts)))) | |
269 | (else (visit-conts conts)))))) | |
270 | (define (visit-cont cont) | |
271 | (match cont | |
272 | (($ $cont label cont) | |
273 | (let ((label (relabel label))) | |
274 | (and | |
275 | label | |
276 | (rewrite-cps-cont cont | |
277 | (($ $kargs names vars body) | |
278 | (label ($kargs names (map rename vars) ,(visit-term body)))) | |
279 | (($ $kfun src meta self tail clause) | |
280 | (label | |
281 | ($kfun src meta (rename self) ,(must-visit-cont tail) | |
282 | ,(and clause (must-visit-cont clause))))) | |
283 | (($ $ktail) | |
284 | (label ($ktail))) | |
285 | (($ $kclause arity body alternate) | |
286 | (label | |
287 | ($kclause ,(rename-kw-arity arity) ,(must-visit-cont body) | |
288 | ,(and alternate (must-visit-cont alternate))))) | |
289 | (($ $kreceive ($ $arity req () rest () #f) kargs) | |
59258f7c | 290 | (label ($kreceive req rest (relabel kargs)))))))))) |
cf8bb037 AW |
291 | (define (visit-term term) |
292 | (rewrite-cps-term term | |
293 | (($ $letk conts body) | |
294 | ,(match (visit-conts conts) | |
295 | (() (visit-term body)) | |
296 | (conts (build-cps-term ($letk ,conts ,(visit-term body)))))) | |
297 | (($ $letrec names vars funs body) | |
298 | ($letrec names (map rename vars) (map visit-fun funs) | |
299 | ,(visit-term body))) | |
300 | (($ $continue k src exp) | |
301 | ($continue (relabel k) src ,(visit-exp exp))))) | |
302 | (define (visit-exp exp) | |
303 | (match exp | |
304 | ((or ($ $void) ($ $const) ($ $prim)) | |
305 | exp) | |
306 | (($ $closure k nfree) | |
307 | (build-cps-exp ($closure (relabel k) nfree))) | |
308 | (($ $fun) | |
309 | (visit-fun exp)) | |
310 | (($ $values args) | |
311 | (let ((args (map rename args))) | |
312 | (build-cps-exp ($values args)))) | |
313 | (($ $call proc args) | |
314 | (let ((args (map rename args))) | |
315 | (build-cps-exp ($call (rename proc) args)))) | |
316 | (($ $callk k proc args) | |
317 | (let ((args (map rename args))) | |
318 | (build-cps-exp ($callk (relabel k) (rename proc) args)))) | |
92805e21 AW |
319 | (($ $branch kt exp) |
320 | (build-cps-exp ($branch (relabel kt) ,(visit-exp exp)))) | |
cf8bb037 AW |
321 | (($ $primcall name args) |
322 | (let ((args (map rename args))) | |
323 | (build-cps-exp ($primcall name args)))) | |
324 | (($ $prompt escape? tag handler) | |
325 | (build-cps-exp | |
326 | ($prompt escape? (rename tag) (relabel handler)))))) | |
327 | (define (visit-fun fun) | |
328 | (rewrite-cps-exp fun | |
329 | (($ $fun free body) | |
330 | ($fun (map rename free) ,(must-visit-cont body))))) | |
331 | ||
332 | (match term | |
333 | (($ $cont) | |
334 | (must-visit-cont term)) | |
335 | (($ $program conts) | |
336 | (build-cps-term | |
337 | ($program ,(map must-visit-cont conts)))))) | |
338 | ||
339 | (define (renumber term) | |
340 | (call-with-values (lambda () (compute-new-labels-and-vars term)) | |
a0329d01 | 341 | (lambda (labels vars nlabels nvars) |
cf8bb037 | 342 | (values (apply-renumbering term labels vars) nlabels nvars)))) |