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