Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / module / language / tree-il / compile-glil.scm
CommitLineData
811d10f5
AW
1;;; TREE-IL -> GLIL compiler
2
9dadfa47 3;; Copyright (C) 2001,2008,2009,2010,2011 Free Software Foundation, Inc.
811d10f5 4
53befeb7
NJ
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
811d10f5
AW
18
19;;; Code:
20
21(define-module (language tree-il compile-glil)
22 #:use-module (system base syntax)
66d3e9a3 23 #:use-module (system base pmatch)
4b856371 24 #:use-module (system base message)
cf10678f 25 #:use-module (ice-9 receive)
811d10f5 26 #:use-module (language glil)
60ed31d2 27 #:use-module (system vm instruction)
811d10f5 28 #:use-module (language tree-il)
073bb617 29 #:use-module (language tree-il optimize)
b275fb26 30 #:use-module (language tree-il canonicalize)
cf10678f 31 #:use-module (language tree-il analyze)
48b1db75 32 #:use-module ((srfi srfi-1) #:select (filter-map))
811d10f5
AW
33 #:export (compile-glil))
34
073bb617 35;; allocation:
66d3e9a3 36;; sym -> {lambda -> address}
8a4ca0ea
AW
37;; lambda -> (labels . free-locs)
38;; lambda-case -> (gensym . nlocs)
66d3e9a3 39;;
8a4ca0ea
AW
40;; address ::= (local? boxed? . index)
41;; labels ::= ((sym . lambda) ...)
66d3e9a3
AW
42;; free-locs ::= ((sym0 . address0) (sym1 . address1) ...)
43;; free variable addresses are relative to parent proc.
073bb617 44
a1a482e0
AW
45(define *comp-module* (make-fluid))
46
4b856371 47(define %warning-passes
48b1db75 48 `((unused-variable . ,unused-variable-analysis)
bcae9a98 49 (unused-toplevel . ,unused-toplevel-analysis)
ae03cf1f 50 (unbound-variable . ,unbound-variable-analysis)
75365375
LC
51 (arity-mismatch . ,arity-analysis)
52 (format . ,format-analysis)))
4b856371 53
811d10f5 54(define (compile-glil x e opts)
4b856371
LC
55 (define warnings
56 (or (and=> (memq #:warnings opts) cadr)
57 '()))
58
43eb8aca 59 ;; Go through the warning passes.
48b1db75
LC
60 (let ((analyses (filter-map (lambda (kind)
61 (assoc-ref %warning-passes kind))
62 warnings)))
63 (analyze-tree analyses x e))
aaae0d5a 64
8a4ca0ea 65 (let* ((x (make-lambda (tree-il-src x) '()
1e2a8edb 66 (make-lambda-case #f '() #f #f #f '() '() x #f)))
aaae0d5a 67 (x (optimize! x e opts))
b275fb26 68 (x (canonicalize! x))
aaae0d5a 69 (allocation (analyze-lexicals x)))
4b856371 70
eddd16d7
AW
71 (with-fluids ((*comp-module* e))
72 (values (flatten-lambda x #f allocation)
73 e
74 e))))
811d10f5
AW
75
76\f
811d10f5 77
112edbae
AW
78(define *primcall-ops* (make-hash-table))
79(for-each
80 (lambda (x) (hash-set! *primcall-ops* (car x) (cdr x)))
81 '(((eq? . 2) . eq?)
82 ((eqv? . 2) . eqv?)
83 ((equal? . 2) . equal?)
84 ((= . 2) . ee?)
85 ((< . 2) . lt?)
86 ((> . 2) . gt?)
87 ((<= . 2) . le?)
88 ((>= . 2) . ge?)
89 ((+ . 2) . add)
90 ((- . 2) . sub)
7382f23e
AW
91 ((1+ . 1) . add1)
92 ((1- . 1) . sub1)
112edbae
AW
93 ((* . 2) . mul)
94 ((/ . 2) . div)
95 ((quotient . 2) . quo)
96 ((remainder . 2) . rem)
97 ((modulo . 2) . mod)
b10d9330
AW
98 ((ash . 2) . ash)
99 ((logand . 2) . logand)
100 ((logior . 2) . logior)
101 ((logxor . 2) . logxor)
112edbae
AW
102 ((not . 1) . not)
103 ((pair? . 1) . pair?)
104 ((cons . 2) . cons)
105 ((car . 1) . car)
106 ((cdr . 1) . cdr)
107 ((set-car! . 2) . set-car!)
108 ((set-cdr! . 2) . set-cdr!)
109 ((null? . 1) . null?)
c11f46af 110 ((list? . 1) . list?)
cf45ff03
AW
111 ((symbol? . 1) . symbol?)
112 ((vector? . 1) . vector?)
c11f46af 113 (list . list)
ad9b8c45 114 (vector . vector)
aec4a84a 115 ((class-of . 1) . class-of)
ad9b8c45 116 ((@slot-ref . 2) . slot-ref)
d6f1ce3d 117 ((@slot-set! . 3) . slot-set)
d5a4f51f
AW
118 ((string-length . 1) . string-length)
119 ((string-ref . 2) . string-ref)
120 ((vector-length . 1) . vector-length)
d6f1ce3d
AW
121 ((vector-ref . 2) . vector-ref)
122 ((vector-set! . 3) . vector-set)
1d30393f
AW
123 ((variable-ref . 1) . variable-ref)
124 ;; nb, *not* variable-set! -- the args are switched
d27a7811 125 ((variable-bound? . 1) . variable-bound?)
bd91ecce
LC
126 ((struct? . 1) . struct?)
127 ((struct-vtable . 1) . struct-vtable)
a752c0dc
LC
128 ((struct-ref . 2) . struct-ref)
129 ((struct-set! . 3) . struct-set)
9a974fd3 130 (make-struct/no-tail . make-struct)
39141c87 131
d61e866c 132 ;; hack for javascript
52272fc7 133 ((return . 1) . return)
9582b26c
AW
134 ;; hack for lua
135 (return/values . return/values)
d61e866c 136
39141c87
AW
137 ((bytevector-u8-ref . 2) . bv-u8-ref)
138 ((bytevector-u8-set! . 3) . bv-u8-set)
139 ((bytevector-s8-ref . 2) . bv-s8-ref)
140 ((bytevector-s8-set! . 3) . bv-s8-set)
141
142 ((bytevector-u16-ref . 3) . bv-u16-ref)
143 ((bytevector-u16-set! . 4) . bv-u16-set)
144 ((bytevector-u16-native-ref . 2) . bv-u16-native-ref)
145 ((bytevector-u16-native-set! . 3) . bv-u16-native-set)
146 ((bytevector-s16-ref . 3) . bv-s16-ref)
147 ((bytevector-s16-set! . 4) . bv-s16-set)
148 ((bytevector-s16-native-ref . 2) . bv-s16-native-ref)
149 ((bytevector-s16-native-set! . 3) . bv-s16-native-set)
150
151 ((bytevector-u32-ref . 3) . bv-u32-ref)
152 ((bytevector-u32-set! . 4) . bv-u32-set)
153 ((bytevector-u32-native-ref . 2) . bv-u32-native-ref)
154 ((bytevector-u32-native-set! . 3) . bv-u32-native-set)
155 ((bytevector-s32-ref . 3) . bv-s32-ref)
156 ((bytevector-s32-set! . 4) . bv-s32-set)
157 ((bytevector-s32-native-ref . 2) . bv-s32-native-ref)
158 ((bytevector-s32-native-set! . 3) . bv-s32-native-set)
159
160 ((bytevector-u64-ref . 3) . bv-u64-ref)
161 ((bytevector-u64-set! . 4) . bv-u64-set)
162 ((bytevector-u64-native-ref . 2) . bv-u64-native-ref)
163 ((bytevector-u64-native-set! . 3) . bv-u64-native-set)
164 ((bytevector-s64-ref . 3) . bv-s64-ref)
165 ((bytevector-s64-set! . 4) . bv-s64-set)
166 ((bytevector-s64-native-ref . 2) . bv-s64-native-ref)
167 ((bytevector-s64-native-set! . 3) . bv-s64-native-set)
168
169 ((bytevector-ieee-single-ref . 3) . bv-f32-ref)
170 ((bytevector-ieee-single-set! . 4) . bv-f32-set)
171 ((bytevector-ieee-single-native-ref . 2) . bv-f32-native-ref)
172 ((bytevector-ieee-single-native-set! . 3) . bv-f32-native-set)
173 ((bytevector-ieee-double-ref . 3) . bv-f64-ref)
174 ((bytevector-ieee-double-set! . 4) . bv-f64-set)
175 ((bytevector-ieee-double-native-ref . 2) . bv-f64-native-ref)
176 ((bytevector-ieee-double-native-set! . 3) . bv-f64-native-set)))
177
178
179\f
112edbae 180
811d10f5
AW
181(define (make-label) (gensym ":L"))
182
66d3e9a3 183(define (vars->bind-list ids vars allocation proc)
2ce77f2d 184 (map (lambda (id v)
66d3e9a3
AW
185 (pmatch (hashq-ref (hashq-ref allocation v) proc)
186 ((#t ,boxed? . ,n)
187 (list id boxed? n))
3b24aee6 188 (,x (error "bad var list element" id v x))))
2ce77f2d 189 ids
cf10678f
AW
190 vars))
191
66d3e9a3 192(define (emit-bindings src ids vars allocation proc emit-code)
d97b69d9
AW
193 (emit-code src (make-glil-bind
194 (vars->bind-list ids vars allocation proc))))
cf10678f
AW
195
196(define (with-output-to-code proc)
197 (let ((out '()))
198 (define (emit-code src x)
199 (set! out (cons x out))
200 (if src
201 (set! out (cons (make-glil-source src) out))))
202 (proc emit-code)
203 (reverse out)))
204
9b29d607 205(define (flatten-lambda x self-label allocation)
8a4ca0ea
AW
206 (record-case x
207 ((<lambda> src meta body)
208 (make-glil-program
209 meta
210 (with-output-to-code
211 (lambda (emit-code)
212 ;; write source info for proc
213 (if src (emit-code #f (make-glil-source src)))
8a4ca0ea 214 ;; compile the body, yo
0083cb5e
AW
215 (flatten-lambda-case body allocation x self-label
216 (car (hashq-ref allocation x))
217 emit-code)))))))
cf10678f 218
0083cb5e
AW
219(define (flatten-lambda-case lcase allocation self self-label fix-labels
220 emit-code)
cf10678f
AW
221 (define (emit-label label)
222 (emit-code #f (make-glil-label label)))
223 (define (emit-branch src inst label)
224 (emit-code src (make-glil-branch inst label)))
225
230cfcfb
AW
226 ;; RA: "return address"; #f unless we're in a non-tail fix with labels
227 ;; MVRA: "multiple-values return address"; #f unless we're in a let-values
0083cb5e 228 (let comp ((x lcase) (context 'tail) (RA #f) (MVRA #f))
230cfcfb
AW
229 (define (comp-tail tree) (comp tree context RA MVRA))
230 (define (comp-push tree) (comp tree 'push #f #f))
231 (define (comp-drop tree) (comp tree 'drop #f #f))
232 (define (comp-vals tree MVRA) (comp tree 'vals #f MVRA))
233 (define (comp-fix tree RA) (comp tree context RA MVRA))
234
235 ;; A couple of helpers. Note that if we are in tail context, we
236 ;; won't have an RA.
237 (define (maybe-emit-return)
238 (if RA
239 (emit-branch #f 'br RA)
240 (if (eq? context 'tail)
241 (emit-code #f (make-glil-call 'return 1)))))
242
fb135e12
AW
243 ;; After lexical binding forms in non-tail context, call this
244 ;; function to clear stack slots, allowing their previous values to
245 ;; be collected.
246 (define (clear-stack-slots context syms)
247 (case context
248 ((push drop)
249 (for-each (lambda (v)
250 (and=>
251 ;; Can be #f if the var is labels-allocated.
252 (hashq-ref allocation v)
253 (lambda (h)
254 (pmatch (hashq-ref h self)
255 ((#t _ . ,n)
256 (emit-code #f (make-glil-void))
257 (emit-code #f (make-glil-lexical #t #f 'set n)))
258 (,loc (error "bad let var allocation" x loc))))))
259 syms))))
260
cf10678f
AW
261 (record-case x
262 ((<void>)
263 (case context
230cfcfb
AW
264 ((push vals tail)
265 (emit-code #f (make-glil-void))))
266 (maybe-emit-return))
cf10678f
AW
267
268 ((<const> src exp)
269 (case context
230cfcfb
AW
270 ((push vals tail)
271 (emit-code src (make-glil-const exp))))
272 (maybe-emit-return))
cf10678f 273
6fc3eae4
AW
274 ((<seq> head tail)
275 (comp-drop head)
276 (comp-tail tail))
277
7081d4f9 278 ((<call> src proc args)
112edbae 279 (cond
0083cb5e 280 ;; call to the same lambda-case in tail position
9b29d607
AW
281 ((and (lexical-ref? proc)
282 self-label (eq? (lexical-ref-gensym proc) self-label)
0083cb5e
AW
283 (eq? context 'tail)
284 (not (lambda-case-kw lcase))
285 (not (lambda-case-rest lcase))
286 (= (length args)
287 (+ (length (lambda-case-req lcase))
288 (or (and=> (lambda-case-opt lcase) length) 0))))
289 (for-each comp-push args)
290 (for-each (lambda (sym)
291 (pmatch (hashq-ref (hashq-ref allocation sym) self)
292 ((#t #f . ,index) ; unboxed
293 (emit-code #f (make-glil-lexical #t #f 'set index)))
294 ((#t #t . ,index) ; boxed
295 ;; new box
296 (emit-code #f (make-glil-lexical #t #t 'box index)))
297 (,x (error "bad lambda-case arg allocation" x))))
298 (reverse (lambda-case-gensyms lcase)))
299 (emit-branch src 'br (car (hashq-ref allocation lcase))))
9b29d607 300
230cfcfb
AW
301 ;; lambda, the ultimate goto
302 ((and (lexical-ref? proc)
303 (assq (lexical-ref-gensym proc) fix-labels))
8a4ca0ea
AW
304 ;; like the self-tail-call case, though we can handle "drop"
305 ;; contexts too. first, evaluate new values, pushing them on
306 ;; the stack
230cfcfb 307 (for-each comp-push args)
8a4ca0ea
AW
308 ;; find the specific case, rename args, and goto the case label
309 (let lp ((lcase (lambda-body
310 (assq-ref fix-labels (lexical-ref-gensym proc)))))
311 (cond
312 ((and (lambda-case? lcase)
313 (not (lambda-case-kw lcase))
314 (not (lambda-case-opt lcase))
315 (not (lambda-case-rest lcase))
316 (= (length args) (length (lambda-case-req lcase))))
317 ;; we have a case that matches the args; rename variables
318 ;; and goto the case label
319 (for-each (lambda (sym)
320 (pmatch (hashq-ref (hashq-ref allocation sym) self)
321 ((#t #f . ,index) ; unboxed
322 (emit-code #f (make-glil-lexical #t #f 'set index)))
323 ((#t #t . ,index) ; boxed
324 (emit-code #f (make-glil-lexical #t #t 'box index)))
3b24aee6 325 (,x (error "bad lambda-case arg allocation" x))))
93f63467 326 (reverse (lambda-case-gensyms lcase)))
8a4ca0ea
AW
327 (emit-branch src 'br (car (hashq-ref allocation lcase))))
328 ((lambda-case? lcase)
329 ;; no match, try next case
3a88cb3b 330 (lp (lambda-case-alternate lcase)))
8a4ca0ea
AW
331 (else
332 ;; no cases left. we can't really handle this currently.
333 ;; ideally we would push on a new frame, then do a "local
334 ;; call" -- which doesn't require consing up a program
335 ;; object. but for now error, as this sort of case should
336 ;; preclude label allocation.
337 (error "couldn't find matching case for label call" x)))))
230cfcfb 338
112edbae 339 (else
b7946e9e
AW
340 (if (not (eq? context 'tail))
341 (emit-code src (make-glil-call 'new-frame 0)))
112edbae
AW
342 (comp-push proc)
343 (for-each comp-push args)
dce042f1
AW
344 (let ((len (length args)))
345 (case context
a5bbb22e 346 ((tail) (emit-code src (make-glil-call 'tail-call len)))
230cfcfb
AW
347 ((push) (emit-code src (make-glil-call 'call len))
348 (maybe-emit-return))
349 ((vals) (emit-code src (make-glil-mv-call len MVRA))
350 (maybe-emit-return))
351 ((drop) (let ((MV (make-label)) (POST (make-label)))
352 (emit-code src (make-glil-mv-call len MV))
353 (emit-code #f (make-glil-call 'drop 1))
354 (emit-branch #f 'br (or RA POST))
355 (emit-label MV)
05c51bcf 356 (emit-code #f (make-glil-mv-bind 0 #f))
230cfcfb
AW
357 (if RA
358 (emit-branch #f 'br RA)
359 (emit-label POST)))))))))
073bb617 360
a881a4ae
AW
361 ((<primcall> src name args)
362 (pmatch (cons name args)
363 ((@apply ,proc . ,args)
364 (cond
365 ((and (primitive-ref? proc) (eq? (primitive-ref-name proc) 'values)
366 (not (eq? context 'push)) (not (eq? context 'vals)))
367 ;; tail: (lambda () (apply values '(1 2)))
368 ;; drop: (lambda () (apply values '(1 2)) 3)
369 ;; push: (lambda () (list (apply values '(10 12)) 1))
370 (case context
371 ((drop) (for-each comp-drop args) (maybe-emit-return))
372 ((tail)
373 (for-each comp-push args)
374 (emit-code src (make-glil-call 'return/values* (length args))))))
375
376 (else
377 (case context
378 ((tail)
379 (comp-push proc)
380 (for-each comp-push args)
381 (emit-code src (make-glil-call 'tail-apply (1+ (length args)))))
382 ((push)
383 (emit-code src (make-glil-call 'new-frame 0))
384 (comp-push proc)
385 (for-each comp-push args)
386 (emit-code src (make-glil-call 'apply (1+ (length args))))
387 (maybe-emit-return))
388 (else
389 (comp-tail (make-primcall src 'apply (cons proc args))))))))
390
78f0ef20 391 ((values . _)
a881a4ae
AW
392 ;; tail: (lambda () (values '(1 2)))
393 ;; drop: (lambda () (values '(1 2)) 3)
394 ;; push: (lambda () (list (values '(10 12)) 1))
395 ;; vals: (let-values (((a b ...) (values 1 2 ...))) ...)
396 (case context
397 ((drop) (for-each comp-drop args) (maybe-emit-return))
78f0ef20
AW
398 ((push)
399 (case (length args)
400 ((0)
401 ;; FIXME: This is surely an error. We need to add a
402 ;; values-mismatch warning pass.
403 (comp-push (make-call src (make-primitive-ref #f 'values)
404 '())))
405 ((1)
406 (comp-push (car args)))
407 (else
408 ;; Taking advantage of unspecified order of evaluation of
409 ;; arguments.
410 (for-each comp-drop (cdr args))
411 (comp-push (car args)))))
a881a4ae
AW
412 ((vals)
413 (for-each comp-push args)
414 (emit-code #f (make-glil-const (length args)))
415 (emit-branch src 'br MVRA))
416 ((tail)
417 (for-each comp-push args)
78f0ef20
AW
418 (emit-code src (let ((len (length args)))
419 (if (= len 1)
420 (make-glil-call 'return 1)
421 (make-glil-call 'return/values len)))))))
a881a4ae
AW
422
423 ((@call-with-values ,producer ,consumer)
424 ;; CONSUMER
425 ;; PRODUCER
426 ;; (mv-call MV)
427 ;; ([tail]-call 1)
428 ;; goto POST
429 ;; MV: [tail-]call/nargs
430 ;; POST: (maybe-drop)
431 (case context
432 ((vals)
433 ;; Fall back.
434 (comp-tail (make-primcall src 'call-with-values args)))
435 (else
436 (let ((MV (make-label)) (POST (make-label)))
437 (if (not (eq? context 'tail))
438 (emit-code src (make-glil-call 'new-frame 0)))
439 (comp-push consumer)
440 (emit-code src (make-glil-call 'new-frame 0))
441 (comp-push producer)
442 (emit-code src (make-glil-mv-call 0 MV))
443 (case context
444 ((tail) (emit-code src (make-glil-call 'tail-call 1)))
445 (else (emit-code src (make-glil-call 'call 1))
446 (emit-branch #f 'br POST)))
447 (emit-label MV)
448 (case context
449 ((tail) (emit-code src (make-glil-call 'tail-call/nargs 0)))
450 (else (emit-code src (make-glil-call 'call/nargs 0))
451 (emit-label POST)
452 (if (eq? context 'drop)
453 (emit-code #f (make-glil-call 'drop 1)))
454 (maybe-emit-return)))))))
455
456 ((@call-with-current-continuation ,proc)
457 (case context
458 ((tail)
459 (comp-push proc)
460 (emit-code src (make-glil-call 'tail-call/cc 1)))
461 ((vals)
462 (comp-vals
463 (make-primcall src 'call-with-current-continuation args)
464 MVRA)
465 (maybe-emit-return))
466 ((push)
467 (comp-push proc)
468 (emit-code src (make-glil-call 'call/cc 1))
469 (maybe-emit-return))
470 ((drop)
471 ;; Fall back.
472 (comp-tail
473 (make-primcall src 'call-with-current-continuation args)))))
474
475 ;; A hack for variable-set, the opcode for which takes its args
476 ;; reversed, relative to the variable-set! function
477 ((variable-set! ,var ,val)
478 (comp-push val)
479 (comp-push var)
480 (emit-code src (make-glil-call 'variable-set 2))
481 (case context
482 ((tail push vals) (emit-code #f (make-glil-void))))
483 (maybe-emit-return))
484
485 (else
486 (cond
487 ((or (hash-ref *primcall-ops* (cons name (length args)))
488 (hash-ref *primcall-ops* name))
489 => (lambda (op)
490 (for-each comp-push args)
491 (emit-code src (make-glil-call op (length args)))
492 (case (instruction-pushes op)
493 ((0)
494 (case context
495 ((tail push vals) (emit-code #f (make-glil-void))))
496 (maybe-emit-return))
497 ((1)
498 (case context
499 ((drop) (emit-code #f (make-glil-call 'drop 1))))
500 (maybe-emit-return))
501 ((-1)
502 ;; A control instruction, like return/values. Here we
503 ;; just have to hope that the author of the tree-il
504 ;; knew what they were doing.
505 *unspecified*)
506 (else
507 (error "bad primitive op: too many pushes"
508 op (instruction-pushes op))))))
509 (else
510 ;; Fall back to the normal compilation strategy.
511 (comp-tail (make-call src (make-primitive-ref #f name) args)))))))
512
b6d93b11 513 ((<conditional> src test consequent alternate)
073bb617
AW
514 ;; TEST
515 ;; (br-if-not L1)
b6d93b11 516 ;; consequent
073bb617 517 ;; (br L2)
b6d93b11 518 ;; L1: alternate
073bb617
AW
519 ;; L2:
520 (let ((L1 (make-label)) (L2 (make-label)))
b4a595a5 521 (record-case test
a881a4ae
AW
522 ((<primcall> name args)
523 (pmatch (cons name args)
524 ((eq? ,a ,b)
525 (comp-push a)
526 (comp-push b)
527 (emit-branch src 'br-if-not-eq L1))
528 ((null? ,x)
529 (comp-push x)
530 (emit-branch src 'br-if-not-null L1))
531 ((not ,x)
532 (record-case x
533 ((<primcall> name args)
534 (pmatch (cons name args)
535 ((eq? ,a ,b)
536 (comp-push a)
537 (comp-push b)
538 (emit-branch src 'br-if-eq L1))
539 ((null? ,x)
540 (comp-push x)
541 (emit-branch src 'br-if-null L1))
542 (else
543 (comp-push x)
544 (emit-branch src 'br-if L1))))
545 (else
546 (comp-push x)
547 (emit-branch src 'br-if L1))))
b4a595a5
AW
548 (else
549 (comp-push test)
550 (emit-branch src 'br-if-not L1))))
551 (else
552 (comp-push test)
553 (emit-branch src 'br-if-not L1)))
554
b6d93b11 555 (comp-tail consequent)
d97b69d9
AW
556 ;; if there is an RA, comp-tail will cause a jump to it -- just
557 ;; have to clean up here if there is no RA.
558 (if (and (not RA) (not (eq? context 'tail)))
559 (emit-branch #f 'br L2))
cf10678f 560 (emit-label L1)
b4a595a5 561 (comp-tail alternate)
d97b69d9
AW
562 (if (and (not RA) (not (eq? context 'tail)))
563 (emit-label L2))))
564
cf10678f 565 ((<primitive-ref> src name)
a1a482e0
AW
566 (cond
567 ((eq? (module-variable (fluid-ref *comp-module*) name)
568 (module-variable the-root-module name))
569 (case context
230cfcfb
AW
570 ((tail push vals)
571 (emit-code src (make-glil-toplevel 'ref name))))
572 (maybe-emit-return))
94ff26b9 573 ((module-variable the-root-module name)
a1a482e0 574 (case context
230cfcfb
AW
575 ((tail push vals)
576 (emit-code src (make-glil-module 'ref '(guile) name #f))))
94ff26b9
AW
577 (maybe-emit-return))
578 (else
579 (case context
580 ((tail push vals)
581 (emit-code src (make-glil-module
582 'ref (module-name (fluid-ref *comp-module*)) name #f))))
230cfcfb 583 (maybe-emit-return))))
cf10678f 584
e5f5113c 585 ((<lexical-ref> src gensym)
cf10678f 586 (case context
f4aa8d53 587 ((push vals tail)
9b29d607 588 (pmatch (hashq-ref (hashq-ref allocation gensym) self)
66d3e9a3
AW
589 ((,local? ,boxed? . ,index)
590 (emit-code src (make-glil-lexical local? boxed? 'ref index)))
591 (,loc
3b24aee6 592 (error "bad lexical allocation" x loc)))))
230cfcfb 593 (maybe-emit-return))
66d3e9a3 594
e5f5113c 595 ((<lexical-set> src gensym exp)
cf10678f 596 (comp-push exp)
9b29d607 597 (pmatch (hashq-ref (hashq-ref allocation gensym) self)
66d3e9a3
AW
598 ((,local? ,boxed? . ,index)
599 (emit-code src (make-glil-lexical local? boxed? 'set index)))
600 (,loc
3b24aee6 601 (error "bad lexical allocation" x loc)))
cf10678f 602 (case context
230cfcfb
AW
603 ((tail push vals)
604 (emit-code #f (make-glil-void))))
605 (maybe-emit-return))
cf10678f
AW
606
607 ((<module-ref> src mod name public?)
608 (emit-code src (make-glil-module 'ref mod name public?))
609 (case context
230cfcfb
AW
610 ((drop) (emit-code #f (make-glil-call 'drop 1))))
611 (maybe-emit-return))
cf10678f
AW
612
613 ((<module-set> src mod name public? exp)
614 (comp-push exp)
615 (emit-code src (make-glil-module 'set mod name public?))
616 (case context
230cfcfb
AW
617 ((tail push vals)
618 (emit-code #f (make-glil-void))))
619 (maybe-emit-return))
cf10678f
AW
620
621 ((<toplevel-ref> src name)
622 (emit-code src (make-glil-toplevel 'ref name))
623 (case context
230cfcfb
AW
624 ((drop) (emit-code #f (make-glil-call 'drop 1))))
625 (maybe-emit-return))
cf10678f
AW
626
627 ((<toplevel-set> src name exp)
628 (comp-push exp)
629 (emit-code src (make-glil-toplevel 'set name))
630 (case context
230cfcfb
AW
631 ((tail push vals)
632 (emit-code #f (make-glil-void))))
633 (maybe-emit-return))
cf10678f
AW
634
635 ((<toplevel-define> src name exp)
636 (comp-push exp)
637 (emit-code src (make-glil-toplevel 'define name))
638 (case context
230cfcfb
AW
639 ((tail push vals)
640 (emit-code #f (make-glil-void))))
641 (maybe-emit-return))
cf10678f
AW
642
643 ((<lambda>)
8a4ca0ea 644 (let ((free-locs (cdr (hashq-ref allocation x))))
66d3e9a3
AW
645 (case context
646 ((push vals tail)
9b29d607 647 (emit-code #f (flatten-lambda x #f allocation))
66d3e9a3
AW
648 (if (not (null? free-locs))
649 (begin
650 (for-each
651 (lambda (loc)
652 (pmatch loc
d773ba23 653 ((,local? ,boxed? . ,n)
66d3e9a3 654 (emit-code #f (make-glil-lexical local? #f 'ref n)))
3b24aee6 655 (else (error "bad lambda free var allocation" x loc))))
66d3e9a3 656 free-locs)
6f16379e
AW
657 (emit-code #f (make-glil-call 'make-closure
658 (length free-locs))))))))
230cfcfb 659 (maybe-emit-return))
66d3e9a3 660
93f63467 661 ((<lambda-case> src req opt rest kw inits gensyms alternate body)
899d37a6
AW
662 ;; o/~ feature on top of feature o/~
663 ;; req := (name ...)
b0c8c187 664 ;; opt := (name ...) | #f
899d37a6 665 ;; rest := name | #f
b0c8c187 666 ;; kw: (allow-other-keys? (keyword name var) ...) | #f
93f63467
AW
667 ;; gensyms: (sym ...)
668 ;; init: tree-il in context of gensyms
669 ;; gensyms map to named arguments in the following order:
899d37a6
AW
670 ;; required, optional (positional), rest, keyword.
671 (let* ((nreq (length req))
672 (nopt (if opt (length opt) 0))
673 (rest-idx (and rest (+ nreq nopt)))
b0c8c187 674 (opt-names (or opt '()))
899d37a6
AW
675 (allow-other-keys? (if kw (car kw) #f))
676 (kw-indices (map (lambda (x)
677 (pmatch x
b0c8c187 678 ((,key ,name ,var)
93f63467 679 (cons key (list-index gensyms var)))
899d37a6
AW
680 (else (error "bad kwarg" x))))
681 (if kw (cdr kw) '())))
b0c8c187
AW
682 (nargs (apply max (+ nreq nopt (if rest 1 0))
683 (map 1+ (map cdr kw-indices))))
899d37a6 684 (nlocs (cdr (hashq-ref allocation x)))
3a88cb3b 685 (alternate-label (and alternate (make-label))))
899d37a6 686 (or (= nargs
93f63467 687 (length gensyms)
b0c8c187 688 (+ nreq (length inits) (if rest 1 0)))
3b24aee6 689 (error "lambda-case gensyms don't correspond to args"
93f63467 690 req opt rest kw inits gensyms nreq nopt kw-indices nargs))
7e01997e
AW
691 ;; the prelude, to check args & reset the stack pointer,
692 ;; allowing room for locals
693 (emit-code
694 src
695 (cond
7e01997e 696 (kw
899d37a6 697 (make-glil-kw-prelude nreq nopt rest-idx kw-indices
3a88cb3b 698 allow-other-keys? nlocs alternate-label))
7e01997e 699 ((or rest opt)
3a88cb3b 700 (make-glil-opt-prelude nreq nopt rest-idx nlocs alternate-label))
7e01997e 701 (#t
3a88cb3b 702 (make-glil-std-prelude nreq nlocs alternate-label))))
7e01997e
AW
703 ;; box args if necessary
704 (for-each
705 (lambda (v)
706 (pmatch (hashq-ref (hashq-ref allocation v) self)
707 ((#t #t . ,n)
708 (emit-code #f (make-glil-lexical #t #f 'ref n))
709 (emit-code #f (make-glil-lexical #t #t 'box n)))))
93f63467 710 gensyms)
7e01997e 711 ;; write bindings info
93f63467 712 (if (not (null? gensyms))
7e01997e
AW
713 (emit-bindings
714 #f
715 (let lp ((kw (if kw (cdr kw) '()))
b0c8c187 716 (names (append (reverse opt-names) (reverse req)))
93f63467 717 (gensyms (list-tail gensyms (+ nreq nopt
7e01997e
AW
718 (if rest 1 0)))))
719 (pmatch kw
899d37a6 720 (()
93f63467 721 ;; fixme: check that gensyms is empty
899d37a6 722 (reverse (if rest (cons rest names) names)))
7e01997e 723 (((,key ,name ,var) . ,kw)
93f63467
AW
724 (if (memq var gensyms)
725 (lp kw (cons name names) (delq var gensyms))
726 (lp kw names gensyms)))
7e01997e 727 (,kw (error "bad keywords, yo" kw))))
93f63467 728 gensyms allocation self emit-code))
b0c8c187 729 ;; init optional/kw args
93f63467 730 (let lp ((inits inits) (n nreq) (gensyms (list-tail gensyms nreq)))
b0c8c187
AW
731 (cond
732 ((null? inits)) ; done
733 ((and rest-idx (= n rest-idx))
93f63467 734 (lp inits (1+ n) (cdr gensyms)))
b0c8c187 735 (#t
93f63467 736 (pmatch (hashq-ref (hashq-ref allocation (car gensyms)) self)
b0c8c187
AW
737 ((#t ,boxed? . ,n*) (guard (= n* n))
738 (let ((L (make-label)))
739 (emit-code #f (make-glil-lexical #t boxed? 'bound? n))
740 (emit-code #f (make-glil-branch 'br-if L))
741 (comp-push (car inits))
742 (emit-code #f (make-glil-lexical #t boxed? 'set n))
743 (emit-label L)
93f63467 744 (lp (cdr inits) (1+ n) (cdr gensyms))))
3b24aee6 745 (#t (error "bad arg allocation" (car gensyms) inits))))))
7e01997e
AW
746 ;; post-prelude case label for label calls
747 (emit-label (car (hashq-ref allocation x)))
8a4ca0ea 748 (comp-tail body)
93f63467 749 (if (not (null? gensyms))
8a4ca0ea 750 (emit-code #f (make-glil-unbind)))
3a88cb3b 751 (if alternate-label
8a4ca0ea 752 (begin
3a88cb3b 753 (emit-label alternate-label)
0083cb5e
AW
754 (flatten-lambda-case alternate allocation self self-label
755 fix-labels emit-code)))))
8a4ca0ea 756
93f63467 757 ((<let> src names gensyms vals body)
073bb617 758 (for-each comp-push vals)
93f63467 759 (emit-bindings src names gensyms allocation self emit-code)
cf10678f 760 (for-each (lambda (v)
9b29d607 761 (pmatch (hashq-ref (hashq-ref allocation v) self)
66d3e9a3
AW
762 ((#t #f . ,n)
763 (emit-code src (make-glil-lexical #t #f 'set n)))
764 ((#t #t . ,n)
765 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6 766 (,loc (error "bad let var allocation" x loc))))
93f63467 767 (reverse gensyms))
f4aa8d53 768 (comp-tail body)
fb135e12 769 (clear-stack-slots context gensyms)
cf10678f
AW
770 (emit-code #f (make-glil-unbind)))
771
60d4b224
AW
772 ((<letrec> src in-order? names gensyms vals body)
773 ;; First prepare heap storage slots.
66d3e9a3 774 (for-each (lambda (v)
9b29d607 775 (pmatch (hashq-ref (hashq-ref allocation v) self)
66d3e9a3
AW
776 ((#t #t . ,n)
777 (emit-code src (make-glil-lexical #t #t 'empty-box n)))
3b24aee6 778 (,loc (error "bad letrec var allocation" x loc))))
93f63467 779 gensyms)
60d4b224 780 ;; Even though the slots are empty, the bindings are valid.
93f63467 781 (emit-bindings src names gensyms allocation self emit-code)
60d4b224
AW
782 (cond
783 (in-order?
784 ;; For letrec*, bind values in order.
785 (for-each (lambda (name v val)
786 (pmatch (hashq-ref (hashq-ref allocation v) self)
787 ((#t #t . ,n)
788 (comp-push val)
789 (emit-code src (make-glil-lexical #t #t 'set n)))
3b24aee6 790 (,loc (error "bad letrec var allocation" x loc))))
60d4b224
AW
791 names gensyms vals))
792 (else
793 ;; But for letrec, eval all values, then bind.
794 (for-each comp-push vals)
795 (for-each (lambda (v)
796 (pmatch (hashq-ref (hashq-ref allocation v) self)
797 ((#t #t . ,n)
798 (emit-code src (make-glil-lexical #t #t 'set n)))
3b24aee6 799 (,loc (error "bad letrec var allocation" x loc))))
60d4b224 800 (reverse gensyms))))
f4aa8d53 801 (comp-tail body)
fb135e12 802 (clear-stack-slots context gensyms)
f4aa8d53
AW
803 (emit-code #f (make-glil-unbind)))
804
93f63467 805 ((<fix> src names gensyms vals body)
230cfcfb
AW
806 ;; The ideal here is to just render the lambda bodies inline, and
807 ;; wire the code together with gotos. We can do that if
808 ;; analyze-lexicals has determined that a given var has "label"
809 ;; allocation -- which is the case if it is in `fix-labels'.
810 ;;
811 ;; But even for closures that we can't inline, we can do some
812 ;; tricks to avoid heap-allocation for the binding itself. Since
813 ;; we know the vals are lambdas, we can set them to their local
814 ;; var slots first, then capture their bindings, mutating them in
815 ;; place.
7f7b85cb 816 (let ((new-RA (if (or (eq? context 'tail) RA) #f (make-label))))
230cfcfb
AW
817 (for-each
818 (lambda (x v)
819 (cond
820 ((hashq-ref allocation x)
821 ;; allocating a closure
822 (emit-code #f (flatten-lambda x v allocation))
6f16379e
AW
823 (let ((free-locs (cdr (hashq-ref allocation x))))
824 (if (not (null? free-locs))
825 ;; Need to make-closure first, so we have a fresh closure on
826 ;; the heap, but with a temporary free values.
827 (begin
828 (for-each (lambda (loc)
829 (emit-code #f (make-glil-const #f)))
830 free-locs)
831 (emit-code #f (make-glil-call 'make-closure
832 (length free-locs))))))
230cfcfb
AW
833 (pmatch (hashq-ref (hashq-ref allocation v) self)
834 ((#t #f . ,n)
835 (emit-code src (make-glil-lexical #t #f 'set n)))
3b24aee6 836 (,loc (error "bad fix var allocation" x loc))))
230cfcfb
AW
837 (else
838 ;; labels allocation: emit label & body, but jump over it
839 (let ((POST (make-label)))
840 (emit-branch #f 'br POST)
8a4ca0ea
AW
841 (let lp ((lcase (lambda-body x)))
842 (if lcase
843 (record-case lcase
93f63467 844 ((<lambda-case> src req gensyms body alternate)
8a4ca0ea
AW
845 (emit-label (car (hashq-ref allocation lcase)))
846 ;; FIXME: opt & kw args in the bindings
93f63467 847 (emit-bindings #f req gensyms allocation self emit-code)
8a4ca0ea
AW
848 (if src
849 (emit-code #f (make-glil-source src)))
850 (comp-fix body (or RA new-RA))
851 (emit-code #f (make-glil-unbind))
3a88cb3b 852 (lp alternate)))
8a4ca0ea 853 (emit-label POST)))))))
230cfcfb 854 vals
93f63467 855 gensyms)
230cfcfb 856 ;; Emit bindings metadata for closures
93f63467
AW
857 (let ((binds (let lp ((out '()) (gensyms gensyms) (names names))
858 (cond ((null? gensyms) (reverse! out))
859 ((assq (car gensyms) fix-labels)
860 (lp out (cdr gensyms) (cdr names)))
230cfcfb 861 (else
93f63467
AW
862 (lp (acons (car gensyms) (car names) out)
863 (cdr gensyms) (cdr names)))))))
230cfcfb
AW
864 (emit-bindings src (map cdr binds) (map car binds)
865 allocation self emit-code))
866 ;; Now go back and fix up the bindings for closures.
867 (for-each
868 (lambda (x v)
869 (let ((free-locs (if (hashq-ref allocation x)
8a4ca0ea 870 (cdr (hashq-ref allocation x))
230cfcfb
AW
871 ;; can hit this latter case for labels allocation
872 '())))
873 (if (not (null? free-locs))
874 (begin
875 (for-each
876 (lambda (loc)
877 (pmatch loc
d773ba23 878 ((,local? ,boxed? . ,n)
230cfcfb 879 (emit-code #f (make-glil-lexical local? #f 'ref n)))
3b24aee6 880 (else (error "bad free var allocation" x loc))))
230cfcfb 881 free-locs)
230cfcfb
AW
882 (pmatch (hashq-ref (hashq-ref allocation v) self)
883 ((#t #f . ,n)
884 (emit-code #f (make-glil-lexical #t #f 'fix n)))
3b24aee6 885 (,loc (error "bad fix var allocation" x loc)))))))
230cfcfb 886 vals
93f63467 887 gensyms)
230cfcfb 888 (comp-tail body)
7f7b85cb
AW
889 (if new-RA
890 (emit-label new-RA))
fb135e12 891 (clear-stack-slots context gensyms)
230cfcfb 892 (emit-code #f (make-glil-unbind))))
c21c89b1 893
8a4ca0ea
AW
894 ((<let-values> src exp body)
895 (record-case body
93f63467 896 ((<lambda-case> req opt kw rest gensyms body alternate)
3a88cb3b 897 (if (or opt kw alternate)
8a4ca0ea
AW
898 (error "unexpected lambda-case in let-values" x))
899 (let ((MV (make-label)))
900 (comp-vals exp MV)
901 (emit-code #f (make-glil-const 1))
902 (emit-label MV)
903 (emit-code src (make-glil-mv-bind
904 (vars->bind-list
905 (append req (if rest (list rest) '()))
93f63467 906 gensyms allocation self)
8a4ca0ea
AW
907 (and rest #t)))
908 (for-each (lambda (v)
909 (pmatch (hashq-ref (hashq-ref allocation v) self)
910 ((#t #f . ,n)
911 (emit-code src (make-glil-lexical #t #f 'set n)))
912 ((#t #t . ,n)
913 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6 914 (,loc (error "bad let-values var allocation" x loc))))
93f63467 915 (reverse gensyms))
8a4ca0ea 916 (comp-tail body)
fb135e12 917 (clear-stack-slots context gensyms)
c6601f10
AW
918 (emit-code #f (make-glil-unbind))))))
919
920 ;; much trickier than i thought this would be, at first, due to the need
921 ;; to have body's return value(s) on the stack while the unwinder runs,
922 ;; then proceed with returning or dropping or what-have-you, interacting
923 ;; with RA and MVRA. What have you, I say.
880e7948 924 ((<dynwind> src winder pre body post unwinder)
c6601f10
AW
925 (comp-push winder)
926 (comp-push unwinder)
880e7948 927 (comp-drop pre)
c6601f10
AW
928 (emit-code #f (make-glil-call 'wind 2))
929
930 (case context
931 ((tail)
932 (let ((MV (make-label)))
933 (comp-vals body MV)
934 ;; one value: unwind...
935 (emit-code #f (make-glil-call 'unwind 0))
880e7948 936 (comp-drop post)
c6601f10
AW
937 ;; ...and return the val
938 (emit-code #f (make-glil-call 'return 1))
939
940 (emit-label MV)
941 ;; multiple values: unwind...
942 (emit-code #f (make-glil-call 'unwind 0))
880e7948 943 (comp-drop post)
c6601f10
AW
944 ;; and return the values.
945 (emit-code #f (make-glil-call 'return/nvalues 1))))
946
947 ((push)
948 ;; we only want one value. so ask for one value
949 (comp-push body)
950 ;; and unwind, leaving the val on the stack
951 (emit-code #f (make-glil-call 'unwind 0))
880e7948 952 (comp-drop post))
c6601f10
AW
953
954 ((vals)
955 (let ((MV (make-label)))
956 (comp-vals body MV)
957 ;; one value: push 1 and fall through to MV case
958 (emit-code #f (make-glil-const 1))
959
960 (emit-label MV)
961 ;; multiple values: unwind...
962 (emit-code #f (make-glil-call 'unwind 0))
880e7948 963 (comp-drop post)
c6601f10
AW
964 ;; and goto the MVRA.
965 (emit-branch #f 'br MVRA)))
966
967 ((drop)
968 ;; compile body, discarding values. then unwind...
969 (comp-drop body)
970 (emit-code #f (make-glil-call 'unwind 0))
880e7948 971 (comp-drop post)
c6601f10 972 ;; and fall through, or goto RA if there is one.
b50511b4
AW
973 (if RA
974 (emit-branch #f 'br RA)))))
975
976 ((<dynlet> src fluids vals body)
977 (for-each comp-push fluids)
978 (for-each comp-push vals)
979 (emit-code #f (make-glil-call 'wind-fluids (length fluids)))
980
981 (case context
982 ((tail)
983 (let ((MV (make-label)))
984 ;; NB: in tail case, it is possible to preserve asymptotic tail
985 ;; recursion, via merging unwind-fluids structures -- but we'd need
986 ;; to compile in the body twice (once in tail context, assuming the
987 ;; caller unwinds, and once with this trampoline thing, unwinding
988 ;; ourselves).
989 (comp-vals body MV)
990 ;; one value: unwind and return
991 (emit-code #f (make-glil-call 'unwind-fluids 0))
992 (emit-code #f (make-glil-call 'return 1))
993
994 (emit-label MV)
995 ;; multiple values: unwind and return values
996 (emit-code #f (make-glil-call 'unwind-fluids 0))
997 (emit-code #f (make-glil-call 'return/nvalues 1))))
998
999 ((push)
1000 (comp-push body)
1001 (emit-code #f (make-glil-call 'unwind-fluids 0)))
1002
1003 ((vals)
1004 (let ((MV (make-label)))
1005 (comp-vals body MV)
1006 ;; one value: push 1 and fall through to MV case
1007 (emit-code #f (make-glil-const 1))
1008
1009 (emit-label MV)
1010 ;; multiple values: unwind and goto MVRA
1011 (emit-code #f (make-glil-call 'unwind-fluids 0))
1012 (emit-branch #f 'br MVRA)))
1013
1014 ((drop)
1015 ;; compile body, discarding values. then unwind...
1016 (comp-drop body)
1017 (emit-code #f (make-glil-call 'unwind-fluids 0))
1018 ;; and fall through, or goto RA if there is one.
c6601f10
AW
1019 (if RA
1020 (emit-branch #f 'br RA)))))
1021
706a705e
AW
1022 ((<dynref> src fluid)
1023 (case context
1024 ((drop)
1025 (comp-drop fluid))
1026 ((push vals tail)
1027 (comp-push fluid)
1028 (emit-code #f (make-glil-call 'fluid-ref 1))))
1029 (maybe-emit-return))
1030
1031 ((<dynset> src fluid exp)
1032 (comp-push fluid)
1033 (comp-push exp)
1034 (emit-code #f (make-glil-call 'fluid-set 2))
1035 (case context
1036 ((push vals tail)
1037 (emit-code #f (make-glil-void))))
1038 (maybe-emit-return))
1039
c6601f10
AW
1040 ;; What's the deal here? The deal is that we are compiling the start of a
1041 ;; delimited continuation. We try to avoid heap allocation in the normal
1042 ;; case; so the body is an expression, not a thunk, and we try to render
1043 ;; the handler inline. Also we did some analysis, in analyze.scm, so that
1044 ;; if the continuation isn't referenced, we don't reify it. This makes it
1045 ;; possible to implement catch and throw with delimited continuations,
1046 ;; without any overhead.
07a0c7d5 1047 ((<prompt> src tag body handler)
c6601f10
AW
1048 (let ((H (make-label))
1049 (POST (make-label))
c6601f10
AW
1050 (escape-only? (hashq-ref allocation x)))
1051 ;; First, set up the prompt.
1052 (comp-push tag)
ea6b18e8 1053 (emit-code src (make-glil-prompt H escape-only?))
c6601f10
AW
1054
1055 ;; Then we compile the body, with its normal return path, unwinding
1056 ;; before proceeding.
1057 (case context
1058 ((tail)
1059 (let ((MV (make-label)))
1060 (comp-vals body MV)
1061 ;; one value: unwind and return
1062 (emit-code #f (make-glil-call 'unwind 0))
1063 (emit-code #f (make-glil-call 'return 1))
1064 ;; multiple values: unwind and return
1065 (emit-label MV)
1066 (emit-code #f (make-glil-call 'unwind 0))
1067 (emit-code #f (make-glil-call 'return/nvalues 1))))
1068
1069 ((push)
1070 ;; we only want one value. so ask for one value, unwind, and jump to
1071 ;; post
1072 (comp-push body)
1073 (emit-code #f (make-glil-call 'unwind 0))
9dadfa47 1074 (emit-branch #f 'br (or RA POST)))
c6601f10
AW
1075
1076 ((vals)
1077 (let ((MV (make-label)))
1078 (comp-vals body MV)
1079 ;; one value: push 1 and fall through to MV case
1080 (emit-code #f (make-glil-const 1))
1081 ;; multiple values: unwind and goto MVRA
1082 (emit-label MV)
1083 (emit-code #f (make-glil-call 'unwind 0))
1084 (emit-branch #f 'br MVRA)))
1085
1086 ((drop)
1087 ;; compile body, discarding values, then unwind & fall through.
1088 (comp-drop body)
1089 (emit-code #f (make-glil-call 'unwind 0))
1090 (emit-branch #f 'br (or RA POST))))
1091
c6601f10 1092 (emit-label H)
ea6b18e8
AW
1093 ;; Now the handler. The stack is now made up of the continuation, and
1094 ;; then the args to the continuation (pushed separately), and then the
1095 ;; number of args, including the continuation.
1096 (record-case handler
93f63467 1097 ((<lambda-case> req opt kw rest gensyms body alternate)
ea6b18e8
AW
1098 (if (or opt kw alternate)
1099 (error "unexpected lambda-case in prompt" x))
1100 (emit-code src (make-glil-mv-bind
1101 (vars->bind-list
1102 (append req (if rest (list rest) '()))
93f63467 1103 gensyms allocation self)
ea6b18e8
AW
1104 (and rest #t)))
1105 (for-each (lambda (v)
1106 (pmatch (hashq-ref (hashq-ref allocation v) self)
1107 ((#t #f . ,n)
1108 (emit-code src (make-glil-lexical #t #f 'set n)))
1109 ((#t #t . ,n)
1110 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6
AW
1111 (,loc
1112 (error "bad prompt handler arg allocation" x loc))))
93f63467 1113 (reverse gensyms))
ea6b18e8
AW
1114 (comp-tail body)
1115 (emit-code #f (make-glil-unbind))))
c6601f10 1116
9dadfa47
AW
1117 (if (and (not RA)
1118 (or (eq? context 'push) (eq? context 'drop)))
c6601f10
AW
1119 (emit-label POST))))
1120
2d026f04 1121 ((<abort> src tag args tail)
c6601f10 1122 (comp-push tag)
6e84cb95 1123 (for-each comp-push args)
2d026f04 1124 (comp-push tail)
eaefabee
AW
1125 (emit-code src (make-glil-call 'abort (length args)))
1126 ;; so, the abort can actually return. if it does, the values will be on
1127 ;; the stack, then the MV marker, just as in an MV context.
1128 (case context
1129 ((tail)
1130 ;; Return values.
1131 (emit-code #f (make-glil-call 'return/nvalues 1)))
1132 ((drop)
1133 ;; Drop all values and goto RA, or otherwise fall through.
05c51bcf 1134 (emit-code #f (make-glil-mv-bind 0 #f))
eaefabee
AW
1135 (if RA (emit-branch #f 'br RA)))
1136 ((push)
1137 ;; Truncate to one value.
05c51bcf 1138 (emit-code #f (make-glil-mv-bind 1 #f)))
eaefabee
AW
1139 ((vals)
1140 ;; Go to MVRA.
1141 (emit-branch #f 'br MVRA)))))))