Eliminate use of deprecated 'SCM_WTA_DISPATCH_2' in numbers.c.
[bpt/guile.git] / test-suite / tests / peval.test
CommitLineData
de1eb420
AW
1;;;; tree-il.test --- test suite for compiling tree-il -*- scheme -*-
2;;;; Andy Wingo <wingo@pobox.com> --- May 2009
3;;;;
30c3dac7 4;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
de1eb420
AW
5;;;;
6;;;; This library is free software; you can redistribute it and/or
7;;;; modify it under the terms of the GNU Lesser General Public
8;;;; License as published by the Free Software Foundation; either
9;;;; version 3 of the License, or (at your option) any later version.
10;;;;
11;;;; This library is distributed in the hope that it will be useful,
12;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14;;;; Lesser General Public License for more details.
15;;;;
16;;;; You should have received a copy of the GNU Lesser General Public
17;;;; License along with this library; if not, write to the Free Software
18;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20(define-module (test-suite tree-il)
21 #:use-module (test-suite lib)
22 #:use-module (system base compile)
23 #:use-module (system base pmatch)
24 #:use-module (system base message)
25 #:use-module (language tree-il)
26 #:use-module (language tree-il primitives)
27 #:use-module (language glil)
8598dd8d 28 #:use-module (rnrs bytevectors) ;; for the bytevector primitives
de1eb420
AW
29 #:use-module (srfi srfi-13))
30
31(define peval
32 ;; The partial evaluator.
33 (@@ (language tree-il optimize) peval))
34
35(define-syntax pass-if-peval
2aed2667 36 (syntax-rules ()
de1eb420 37 ((_ in pat)
de1eb420 38 (pass-if-peval in pat
25450a0d 39 (expand-primitives
403d78f9 40 (resolve-primitives
de1eb420
AW
41 (compile 'in #:from 'scheme #:to 'tree-il)
42 (current-module)))))
43 ((_ in pat code)
44 (pass-if 'in
45 (let ((evaled (unparse-tree-il (peval code))))
46 (pmatch evaled
47 (pat #t)
48 (_ (pk 'peval-mismatch)
49 ((@ (ice-9 pretty-print) pretty-print)
50 'in)
51 (newline)
52 ((@ (ice-9 pretty-print) pretty-print)
53 evaled)
54 (newline)
55 ((@ (ice-9 pretty-print) pretty-print)
56 'pat)
57 (newline)
58 #f)))))))
59
60\f
61(with-test-prefix "partial evaluation"
62
63 (pass-if-peval
64 ;; First order, primitive.
65 (let ((x 1) (y 2)) (+ x y))
66 (const 3))
67
68 (pass-if-peval
69 ;; First order, thunk.
70 (let ((x 1) (y 2))
71 (let ((f (lambda () (+ x y))))
72 (f)))
73 (const 3))
74
c46e0a8a 75 (pass-if-peval
de1eb420
AW
76 ;; First order, let-values (requires primitive expansion for
77 ;; `call-with-values'.)
78 (let ((x 0))
79 (call-with-values
80 (lambda () (if (zero? x) (values 1 2) (values 3 4)))
81 (lambda (a b)
82 (+ a b))))
83 (const 3))
84
c46e0a8a 85 (pass-if-peval
de1eb420
AW
86 ;; First order, multiple values.
87 (let ((x 1) (y 2))
88 (values x y))
c46e0a8a 89 (primcall values (const 1) (const 2)))
de1eb420 90
c46e0a8a 91 (pass-if-peval
de1eb420
AW
92 ;; First order, multiple values truncated.
93 (let ((x (values 1 'a)) (y 2))
94 (values x y))
c46e0a8a 95 (primcall values (const 1) (const 2)))
de1eb420 96
c46e0a8a 97 (pass-if-peval
de1eb420
AW
98 ;; First order, multiple values truncated.
99 (or (values 1 2) 3)
100 (const 1))
101
102 (pass-if-peval
103 ;; First order, coalesced, mutability preserved.
104 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
c46e0a8a
AW
105 (primcall list
106 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
de1eb420
AW
107
108 (pass-if-peval
109 ;; First order, coalesced, immutability preserved.
110 (cons 0 (cons 1 (cons 2 '(3 4 5))))
c46e0a8a
AW
111 (primcall cons (const 0)
112 (primcall cons (const 1)
113 (primcall cons (const 2)
114 (const (3 4 5))))))
de1eb420
AW
115
116 ;; These two tests doesn't work any more because we changed the way we
117 ;; deal with constants -- now the algorithm will see a construction as
118 ;; being bound to the lexical, so it won't propagate it. It can't
119 ;; even propagate it in the case that it is only referenced once,
120 ;; because:
121 ;;
122 ;; (let ((x (cons 1 2))) (lambda () x))
123 ;;
124 ;; is not the same as
125 ;;
126 ;; (lambda () (cons 1 2))
127 ;;
128 ;; Perhaps if we determined that not only was it only referenced once,
129 ;; it was not closed over by a lambda, then we could propagate it, and
130 ;; re-enable these two tests.
131 ;;
132 #;
133 (pass-if-peval
134 ;; First order, mutability preserved.
135 (let loop ((i 3) (r '()))
136 (if (zero? i)
137 r
138 (loop (1- i) (cons (cons i i) r))))
c46e0a8a
AW
139 (primcall list
140 (primcall cons (const 1) (const 1))
141 (primcall cons (const 2) (const 2))
142 (primcall cons (const 3) (const 3))))
de1eb420
AW
143 ;;
144 ;; See above.
145 #;
146 (pass-if-peval
147 ;; First order, evaluated.
148 (let loop ((i 7)
149 (r '()))
150 (if (<= i 0)
151 (car r)
152 (loop (1- i) (cons i r))))
153 (const 1))
154
155 ;; Instead here are tests for what happens for the above cases: they
156 ;; unroll but they don't fold.
157 (pass-if-peval
158 (let loop ((i 3) (r '()))
159 (if (zero? i)
160 r
161 (loop (1- i) (cons (cons i i) r))))
162 (let (r) (_)
c46e0a8a
AW
163 ((primcall list
164 (primcall cons (const 3) (const 3))))
de1eb420 165 (let (r) (_)
c46e0a8a
AW
166 ((primcall cons
167 (primcall cons (const 2) (const 2))
168 (lexical r _)))
169 (primcall cons
170 (primcall cons (const 1) (const 1))
171 (lexical r _)))))
de1eb420
AW
172
173 ;; See above.
174 (pass-if-peval
175 (let loop ((i 4)
176 (r '()))
177 (if (<= i 0)
178 (car r)
179 (loop (1- i) (cons i r))))
180 (let (r) (_)
c46e0a8a 181 ((primcall list (const 4)))
de1eb420 182 (let (r) (_)
c46e0a8a
AW
183 ((primcall cons
184 (const 3)
185 (lexical r _)))
de1eb420 186 (let (r) (_)
c46e0a8a
AW
187 ((primcall cons
188 (const 2)
189 (lexical r _)))
de1eb420 190 (let (r) (_)
c46e0a8a
AW
191 ((primcall cons
192 (const 1)
193 (lexical r _)))
194 (primcall car
195 (lexical r _)))))))
de1eb420
AW
196
197 ;; Static sums.
198 (pass-if-peval
199 (let loop ((l '(1 2 3 4)) (sum 0))
200 (if (null? l)
201 sum
202 (loop (cdr l) (+ sum (car l)))))
203 (const 10))
204
c46e0a8a 205 (pass-if-peval
de1eb420
AW
206 (let ((string->chars
207 (lambda (s)
208 (define (char-at n)
209 (string-ref s n))
210 (define (len)
211 (string-length s))
212 (let loop ((i 0))
213 (if (< i (len))
214 (cons (char-at i)
215 (loop (1+ i)))
216 '())))))
217 (string->chars "yo"))
c46e0a8a 218 (primcall list (const #\y) (const #\o)))
de1eb420
AW
219
220 (pass-if-peval
221 ;; Primitives in module-refs are resolved (the expansion of `pmatch'
222 ;; below leads to calls to (@@ (system base pmatch) car) and
223 ;; similar, which is what we want to be inlined.)
224 (begin
225 (use-modules (system base pmatch))
226 (pmatch '(a b c d)
227 ((a b . _)
228 #t)))
c46e0a8a
AW
229 (seq (call . _)
230 (const #t)))
de1eb420
AW
231
232 (pass-if-peval
233 ;; Mutability preserved.
234 ((lambda (x y z) (list x y z)) 1 2 3)
c46e0a8a 235 (primcall list (const 1) (const 2) (const 3)))
de1eb420
AW
236
237 (pass-if-peval
238 ;; Don't propagate effect-free expressions that operate on mutable
239 ;; objects.
240 (let* ((x (list 1))
241 (y (car x)))
242 (set-car! x 0)
243 y)
c46e0a8a
AW
244 (let (x) (_) ((primcall list (const 1)))
245 (let (y) (_) ((primcall car (lexical x _)))
246 (seq
247 (primcall set-car! (lexical x _) (const 0))
de1eb420
AW
248 (lexical y _)))))
249
250 (pass-if-peval
251 ;; Don't propagate effect-free expressions that operate on objects we
252 ;; don't know about.
253 (let ((y (car x)))
254 (set-car! x 0)
255 y)
c46e0a8a
AW
256 (let (y) (_) ((primcall car (toplevel x)))
257 (seq
258 (primcall set-car! (toplevel x) (const 0))
de1eb420
AW
259 (lexical y _))))
260
261 (pass-if-peval
262 ;; Infinite recursion
263 ((lambda (x) (x x)) (lambda (x) (x x)))
264 (let (x) (_)
265 ((lambda _
266 (lambda-case
267 (((x) _ _ _ _ _)
c46e0a8a
AW
268 (call (lexical x _) (lexical x _))))))
269 (call (lexical x _) (lexical x _))))
de1eb420
AW
270
271 (pass-if-peval
272 ;; First order, aliased primitive.
273 (let* ((x *) (y (x 1 2))) y)
274 (const 2))
275
276 (pass-if-peval
277 ;; First order, shadowed primitive.
278 (begin
279 (define (+ x y) (pk x y))
280 (+ 1 2))
c46e0a8a 281 (seq
de1eb420
AW
282 (define +
283 (lambda (_)
284 (lambda-case
285 (((x y) #f #f #f () (_ _))
c46e0a8a
AW
286 (call (toplevel pk) (lexical x _) (lexical y _))))))
287 (call (toplevel +) (const 1) (const 2))))
de1eb420
AW
288
289 (pass-if-peval
290 ;; First-order, effects preserved.
291 (let ((x 2))
292 (do-something!)
293 x)
c46e0a8a
AW
294 (seq
295 (call (toplevel do-something!))
de1eb420
AW
296 (const 2)))
297
298 (pass-if-peval
299 ;; First order, residual bindings removed.
300 (let ((x 2) (y 3))
301 (* (+ x y) z))
c46e0a8a 302 (primcall * (const 5) (toplevel z)))
de1eb420
AW
303
304 (pass-if-peval
305 ;; First order, with lambda.
306 (define (foo x)
307 (define (bar z) (* z z))
308 (+ x (bar 3)))
309 (define foo
310 (lambda (_)
311 (lambda-case
312 (((x) #f #f #f () (_))
c46e0a8a 313 (primcall + (lexical x _) (const 9)))))))
de1eb420
AW
314
315 (pass-if-peval
316 ;; First order, with lambda inlined & specialized twice.
317 (let ((f (lambda (x y)
318 (+ (* x top) y)))
319 (x 2)
320 (y 3))
321 (+ (* x (f x y))
322 (f something x)))
c46e0a8a
AW
323 (primcall +
324 (primcall *
325 (const 2)
326 (primcall + ; (f 2 3)
327 (primcall *
328 (const 2)
329 (toplevel top))
330 (const 3)))
331 (let (x) (_) ((toplevel something)) ; (f something 2)
332 ;; `something' is not const, so preserve order of
333 ;; effects with a lexical binding.
334 (primcall +
335 (primcall *
336 (lexical x _)
337 (toplevel top))
338 (const 2)))))
de1eb420
AW
339
340 (pass-if-peval
341 ;; First order, with lambda inlined & specialized 3 times.
342 (let ((f (lambda (x y) (if (> x 0) y x))))
343 (+ (f -1 0)
344 (f 1 0)
345 (f -1 y)
346 (f 2 y)
347 (f z y)))
c46e0a8a
AW
348 (primcall
349 +
350 (const -1) ; (f -1 0)
351 (primcall
352 +
353 (const 0) ; (f 1 0)
354 (primcall
355 +
356 (seq (toplevel y) (const -1)) ; (f -1 y)
357 (primcall
358 +
359 (toplevel y) ; (f 2 y)
360 (let (x y) (_ _) ((toplevel z) (toplevel y)) ; (f z y)
361 (if (primcall > (lexical x _) (const 0))
362 (lexical y _)
363 (lexical x _))))))))
de1eb420
AW
364
365 (pass-if-peval
366 ;; First order, conditional.
367 (let ((y 2))
368 (lambda (x)
369 (if (> y 0)
370 (display x)
371 'never-reached)))
372 (lambda ()
373 (lambda-case
374 (((x) #f #f #f () (_))
c46e0a8a 375 (call (toplevel display) (lexical x _))))))
de1eb420
AW
376
377 (pass-if-peval
378 ;; First order, recursive procedure.
379 (letrec ((fibo (lambda (n)
380 (if (<= n 1)
381 n
382 (+ (fibo (- n 1))
383 (fibo (- n 2)))))))
384 (fibo 4))
385 (const 3))
386
387 (pass-if-peval
388 ;; Don't propagate toplevel references, as intervening expressions
389 ;; could alter their bindings.
390 (let ((x top))
391 (foo)
392 x)
393 (let (x) (_) ((toplevel top))
c46e0a8a
AW
394 (seq
395 (call (toplevel foo))
de1eb420
AW
396 (lexical x _))))
397
398 (pass-if-peval
399 ;; Higher order.
400 ((lambda (f x)
401 (f (* (car x) (cadr x))))
402 (lambda (x)
403 (+ x 1))
404 '(2 3))
405 (const 7))
406
407 (pass-if-peval
408 ;; Higher order with optional argument (default value).
409 ((lambda* (f x #:optional (y 0))
410 (+ y (f (* (car x) (cadr x)))))
411 (lambda (x)
412 (+ x 1))
413 '(2 3))
414 (const 7))
415
416 (pass-if-peval
417 ;; Higher order with optional argument (caller-supplied value).
418 ((lambda* (f x #:optional (y 0))
419 (+ y (f (* (car x) (cadr x)))))
420 (lambda (x)
421 (+ x 1))
422 '(2 3)
423 35)
424 (const 42))
425
426 (pass-if-peval
427 ;; Higher order with optional argument (side-effecting default
428 ;; value).
429 ((lambda* (f x #:optional (y (foo)))
430 (+ y (f (* (car x) (cadr x)))))
431 (lambda (x)
432 (+ x 1))
433 '(2 3))
c46e0a8a
AW
434 (let (y) (_) ((call (toplevel foo)))
435 (primcall + (lexical y _) (const 7))))
de1eb420
AW
436
437 (pass-if-peval
438 ;; Higher order with optional argument (caller-supplied value).
439 ((lambda* (f x #:optional (y (foo)))
440 (+ y (f (* (car x) (cadr x)))))
441 (lambda (x)
442 (+ x 1))
443 '(2 3)
444 35)
445 (const 42))
446
447 (pass-if-peval
448 ;; Higher order.
449 ((lambda (f) (f x)) (lambda (x) x))
450 (toplevel x))
451
452 (pass-if-peval
453 ;; Bug reported at
454 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
455 (let ((fold (lambda (f g) (f (g top)))))
456 (fold 1+ (lambda (x) x)))
c46e0a8a 457 (primcall 1+ (toplevel top)))
de1eb420
AW
458
459 (pass-if-peval
460 ;; Procedure not inlined when residual code contains recursive calls.
461 ;; <http://debbugs.gnu.org/9542>
462 (letrec ((fold (lambda (f x3 b null? car cdr)
463 (if (null? x3)
464 b
465 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
466 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
467 (letrec (fold) (_) (_)
c46e0a8a 468 (call (lexical fold _)
de1eb420
AW
469 (primitive *)
470 (toplevel x)
471 (const 1)
472 (primitive zero?)
473 (lambda ()
474 (lambda-case
475 (((x1) #f #f #f () (_))
476 (lexical x1 _))))
477 (lambda ()
478 (lambda-case
479 (((x2) #f #f #f () (_))
c46e0a8a 480 (primcall 1- (lexical x2 _))))))))
de1eb420
AW
481
482 (pass-if "inlined lambdas are alpha-renamed"
483 ;; In this example, `make-adder' is inlined more than once; thus,
484 ;; they should use different gensyms for their arguments, because
485 ;; the various optimization passes assume uniquely-named variables.
486 ;;
487 ;; Bug reported at
488 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
489 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
490 (pmatch (unparse-tree-il
25450a0d 491 (peval (expand-primitives
403d78f9 492 (resolve-primitives
c46e0a8a
AW
493 (compile
494 '(let ((make-adder
495 (lambda (x) (lambda (y) (+ x y)))))
496 (cons (make-adder 1) (make-adder 2)))
497 #:to 'tree-il)
498 (current-module)))))
499 ((primcall cons
500 (lambda ()
501 (lambda-case
502 (((y) #f #f #f () (,gensym1))
503 (primcall +
504 (const 1)
505 (lexical y ,ref1)))))
506 (lambda ()
507 (lambda-case
508 (((y) #f #f #f () (,gensym2))
509 (primcall +
510 (const 2)
511 (lexical y ,ref2))))))
de1eb420
AW
512 (and (eq? gensym1 ref1)
513 (eq? gensym2 ref2)
514 (not (eq? gensym1 gensym2))))
515 (_ #f)))
516
517 (pass-if-peval
518 ;; Unused letrec bindings are pruned.
519 (letrec ((a (lambda () (b)))
520 (b (lambda () (a)))
521 (c (lambda (x) x)))
522 (c 10))
523 (const 10))
524
525 (pass-if-peval
526 ;; Unused letrec bindings are pruned.
527 (letrec ((a (foo!))
528 (b (lambda () (a)))
529 (c (lambda (x) x)))
530 (c 10))
c46e0a8a
AW
531 (seq (call (toplevel foo!))
532 (const 10)))
de1eb420
AW
533
534 (pass-if-peval
535 ;; Higher order, mutually recursive procedures.
536 (letrec ((even? (lambda (x)
537 (or (= 0 x)
538 (odd? (- x 1)))))
539 (odd? (lambda (x)
540 (not (even? x)))))
541 (and (even? 4) (odd? 7)))
542 (const #t))
543
544 (pass-if-peval
545 ;; Memv with constants.
546 (memv 1 '(3 2 1))
547 (const '(1)))
548
549 (pass-if-peval
550 ;; Memv with non-constant list. It could fold but doesn't
551 ;; currently.
552 (memv 1 (list 3 2 1))
c46e0a8a
AW
553 (primcall memv
554 (const 1)
555 (primcall list (const 3) (const 2) (const 1))))
de1eb420
AW
556
557 (pass-if-peval
558 ;; Memv with non-constant key, constant list, test context
559 (case foo
560 ((3 2 1) 'a)
561 (else 'b))
562 (let (key) (_) ((toplevel foo))
c46e0a8a 563 (if (if (primcall eqv? (lexical key _) (const 3))
de1eb420 564 (const #t)
c46e0a8a 565 (if (primcall eqv? (lexical key _) (const 2))
de1eb420 566 (const #t)
c46e0a8a 567 (primcall eqv? (lexical key _) (const 1))))
de1eb420
AW
568 (const a)
569 (const b))))
570
571 (pass-if-peval
c46e0a8a 572 ;; Memv with non-constant key, empty list, test context.
de1eb420
AW
573 (case foo
574 (() 'a)
575 (else 'b))
c46e0a8a 576 (seq (toplevel foo) (const 'b)))
de1eb420
AW
577
578 ;;
579 ;; Below are cases where constant propagation should bail out.
580 ;;
581
582 (pass-if-peval
583 ;; Non-constant lexical is not propagated.
584 (let ((v (make-vector 6 #f)))
585 (lambda (n)
586 (vector-set! v n n)))
587 (let (v) (_)
c46e0a8a 588 ((call (toplevel make-vector) (const 6) (const #f)))
de1eb420
AW
589 (lambda ()
590 (lambda-case
591 (((n) #f #f #f () (_))
c46e0a8a
AW
592 (primcall vector-set!
593 (lexical v _) (lexical n _) (lexical n _)))))))
de1eb420
AW
594
595 (pass-if-peval
596 ;; Mutable lexical is not propagated.
597 (let ((v (vector 1 2 3)))
598 (lambda ()
599 v))
600 (let (v) (_)
c46e0a8a 601 ((primcall vector (const 1) (const 2) (const 3)))
de1eb420
AW
602 (lambda ()
603 (lambda-case
604 ((() #f #f #f () ())
605 (lexical v _))))))
606
607 (pass-if-peval
608 ;; Lexical that is not provably pure is not inlined nor propagated.
609 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
610 (y (* x 2)))
611 (+ x x y))
c46e0a8a
AW
612 (let (x) (_) ((if (primcall > (toplevel p) (toplevel q))
613 (call (toplevel frob!))
614 (call (toplevel display) (const chbouib))))
615 (let (y) (_) ((primcall * (lexical x _) (const 2)))
616 (primcall +
617 (lexical x _)
618 (primcall + (lexical x _) (lexical y _))))))
de1eb420
AW
619
620 (pass-if-peval
621 ;; Non-constant arguments not propagated to lambdas.
622 ((lambda (x y z)
623 (vector-set! x 0 0)
624 (set-car! y 0)
625 (set-cdr! z '()))
626 (vector 1 2 3)
627 (make-list 10)
628 (list 1 2 3))
629 (let (x y z) (_ _ _)
c46e0a8a
AW
630 ((primcall vector (const 1) (const 2) (const 3))
631 (call (toplevel make-list) (const 10))
632 (primcall list (const 1) (const 2) (const 3)))
633 (seq
634 (primcall vector-set!
635 (lexical x _) (const 0) (const 0))
636 (seq (primcall set-car!
637 (lexical y _) (const 0))
638 (primcall set-cdr!
639 (lexical z _) (const ()))))))
de1eb420
AW
640
641 (pass-if-peval
642 (let ((foo top-foo) (bar top-bar))
643 (let* ((g (lambda (x y) (+ x y)))
644 (f (lambda (g x) (g x x))))
645 (+ (f g foo) (f g bar))))
646 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
c46e0a8a
AW
647 (primcall +
648 (primcall + (lexical foo _) (lexical foo _))
649 (primcall + (lexical bar _) (lexical bar _)))))
de1eb420
AW
650
651 (pass-if-peval
652 ;; Fresh objects are not turned into constants, nor are constants
653 ;; turned into fresh objects.
654 (let* ((c '(2 3))
655 (x (cons 1 c))
656 (y (cons 0 x)))
657 y)
c46e0a8a
AW
658 (let (x) (_) ((primcall cons (const 1) (const (2 3))))
659 (primcall cons (const 0) (lexical x _))))
de1eb420
AW
660
661 (pass-if-peval
662 ;; Bindings mutated.
663 (let ((x 2))
664 (set! x 3)
665 x)
666 (let (x) (_) ((const 2))
c46e0a8a 667 (seq
de1eb420
AW
668 (set! (lexical x _) (const 3))
669 (lexical x _))))
670
671 (pass-if-peval
672 ;; Bindings mutated.
673 (letrec ((x 0)
674 (f (lambda ()
675 (set! x (+ 1 x))
676 x)))
677 (frob f) ; may mutate `x'
678 x)
679 (letrec (x) (_) ((const 0))
c46e0a8a
AW
680 (seq
681 (call (toplevel frob) (lambda _ _))
de1eb420
AW
682 (lexical x _))))
683
684 (pass-if-peval
685 ;; Bindings mutated.
686 (letrec ((f (lambda (x)
687 (set! f (lambda (_) x))
688 x)))
689 (f 2))
690 (letrec _ . _))
691
692 (pass-if-peval
693 ;; Bindings possibly mutated.
694 (let ((x (make-foo)))
695 (frob! x) ; may mutate `x'
696 x)
c46e0a8a
AW
697 (let (x) (_) ((call (toplevel make-foo)))
698 (seq
699 (call (toplevel frob!) (lexical x _))
de1eb420
AW
700 (lexical x _))))
701
702 (pass-if-peval
703 ;; Inlining stops at recursive calls with dynamic arguments.
704 (let loop ((x x))
705 (if (< x 0) x (loop (1- x))))
706 (letrec (loop) (_) ((lambda (_)
707 (lambda-case
708 (((x) #f #f #f () (_))
709 (if _ _
c46e0a8a
AW
710 (call (lexical loop _)
711 (primcall 1-
712 (lexical x _))))))))
713 (call (lexical loop _) (toplevel x))))
de1eb420
AW
714
715 (pass-if-peval
716 ;; Recursion on the 2nd argument is fully evaluated.
717 (let ((x (top)))
718 (let loop ((x x) (y 10))
719 (if (> y 0)
720 (loop x (1- y))
721 (foo x y))))
c46e0a8a
AW
722 (let (x) (_) ((call (toplevel top)))
723 (call (toplevel foo) (lexical x _) (const 0))))
de1eb420
AW
724
725 (pass-if-peval
726 ;; Inlining aborted when residual code contains recursive calls.
727 ;;
728 ;; <http://debbugs.gnu.org/9542>
729 (let loop ((x x) (y 0))
730 (if (> y 0)
731 (loop (1- x) (1- y))
732 (if (< x 0)
733 x
734 (loop (1+ x) (1+ y)))))
735 (letrec (loop) (_) ((lambda (_)
736 (lambda-case
737 (((x y) #f #f #f () (_ _))
c46e0a8a
AW
738 (if (primcall >
739 (lexical y _) (const 0))
de1eb420 740 _ _)))))
c46e0a8a 741 (call (lexical loop _) (toplevel x) (const 0))))
de1eb420
AW
742
743 (pass-if-peval
744 ;; Infinite recursion: `peval' gives up and leaves it as is.
745 (letrec ((f (lambda (x) (g (1- x))))
746 (g (lambda (x) (h (1+ x))))
747 (h (lambda (x) (f x))))
748 (f 0))
749 (letrec _ . _))
750
751 (pass-if-peval
752 ;; Infinite recursion: all the arguments to `loop' are static, but
753 ;; unrolling it would lead `peval' to enter an infinite loop.
754 (let loop ((x 0))
755 (and (< x top)
756 (loop (1+ x))))
757 (letrec (loop) (_) ((lambda . _))
c46e0a8a 758 (call (lexical loop _) (const 0))))
de1eb420
AW
759
760 (pass-if-peval
761 ;; This test checks that the `start' binding is indeed residualized.
762 ;; See the `referenced?' procedure in peval's `prune-bindings'.
763 (let ((pos 0))
de1eb420 764 (let ((here (let ((start pos)) (lambda () start))))
1cd63115 765 (set! pos 1) ;; Cause references to `pos' to residualize.
de1eb420
AW
766 (here)))
767 (let (pos) (_) ((const 0))
1cd63115 768 (let (here) (_) (_)
79d29f96
AW
769 (seq
770 (set! (lexical pos _) (const 1))
771 (call (lexical here _))))))
772
de1eb420
AW
773 (pass-if-peval
774 ;; FIXME: should this one residualize the binding?
775 (letrec ((a a))
776 1)
777 (const 1))
778
779 (pass-if-peval
780 ;; This is a fun one for peval to handle.
781 (letrec ((a a))
782 a)
783 (letrec (a) (_) ((lexical a _))
784 (lexical a _)))
785
786 (pass-if-peval
787 ;; Another interesting recursive case.
788 (letrec ((a b) (b a))
789 a)
790 (letrec (a) (_) ((lexical a _))
791 (lexical a _)))
792
793 (pass-if-peval
794 ;; Another pruning case, that `a' is residualized.
795 (letrec ((a (lambda () (a)))
796 (b (lambda () (a)))
797 (c (lambda (x) x)))
798 (let ((d (foo b)))
799 (c d)))
800
801 ;; "b c a" is the current order that we get with unordered letrec,
802 ;; but it's not important to this test, so if it changes, just adapt
803 ;; the test.
804 (letrec (b c a) (_ _ _)
805 ((lambda _
806 (lambda-case
807 ((() #f #f #f () ())
c46e0a8a 808 (call (lexical a _)))))
de1eb420
AW
809 (lambda _
810 (lambda-case
811 (((x) #f #f #f () (_))
812 (lexical x _))))
813 (lambda _
814 (lambda-case
815 ((() #f #f #f () ())
c46e0a8a 816 (call (lexical a _))))))
de1eb420
AW
817 (let (d)
818 (_)
c46e0a8a
AW
819 ((call (toplevel foo) (lexical b _)))
820 (call (lexical c _) (lexical d _)))))
de1eb420
AW
821
822 (pass-if-peval
823 ;; In this case, we can prune the bindings. `a' ends up being copied
824 ;; because it is only referenced once in the source program. Oh
825 ;; well.
826 (letrec* ((a (lambda (x) (top x)))
827 (b (lambda () a)))
828 (foo (b) (b)))
c46e0a8a
AW
829 (call (toplevel foo)
830 (lambda _
831 (lambda-case
832 (((x) #f #f #f () (_))
833 (call (toplevel top) (lexical x _)))))
834 (lambda _
835 (lambda-case
836 (((x) #f #f #f () (_))
837 (call (toplevel top) (lexical x _)))))))
de1eb420 838
9b977c83 839 (pass-if-peval
30c3dac7
AW
840 ;; The inliner sees through a `let'.
841 ((let ((a 10)) (lambda (b) (* b 2))) 30)
842 (const 60))
843
844 (pass-if-peval
845 ((lambda ()
846 (define (const x) (lambda (_) x))
847 (let ((v #f))
848 ((const #t) v))))
849 (const #t))
850
564f5e70
AW
851 (pass-if-peval
852 ;; Applications of procedures with rest arguments can get inlined.
853 ((lambda (x y . z)
854 (list x y z))
855 1 2 3 4)
9b977c83
AW
856 (let (z) (_) ((primcall list (const 3) (const 4)))
857 (primcall list (const 1) (const 2) (lexical z _))))
564f5e70 858
9b977c83 859 (pass-if-peval
d21537ef
AW
860 ;; Unmutated lists can get inlined.
861 (let ((args (list 2 3)))
862 (apply (lambda (x y z w)
863 (list x y z w))
864 0 1 args))
9b977c83 865 (primcall list (const 0) (const 1) (const 2) (const 3)))
d21537ef 866
9b977c83 867 (pass-if-peval
d21537ef
AW
868 ;; However if the list might have been mutated, it doesn't propagate.
869 (let ((args (list 2 3)))
870 (foo! args)
871 (apply (lambda (x y z w)
872 (list x y z w))
873 0 1 args))
9b977c83
AW
874 (let (args) (_) ((primcall list (const 2) (const 3)))
875 (seq
876 (call (toplevel foo!) (lexical args _))
39caffe7 877 (primcall apply
9b977c83
AW
878 (lambda ()
879 (lambda-case
880 (((x y z w) #f #f #f () (_ _ _ _))
881 (primcall list
882 (lexical x _) (lexical y _)
883 (lexical z _) (lexical w _)))))
884 (const 0)
885 (const 1)
886 (lexical args _)))))
887
888 (pass-if-peval
8598dd8d
AW
889 ;; Here the `args' that gets built by the application of the lambda
890 ;; takes more than effort "10" to visit. Test that we fall back to
891 ;; the source expression of the operand, which is still a call to
892 ;; `list', so the inlining still happens.
893 (lambda (bv offset n)
894 (let ((x (bytevector-ieee-single-native-ref
895 bv
896 (+ offset 0)))
897 (y (bytevector-ieee-single-native-ref
898 bv
899 (+ offset 4))))
900 (let ((args (list x y)))
39caffe7 901 (apply
8598dd8d
AW
902 (lambda (bv offset x y)
903 (bytevector-ieee-single-native-set!
904 bv
905 (+ offset 0)
906 x)
907 (bytevector-ieee-single-native-set!
908 bv
909 (+ offset 4)
910 y))
911 bv
912 offset
913 args))))
914 (lambda ()
915 (lambda-case
916 (((bv offset n) #f #f #f () (_ _ _))
9b977c83
AW
917 (let (x y) (_ _) ((primcall bytevector-ieee-single-native-ref
918 (lexical bv _)
919 (primcall +
920 (lexical offset _) (const 0)))
921 (primcall bytevector-ieee-single-native-ref
922 (lexical bv _)
923 (primcall +
924 (lexical offset _) (const 4))))
925 (seq
926 (primcall bytevector-ieee-single-native-set!
927 (lexical bv _)
928 (primcall +
929 (lexical offset _) (const 0))
930 (lexical x _))
931 (primcall bytevector-ieee-single-native-set!
932 (lexical bv _)
933 (primcall +
934 (lexical offset _) (const 4))
935 (lexical y _))))))))
936
937 (pass-if-peval
8598dd8d
AW
938 ;; Here we ensure that non-constant expressions are not copied.
939 (lambda ()
940 (let ((args (list (foo!))))
39caffe7 941 (apply
8598dd8d
AW
942 (lambda (z x)
943 (list z x))
944 ;; This toplevel ref might raise an unbound variable exception.
945 ;; The effects of `(foo!)' must be visible before this effect.
946 z
947 args)))
91c763ee
AW
948 (lambda ()
949 (lambda-case
950 ((() #f #f #f () ())
9b977c83 951 (let (_) (_) ((call (toplevel foo!)))
91c763ee 952 (let (z) (_) ((toplevel z))
9b977c83
AW
953 (primcall 'list
954 (lexical z _)
955 (lexical _ _))))))))
91c763ee 956
9b977c83 957 (pass-if-peval
91c763ee
AW
958 ;; Rest args referenced more than once are not destructured.
959 (lambda ()
960 (let ((args (list 'foo)))
961 (set-car! args 'bar)
39caffe7 962 (apply
91c763ee
AW
963 (lambda (z x)
964 (list z x))
965 z
966 args)))
8598dd8d
AW
967 (lambda ()
968 (lambda-case
969 ((() #f #f #f () ())
970 (let (args) (_)
9b977c83
AW
971 ((primcall list (const foo)))
972 (seq
973 (primcall set-car! (lexical args _) (const bar))
39caffe7 974 (primcall apply
9b977c83
AW
975 (lambda . _)
976 (toplevel z)
977 (lexical args _))))))))
978
979 (pass-if-peval
85edd670
AW
980 ;; Let-values inlining, even with consumers with rest args.
981 (call-with-values (lambda () (values 1 2))
982 (lambda args
983 (apply list args)))
9b977c83 984 (primcall list (const 1) (const 2)))
85edd670 985
e6450062
AW
986 (pass-if-peval
987 ;; When we can't inline let-values but can prove that the producer
988 ;; has just one value, reduce to "let" (which can then fold
989 ;; further).
990 (call-with-values (lambda () (if foo 1 2))
991 (lambda args
992 (apply values args)))
993 (if (toplevel foo) (const 1) (const 2)))
994
de1eb420
AW
995 (pass-if-peval
996 ;; Constant folding: cons of #nil does not make list
997 (cons 1 #nil)
c46e0a8a 998 (primcall cons (const 1) (const '#nil)))
de1eb420
AW
999
1000 (pass-if-peval
1001 ;; Constant folding: cons
1002 (begin (cons 1 2) #f)
1003 (const #f))
1004
1005 (pass-if-peval
1006 ;; Constant folding: cons
1007 (begin (cons (foo) 2) #f)
c46e0a8a 1008 (seq (call (toplevel foo)) (const #f)))
de1eb420
AW
1009
1010 (pass-if-peval
1011 ;; Constant folding: cons
1012 (if (cons 0 0) 1 2)
1013 (const 1))
1014
1015 (pass-if-peval
1016 ;; Constant folding: car+cons
1017 (car (cons 1 0))
1018 (const 1))
1019
1020 (pass-if-peval
1021 ;; Constant folding: cdr+cons
1022 (cdr (cons 1 0))
1023 (const 0))
1024
1025 (pass-if-peval
1026 ;; Constant folding: car+cons, impure
1027 (car (cons 1 (bar)))
c46e0a8a 1028 (seq (call (toplevel bar)) (const 1)))
de1eb420
AW
1029
1030 (pass-if-peval
1031 ;; Constant folding: cdr+cons, impure
1032 (cdr (cons (bar) 0))
c46e0a8a 1033 (seq (call (toplevel bar)) (const 0)))
de1eb420
AW
1034
1035 (pass-if-peval
1036 ;; Constant folding: car+list
1037 (car (list 1 0))
1038 (const 1))
1039
1040 (pass-if-peval
1041 ;; Constant folding: cdr+list
1042 (cdr (list 1 0))
c46e0a8a 1043 (primcall list (const 0)))
de1eb420
AW
1044
1045 (pass-if-peval
1046 ;; Constant folding: car+list, impure
1047 (car (list 1 (bar)))
c46e0a8a 1048 (seq (call (toplevel bar)) (const 1)))
de1eb420
AW
1049
1050 (pass-if-peval
1051 ;; Constant folding: cdr+list, impure
1052 (cdr (list (bar) 0))
c46e0a8a
AW
1053 (seq (call (toplevel bar)) (primcall list (const 0))))
1054
1055 (pass-if-peval
1056 ;; Equality primitive: same lexical
1057 (let ((x (random))) (eq? x x))
1058 (seq (call (toplevel random)) (const #t)))
1059
1060 (pass-if-peval
1061 ;; Equality primitive: merge lexical identities
1062 (let* ((x (random)) (y x)) (eq? x y))
1063 (seq (call (toplevel random)) (const #t)))
de1eb420
AW
1064
1065 (pass-if-peval
9b965638
AW
1066 ;; Non-constant guards get lexical bindings, invocation of winder and
1067 ;; unwinder lifted out. Unfortunately both have the generic variable
1068 ;; name "tmp", so we can't distinguish them in this test, and they
1069 ;; also collide in generic names with the single-value result from
1070 ;; the dynwind; alack.
de1eb420 1071 (dynamic-wind foo (lambda () bar) baz)
9b965638 1072 (let (tmp tmp) (_ _) ((toplevel foo) (toplevel baz))
bb97e4ab
AW
1073 (seq (seq (if (primcall thunk? (lexical tmp _))
1074 (call (lexical tmp _))
1075 (primcall scm-error . _))
1076 (primcall wind (lexical tmp _) (lexical tmp _)))
1077 (let (tmp) (_) ((toplevel bar))
1078 (seq (seq (primcall unwind)
1079 (call (lexical tmp _)))
9b965638 1080 (lexical tmp _))))))
de1eb420
AW
1081
1082 (pass-if-peval
bb97e4ab 1083 ;; Constant guards don't need lexical bindings or thunk? checks.
de1eb420 1084 (dynamic-wind (lambda () foo) (lambda () bar) (lambda () baz))
bb97e4ab
AW
1085 (seq (seq (toplevel foo)
1086 (primcall wind
1087 (lambda ()
1088 (lambda-case
1089 ((() #f #f #f () ()) (toplevel foo))))
1090 (lambda ()
1091 (lambda-case
1092 ((() #f #f #f () ()) (toplevel baz))))))
1093 (let (tmp) (_) ((toplevel bar))
1094 (seq (seq (primcall unwind)
1095 (toplevel baz))
9b965638
AW
1096 (lexical tmp _)))))
1097
1098 (pass-if-peval
1099 ;; Dynwind bodies that return an unknown number of values need a
1100 ;; let-values.
1101 (dynamic-wind (lambda () foo) (lambda () (bar)) (lambda () baz))
bb97e4ab
AW
1102 (seq (seq (toplevel foo)
1103 (primcall wind
1104 (lambda ()
1105 (lambda-case
1106 ((() #f #f #f () ()) (toplevel foo))))
1107 (lambda ()
1108 (lambda-case
1109 ((() #f #f #f () ()) (toplevel baz))))))
1110 (let-values (call (toplevel bar))
9b965638
AW
1111 (lambda-case
1112 ((() #f vals #f () (_))
bb97e4ab
AW
1113 (seq (seq (primcall unwind)
1114 (toplevel baz))
39caffe7 1115 (primcall apply (primitive values) (lexical vals _))))))))
de1eb420
AW
1116
1117 (pass-if-peval
de1eb420
AW
1118 ;; Prompt is removed if tag is unreferenced
1119 (let ((tag (make-prompt-tag)))
1120 (call-with-prompt tag
1121 (lambda () 1)
1122 (lambda args args)))
1123 (const 1))
1124
1125 (pass-if-peval
de1eb420
AW
1126 ;; Prompt is removed if tag is unreferenced, with explicit stem
1127 (let ((tag (make-prompt-tag "foo")))
1128 (call-with-prompt tag
1129 (lambda () 1)
1130 (lambda args args)))
1131 (const 1))
1132
1133 ;; Handler lambda inlined
1134 (pass-if-peval
de1eb420
AW
1135 (call-with-prompt tag
1136 (lambda () 1)
1137 (lambda (k x) x))
178a4092
AW
1138 (prompt #t
1139 (toplevel tag)
1140 (lambda _
1141 (lambda-case
1142 ((() #f #f #f () ())
1143 (const 1))))
1144 (lambda _
1145 (lambda-case
1146 (((k x) #f #f #f () (_ _))
1147 (lexical x _))))))
de1eb420
AW
1148
1149 ;; Handler toplevel not inlined
1150 (pass-if-peval
178a4092
AW
1151 (call-with-prompt tag
1152 (lambda () 1)
1153 handler)
1154 (prompt #f
1155 (toplevel tag)
1156 (lambda _
1157 (lambda-case
1158 ((() #f #f #f () ())
1159 (const 1))))
1160 (toplevel handler)))
de1eb420
AW
1161
1162 (pass-if-peval
de1eb420
AW
1163 ;; `while' without `break' or `continue' has no prompts and gets its
1164 ;; condition folded. Unfortunately the outer `lp' does not yet get
997ed300
AW
1165 ;; elided, and the continuation tag stays around. (The continue tag
1166 ;; stays around because although it is not referenced, recursively
1167 ;; visiting the loop in the continue handler manages to visit the tag
1168 ;; twice before aborting. The abort doesn't unroll the recursive
1169 ;; reference.)
de1eb420 1170 (while #t #t)
2aed2667 1171 (let (_) (_) ((primcall make-prompt-tag . _))
997ed300
AW
1172 (letrec (lp) (_)
1173 ((lambda _
1174 (lambda-case
1175 ((() #f #f #f () ())
1176 (letrec (loop) (_)
1177 ((lambda _
1178 (lambda-case
1179 ((() #f #f #f () ())
2aed2667
AW
1180 (call (lexical loop _))))))
1181 (call (lexical loop _)))))))
1182 (call (lexical lp _)))))
de1eb420
AW
1183
1184 (pass-if-peval
de1eb420
AW
1185 (lambda (a . rest)
1186 (apply (lambda (x y) (+ x y))
1187 a rest))
1188 (lambda _
1189 (lambda-case
1190 (((x y) #f #f #f () (_ _))
1191 _))))
1192
c46e0a8a 1193 (pass-if-peval
de1eb420 1194 (car '(1 2))
985702f7
AW
1195 (const 1))
1196
1197 ;; If we bail out when inlining an identifier because it's too big,
1198 ;; but the identifier simply aliases some other identifier, then avoid
1199 ;; residualizing a reference to the leaf identifier. The bailout is
1200 ;; driven by the recursive-effort-limit, which is currently 100. We
1201 ;; make sure to trip it with this recursive sum thing.
4105f688 1202 (pass-if-peval
985702f7
AW
1203 (let ((x (let sum ((n 0) (out 0))
1204 (if (< n 10000)
1205 (sum (1+ n) (+ out n))
1206 out))))
1207 ((lambda (y) (list y)) x))
1208 (let (x) (_) (_)
74bbb994 1209 (primcall list (lexical x _))))
f49fd9af
AW
1210
1211 ;; Here we test that a common test in a chain of ifs gets lifted.
74bbb994 1212 (pass-if-peval
f49fd9af
AW
1213 (if (and (struct? x) (eq? (struct-vtable x) A))
1214 (foo x)
1215 (if (and (struct? x) (eq? (struct-vtable x) B))
1216 (bar x)
1217 (if (and (struct? x) (eq? (struct-vtable x) C))
1218 (baz x)
1219 (qux x))))
1220 (let (failure) (_) ((lambda _
1221 (lambda-case
1222 ((() #f #f #f () ())
74bbb994
AW
1223 (call (toplevel qux) (toplevel x))))))
1224 (if (primcall struct? (toplevel x))
1225 (if (primcall eq?
1226 (primcall struct-vtable (toplevel x))
1227 (toplevel A))
1228 (call (toplevel foo) (toplevel x))
1229 (if (primcall eq?
1230 (primcall struct-vtable (toplevel x))
1231 (toplevel B))
1232 (call (toplevel bar) (toplevel x))
1233 (if (primcall eq?
1234 (primcall struct-vtable (toplevel x))
1235 (toplevel C))
1236 (call (toplevel baz) (toplevel x))
1237 (call (lexical failure _)))))
1238 (call (lexical failure _)))))
9b1750ed
AW
1239
1240 ;; Multiple common tests should get lifted as well.
74bbb994 1241 (pass-if-peval
9b1750ed
AW
1242 (if (and (struct? x) (eq? (struct-vtable x) A) B)
1243 (foo x)
1244 (if (and (struct? x) (eq? (struct-vtable x) A) C)
1245 (bar x)
1246 (if (and (struct? x) (eq? (struct-vtable x) A) D)
1247 (baz x)
1248 (qux x))))
1249 (let (failure) (_) ((lambda _
1250 (lambda-case
1251 ((() #f #f #f () ())
74bbb994
AW
1252 (call (toplevel qux) (toplevel x))))))
1253 (if (primcall struct? (toplevel x))
1254 (if (primcall eq?
1255 (primcall struct-vtable (toplevel x))
1256 (toplevel A))
9b1750ed 1257 (if (toplevel B)
74bbb994 1258 (call (toplevel foo) (toplevel x))
9b1750ed 1259 (if (toplevel C)
74bbb994 1260 (call (toplevel bar) (toplevel x))
9b1750ed 1261 (if (toplevel D)
74bbb994
AW
1262 (call (toplevel baz) (toplevel x))
1263 (call (lexical failure _)))))
1264 (call (lexical failure _)))
2aed2667 1265 (call (lexical failure _)))))
3d2bcd2c 1266
2aed2667 1267 (pass-if-peval
3d2bcd2c 1268 (apply (lambda (x y) (cons x y)) '(1 2))
2aed2667 1269 (primcall cons (const 1) (const 2)))
3d2bcd2c 1270
2aed2667 1271 (pass-if-peval
3d2bcd2c 1272 (apply (lambda (x y) (cons x y)) (list 1 2))
2aed2667 1273 (primcall cons (const 1) (const 2)))
997ed300 1274
2aed2667 1275 (pass-if-peval
997ed300
AW
1276 (let ((t (make-prompt-tag)))
1277 (call-with-prompt t
1278 (lambda () (abort-to-prompt t 1 2 3))
1279 (lambda (k x y z) (list x y z))))
64fc50c2
AW
1280 (primcall list (const 1) (const 2) (const 3)))
1281
1282 (pass-if-peval
1283 (call-with-values foo (lambda (x) (bar x)))
1284 (let (x) (_) ((call (toplevel foo)))
1285 (call (toplevel bar) (lexical x _)))))