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