peval.test 45 KB

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