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