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