remove @apply memoizer
[bpt/guile.git] / module / language / tree-il / compile-glil.scm
CommitLineData
811d10f5
AW
1;;; TREE-IL -> GLIL compiler
2
d0ecf8eb 3;; Copyright (C) 2001,2008,2009,2010,2011,2012,2013 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)))
25450a0d 67 (x (optimize x e opts))
403d78f9 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
d0ecf8eb
AW
347 ((tail) (if (<= len #xff)
348 (emit-code src (make-glil-call 'tail-call len))
349 (begin
350 (comp-push (make-const #f len))
351 (emit-code src (make-glil-call 'tail-call/nargs 0)))))
352 ((push) (if (<= len #xff)
353 (emit-code src (make-glil-call 'call len))
354 (begin
355 (comp-push (make-const #f len))
356 (emit-code src (make-glil-call 'call/nargs 0))))
230cfcfb 357 (maybe-emit-return))
d0ecf8eb
AW
358 ;; FIXME: mv-call doesn't have a /nargs variant, so it is
359 ;; limited to 255 args. Can work around it with a
360 ;; trampoline and tail-call/nargs, but it's not so nice.
230cfcfb
AW
361 ((vals) (emit-code src (make-glil-mv-call len MVRA))
362 (maybe-emit-return))
363 ((drop) (let ((MV (make-label)) (POST (make-label)))
364 (emit-code src (make-glil-mv-call len MV))
365 (emit-code #f (make-glil-call 'drop 1))
366 (emit-branch #f 'br (or RA POST))
367 (emit-label MV)
05c51bcf 368 (emit-code #f (make-glil-mv-bind 0 #f))
230cfcfb
AW
369 (if RA
370 (emit-branch #f 'br RA)
371 (emit-label POST)))))))))
073bb617 372
a881a4ae
AW
373 ((<primcall> src name args)
374 (pmatch (cons name args)
39caffe7 375 ((apply ,proc . ,args)
a881a4ae
AW
376 (cond
377 ((and (primitive-ref? proc) (eq? (primitive-ref-name proc) 'values)
378 (not (eq? context 'push)) (not (eq? context 'vals)))
379 ;; tail: (lambda () (apply values '(1 2)))
380 ;; drop: (lambda () (apply values '(1 2)) 3)
381 ;; push: (lambda () (list (apply values '(10 12)) 1))
382 (case context
383 ((drop) (for-each comp-drop args) (maybe-emit-return))
384 ((tail)
385 (for-each comp-push args)
386 (emit-code src (make-glil-call 'return/values* (length args))))))
387
388 (else
389 (case context
390 ((tail)
391 (comp-push proc)
392 (for-each comp-push args)
393 (emit-code src (make-glil-call 'tail-apply (1+ (length args)))))
394 ((push)
395 (emit-code src (make-glil-call 'new-frame 0))
396 (comp-push proc)
397 (for-each comp-push args)
398 (emit-code src (make-glil-call 'apply (1+ (length args))))
399 (maybe-emit-return))
400 (else
39caffe7
AW
401 (comp-tail (make-call src (make-primitive-ref #f 'apply)
402 (cons proc args))))))))
a881a4ae 403
78f0ef20 404 ((values . _)
a881a4ae
AW
405 ;; tail: (lambda () (values '(1 2)))
406 ;; drop: (lambda () (values '(1 2)) 3)
407 ;; push: (lambda () (list (values '(10 12)) 1))
408 ;; vals: (let-values (((a b ...) (values 1 2 ...))) ...)
409 (case context
410 ((drop) (for-each comp-drop args) (maybe-emit-return))
78f0ef20
AW
411 ((push)
412 (case (length args)
413 ((0)
414 ;; FIXME: This is surely an error. We need to add a
415 ;; values-mismatch warning pass.
416 (comp-push (make-call src (make-primitive-ref #f 'values)
417 '())))
78f0ef20
AW
418 (else
419 ;; Taking advantage of unspecified order of evaluation of
420 ;; arguments.
421 (for-each comp-drop (cdr args))
252acfe8
AW
422 (comp-push (car args))
423 (maybe-emit-return))))
a881a4ae
AW
424 ((vals)
425 (for-each comp-push args)
426 (emit-code #f (make-glil-const (length args)))
427 (emit-branch src 'br MVRA))
428 ((tail)
429 (for-each comp-push args)
78f0ef20
AW
430 (emit-code src (let ((len (length args)))
431 (if (= len 1)
432 (make-glil-call 'return 1)
433 (make-glil-call 'return/values len)))))))
a881a4ae
AW
434
435 ((@call-with-values ,producer ,consumer)
436 ;; CONSUMER
437 ;; PRODUCER
438 ;; (mv-call MV)
439 ;; ([tail]-call 1)
440 ;; goto POST
441 ;; MV: [tail-]call/nargs
442 ;; POST: (maybe-drop)
443 (case context
444 ((vals)
445 ;; Fall back.
446 (comp-tail (make-primcall src 'call-with-values args)))
447 (else
448 (let ((MV (make-label)) (POST (make-label)))
449 (if (not (eq? context 'tail))
450 (emit-code src (make-glil-call 'new-frame 0)))
451 (comp-push consumer)
452 (emit-code src (make-glil-call 'new-frame 0))
453 (comp-push producer)
454 (emit-code src (make-glil-mv-call 0 MV))
455 (case context
456 ((tail) (emit-code src (make-glil-call 'tail-call 1)))
457 (else (emit-code src (make-glil-call 'call 1))
458 (emit-branch #f 'br POST)))
459 (emit-label MV)
460 (case context
461 ((tail) (emit-code src (make-glil-call 'tail-call/nargs 0)))
462 (else (emit-code src (make-glil-call 'call/nargs 0))
463 (emit-label POST)
464 (if (eq? context 'drop)
465 (emit-code #f (make-glil-call 'drop 1)))
466 (maybe-emit-return)))))))
467
468 ((@call-with-current-continuation ,proc)
469 (case context
470 ((tail)
471 (comp-push proc)
472 (emit-code src (make-glil-call 'tail-call/cc 1)))
473 ((vals)
474 (comp-vals
475 (make-primcall src 'call-with-current-continuation args)
476 MVRA)
477 (maybe-emit-return))
478 ((push)
479 (comp-push proc)
480 (emit-code src (make-glil-call 'call/cc 1))
481 (maybe-emit-return))
482 ((drop)
483 ;; Fall back.
484 (comp-tail
485 (make-primcall src 'call-with-current-continuation args)))))
486
487 ;; A hack for variable-set, the opcode for which takes its args
488 ;; reversed, relative to the variable-set! function
489 ((variable-set! ,var ,val)
490 (comp-push val)
491 (comp-push var)
492 (emit-code src (make-glil-call 'variable-set 2))
493 (case context
494 ((tail push vals) (emit-code #f (make-glil-void))))
495 (maybe-emit-return))
496
497 (else
498 (cond
499 ((or (hash-ref *primcall-ops* (cons name (length args)))
500 (hash-ref *primcall-ops* name))
501 => (lambda (op)
502 (for-each comp-push args)
503 (emit-code src (make-glil-call op (length args)))
504 (case (instruction-pushes op)
505 ((0)
506 (case context
507 ((tail push vals) (emit-code #f (make-glil-void))))
508 (maybe-emit-return))
509 ((1)
510 (case context
511 ((drop) (emit-code #f (make-glil-call 'drop 1))))
512 (maybe-emit-return))
513 ((-1)
514 ;; A control instruction, like return/values. Here we
515 ;; just have to hope that the author of the tree-il
516 ;; knew what they were doing.
517 *unspecified*)
518 (else
519 (error "bad primitive op: too many pushes"
520 op (instruction-pushes op))))))
521 (else
522 ;; Fall back to the normal compilation strategy.
523 (comp-tail (make-call src (make-primitive-ref #f name) args)))))))
524
b6d93b11 525 ((<conditional> src test consequent alternate)
073bb617
AW
526 ;; TEST
527 ;; (br-if-not L1)
b6d93b11 528 ;; consequent
073bb617 529 ;; (br L2)
b6d93b11 530 ;; L1: alternate
073bb617
AW
531 ;; L2:
532 (let ((L1 (make-label)) (L2 (make-label)))
b4a595a5 533 (record-case test
a881a4ae
AW
534 ((<primcall> name args)
535 (pmatch (cons name args)
536 ((eq? ,a ,b)
537 (comp-push a)
538 (comp-push b)
539 (emit-branch src 'br-if-not-eq L1))
540 ((null? ,x)
541 (comp-push x)
542 (emit-branch src 'br-if-not-null L1))
5ddd9645
BT
543 ((nil? ,x)
544 (comp-push x)
545 (emit-branch src 'br-if-not-nil L1))
a881a4ae
AW
546 ((not ,x)
547 (record-case x
548 ((<primcall> name args)
549 (pmatch (cons name args)
550 ((eq? ,a ,b)
551 (comp-push a)
552 (comp-push b)
553 (emit-branch src 'br-if-eq L1))
554 ((null? ,x)
555 (comp-push x)
556 (emit-branch src 'br-if-null L1))
5ddd9645
BT
557 ((nil? ,x)
558 (comp-push x)
559 (emit-branch src 'br-if-nil L1))
a881a4ae
AW
560 (else
561 (comp-push x)
562 (emit-branch src 'br-if L1))))
563 (else
564 (comp-push x)
565 (emit-branch src 'br-if L1))))
b4a595a5
AW
566 (else
567 (comp-push test)
568 (emit-branch src 'br-if-not L1))))
569 (else
570 (comp-push test)
571 (emit-branch src 'br-if-not L1)))
572
b6d93b11 573 (comp-tail consequent)
d97b69d9
AW
574 ;; if there is an RA, comp-tail will cause a jump to it -- just
575 ;; have to clean up here if there is no RA.
576 (if (and (not RA) (not (eq? context 'tail)))
577 (emit-branch #f 'br L2))
cf10678f 578 (emit-label L1)
b4a595a5 579 (comp-tail alternate)
d97b69d9
AW
580 (if (and (not RA) (not (eq? context 'tail)))
581 (emit-label L2))))
582
cf10678f 583 ((<primitive-ref> src name)
a1a482e0
AW
584 (cond
585 ((eq? (module-variable (fluid-ref *comp-module*) name)
586 (module-variable the-root-module name))
587 (case context
230cfcfb
AW
588 ((tail push vals)
589 (emit-code src (make-glil-toplevel 'ref name))))
590 (maybe-emit-return))
94ff26b9 591 ((module-variable the-root-module name)
a1a482e0 592 (case context
230cfcfb
AW
593 ((tail push vals)
594 (emit-code src (make-glil-module 'ref '(guile) name #f))))
94ff26b9
AW
595 (maybe-emit-return))
596 (else
597 (case context
598 ((tail push vals)
599 (emit-code src (make-glil-module
600 'ref (module-name (fluid-ref *comp-module*)) name #f))))
230cfcfb 601 (maybe-emit-return))))
cf10678f 602
e5f5113c 603 ((<lexical-ref> src gensym)
cf10678f 604 (case context
f4aa8d53 605 ((push vals tail)
9b29d607 606 (pmatch (hashq-ref (hashq-ref allocation gensym) self)
66d3e9a3
AW
607 ((,local? ,boxed? . ,index)
608 (emit-code src (make-glil-lexical local? boxed? 'ref index)))
609 (,loc
3b24aee6 610 (error "bad lexical allocation" x loc)))))
230cfcfb 611 (maybe-emit-return))
66d3e9a3 612
e5f5113c 613 ((<lexical-set> src gensym exp)
cf10678f 614 (comp-push exp)
9b29d607 615 (pmatch (hashq-ref (hashq-ref allocation gensym) self)
66d3e9a3
AW
616 ((,local? ,boxed? . ,index)
617 (emit-code src (make-glil-lexical local? boxed? 'set index)))
618 (,loc
3b24aee6 619 (error "bad lexical allocation" x loc)))
cf10678f 620 (case context
230cfcfb
AW
621 ((tail push vals)
622 (emit-code #f (make-glil-void))))
623 (maybe-emit-return))
cf10678f
AW
624
625 ((<module-ref> src mod name public?)
626 (emit-code src (make-glil-module 'ref mod name public?))
627 (case context
230cfcfb
AW
628 ((drop) (emit-code #f (make-glil-call 'drop 1))))
629 (maybe-emit-return))
cf10678f
AW
630
631 ((<module-set> src mod name public? exp)
632 (comp-push exp)
633 (emit-code src (make-glil-module 'set mod name public?))
634 (case context
230cfcfb
AW
635 ((tail push vals)
636 (emit-code #f (make-glil-void))))
637 (maybe-emit-return))
cf10678f
AW
638
639 ((<toplevel-ref> src name)
640 (emit-code src (make-glil-toplevel 'ref name))
641 (case context
230cfcfb
AW
642 ((drop) (emit-code #f (make-glil-call 'drop 1))))
643 (maybe-emit-return))
cf10678f
AW
644
645 ((<toplevel-set> src name exp)
646 (comp-push exp)
647 (emit-code src (make-glil-toplevel 'set name))
648 (case context
230cfcfb
AW
649 ((tail push vals)
650 (emit-code #f (make-glil-void))))
651 (maybe-emit-return))
cf10678f
AW
652
653 ((<toplevel-define> src name exp)
654 (comp-push exp)
655 (emit-code src (make-glil-toplevel 'define name))
656 (case context
230cfcfb
AW
657 ((tail push vals)
658 (emit-code #f (make-glil-void))))
659 (maybe-emit-return))
cf10678f
AW
660
661 ((<lambda>)
8a4ca0ea 662 (let ((free-locs (cdr (hashq-ref allocation x))))
66d3e9a3
AW
663 (case context
664 ((push vals tail)
9b29d607 665 (emit-code #f (flatten-lambda x #f allocation))
66d3e9a3
AW
666 (if (not (null? free-locs))
667 (begin
668 (for-each
669 (lambda (loc)
670 (pmatch loc
d773ba23 671 ((,local? ,boxed? . ,n)
66d3e9a3 672 (emit-code #f (make-glil-lexical local? #f 'ref n)))
3b24aee6 673 (else (error "bad lambda free var allocation" x loc))))
66d3e9a3 674 free-locs)
6f16379e
AW
675 (emit-code #f (make-glil-call 'make-closure
676 (length free-locs))))))))
230cfcfb 677 (maybe-emit-return))
66d3e9a3 678
93f63467 679 ((<lambda-case> src req opt rest kw inits gensyms alternate body)
899d37a6
AW
680 ;; o/~ feature on top of feature o/~
681 ;; req := (name ...)
b0c8c187 682 ;; opt := (name ...) | #f
899d37a6 683 ;; rest := name | #f
b0c8c187 684 ;; kw: (allow-other-keys? (keyword name var) ...) | #f
93f63467
AW
685 ;; gensyms: (sym ...)
686 ;; init: tree-il in context of gensyms
687 ;; gensyms map to named arguments in the following order:
899d37a6
AW
688 ;; required, optional (positional), rest, keyword.
689 (let* ((nreq (length req))
690 (nopt (if opt (length opt) 0))
691 (rest-idx (and rest (+ nreq nopt)))
b0c8c187 692 (opt-names (or opt '()))
899d37a6
AW
693 (allow-other-keys? (if kw (car kw) #f))
694 (kw-indices (map (lambda (x)
695 (pmatch x
b0c8c187 696 ((,key ,name ,var)
93f63467 697 (cons key (list-index gensyms var)))
899d37a6
AW
698 (else (error "bad kwarg" x))))
699 (if kw (cdr kw) '())))
b0c8c187
AW
700 (nargs (apply max (+ nreq nopt (if rest 1 0))
701 (map 1+ (map cdr kw-indices))))
899d37a6 702 (nlocs (cdr (hashq-ref allocation x)))
3a88cb3b 703 (alternate-label (and alternate (make-label))))
899d37a6 704 (or (= nargs
93f63467 705 (length gensyms)
b0c8c187 706 (+ nreq (length inits) (if rest 1 0)))
3b24aee6 707 (error "lambda-case gensyms don't correspond to args"
93f63467 708 req opt rest kw inits gensyms nreq nopt kw-indices nargs))
7e01997e
AW
709 ;; the prelude, to check args & reset the stack pointer,
710 ;; allowing room for locals
711 (emit-code
712 src
713 (cond
7e01997e 714 (kw
899d37a6 715 (make-glil-kw-prelude nreq nopt rest-idx kw-indices
3a88cb3b 716 allow-other-keys? nlocs alternate-label))
7e01997e 717 ((or rest opt)
3a88cb3b 718 (make-glil-opt-prelude nreq nopt rest-idx nlocs alternate-label))
7e01997e 719 (#t
3a88cb3b 720 (make-glil-std-prelude nreq nlocs alternate-label))))
7e01997e
AW
721 ;; box args if necessary
722 (for-each
723 (lambda (v)
724 (pmatch (hashq-ref (hashq-ref allocation v) self)
725 ((#t #t . ,n)
726 (emit-code #f (make-glil-lexical #t #f 'ref n))
727 (emit-code #f (make-glil-lexical #t #t 'box n)))))
93f63467 728 gensyms)
7e01997e 729 ;; write bindings info
93f63467 730 (if (not (null? gensyms))
7e01997e
AW
731 (emit-bindings
732 #f
733 (let lp ((kw (if kw (cdr kw) '()))
b0c8c187 734 (names (append (reverse opt-names) (reverse req)))
93f63467 735 (gensyms (list-tail gensyms (+ nreq nopt
7e01997e
AW
736 (if rest 1 0)))))
737 (pmatch kw
899d37a6 738 (()
93f63467 739 ;; fixme: check that gensyms is empty
899d37a6 740 (reverse (if rest (cons rest names) names)))
7e01997e 741 (((,key ,name ,var) . ,kw)
93f63467
AW
742 (if (memq var gensyms)
743 (lp kw (cons name names) (delq var gensyms))
744 (lp kw names gensyms)))
7e01997e 745 (,kw (error "bad keywords, yo" kw))))
93f63467 746 gensyms allocation self emit-code))
b0c8c187 747 ;; init optional/kw args
93f63467 748 (let lp ((inits inits) (n nreq) (gensyms (list-tail gensyms nreq)))
b0c8c187
AW
749 (cond
750 ((null? inits)) ; done
751 ((and rest-idx (= n rest-idx))
93f63467 752 (lp inits (1+ n) (cdr gensyms)))
b0c8c187 753 (#t
93f63467 754 (pmatch (hashq-ref (hashq-ref allocation (car gensyms)) self)
b0c8c187
AW
755 ((#t ,boxed? . ,n*) (guard (= n* n))
756 (let ((L (make-label)))
757 (emit-code #f (make-glil-lexical #t boxed? 'bound? n))
758 (emit-code #f (make-glil-branch 'br-if L))
759 (comp-push (car inits))
760 (emit-code #f (make-glil-lexical #t boxed? 'set n))
761 (emit-label L)
93f63467 762 (lp (cdr inits) (1+ n) (cdr gensyms))))
3b24aee6 763 (#t (error "bad arg allocation" (car gensyms) inits))))))
7e01997e
AW
764 ;; post-prelude case label for label calls
765 (emit-label (car (hashq-ref allocation x)))
8a4ca0ea 766 (comp-tail body)
93f63467 767 (if (not (null? gensyms))
8a4ca0ea 768 (emit-code #f (make-glil-unbind)))
3a88cb3b 769 (if alternate-label
8a4ca0ea 770 (begin
3a88cb3b 771 (emit-label alternate-label)
0083cb5e
AW
772 (flatten-lambda-case alternate allocation self self-label
773 fix-labels emit-code)))))
8a4ca0ea 774
93f63467 775 ((<let> src names gensyms vals body)
073bb617 776 (for-each comp-push vals)
93f63467 777 (emit-bindings src names gensyms allocation self emit-code)
cf10678f 778 (for-each (lambda (v)
9b29d607 779 (pmatch (hashq-ref (hashq-ref allocation v) self)
66d3e9a3
AW
780 ((#t #f . ,n)
781 (emit-code src (make-glil-lexical #t #f 'set n)))
782 ((#t #t . ,n)
783 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6 784 (,loc (error "bad let var allocation" x loc))))
93f63467 785 (reverse gensyms))
f4aa8d53 786 (comp-tail body)
fb135e12 787 (clear-stack-slots context gensyms)
cf10678f
AW
788 (emit-code #f (make-glil-unbind)))
789
60d4b224
AW
790 ((<letrec> src in-order? names gensyms vals body)
791 ;; First prepare heap storage slots.
66d3e9a3 792 (for-each (lambda (v)
9b29d607 793 (pmatch (hashq-ref (hashq-ref allocation v) self)
66d3e9a3
AW
794 ((#t #t . ,n)
795 (emit-code src (make-glil-lexical #t #t 'empty-box n)))
3b24aee6 796 (,loc (error "bad letrec var allocation" x loc))))
93f63467 797 gensyms)
60d4b224 798 ;; Even though the slots are empty, the bindings are valid.
93f63467 799 (emit-bindings src names gensyms allocation self emit-code)
60d4b224
AW
800 (cond
801 (in-order?
802 ;; For letrec*, bind values in order.
803 (for-each (lambda (name v val)
804 (pmatch (hashq-ref (hashq-ref allocation v) self)
805 ((#t #t . ,n)
806 (comp-push val)
807 (emit-code src (make-glil-lexical #t #t 'set n)))
3b24aee6 808 (,loc (error "bad letrec var allocation" x loc))))
60d4b224
AW
809 names gensyms vals))
810 (else
811 ;; But for letrec, eval all values, then bind.
812 (for-each comp-push vals)
813 (for-each (lambda (v)
814 (pmatch (hashq-ref (hashq-ref allocation v) self)
815 ((#t #t . ,n)
816 (emit-code src (make-glil-lexical #t #t 'set n)))
3b24aee6 817 (,loc (error "bad letrec var allocation" x loc))))
60d4b224 818 (reverse gensyms))))
f4aa8d53 819 (comp-tail body)
fb135e12 820 (clear-stack-slots context gensyms)
f4aa8d53
AW
821 (emit-code #f (make-glil-unbind)))
822
93f63467 823 ((<fix> src names gensyms vals body)
230cfcfb
AW
824 ;; The ideal here is to just render the lambda bodies inline, and
825 ;; wire the code together with gotos. We can do that if
826 ;; analyze-lexicals has determined that a given var has "label"
827 ;; allocation -- which is the case if it is in `fix-labels'.
828 ;;
829 ;; But even for closures that we can't inline, we can do some
830 ;; tricks to avoid heap-allocation for the binding itself. Since
831 ;; we know the vals are lambdas, we can set them to their local
832 ;; var slots first, then capture their bindings, mutating them in
833 ;; place.
7f7b85cb 834 (let ((new-RA (if (or (eq? context 'tail) RA) #f (make-label))))
230cfcfb
AW
835 (for-each
836 (lambda (x v)
837 (cond
838 ((hashq-ref allocation x)
839 ;; allocating a closure
840 (emit-code #f (flatten-lambda x v allocation))
6f16379e
AW
841 (let ((free-locs (cdr (hashq-ref allocation x))))
842 (if (not (null? free-locs))
843 ;; Need to make-closure first, so we have a fresh closure on
844 ;; the heap, but with a temporary free values.
845 (begin
846 (for-each (lambda (loc)
847 (emit-code #f (make-glil-const #f)))
848 free-locs)
849 (emit-code #f (make-glil-call 'make-closure
850 (length free-locs))))))
230cfcfb
AW
851 (pmatch (hashq-ref (hashq-ref allocation v) self)
852 ((#t #f . ,n)
853 (emit-code src (make-glil-lexical #t #f 'set n)))
3b24aee6 854 (,loc (error "bad fix var allocation" x loc))))
230cfcfb
AW
855 (else
856 ;; labels allocation: emit label & body, but jump over it
857 (let ((POST (make-label)))
858 (emit-branch #f 'br POST)
8a4ca0ea
AW
859 (let lp ((lcase (lambda-body x)))
860 (if lcase
861 (record-case lcase
93f63467 862 ((<lambda-case> src req gensyms body alternate)
8a4ca0ea
AW
863 (emit-label (car (hashq-ref allocation lcase)))
864 ;; FIXME: opt & kw args in the bindings
93f63467 865 (emit-bindings #f req gensyms allocation self emit-code)
8a4ca0ea
AW
866 (if src
867 (emit-code #f (make-glil-source src)))
868 (comp-fix body (or RA new-RA))
869 (emit-code #f (make-glil-unbind))
3a88cb3b 870 (lp alternate)))
8a4ca0ea 871 (emit-label POST)))))))
230cfcfb 872 vals
93f63467 873 gensyms)
230cfcfb 874 ;; Emit bindings metadata for closures
93f63467
AW
875 (let ((binds (let lp ((out '()) (gensyms gensyms) (names names))
876 (cond ((null? gensyms) (reverse! out))
877 ((assq (car gensyms) fix-labels)
878 (lp out (cdr gensyms) (cdr names)))
230cfcfb 879 (else
93f63467
AW
880 (lp (acons (car gensyms) (car names) out)
881 (cdr gensyms) (cdr names)))))))
230cfcfb
AW
882 (emit-bindings src (map cdr binds) (map car binds)
883 allocation self emit-code))
884 ;; Now go back and fix up the bindings for closures.
885 (for-each
886 (lambda (x v)
887 (let ((free-locs (if (hashq-ref allocation x)
8a4ca0ea 888 (cdr (hashq-ref allocation x))
230cfcfb
AW
889 ;; can hit this latter case for labels allocation
890 '())))
891 (if (not (null? free-locs))
892 (begin
893 (for-each
894 (lambda (loc)
895 (pmatch loc
d773ba23 896 ((,local? ,boxed? . ,n)
230cfcfb 897 (emit-code #f (make-glil-lexical local? #f 'ref n)))
3b24aee6 898 (else (error "bad free var allocation" x loc))))
230cfcfb 899 free-locs)
230cfcfb
AW
900 (pmatch (hashq-ref (hashq-ref allocation v) self)
901 ((#t #f . ,n)
902 (emit-code #f (make-glil-lexical #t #f 'fix n)))
3b24aee6 903 (,loc (error "bad fix var allocation" x loc)))))))
230cfcfb 904 vals
93f63467 905 gensyms)
230cfcfb 906 (comp-tail body)
7f7b85cb
AW
907 (if new-RA
908 (emit-label new-RA))
fb135e12 909 (clear-stack-slots context gensyms)
230cfcfb 910 (emit-code #f (make-glil-unbind))))
c21c89b1 911
8a4ca0ea
AW
912 ((<let-values> src exp body)
913 (record-case body
93f63467 914 ((<lambda-case> req opt kw rest gensyms body alternate)
3a88cb3b 915 (if (or opt kw alternate)
8a4ca0ea
AW
916 (error "unexpected lambda-case in let-values" x))
917 (let ((MV (make-label)))
918 (comp-vals exp MV)
919 (emit-code #f (make-glil-const 1))
920 (emit-label MV)
921 (emit-code src (make-glil-mv-bind
922 (vars->bind-list
923 (append req (if rest (list rest) '()))
93f63467 924 gensyms allocation self)
8a4ca0ea
AW
925 (and rest #t)))
926 (for-each (lambda (v)
927 (pmatch (hashq-ref (hashq-ref allocation v) self)
928 ((#t #f . ,n)
929 (emit-code src (make-glil-lexical #t #f 'set n)))
930 ((#t #t . ,n)
931 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6 932 (,loc (error "bad let-values var allocation" x loc))))
93f63467 933 (reverse gensyms))
8a4ca0ea 934 (comp-tail body)
fb135e12 935 (clear-stack-slots context gensyms)
c6601f10
AW
936 (emit-code #f (make-glil-unbind))))))
937
9b965638 938 ((<dynwind> src winder body unwinder)
d5dbe0c1
AW
939 (define (thunk? x)
940 (and (lambda? x)
941 (null? (lambda-case-gensyms (lambda-body x)))))
942 (define (make-wrong-type-arg x)
943 (make-primcall src 'scm-error
944 (list
945 (make-const #f 'wrong-type-arg)
946 (make-const #f "dynamic-wind")
947 (make-const #f "Wrong type (expecting thunk): ~S")
948 (make-primcall #f 'list (list x))
949 (make-primcall #f 'list (list x)))))
950 (define (emit-thunk-check x)
951 (comp-drop (make-conditional
952 src
953 (make-primcall src 'thunk? (list x))
954 (make-void #f)
955 (make-wrong-type-arg x))))
956
9b965638
AW
957 ;; The `winder' and `unwinder' of a dynwind are constant
958 ;; expressions and can be duplicated.
d5dbe0c1
AW
959 (if (not (thunk? winder))
960 (emit-thunk-check winder))
c6601f10 961 (comp-push winder)
d5dbe0c1
AW
962 (if (not (thunk? unwinder))
963 (emit-thunk-check unwinder))
c6601f10 964 (comp-push unwinder)
c6601f10
AW
965 (emit-code #f (make-glil-call 'wind 2))
966
967 (case context
968 ((tail)
969 (let ((MV (make-label)))
970 (comp-vals body MV)
9b965638 971 ;; One value. Unwind and return the value.
c6601f10 972 (emit-code #f (make-glil-call 'unwind 0))
c6601f10
AW
973 (emit-code #f (make-glil-call 'return 1))
974
975 (emit-label MV)
9b965638 976 ;; Multiple values. Unwind and return the values.
c6601f10 977 (emit-code #f (make-glil-call 'unwind 0))
c6601f10
AW
978 (emit-code #f (make-glil-call 'return/nvalues 1))))
979
980 ((push)
9b965638
AW
981 ;; We only want one value, so ask for one value and then
982 ;; unwind, leaving the value on the stack.
c6601f10 983 (comp-push body)
9b965638 984 (emit-code #f (make-glil-call 'unwind 0)))
c6601f10
AW
985
986 ((vals)
987 (let ((MV (make-label)))
988 (comp-vals body MV)
9b965638
AW
989 ;; Transform a singly-valued return to a multiple-value
990 ;; return and fall through to MV case.
c6601f10
AW
991 (emit-code #f (make-glil-const 1))
992
993 (emit-label MV)
9b965638 994 ;; Multiple values: unwind and go to the MVRA.
c6601f10 995 (emit-code #f (make-glil-call 'unwind 0))
c6601f10
AW
996 (emit-branch #f 'br MVRA)))
997
998 ((drop)
9b965638
AW
999 ;; Compile body, discarding values. Then unwind and fall
1000 ;; through, or goto RA if there is one.
c6601f10
AW
1001 (comp-drop body)
1002 (emit-code #f (make-glil-call 'unwind 0))
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)))))))