Commit | Line | Data |
---|---|---|
4b8de65e AW |
1 | ;;; Continuation-passing style (CPS) intermediate language (IL) |
2 | ||
7ab76a83 | 3 | ;; Copyright (C) 2013, 2014 Free Software Foundation, Inc. |
4b8de65e AW |
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 | ;;; This pass converts a CPS term in such a way that no function has any | |
22 | ;;; free variables. Instead, closures are built explicitly with | |
23 | ;;; make-closure primcalls, and free variables are referenced through | |
24 | ;;; the closure. | |
25 | ;;; | |
26 | ;;; Closure conversion also removes any $letrec forms that contification | |
27 | ;;; did not handle. See (language cps) for a further discussion of | |
28 | ;;; $letrec. | |
29 | ;;; | |
30 | ;;; Code: | |
31 | ||
32 | (define-module (language cps closure-conversion) | |
33 | #:use-module (ice-9 match) | |
34 | #:use-module ((srfi srfi-1) #:select (fold | |
35 | lset-union lset-difference | |
36 | list-index)) | |
8b1a4b23 | 37 | #:use-module (srfi srfi-9) |
4b8de65e AW |
38 | #:use-module (srfi srfi-26) |
39 | #:use-module (language cps) | |
8b1a4b23 | 40 | #:use-module (language cps dfg) |
4b8de65e AW |
41 | #:export (convert-closures)) |
42 | ||
cf8bb037 | 43 | ;; free := var ... |
4b8de65e | 44 | |
8b1a4b23 | 45 | (define (analyze-closures exp dfg) |
cf8bb037 AW |
46 | "Compute the set of free variables for all $fun instances in |
47 | @var{exp}." | |
8b1a4b23 | 48 | (let ((free-vars (make-hash-table)) |
983413a1 | 49 | (named-funs (make-hash-table)) |
6dc886fa | 50 | (well-known-vars (make-bitvector (var-counter) #t))) |
983413a1 AW |
51 | (define (add-named-fun! var cont) |
52 | (hashq-set! named-funs var cont)) | |
8b1a4b23 | 53 | (define (clear-well-known! var) |
6dc886fa AW |
54 | (bitvector-set! well-known-vars var #f)) |
55 | (define (compute-well-known-labels) | |
56 | (let ((bv (make-bitvector (label-counter) #f))) | |
57 | (hash-for-each | |
58 | (lambda (var cont) | |
59 | (match cont | |
60 | (($ $cont label ($ $kfun src meta self)) | |
61 | (unless (equal? var self) | |
62 | (bitvector-set! bv label | |
63 | (and (bitvector-ref well-known-vars var) | |
64 | (bitvector-ref well-known-vars self))))))) | |
65 | named-funs) | |
66 | bv)) | |
cf8bb037 AW |
67 | (define (union a b) |
68 | (lset-union eq? a b)) | |
69 | (define (difference a b) | |
70 | (lset-difference eq? a b)) | |
71 | (define (visit-cont cont bound) | |
72 | (match cont | |
73 | (($ $cont label ($ $kargs names vars body)) | |
74 | (visit-term body (append vars bound))) | |
75 | (($ $cont label ($ $kfun src meta self tail clause)) | |
983413a1 | 76 | (add-named-fun! self cont) |
cf8bb037 AW |
77 | (let ((free (if clause |
78 | (visit-cont clause (list self)) | |
79 | '()))) | |
6dc886fa | 80 | (hashq-set! free-vars label free) |
cf8bb037 AW |
81 | (difference free bound))) |
82 | (($ $cont label ($ $kclause arity body alternate)) | |
83 | (let ((free (visit-cont body bound))) | |
84 | (if alternate | |
85 | (union (visit-cont alternate bound) free) | |
4b8de65e | 86 | free))) |
cf8bb037 AW |
87 | (($ $cont) '()))) |
88 | (define (visit-term term bound) | |
89 | (match term | |
90 | (($ $letk conts body) | |
91 | (fold (lambda (cont free) | |
92 | (union (visit-cont cont bound) free)) | |
93 | (visit-term body bound) | |
94 | conts)) | |
95 | (($ $letrec names vars (($ $fun () cont) ...) body) | |
96 | (let ((bound (append vars bound))) | |
983413a1 | 97 | (for-each add-named-fun! vars cont) |
cf8bb037 AW |
98 | (fold (lambda (cont free) |
99 | (union (visit-cont cont bound) free)) | |
100 | (visit-term body bound) | |
101 | cont))) | |
102 | (($ $continue k src ($ $fun () body)) | |
8b1a4b23 AW |
103 | (match (lookup-predecessors k dfg) |
104 | ((_) (match (lookup-cont k dfg) | |
105 | (($ $kargs (name) (var)) | |
983413a1 | 106 | (add-named-fun! var body)))) |
8b1a4b23 | 107 | (_ #f)) |
cf8bb037 AW |
108 | (visit-cont body bound)) |
109 | (($ $continue k src exp) | |
110 | (visit-exp exp bound)))) | |
111 | (define (visit-exp exp bound) | |
112 | (define (adjoin var free) | |
113 | (if (or (memq var bound) (memq var free)) | |
114 | free | |
115 | (cons var free))) | |
116 | (match exp | |
117 | ((or ($ $void) ($ $const) ($ $prim)) '()) | |
118 | (($ $call proc args) | |
8b1a4b23 | 119 | (for-each clear-well-known! args) |
cf8bb037 AW |
120 | (fold adjoin (adjoin proc '()) args)) |
121 | (($ $primcall name args) | |
8b1a4b23 | 122 | (for-each clear-well-known! args) |
cf8bb037 AW |
123 | (fold adjoin '() args)) |
124 | (($ $values args) | |
8b1a4b23 | 125 | (for-each clear-well-known! args) |
cf8bb037 AW |
126 | (fold adjoin '() args)) |
127 | (($ $prompt escape? tag handler) | |
8b1a4b23 | 128 | (clear-well-known! tag) |
cf8bb037 | 129 | (adjoin tag '())))) |
4b8de65e | 130 | |
cf8bb037 AW |
131 | (let ((free (visit-cont exp '()))) |
132 | (unless (null? free) | |
133 | (error "Expected no free vars in toplevel thunk" free exp)) | |
6dc886fa | 134 | (values free-vars named-funs (compute-well-known-labels))))) |
4b8de65e | 135 | |
32e62c2d | 136 | (define (prune-free-vars free-vars named-funs well-known var-aliases) |
cd130361 AW |
137 | (define (well-known? label) |
138 | (bitvector-ref well-known label)) | |
32e62c2d AW |
139 | (let ((eliminated (make-bitvector (label-counter) #f)) |
140 | (label-aliases (make-vector (label-counter) #f))) | |
cd130361 AW |
141 | (let lp ((label 0)) |
142 | (let ((label (bit-position #t well-known label))) | |
143 | (when label | |
144 | (match (hashq-ref free-vars label) | |
32e62c2d AW |
145 | ;; Mark all well-known closures that have no free variables |
146 | ;; for elimination. | |
cd130361 | 147 | (() (bitvector-set! eliminated label #t)) |
32e62c2d AW |
148 | ;; Replace well-known closures that have just one free |
149 | ;; variable by references to that free variable. | |
150 | ((var) | |
151 | (vector-set! label-aliases label var)) | |
cd130361 AW |
152 | (_ #f)) |
153 | (lp (1+ label))))) | |
32e62c2d | 154 | ;; Iterative free variable elimination. |
cd130361 AW |
155 | (let lp () |
156 | (let ((recurse? #f)) | |
32e62c2d AW |
157 | (define (adjoin elt list) |
158 | ;; Normally you wouldn't see duplicates in a free variable | |
159 | ;; list, but with aliases that is possible. | |
160 | (if (memq elt list) list (cons elt list))) | |
161 | (define (filter-out-eliminated free) | |
162 | (match free | |
163 | (() '()) | |
164 | ((var . free) | |
165 | (let lp ((var var) (alias-stack '())) | |
166 | (match (hashq-ref named-funs var) | |
167 | (($ $cont label) | |
168 | (cond | |
169 | ((bitvector-ref eliminated label) | |
170 | (filter-out-eliminated free)) | |
171 | ((vector-ref label-aliases label) | |
172 | => (lambda (var) | |
173 | (cond | |
174 | ((memq label alias-stack) | |
175 | ;; We have found a set of mutually recursive | |
176 | ;; well-known procedures, each of which only | |
177 | ;; closes over one of the others. Mark them | |
178 | ;; all for elimination. | |
179 | (for-each (lambda (label) | |
180 | (bitvector-set! eliminated label #t) | |
181 | (set! recurse? #t)) | |
182 | alias-stack) | |
183 | (filter-out-eliminated free)) | |
184 | (else | |
185 | (lp var (cons label alias-stack)))))) | |
186 | (else | |
187 | (adjoin var (filter-out-eliminated free))))) | |
188 | (_ (adjoin var (filter-out-eliminated free)))))))) | |
cd130361 AW |
189 | (hash-for-each-handle |
190 | (lambda (pair) | |
191 | (match pair | |
192 | ((label . ()) #t) | |
193 | ((label . free) | |
32e62c2d AW |
194 | (let ((orig-nfree (length free)) |
195 | (free (filter-out-eliminated free))) | |
cd130361 | 196 | (set-cdr! pair free) |
32e62c2d AW |
197 | ;; If we managed to eliminate one or more free variables |
198 | ;; from a well-known function, it could be that we can | |
199 | ;; eliminate or alias this function as well. | |
200 | (when (and (well-known? label) | |
201 | (< (length free) orig-nfree)) | |
202 | (match free | |
203 | (() | |
204 | (bitvector-set! eliminated label #t) | |
205 | (set! recurse? #t)) | |
206 | ((var) | |
207 | (vector-set! label-aliases label var) | |
208 | (set! recurse? #t)) | |
209 | (_ #t))))))) | |
cd130361 AW |
210 | free-vars) |
211 | ;; Iterate to fixed point. | |
32e62c2d AW |
212 | (when recurse? (lp)))) |
213 | ;; Populate var-aliases from label-aliases. | |
214 | (hash-for-each (lambda (var cont) | |
215 | (match cont | |
216 | (($ $cont label) | |
217 | (let ((alias (vector-ref label-aliases label))) | |
218 | (when alias | |
219 | (vector-set! var-aliases var alias)))))) | |
220 | named-funs))) | |
cd130361 | 221 | |
32e62c2d | 222 | (define (convert-one label fun free-vars named-funs well-known aliases) |
cd130361 AW |
223 | (define (well-known? label) |
224 | (bitvector-ref well-known label)) | |
225 | ||
6dc886fa | 226 | (let ((free (hashq-ref free-vars label)) |
cd130361 | 227 | (self-known? (well-known? label)) |
6dc886fa | 228 | (self (match fun (($ $kfun _ _ self) self)))) |
2920554a AW |
229 | (define (convert-free-var var k) |
230 | "Convert one possibly free variable reference to a bound reference. | |
231 | ||
232 | If @var{var} is free, it is replaced by a closure reference via a | |
233 | @code{free-ref} primcall, and @var{k} is called with the new var. | |
234 | Otherwise @var{var} is bound, so @var{k} is called with @var{var}." | |
235 | (cond | |
236 | ((list-index (cut eq? <> var) free) | |
237 | => (lambda (free-idx) | |
238 | (match (cons self-known? free) | |
239 | ;; A reference to the one free var of a well-known function. | |
240 | ((#t _) (k self)) | |
241 | ;; A reference to one of the two free vars in a well-known | |
242 | ;; function. | |
243 | ((#t _ _) | |
244 | (let-fresh (k*) (var*) | |
245 | (build-cps-term | |
246 | ($letk ((k* ($kargs (var*) (var*) ,(k var*)))) | |
247 | ($continue k* #f | |
248 | ($primcall (match free-idx (0 'car) (1 'cdr)) (self))))))) | |
249 | (_ | |
250 | (let-fresh (k* kidx) (idx var*) | |
251 | (build-cps-term | |
252 | ($letk ((kidx ($kargs ('idx) (idx) | |
253 | ($letk ((k* ($kargs (var*) (var*) ,(k var*)))) | |
254 | ($continue k* #f | |
255 | ($primcall | |
256 | (cond | |
257 | ((not self-known?) 'free-ref) | |
258 | ((<= free-idx #xff) 'vector-ref/immediate) | |
259 | (else 'vector-ref)) | |
260 | (self idx))))))) | |
261 | ($continue kidx #f ($const free-idx))))))))) | |
262 | (else (k var)))) | |
263 | ||
264 | (define (convert-free-vars vars k) | |
265 | "Convert a number of possibly free references to bound references. | |
266 | @var{k} is called with the bound references, and should return the | |
267 | term." | |
268 | (match vars | |
269 | (() (k '())) | |
270 | ((var . vars) | |
271 | (convert-free-var var | |
272 | (lambda (var) | |
273 | (convert-free-vars vars | |
274 | (lambda (vars) | |
275 | (k (cons var vars))))))))) | |
276 | ||
277 | (define (allocate-closure src name var label known? free body) | |
278 | "Allocate a new closure." | |
279 | (match (cons known? free) | |
280 | ((#f . _) | |
281 | (let-fresh (k*) () | |
282 | (build-cps-term | |
283 | ($letk ((k* ($kargs (name) (var) ,body))) | |
284 | ($continue k* src | |
285 | ($closure label (length free))))))) | |
286 | ((#t) | |
287 | ;; Well-known closure with no free variables; elide the | |
288 | ;; binding entirely. | |
289 | body) | |
290 | ((#t _) | |
291 | ;; Well-known closure with one free variable; the free var is the | |
292 | ;; closure, and no new binding need be made. | |
293 | body) | |
294 | ((#t _ _) | |
295 | ;; Well-known closure with two free variables; the closure is a | |
296 | ;; pair. | |
297 | (let-fresh (kinit kfalse) (false) | |
298 | (build-cps-term | |
299 | ($letk ((kinit ($kargs (name) (var) | |
300 | ,body)) | |
301 | (kfalse ($kargs ('false) (false) | |
302 | ($continue kinit src | |
303 | ($primcall 'cons (false false)))))) | |
304 | ($continue kfalse src ($const #f)))))) | |
305 | ;; Well-known callee with more than two free variables; the closure | |
306 | ;; is a vector. | |
307 | ((#t . _) | |
308 | (let ((nfree (length free))) | |
309 | (let-fresh (kinit klen kfalse) (false len-var) | |
310 | (build-cps-term | |
311 | ($letk ((kinit ($kargs (name) (var) ,body)) | |
312 | (kfalse | |
313 | ($kargs ('false) (false) | |
314 | ($letk ((klen | |
315 | ($kargs ('len) (len-var) | |
316 | ($continue kinit src | |
317 | ($primcall (if (<= nfree #xff) | |
318 | 'make-vector/immediate | |
319 | 'make-vector) | |
320 | (len-var false)))))) | |
321 | ($continue klen src ($const nfree)))))) | |
322 | ($continue kfalse src ($const #f))))))))) | |
323 | ||
324 | (define (init-closure src var known? closure-free body) | |
325 | "Initialize the free variables @var{closure-free} in a closure | |
326 | bound to @var{var}, and continue with @var{body}." | |
327 | (match (cons known? closure-free) | |
328 | ;; Well-known callee with no free variables; no initialization | |
329 | ;; necessary. | |
330 | ((#t) body) | |
331 | ;; Well-known callee with one free variable; no initialization | |
332 | ;; necessary. | |
333 | ((#t _) body) | |
334 | ;; Well-known callee with two free variables; do a set-car! and | |
335 | ;; set-cdr!. | |
336 | ((#t v0 v1) | |
337 | (let-fresh (kcar kcdr) () | |
338 | (convert-free-var | |
339 | v0 | |
340 | (lambda (v0) | |
341 | (build-cps-term | |
342 | ($letk ((kcar ($kargs () () | |
343 | ,(convert-free-var | |
344 | v1 | |
345 | (lambda (v1) | |
346 | (build-cps-term | |
347 | ($letk ((kcdr ($kargs () () ,body))) | |
348 | ($continue kcdr src | |
349 | ($primcall 'set-cdr! (var v1)))))))))) | |
350 | ($continue kcar src | |
351 | ($primcall 'set-car! (var v0))))))))) | |
352 | ;; Otherwise residualize a sequence of vector-set! or free-set!, | |
353 | ;; depending on whether the callee is well-known or not. | |
354 | (_ | |
355 | (fold (lambda (free idx body) | |
356 | (let-fresh (k) (idxvar) | |
357 | (build-cps-term | |
358 | ($letk ((k ($kargs () () ,body))) | |
359 | ,(convert-free-var | |
360 | free | |
361 | (lambda (free) | |
362 | (build-cps-term | |
363 | ($letconst (('idx idxvar idx)) | |
364 | ($continue k src | |
365 | ($primcall (cond | |
366 | ((not known?) 'free-set!) | |
367 | ((<= idx #xff) 'vector-set!/immediate) | |
368 | (else 'vector-set!)) | |
369 | (var idxvar free))))))))))) | |
370 | body | |
371 | closure-free | |
372 | (iota (length closure-free)))))) | |
373 | ||
374 | ;; Load the closure for a known call. The callee may or may not be | |
375 | ;; known at all call sites. | |
376 | (define (convert-known-proc-call var label self self-known? free k) | |
377 | ;; Well-known closures with one free variable are replaced at their | |
378 | ;; use sites by uses of the one free variable. The use sites of a | |
379 | ;; well-known closures are only in well-known proc calls, and in | |
380 | ;; free lists of other closures. Here we handle the call case; the | |
381 | ;; free list case is handled by prune-free-vars. | |
382 | (define (rename var) | |
383 | (let ((var* (vector-ref aliases var))) | |
384 | (if var* | |
385 | (rename var*) | |
386 | var))) | |
387 | (match (cons (well-known? label) | |
388 | (hashq-ref free-vars label)) | |
389 | ((#t) | |
390 | ;; Calling a well-known procedure with no free variables; pass #f | |
391 | ;; as the closure. | |
392 | (let-fresh (k*) (v*) | |
393 | (build-cps-term | |
394 | ($letk ((k* ($kargs (v*) (v*) ,(k v*)))) | |
395 | ($continue k* #f ($const #f)))))) | |
396 | ((#t _) | |
397 | ;; Calling a well-known procedure with one free variable; pass | |
398 | ;; the free variable as the closure. | |
399 | (convert-free-var (rename var) k)) | |
400 | (_ | |
401 | (convert-free-var var k)))) | |
402 | ||
6dc886fa AW |
403 | (define (visit-cont cont) |
404 | (rewrite-cps-cont cont | |
405 | (($ $cont label ($ $kargs names vars body)) | |
406 | (label ($kargs names vars ,(visit-term body)))) | |
407 | (($ $cont label ($ $kfun src meta self tail clause)) | |
408 | (label ($kfun src meta self ,tail | |
409 | ,(and clause (visit-cont clause))))) | |
410 | (($ $cont label ($ $kclause arity body alternate)) | |
411 | (label ($kclause ,arity ,(visit-cont body) | |
412 | ,(and alternate (visit-cont alternate))))) | |
413 | (($ $cont) ,cont))) | |
414 | (define (visit-term term) | |
415 | (match term | |
416 | (($ $letk conts body) | |
417 | (build-cps-term | |
418 | ($letk ,(map visit-cont conts) ,(visit-term body)))) | |
4b8de65e | 419 | |
6dc886fa AW |
420 | ;; Remove letrec. |
421 | (($ $letrec names vars funs body) | |
422 | (let lp ((in (map list names vars funs)) | |
423 | (bindings (lambda (body) body)) | |
424 | (body (visit-term body))) | |
425 | (match in | |
426 | (() (bindings body)) | |
427 | (((name var ($ $fun () | |
428 | (and fun-body | |
429 | ($ $cont kfun ($ $kfun src))))) . in) | |
cd130361 AW |
430 | (let ((fun-free (hashq-ref free-vars kfun))) |
431 | (lp in | |
432 | (lambda (body) | |
433 | (allocate-closure | |
434 | src name var kfun (well-known? kfun) fun-free | |
435 | (bindings body))) | |
436 | (init-closure | |
2920554a | 437 | src var (well-known? kfun) fun-free |
cd130361 | 438 | body))))))) |
4b8de65e | 439 | |
6dc886fa AW |
440 | (($ $continue k src (or ($ $void) ($ $const) ($ $prim))) |
441 | term) | |
b3ae2b50 | 442 | |
6dc886fa | 443 | (($ $continue k src ($ $fun () ($ $cont kfun))) |
cd130361 | 444 | (let ((fun-free (hashq-ref free-vars kfun))) |
32e62c2d AW |
445 | (match (cons (well-known? kfun) fun-free) |
446 | ((known?) | |
6dc886fa | 447 | (build-cps-term |
32e62c2d | 448 | ($continue k src ,(if known? |
cd130361 AW |
449 | (build-cps-exp ($const #f)) |
450 | (build-cps-exp ($closure kfun 0)))))) | |
32e62c2d AW |
451 | ((#t _) |
452 | ;; A well-known closure of one free variable is replaced | |
453 | ;; at each use with the free variable itself, so we don't | |
454 | ;; need a binding at all; and yet, the continuation | |
455 | ;; expects one value, so give it something. DCE should | |
456 | ;; clean up later. | |
457 | (build-cps-term | |
458 | ($continue k src ,(build-cps-exp ($const #f))))) | |
cd130361 AW |
459 | (_ |
460 | (let-fresh () (var) | |
461 | (allocate-closure | |
462 | src #f var kfun (well-known? kfun) fun-free | |
463 | (init-closure | |
2920554a | 464 | src var (well-known? kfun) fun-free |
cd130361 | 465 | (build-cps-term ($continue k src ($values (var))))))))))) |
6dc886fa AW |
466 | |
467 | (($ $continue k src ($ $call proc args)) | |
468 | (match (hashq-ref named-funs proc) | |
cd130361 | 469 | (($ $cont kfun) |
6dc886fa | 470 | (convert-known-proc-call |
cd130361 | 471 | proc kfun self self-known? free |
6dc886fa | 472 | (lambda (proc) |
2920554a | 473 | (convert-free-vars args |
6dc886fa AW |
474 | (lambda (args) |
475 | (build-cps-term | |
476 | ($continue k src | |
cd130361 | 477 | ($callk kfun proc args)))))))) |
6dc886fa | 478 | (#f |
2920554a | 479 | (convert-free-vars (cons proc args) |
983413a1 AW |
480 | (match-lambda |
481 | ((proc . args) | |
6dc886fa AW |
482 | (build-cps-term |
483 | ($continue k src | |
484 | ($call proc args))))))))) | |
4b8de65e | 485 | |
6dc886fa | 486 | (($ $continue k src ($ $primcall name args)) |
2920554a | 487 | (convert-free-vars args |
6dc886fa AW |
488 | (lambda (args) |
489 | (build-cps-term | |
490 | ($continue k src ($primcall name args)))))) | |
4b8de65e | 491 | |
6dc886fa | 492 | (($ $continue k src ($ $values args)) |
2920554a | 493 | (convert-free-vars args |
6dc886fa AW |
494 | (lambda (args) |
495 | (build-cps-term | |
496 | ($continue k src ($values args)))))) | |
4b8de65e | 497 | |
6dc886fa | 498 | (($ $continue k src ($ $prompt escape? tag handler)) |
2920554a | 499 | (convert-free-var tag |
6dc886fa AW |
500 | (lambda (tag) |
501 | (build-cps-term | |
502 | ($continue k src | |
503 | ($prompt escape? tag handler)))))))) | |
504 | (visit-cont (build-cps-cont (label ,fun))))) | |
4b8de65e | 505 | |
a0329d01 | 506 | (define (convert-closures fun) |
4b8de65e AW |
507 | "Convert free reference in @var{exp} to primcalls to @code{free-ref}, |
508 | and allocate and initialize flat closures." | |
8b1a4b23 AW |
509 | (let ((dfg (compute-dfg fun))) |
510 | (with-fresh-name-state-from-dfg dfg | |
511 | (call-with-values (lambda () (analyze-closures fun dfg)) | |
983413a1 | 512 | (lambda (free-vars named-funs well-known) |
32e62c2d AW |
513 | (let ((labels (sort (hash-map->list (lambda (k v) k) free-vars) <)) |
514 | (aliases (make-vector (var-counter) #f))) | |
515 | (prune-free-vars free-vars named-funs well-known aliases) | |
8b1a4b23 | 516 | (build-cps-term |
983413a1 | 517 | ($program |
6dc886fa AW |
518 | ,(map (lambda (label) |
519 | (convert-one label (lookup-cont label dfg) | |
32e62c2d | 520 | free-vars named-funs well-known aliases)) |
983413a1 | 521 | labels))))))))) |