Remove "pop" from $prompt
[bpt/guile.git] / module / language / cps / compile-bytecode.scm
CommitLineData
6e8ad823
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
7ab76a83 3;; Copyright (C) 2013, 2014 Free Software Foundation, Inc.
6e8ad823
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;;;
691697de
AW
21;;; Compiling CPS to bytecode. The result is in the bytecode language,
22;;; which happens to be an ELF image as a bytecode.
6e8ad823
AW
23;;;
24;;; Code:
25
691697de 26(define-module (language cps compile-bytecode)
6e8ad823
AW
27 #:use-module (ice-9 match)
28 #:use-module (srfi srfi-1)
29 #:use-module (language cps)
30 #:use-module (language cps arities)
31 #:use-module (language cps closure-conversion)
8ac8e2df 32 #:use-module (language cps contification)
fa3b6e57 33 #:use-module (language cps constructors)
6e8ad823 34 #:use-module (language cps dfg)
7e273b7a 35 #:use-module (language cps elide-values)
6e8ad823
AW
36 #:use-module (language cps primitives)
37 #:use-module (language cps reify-primitives)
38 #:use-module (language cps slot-allocation)
4c906ad5 39 #:use-module (language cps specialize-primcalls)
6e8ad823 40 #:use-module (system vm assembler)
691697de 41 #:export (compile-bytecode))
6e8ad823 42
d258fccc 43;; TODO: Local var names.
6e8ad823
AW
44
45(define (kw-arg-ref args kw default)
46 (match (memq kw args)
47 ((_ val . _) val)
48 (_ default)))
49
50(define (optimize exp opts)
51 (define (run-pass exp pass kw default)
52 (if (kw-arg-ref opts kw default)
1d15832f 53 (pass exp)
6e8ad823
AW
54 exp))
55
56 ;; Calls to source-to-source optimization passes go here.
fa3b6e57 57 (let* ((exp (run-pass exp contify #:contify? #t))
7e273b7a 58 (exp (run-pass exp inline-constructors #:inline-constructors? #t))
4c906ad5 59 (exp (run-pass exp specialize-primcalls #:specialize-primcalls? #t))
7e273b7a 60 (exp (run-pass exp elide-values #:elide-values? #t)))
6e8ad823
AW
61 ;; Passes that are needed:
62 ;;
6e8ad823
AW
63 ;; * Abort contification: turning abort primcalls into continuation
64 ;; calls, and eliding prompts if possible.
65 ;;
66 ;; * Common subexpression elimination. Desperately needed. Requires
67 ;; effects analysis.
68 ;;
69 ;; * Loop peeling. Unrolls the first round through a loop if the
70 ;; loop has effects that CSE can work on. Requires effects
71 ;; analysis. When run before CSE, loop peeling is the equivalent
72 ;; of loop-invariant code motion (LICM).
73 ;;
74 ;; * Generic simplification pass, to be run as needed. Used to
75 ;; "clean up", both on the original raw input and after specific
76 ;; optimization passes.
77
78 exp))
79
d258fccc 80(define (collect-conts f cfa)
6e422a35 81 (let ((contv (make-vector (cfa-k-count cfa) #f)))
d258fccc 82 (fold-local-conts
6e422a35 83 (lambda (k cont tail)
d258fccc
AW
84 (let ((idx (cfa-k-idx cfa k #:default (lambda (k) #f))))
85 (when idx
d258fccc
AW
86 (vector-set! contv idx cont))))
87 '()
88 (match f
6e422a35 89 (($ $fun src meta free entry)
d258fccc 90 entry)))
6e422a35 91 contv))
d258fccc
AW
92
93(define (compile-fun f asm)
94 (let* ((dfg (compute-dfg f #:global? #f))
95 (cfa (analyze-control-flow f dfg))
6e422a35
AW
96 (allocation (allocate-slots f dfg))
97 (contv (collect-conts f cfa)))
98 (define (lookup-cont k)
99 (vector-ref contv (cfa-k-idx cfa k)))
100
987c1f5f
AW
101 (define (maybe-slot sym)
102 (lookup-maybe-slot sym allocation))
103
6e422a35
AW
104 (define (slot sym)
105 (lookup-slot sym allocation))
106
107 (define (constant sym)
108 (lookup-constant-value sym allocation))
109
110 (define (maybe-mov dst src)
111 (unless (= dst src)
112 (emit-mov asm dst src)))
113
114 (define (maybe-load-constant slot src)
115 (call-with-values (lambda ()
116 (lookup-maybe-constant-value src allocation))
117 (lambda (has-const? val)
118 (and has-const?
119 (begin
120 (emit-load-constant asm slot val)
121 #t)))))
122
123 (define (compile-entry meta)
124 (match (vector-ref contv 0)
125 (($ $kentry self tail clauses)
126 (emit-begin-program asm (cfa-k-sym cfa 0) meta)
127 (let lp ((n 1)
128 (ks (map (match-lambda (($ $cont k) k)) clauses)))
129 (match ks
130 (()
131 (unless (= n (vector-length contv))
132 (error "unexpected end of clauses"))
133 (emit-end-program asm))
134 ((k . ks)
135 (unless (eq? (cfa-k-sym cfa n) k)
136 (error "unexpected k" k))
137 (lp (compile-clause n (and (pair? ks) (car ks)))
138 ks)))))))
139
140 (define (compile-clause n alternate)
141 (match (vector-ref contv n)
142 (($ $kclause ($ $arity req opt rest kw allow-other-keys?))
143 (let* ((kw-indices (map (match-lambda
144 ((key name sym)
145 (cons key (lookup-slot sym allocation))))
146 kw))
147 (k (cfa-k-sym cfa n))
148 (nlocals (lookup-nlocals k allocation)))
149 (emit-label asm k)
150 (emit-begin-kw-arity asm req opt rest kw-indices
151 allow-other-keys? nlocals alternate)
152 (let ((next (compile-body (1+ n) nlocals)))
153 (emit-end-arity asm)
154 next)))))
155
156 (define (compile-body n nlocals)
157 (let compile-cont ((n n))
158 (if (= n (vector-length contv))
159 n
160 (match (vector-ref contv n)
161 (($ $kclause) n)
162 (($ $kargs _ _ term)
163 (emit-label asm (cfa-k-sym cfa n))
164 (let find-exp ((term term))
165 (match term
166 (($ $letk conts term)
167 (find-exp term))
168 (($ $continue k src exp)
169 (when src
170 (emit-source asm src))
171 (compile-expression n k exp nlocals)
172 (compile-cont (1+ n))))))
173 (_
174 (emit-label asm (cfa-k-sym cfa n))
175 (compile-cont (1+ n)))))))
176
177 (define (compile-expression n k exp nlocals)
178 (let* ((label (cfa-k-sym cfa n))
179 (k-idx (cfa-k-idx cfa k))
180 (fallthrough? (= k-idx (1+ n))))
181 (define (maybe-emit-jump)
182 (unless (= k-idx (1+ n))
183 (emit-br asm k)))
184 (match (vector-ref contv k-idx)
185 (($ $ktail)
186 (compile-tail label exp))
187 (($ $kargs (name) (sym))
987c1f5f 188 (let ((dst (maybe-slot sym)))
6e422a35
AW
189 (when dst
190 (compile-value label exp dst nlocals)))
191 (maybe-emit-jump))
192 (($ $kargs () ())
193 (compile-effect label exp k nlocals)
194 (maybe-emit-jump))
195 (($ $kargs names syms)
196 (compile-values label exp syms)
197 (maybe-emit-jump))
198 (($ $kif kt kf)
199 (compile-test label exp kt kf
200 (and (= k-idx (1+ n))
201 (< (+ n 2) (cfa-k-count cfa))
202 (cfa-k-sym cfa (+ n 2)))))
987c1f5f 203 (($ $ktrunc ($ $arity req () rest () #f) kargs)
fa48a2f7
AW
204 (compile-trunc label k exp (length req)
205 (and rest
206 (match (vector-ref contv (cfa-k-idx cfa kargs))
207 (($ $kargs names (_ ... rest)) rest)))
208 nlocals)
6e422a35
AW
209 (unless (and (= k-idx (1+ n))
210 (< (+ n 2) (cfa-k-count cfa))
987c1f5f
AW
211 (eq? (cfa-k-sym cfa (+ n 2)) kargs))
212 (emit-br asm kargs))))))
6e422a35
AW
213
214 (define (compile-tail label exp)
215 ;; There are only three kinds of expressions in tail position:
216 ;; tail calls, multiple-value returns, and single-value returns.
217 (match exp
218 (($ $call proc args)
219 (for-each (match-lambda
220 ((src . dst) (emit-mov asm dst src)))
221 (lookup-parallel-moves label allocation))
222 (let ((tail-slots (cdr (iota (1+ (length args))))))
223 (for-each maybe-load-constant tail-slots args))
224 (emit-tail-call asm (1+ (length args))))
987c1f5f
AW
225 (($ $values ())
226 (emit-reset-frame asm 1)
227 (emit-return-values asm))
13085a82 228 (($ $values (arg))
987c1f5f 229 (if (maybe-slot arg)
13085a82
AW
230 (emit-return asm (slot arg))
231 (begin
232 (emit-load-constant asm 1 (constant arg))
233 (emit-return asm 1))))
6e422a35 234 (($ $values args)
13085a82
AW
235 (for-each (match-lambda
236 ((src . dst) (emit-mov asm dst src)))
237 (lookup-parallel-moves label allocation))
6e422a35 238 (let ((tail-slots (cdr (iota (1+ (length args))))))
6e422a35
AW
239 (for-each maybe-load-constant tail-slots args))
240 (emit-reset-frame asm (1+ (length args)))
241 (emit-return-values asm))
242 (($ $primcall 'return (arg))
243 (emit-return asm (slot arg)))))
244
245 (define (compile-value label exp dst nlocals)
246 (match exp
6e422a35
AW
247 (($ $values (arg))
248 (or (maybe-load-constant dst arg)
249 (maybe-mov dst (slot arg))))
250 (($ $void)
251 (emit-load-constant asm dst *unspecified*))
252 (($ $const exp)
253 (emit-load-constant asm dst exp))
254 (($ $fun src meta () ($ $cont k))
255 (emit-load-static-procedure asm dst k))
256 (($ $fun src meta free ($ $cont k))
257 (emit-make-closure asm dst k (length free)))
258 (($ $call proc args)
987c1f5f
AW
259 (let* ((proc-slot (lookup-call-proc-slot label allocation))
260 (nargs (1+ (length args)))
261 (arg-slots (map (lambda (x) (+ x proc-slot)) (iota nargs))))
262 (for-each (match-lambda
263 ((src . dst) (emit-mov asm dst src)))
264 (lookup-parallel-moves label allocation))
265 (for-each maybe-load-constant arg-slots (cons proc args))
266 (emit-call asm proc-slot nargs)
fa48a2f7
AW
267 (cond
268 (dst
269 (emit-receive asm dst proc-slot nlocals))
270 (else
271 ;; FIXME: Only allow more values if there is a rest arg.
272 ;; Express values truncation by the presence of an
273 ;; unused rest arg instead of implicitly.
274 (emit-receive-values asm proc-slot #t 1)
275 (emit-reset-frame asm nlocals)))))
6e422a35
AW
276 (($ $primcall 'current-module)
277 (emit-current-module asm dst))
278 (($ $primcall 'cached-toplevel-box (scope name bound?))
279 (emit-cached-toplevel-box asm dst (constant scope) (constant name)
280 (constant bound?)))
281 (($ $primcall 'cached-module-box (mod name public? bound?))
282 (emit-cached-module-box asm dst (constant mod) (constant name)
283 (constant public?) (constant bound?)))
284 (($ $primcall 'resolve (name bound?))
285 (emit-resolve asm dst (constant bound?) (slot name)))
286 (($ $primcall 'free-ref (closure idx))
287 (emit-free-ref asm dst (slot closure) (constant idx)))
6e422a35 288 (($ $primcall 'vector-ref (vector index))
4c906ad5
AW
289 (emit-vector-ref asm dst (slot vector) (slot index)))
290 (($ $primcall 'make-vector/immediate (length init))
291 (emit-make-vector/immediate asm dst (constant length) (slot init)))
292 (($ $primcall 'vector-ref/immediate (vector index))
293 (emit-vector-ref/immediate asm dst (slot vector) (constant index)))
294 (($ $primcall 'allocate-struct/immediate (vtable nfields))
295 (emit-allocate-struct/immediate asm dst (slot vtable) (constant nfields)))
296 (($ $primcall 'struct-ref/immediate (struct n))
297 (emit-struct-ref/immediate asm dst (slot struct) (constant n)))
6e422a35
AW
298 (($ $primcall 'builtin-ref (name))
299 (emit-builtin-ref asm dst (constant name)))
300 (($ $primcall 'bv-u8-ref (bv idx))
301 (emit-bv-u8-ref asm dst (slot bv) (slot idx)))
d59060ce
AW
302 (($ $primcall 'bv-s8-ref (bv idx))
303 (emit-bv-s8-ref asm dst (slot bv) (slot idx)))
6e422a35
AW
304 (($ $primcall 'bv-u16-ref (bv idx))
305 (emit-bv-u16-ref asm dst (slot bv) (slot idx)))
306 (($ $primcall 'bv-s16-ref (bv idx))
307 (emit-bv-s16-ref asm dst (slot bv) (slot idx)))
308 (($ $primcall 'bv-u32-ref (bv idx val))
309 (emit-bv-u32-ref asm dst (slot bv) (slot idx)))
310 (($ $primcall 'bv-s32-ref (bv idx val))
311 (emit-bv-s32-ref asm dst (slot bv) (slot idx)))
312 (($ $primcall 'bv-u64-ref (bv idx val))
313 (emit-bv-u64-ref asm dst (slot bv) (slot idx)))
314 (($ $primcall 'bv-s64-ref (bv idx val))
315 (emit-bv-s64-ref asm dst (slot bv) (slot idx)))
316 (($ $primcall 'bv-f32-ref (bv idx val))
317 (emit-bv-f32-ref asm dst (slot bv) (slot idx)))
318 (($ $primcall 'bv-f64-ref (bv idx val))
319 (emit-bv-f64-ref asm dst (slot bv) (slot idx)))
320 (($ $primcall name args)
321 ;; FIXME: Inline all the cases.
691697de 322 (let ((inst (prim-instruction name)))
6e422a35
AW
323 (emit-text asm `((,inst ,dst ,@(map slot args))))))))
324
325 (define (compile-effect label exp k nlocals)
326 (match exp
327 (($ $values ()) #f)
7ab76a83 328 (($ $prompt escape? tag handler)
6e422a35
AW
329 (match (lookup-cont handler)
330 (($ $ktrunc ($ $arity req () rest () #f) khandler-body)
331 (let ((receive-args (gensym "handler"))
332 (nreq (length req))
987c1f5f 333 (proc-slot (lookup-call-proc-slot handler allocation)))
6e422a35
AW
334 (emit-prompt asm (slot tag) escape? proc-slot receive-args)
335 (emit-br asm k)
336 (emit-label asm receive-args)
337 (emit-receive-values asm proc-slot (->bool rest) nreq)
fa48a2f7
AW
338 (when (and rest
339 (match (vector-ref contv (cfa-k-idx cfa khandler-body))
340 (($ $kargs names (_ ... rest))
341 (maybe-slot rest))))
6e422a35
AW
342 (emit-bind-rest asm (+ proc-slot 1 nreq)))
343 (for-each (match-lambda
344 ((src . dst) (emit-mov asm dst src)))
345 (lookup-parallel-moves handler allocation))
346 (emit-reset-frame asm nlocals)
347 (emit-br asm khandler-body)))))
348 (($ $primcall 'cache-current-module! (sym scope))
349 (emit-cache-current-module! asm (slot sym) (constant scope)))
350 (($ $primcall 'free-set! (closure idx value))
351 (emit-free-set! asm (slot closure) (slot value) (constant idx)))
352 (($ $primcall 'box-set! (box value))
353 (emit-box-set! asm (slot box) (slot value)))
4c906ad5
AW
354 (($ $primcall 'struct-set!/immediate (struct index value))
355 (emit-struct-set!/immediate asm (slot struct) (constant index) (slot value)))
6e422a35 356 (($ $primcall 'vector-set! (vector index value))
4c906ad5
AW
357 (emit-vector-set! asm (slot vector) (slot index) (slot value)))
358 (($ $primcall 'vector-set!/immediate (vector index value))
359 (emit-vector-set!/immediate asm (slot vector) (constant index)
360 (slot value)))
6e422a35
AW
361 (($ $primcall 'variable-set! (var val))
362 (emit-box-set! asm (slot var) (slot val)))
363 (($ $primcall 'set-car! (pair value))
364 (emit-set-car! asm (slot pair) (slot value)))
365 (($ $primcall 'set-cdr! (pair value))
366 (emit-set-cdr! asm (slot pair) (slot value)))
367 (($ $primcall 'define! (sym value))
368 (emit-define! asm (slot sym) (slot value)))
369 (($ $primcall 'push-fluid (fluid val))
370 (emit-push-fluid asm (slot fluid) (slot val)))
371 (($ $primcall 'pop-fluid ())
372 (emit-pop-fluid asm))
373 (($ $primcall 'wind (winder unwinder))
374 (emit-wind asm (slot winder) (slot unwinder)))
375 (($ $primcall 'bv-u8-set! (bv idx val))
376 (emit-bv-u8-set! asm (slot bv) (slot idx) (slot val)))
d59060ce
AW
377 (($ $primcall 'bv-s8-set! (bv idx val))
378 (emit-bv-s8-set! asm (slot bv) (slot idx) (slot val)))
6e422a35
AW
379 (($ $primcall 'bv-u16-set! (bv idx val))
380 (emit-bv-u16-set! asm (slot bv) (slot idx) (slot val)))
381 (($ $primcall 'bv-s16-set! (bv idx val))
382 (emit-bv-s16-set! asm (slot bv) (slot idx) (slot val)))
383 (($ $primcall 'bv-u32-set! (bv idx val))
384 (emit-bv-u32-set! asm (slot bv) (slot idx) (slot val)))
385 (($ $primcall 'bv-s32-set! (bv idx val))
386 (emit-bv-s32-set! asm (slot bv) (slot idx) (slot val)))
387 (($ $primcall 'bv-u64-set! (bv idx val))
388 (emit-bv-u64-set! asm (slot bv) (slot idx) (slot val)))
389 (($ $primcall 'bv-s64-set! (bv idx val))
390 (emit-bv-s64-set! asm (slot bv) (slot idx) (slot val)))
391 (($ $primcall 'bv-f32-set! (bv idx val))
392 (emit-bv-f32-set! asm (slot bv) (slot idx) (slot val)))
393 (($ $primcall 'bv-f64-set! (bv idx val))
394 (emit-bv-f64-set! asm (slot bv) (slot idx) (slot val)))
395 (($ $primcall 'unwind ())
396 (emit-unwind asm))))
397
398 (define (compile-values label exp syms)
399 (match exp
400 (($ $values args)
401 (for-each (match-lambda
402 ((src . dst) (emit-mov asm dst src)))
403 (lookup-parallel-moves label allocation))
404 (for-each maybe-load-constant (map slot syms) args))))
405
406 (define (compile-test label exp kt kf next-label)
407 (define (unary op sym)
408 (cond
409 ((eq? kt next-label)
410 (op asm (slot sym) #t kf))
411 (else
412 (op asm (slot sym) #f kt)
413 (unless (eq? kf next-label)
414 (emit-br asm kf)))))
415 (define (binary op a b)
416 (cond
417 ((eq? kt next-label)
418 (op asm (slot a) (slot b) #t kf))
419 (else
420 (op asm (slot a) (slot b) #f kt)
421 (unless (eq? kf next-label)
422 (emit-br asm kf)))))
423 (match exp
58ef5f07
AW
424 (($ $values (sym))
425 (call-with-values (lambda ()
426 (lookup-maybe-constant-value sym allocation))
427 (lambda (has-const? val)
428 (if has-const?
429 (if val
430 (unless (eq? kt next-label)
431 (emit-br asm kt))
432 (unless (eq? kf next-label)
433 (emit-br asm kf)))
434 (unary emit-br-if-true sym)))))
6e422a35
AW
435 (($ $primcall 'null? (a)) (unary emit-br-if-null a))
436 (($ $primcall 'nil? (a)) (unary emit-br-if-nil a))
437 (($ $primcall 'pair? (a)) (unary emit-br-if-pair a))
438 (($ $primcall 'struct? (a)) (unary emit-br-if-struct a))
439 (($ $primcall 'char? (a)) (unary emit-br-if-char a))
440 (($ $primcall 'symbol? (a)) (unary emit-br-if-symbol a))
441 (($ $primcall 'variable? (a)) (unary emit-br-if-variable a))
442 (($ $primcall 'vector? (a)) (unary emit-br-if-vector a))
443 (($ $primcall 'string? (a)) (unary emit-br-if-string a))
444 (($ $primcall 'bytevector? (a)) (unary emit-br-if-bytevector a))
445 ;; Add more TC7 tests here. Keep in sync with
446 ;; *branching-primcall-arities* in (language cps primitives) and
447 ;; the set of macro-instructions in assembly.scm.
448 (($ $primcall 'eq? (a b)) (binary emit-br-if-eq a b))
449 (($ $primcall 'eqv? (a b)) (binary emit-br-if-eqv a b))
450 (($ $primcall 'equal? (a b)) (binary emit-br-if-equal a b))
451 (($ $primcall '< (a b)) (binary emit-br-if-< a b))
452 (($ $primcall '<= (a b)) (binary emit-br-if-<= a b))
453 (($ $primcall '= (a b)) (binary emit-br-if-= a b))
454 (($ $primcall '>= (a b)) (binary emit-br-if-<= b a))
455 (($ $primcall '> (a b)) (binary emit-br-if-< b a))))
456
fa48a2f7 457 (define (compile-trunc label k exp nreq rest-var nlocals)
6e422a35
AW
458 (match exp
459 (($ $call proc args)
987c1f5f
AW
460 (let* ((proc-slot (lookup-call-proc-slot label allocation))
461 (nargs (1+ (length args)))
462 (arg-slots (map (lambda (x) (+ x proc-slot)) (iota nargs))))
463 (for-each (match-lambda
464 ((src . dst) (emit-mov asm dst src)))
465 (lookup-parallel-moves label allocation))
466 (for-each maybe-load-constant arg-slots (cons proc args))
467 (emit-call asm proc-slot nargs)
468 ;; FIXME: Only allow more values if there is a rest arg.
469 ;; Express values truncation by the presence of an
470 ;; unused rest arg instead of implicitly.
471 (emit-receive-values asm proc-slot #t nreq)
fa48a2f7 472 (when (and rest-var (maybe-slot rest-var))
987c1f5f
AW
473 (emit-bind-rest asm (+ proc-slot 1 nreq)))
474 (for-each (match-lambda
475 ((src . dst) (emit-mov asm dst src)))
476 (lookup-parallel-moves k allocation))
477 (emit-reset-frame asm nlocals)))))
6e422a35
AW
478
479 (match f
480 (($ $fun src meta free ($ $cont k ($ $kentry self tail clauses)))
481 ;; FIXME: src on kentry instead?
482 (when src
483 (emit-source asm src))
484 (compile-entry (or meta '()))))))
d258fccc 485
6e8ad823
AW
486(define (visit-funs proc exp)
487 (match exp
6e422a35 488 (($ $continue _ _ exp)
6e8ad823
AW
489 (visit-funs proc exp))
490
6e422a35 491 (($ $fun src meta free body)
6e8ad823
AW
492 (proc exp)
493 (visit-funs proc body))
494
495 (($ $letk conts body)
496 (visit-funs proc body)
497 (for-each (lambda (cont) (visit-funs proc cont)) conts))
498
6e422a35 499 (($ $cont sym ($ $kargs names syms body))
6e8ad823
AW
500 (visit-funs proc body))
501
6e422a35 502 (($ $cont sym ($ $kclause arity body))
6e8ad823
AW
503 (visit-funs proc body))
504
6e422a35 505 (($ $cont sym ($ $kentry self tail clauses))
6e8ad823
AW
506 (for-each (lambda (clause) (visit-funs proc clause)) clauses))
507
508 (_ (values))))
509
691697de 510(define (compile-bytecode exp env opts)
6e8ad823
AW
511 (let* ((exp (fix-arities exp))
512 (exp (optimize exp opts))
513 (exp (convert-closures exp))
514 (exp (reify-primitives exp))
515 (asm (make-assembler)))
516 (visit-funs (lambda (fun)
517 (compile-fun fun asm))
518 exp)
519 (values (link-assembly asm #:page-aligned? (kw-arg-ref opts #:to-file? #f))
520 env
521 env)))