closure-conversion.scm 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Commentary:
  17. ;;;
  18. ;;; This pass converts a CPS term in such a way that no function has any
  19. ;;; free variables. Instead, closures are built explicitly with
  20. ;;; make-closure primcalls, and free variables are referenced through
  21. ;;; the closure.
  22. ;;;
  23. ;;; Closure conversion also removes any $rec expressions that
  24. ;;; contification did not handle. See (language cps) for a further
  25. ;;; discussion of $rec.
  26. ;;;
  27. ;;; Code:
  28. (define-module (language cps closure-conversion)
  29. #:use-module (ice-9 match)
  30. #:use-module ((srfi srfi-1) #:select (fold
  31. filter-map
  32. ))
  33. #:use-module (srfi srfi-11)
  34. #:use-module (language cps)
  35. #:use-module (language cps utils)
  36. #:use-module (language cps with-cps)
  37. #:use-module (language cps intmap)
  38. #:use-module (language cps intset)
  39. #:export (convert-closures))
  40. (define (compute-function-bodies conts kfun)
  41. "Compute a map from FUN-LABEL->BODY-LABEL... for all $fun instances in
  42. conts."
  43. (let visit-fun ((kfun kfun) (out empty-intmap))
  44. (let ((body (compute-function-body conts kfun)))
  45. (intset-fold
  46. (lambda (label out)
  47. (match (intmap-ref conts label)
  48. (($ $kargs _ _ ($ $continue _ _ ($ $fun kfun)))
  49. (visit-fun kfun out))
  50. (($ $kargs _ _ ($ $continue _ _ ($ $rec _ _ (($ $fun kfun) ...))))
  51. (fold visit-fun out kfun))
  52. (_ out)))
  53. body
  54. (intmap-add out kfun body)))))
  55. (define (compute-program-body functions)
  56. (intmap-fold (lambda (label body out) (intset-union body out))
  57. functions
  58. empty-intset))
  59. (define (filter-reachable conts functions)
  60. (let ((reachable (compute-program-body functions)))
  61. (intmap-fold
  62. (lambda (label cont out)
  63. (if (intset-ref reachable label)
  64. out
  65. (intmap-remove out label)))
  66. conts conts)))
  67. (define (compute-non-operator-uses conts)
  68. (persistent-intset
  69. (intmap-fold
  70. (lambda (label cont uses)
  71. (define (add-use var uses) (intset-add! uses var))
  72. (define (add-uses vars uses)
  73. (match vars
  74. (() uses)
  75. ((var . vars) (add-uses vars (add-use var uses)))))
  76. (match cont
  77. (($ $kargs _ _ ($ $continue _ _ exp))
  78. (match exp
  79. ((or ($ $const) ($ $prim) ($ $fun) ($ $rec)) uses)
  80. (($ $values args)
  81. (add-uses args uses))
  82. (($ $call proc args)
  83. (add-uses args uses))
  84. (($ $branch kt ($ $values (arg)))
  85. (add-use arg uses))
  86. (($ $branch kt ($ $primcall name args))
  87. (add-uses args uses))
  88. (($ $primcall name args)
  89. (add-uses args uses))
  90. (($ $prompt escape? tag handler)
  91. (add-use tag uses))))
  92. (_ uses)))
  93. conts
  94. empty-intset)))
  95. (define (compute-singly-referenced-labels conts body)
  96. (define (add-ref label single multiple)
  97. (define (ref k single multiple)
  98. (if (intset-ref single k)
  99. (values single (intset-add! multiple k))
  100. (values (intset-add! single k) multiple)))
  101. (define (ref0) (values single multiple))
  102. (define (ref1 k) (ref k single multiple))
  103. (define (ref2 k k*)
  104. (if k*
  105. (let-values (((single multiple) (ref k single multiple)))
  106. (ref k* single multiple))
  107. (ref1 k)))
  108. (match (intmap-ref conts label)
  109. (($ $kreceive arity k) (ref1 k))
  110. (($ $kfun src meta self ktail kclause) (ref2 ktail kclause))
  111. (($ $ktail) (ref0))
  112. (($ $kclause arity kbody kalt) (ref2 kbody kalt))
  113. (($ $kargs names syms ($ $continue k src exp))
  114. (ref2 k (match exp (($ $branch k) k) (($ $prompt _ _ k) k) (_ #f))))))
  115. (let*-values (((single multiple) (values empty-intset empty-intset))
  116. ((single multiple) (intset-fold add-ref body single multiple)))
  117. (intset-subtract (persistent-intset single)
  118. (persistent-intset multiple))))
  119. (define (compute-function-names conts functions)
  120. "Compute a map of FUN-LABEL->BOUND-VAR... for each labelled function
  121. whose bound vars we know."
  122. (define (add-named-fun var kfun out)
  123. (let ((self (match (intmap-ref conts kfun)
  124. (($ $kfun src meta self) self))))
  125. (intmap-add out kfun (intset var self))))
  126. (intmap-fold
  127. (lambda (label body out)
  128. (let ((single (compute-singly-referenced-labels conts body)))
  129. (intset-fold
  130. (lambda (label out)
  131. (match (intmap-ref conts label)
  132. (($ $kargs _ _ ($ $continue k _ ($ $fun kfun)))
  133. (if (intset-ref single k)
  134. (match (intmap-ref conts k)
  135. (($ $kargs (_) (var)) (add-named-fun var kfun out))
  136. (_ out))
  137. out))
  138. (($ $kargs _ _ ($ $continue k _ ($ $rec _ vars (($ $fun kfun) ...))))
  139. (unless (intset-ref single k)
  140. (error "$rec continuation has multiple predecessors??"))
  141. (fold add-named-fun out vars kfun))
  142. (_ out)))
  143. body
  144. out)))
  145. functions
  146. empty-intmap))
  147. (define (compute-well-known-functions conts bound->label)
  148. "Compute a set of labels indicating the well-known functions in
  149. @var{conts}. A well-known function is a function whose bound names we
  150. know and which is never used in a non-operator position."
  151. (intset-subtract
  152. (persistent-intset
  153. (intmap-fold (lambda (bound label candidates)
  154. (intset-add! candidates label))
  155. bound->label
  156. empty-intset))
  157. (persistent-intset
  158. (intset-fold (lambda (var not-well-known)
  159. (match (intmap-ref bound->label var (lambda (_) #f))
  160. (#f not-well-known)
  161. (label (intset-add! not-well-known label))))
  162. (compute-non-operator-uses conts)
  163. empty-intset))))
  164. (define (intset-cons i set)
  165. (intset-add set i))
  166. (define (compute-shared-closures conts well-known)
  167. "Compute a map LABEL->VAR indicating the sets of functions that will
  168. share a closure. If a functions's label is in the map, it is shared.
  169. The entries indicate the var of the shared closure, which will be one of
  170. the bound vars of the closure."
  171. (intmap-fold
  172. (lambda (label cont out)
  173. (match cont
  174. (($ $kargs _ _
  175. ($ $continue _ _ ($ $rec names vars (($ $fun kfuns) ...))))
  176. ;; The split-rec pass should have ensured that this $rec forms a
  177. ;; strongly-connected component, so the free variables from all of
  178. ;; the functions will be alive as long as one of the closures is
  179. ;; alive. For that reason we can consider storing all free
  180. ;; variables in one closure and sharing it.
  181. (let* ((kfuns-set (fold intset-cons empty-intset kfuns))
  182. (unknown-kfuns (intset-subtract kfuns-set well-known)))
  183. (cond
  184. ((or (eq? empty-intset kfuns-set) (trivial-intset kfuns-set))
  185. ;; There is only zero or one function bound here. Trivially
  186. ;; shared already.
  187. out)
  188. ((eq? empty-intset unknown-kfuns)
  189. ;; All functions are well-known; we can share a closure. Use
  190. ;; the first bound variable.
  191. (let ((closure (car vars)))
  192. (intset-fold (lambda (kfun out)
  193. (intmap-add out kfun closure))
  194. kfuns-set out)))
  195. ((trivial-intset unknown-kfuns)
  196. => (lambda (unknown-kfun)
  197. ;; Only one function is not-well-known. Use that
  198. ;; function's closure as the shared closure.
  199. (let ((closure (assq-ref (map cons kfuns vars) unknown-kfun)))
  200. (intset-fold (lambda (kfun out)
  201. (intmap-add out kfun closure))
  202. kfuns-set out))))
  203. (else
  204. ;; More than one not-well-known function means we need more
  205. ;; than one proper closure, so we can't share.
  206. out))))
  207. (_ out)))
  208. conts
  209. empty-intmap))
  210. (define* (rewrite-shared-closure-calls cps functions label->bound shared kfun)
  211. "Rewrite CPS such that every call to a function with a shared closure
  212. instead is a $callk to that label, but passing the shared closure as the
  213. proc argument. For recursive calls, use the appropriate 'self'
  214. variable, if possible. Also rewrite uses of the non-well-known but
  215. shared closures to use the appropriate 'self' variable, if possible."
  216. ;; env := var -> (var . label)
  217. (define (rewrite-fun kfun cps env)
  218. (define (subst var)
  219. (match (intmap-ref env var (lambda (_) #f))
  220. (#f var)
  221. ((var . label) var)))
  222. (define (rename-exp label cps names vars k src exp)
  223. (intmap-replace!
  224. cps label
  225. (build-cont
  226. ($kargs names vars
  227. ($continue k src
  228. ,(rewrite-exp exp
  229. ((or ($ $const) ($ $prim)) ,exp)
  230. (($ $call proc args)
  231. ,(let ((args (map subst args)))
  232. (rewrite-exp (intmap-ref env proc (lambda (_) #f))
  233. (#f ($call proc ,args))
  234. ((closure . label) ($callk label closure ,args)))))
  235. (($ $primcall name args)
  236. ($primcall name ,(map subst args)))
  237. (($ $branch k ($ $values (arg)))
  238. ($branch k ($values ((subst arg)))))
  239. (($ $branch k ($ $primcall name args))
  240. ($branch k ($primcall name ,(map subst args))))
  241. (($ $values args)
  242. ($values ,(map subst args)))
  243. (($ $prompt escape? tag handler)
  244. ($prompt escape? (subst tag) handler))))))))
  245. (define (visit-exp label cps names vars k src exp)
  246. (define (compute-env label bound self rec-bound rec-labels env)
  247. (define (add-bound-var bound label env)
  248. (intmap-add env bound (cons self label) (lambda (old new) new)))
  249. (if (intmap-ref shared label (lambda (_) #f))
  250. ;; Within a function with a shared closure, rewrite
  251. ;; references to bound vars to use the "self" var.
  252. (fold add-bound-var env rec-bound rec-labels)
  253. ;; Otherwise be sure to use "self" references in any
  254. ;; closure.
  255. (add-bound-var bound label env)))
  256. (match exp
  257. (($ $fun label)
  258. (rewrite-fun label cps env))
  259. (($ $rec names vars (($ $fun labels) ...))
  260. (fold (lambda (label var cps)
  261. (match (intmap-ref cps label)
  262. (($ $kfun src meta self)
  263. (rewrite-fun label cps
  264. (compute-env label var self vars labels
  265. env)))))
  266. cps labels vars))
  267. (_ (rename-exp label cps names vars k src exp))))
  268. (define (rewrite-cont label cps)
  269. (match (intmap-ref cps label)
  270. (($ $kargs names vars ($ $continue k src exp))
  271. (visit-exp label cps names vars k src exp))
  272. (_ cps)))
  273. (intset-fold rewrite-cont (intmap-ref functions kfun) cps))
  274. ;; Initial environment is bound-var -> (shared-var . label) map for
  275. ;; functions with shared closures.
  276. (let ((env (intmap-fold (lambda (label shared env)
  277. (intset-fold (lambda (bound env)
  278. (intmap-add env bound
  279. (cons shared label)))
  280. (intset-remove
  281. (intmap-ref label->bound label)
  282. (match (intmap-ref cps label)
  283. (($ $kfun src meta self) self)))
  284. env))
  285. shared
  286. empty-intmap)))
  287. (persistent-intmap (rewrite-fun kfun cps env))))
  288. (define (compute-free-vars conts kfun shared)
  289. "Compute a FUN-LABEL->FREE-VAR... map describing all free variable
  290. references."
  291. (define (add-def var defs) (intset-add! defs var))
  292. (define (add-defs vars defs)
  293. (match vars
  294. (() defs)
  295. ((var . vars) (add-defs vars (add-def var defs)))))
  296. (define (add-use var uses)
  297. (intset-add! uses var))
  298. (define (add-uses vars uses)
  299. (match vars
  300. (() uses)
  301. ((var . vars) (add-uses vars (add-use var uses)))))
  302. (define (visit-nested-funs body)
  303. (intset-fold
  304. (lambda (label out)
  305. (match (intmap-ref conts label)
  306. (($ $kargs _ _ ($ $continue _ _
  307. ($ $fun kfun)))
  308. (intmap-union out (visit-fun kfun)))
  309. (($ $kargs _ _ ($ $continue _ _
  310. ($ $rec _ _ (($ $fun labels) ...))))
  311. (let* ((out (fold (lambda (kfun out)
  312. (intmap-union out (visit-fun kfun)))
  313. out labels))
  314. (free (fold (lambda (kfun free)
  315. (intset-union free (intmap-ref out kfun)))
  316. empty-intset labels)))
  317. (fold (lambda (kfun out)
  318. ;; For functions that share a closure, the free
  319. ;; variables for one will be the union of the free
  320. ;; variables for all.
  321. (if (intmap-ref shared kfun (lambda (_) #f))
  322. (intmap-replace out kfun free)
  323. out))
  324. out
  325. labels)))
  326. (_ out)))
  327. body
  328. empty-intmap))
  329. (define (visit-fun kfun)
  330. (let* ((body (compute-function-body conts kfun))
  331. (free (visit-nested-funs body)))
  332. (call-with-values
  333. (lambda ()
  334. (intset-fold
  335. (lambda (label defs uses)
  336. (match (intmap-ref conts label)
  337. (($ $kargs names vars ($ $continue k src exp))
  338. (values
  339. (add-defs vars defs)
  340. (match exp
  341. ((or ($ $const) ($ $prim)) uses)
  342. (($ $fun kfun)
  343. (intset-union (persistent-intset uses)
  344. (intmap-ref free kfun)))
  345. (($ $rec names vars (($ $fun kfun) ...))
  346. (fold (lambda (kfun uses)
  347. (intset-union (persistent-intset uses)
  348. (intmap-ref free kfun)))
  349. uses kfun))
  350. (($ $values args)
  351. (add-uses args uses))
  352. (($ $call proc args)
  353. (add-use proc (add-uses args uses)))
  354. (($ $callk label proc args)
  355. (add-use proc (add-uses args uses)))
  356. (($ $branch kt ($ $values (arg)))
  357. (add-use arg uses))
  358. (($ $branch kt ($ $primcall name args))
  359. (add-uses args uses))
  360. (($ $primcall name args)
  361. (add-uses args uses))
  362. (($ $prompt escape? tag handler)
  363. (add-use tag uses)))))
  364. (($ $kfun src meta self)
  365. (values (add-def self defs) uses))
  366. (_ (values defs uses))))
  367. body empty-intset empty-intset))
  368. (lambda (defs uses)
  369. (intmap-add free kfun (intset-subtract
  370. (persistent-intset uses)
  371. (persistent-intset defs)))))))
  372. (visit-fun kfun))
  373. (define (eliminate-closure? label free-vars)
  374. (eq? (intmap-ref free-vars label) empty-intset))
  375. (define (closure-label label shared bound->label)
  376. (cond
  377. ((intmap-ref shared label (lambda (_) #f))
  378. => (lambda (closure)
  379. (intmap-ref bound->label closure)))
  380. (else label)))
  381. (define (closure-alias label well-known free-vars)
  382. (and (intset-ref well-known label)
  383. (trivial-intset (intmap-ref free-vars label))))
  384. (define (prune-free-vars free-vars bound->label well-known shared)
  385. "Given the label->bound-var map @var{free-vars}, remove free variables
  386. that are known functions with zero free variables, and replace
  387. references to well-known functions with one free variable with that free
  388. variable, until we reach a fixed point on the free-vars map."
  389. (define (prune-free in-label free free-vars)
  390. (intset-fold (lambda (var free)
  391. (match (intmap-ref bound->label var (lambda (_) #f))
  392. (#f free)
  393. (label
  394. (cond
  395. ((eliminate-closure? label free-vars)
  396. (intset-remove free var))
  397. ((closure-alias (closure-label label shared bound->label)
  398. well-known free-vars)
  399. => (lambda (alias)
  400. ;; If VAR is free in LABEL, then ALIAS must
  401. ;; also be free because its definition must
  402. ;; precede VAR's definition.
  403. (intset-add (intset-remove free var) alias)))
  404. (else free)))))
  405. free free))
  406. (fixpoint (lambda (free-vars)
  407. (intmap-fold (lambda (label free free-vars)
  408. (intmap-replace free-vars label
  409. (prune-free label free free-vars)))
  410. free-vars
  411. free-vars))
  412. free-vars))
  413. (define (intset-find set i)
  414. (let lp ((idx 0) (start #f))
  415. (let ((start (intset-next set start)))
  416. (cond
  417. ((not start) (error "not found" set i))
  418. ((= start i) idx)
  419. (else (lp (1+ idx) (1+ start)))))))
  420. (define (intset-count set)
  421. (intset-fold (lambda (_ count) (1+ count)) set 0))
  422. (define (convert-one cps label body free-vars bound->label well-known shared)
  423. (define (well-known? label)
  424. (intset-ref well-known label))
  425. (let* ((free (intmap-ref free-vars label))
  426. (nfree (intset-count free))
  427. (self-known? (well-known? (closure-label label shared bound->label)))
  428. (self (match (intmap-ref cps label) (($ $kfun _ _ self) self))))
  429. (define (convert-arg cps var k)
  430. "Convert one possibly free variable reference to a bound reference.
  431. If @var{var} is free, it is replaced by a closure reference via a
  432. @code{free-ref} primcall, and @var{k} is called with the new var.
  433. Otherwise @var{var} is bound, so @var{k} is called with @var{var}."
  434. ;; We know that var is not the name of a well-known function.
  435. (cond
  436. ((and=> (intmap-ref bound->label var (lambda (_) #f))
  437. (lambda (kfun)
  438. (and (eq? empty-intset (intmap-ref free-vars kfun))
  439. kfun)))
  440. ;; A not-well-known function with zero free vars. Copy as a
  441. ;; constant, relying on the linker to reify just one copy.
  442. => (lambda (kfun)
  443. (with-cps cps
  444. (letv var*)
  445. (let$ body (k var*))
  446. (letk k* ($kargs (#f) (var*) ,body))
  447. (build-term ($continue k* #f ($closure kfun 0))))))
  448. ((intset-ref free var)
  449. (match (vector self-known? nfree)
  450. (#(#t 1)
  451. ;; A reference to the one free var of a well-known function.
  452. (with-cps cps
  453. ($ (k self))))
  454. (#(#t 2)
  455. ;; A reference to one of the two free vars in a well-known
  456. ;; function.
  457. (let ((op (if (= var (intset-next free)) 'car 'cdr)))
  458. (with-cps cps
  459. (letv var*)
  460. (let$ body (k var*))
  461. (letk k* ($kargs (#f) (var*) ,body))
  462. (build-term ($continue k* #f ($primcall op (self)))))))
  463. (_
  464. (let ((idx (intset-find free var)))
  465. (cond
  466. (self-known?
  467. (with-cps cps
  468. (letv var* u64)
  469. (let$ body (k var*))
  470. (letk k* ($kargs (#f) (var*) ,body))
  471. (letk kunbox ($kargs ('idx) (u64)
  472. ($continue k* #f
  473. ($primcall 'vector-ref (self u64)))))
  474. ($ (with-cps-constants ((idx idx))
  475. (build-term
  476. ($continue kunbox #f
  477. ($primcall 'scm->u64 (idx))))))))
  478. (else
  479. (with-cps cps
  480. (letv var*)
  481. (let$ body (k var*))
  482. (letk k* ($kargs (#f) (var*) ,body))
  483. ($ (with-cps-constants ((idx idx))
  484. (build-term
  485. ($continue k* #f
  486. ($primcall 'free-ref (self idx)))))))))))))
  487. (else
  488. (with-cps cps
  489. ($ (k var))))))
  490. (define (convert-args cps vars k)
  491. "Convert a number of possibly free references to bound references.
  492. @var{k} is called with the bound references, and should return the
  493. term."
  494. (match vars
  495. (()
  496. (with-cps cps
  497. ($ (k '()))))
  498. ((var . vars)
  499. (convert-arg cps var
  500. (lambda (cps var)
  501. (convert-args cps vars
  502. (lambda (cps vars)
  503. (with-cps cps
  504. ($ (k (cons var vars)))))))))))
  505. (define (allocate-closure cps k src label known? nfree)
  506. "Allocate a new closure, and pass it to $var{k}."
  507. (match (vector known? nfree)
  508. (#(#f nfree)
  509. ;; The call sites cannot be enumerated; allocate a closure.
  510. (with-cps cps
  511. (build-term ($continue k src ($closure label nfree)))))
  512. (#(#t 2)
  513. ;; Well-known closure with two free variables; the closure is a
  514. ;; pair.
  515. (with-cps cps
  516. ($ (with-cps-constants ((false #f))
  517. (build-term
  518. ($continue k src ($primcall 'cons (false false))))))))
  519. ;; Well-known callee with more than two free variables; the closure
  520. ;; is a vector.
  521. (#(#t nfree)
  522. (unless (> nfree 2)
  523. (error "unexpected well-known nullary, unary, or binary closure"))
  524. (with-cps cps
  525. ($ (with-cps-constants ((nfree nfree)
  526. (false #f))
  527. (letv u64)
  528. (letk kunbox ($kargs ('nfree) (u64)
  529. ($continue k src
  530. ($primcall 'make-vector (u64 false)))))
  531. (build-term
  532. ($continue kunbox src ($primcall 'scm->u64 (nfree))))))))))
  533. (define (init-closure cps k src var known? free)
  534. "Initialize the free variables @var{closure-free} in a closure
  535. bound to @var{var}, and continue to @var{k}."
  536. (match (vector known? (intset-count free))
  537. ;; Well-known callee with zero or one free variables; no
  538. ;; initialization necessary.
  539. (#(#t (or 0 1))
  540. (with-cps cps
  541. (build-term ($continue k src ($values ())))))
  542. ;; Well-known callee with two free variables; do a set-car! and
  543. ;; set-cdr!.
  544. (#(#t 2)
  545. (let* ((free0 (intset-next free))
  546. (free1 (intset-next free (1+ free0))))
  547. (convert-arg cps free0
  548. (lambda (cps v0)
  549. (with-cps cps
  550. (let$ body
  551. (convert-arg free1
  552. (lambda (cps v1)
  553. (with-cps cps
  554. (build-term
  555. ($continue k src
  556. ($primcall 'set-cdr! (var v1))))))))
  557. (letk kcdr ($kargs () () ,body))
  558. (build-term
  559. ($continue kcdr src ($primcall 'set-car! (var v0)))))))))
  560. ;; Otherwise residualize a sequence of vector-set! or free-set!,
  561. ;; depending on whether the callee is well-known or not.
  562. (_
  563. (let lp ((cps cps) (prev #f) (idx 0))
  564. (match (intset-next free prev)
  565. (#f (with-cps cps
  566. (build-term ($continue k src ($values ())))))
  567. (v (with-cps cps
  568. (let$ body (lp (1+ v) (1+ idx)))
  569. (letk k ($kargs () () ,body))
  570. ($ (convert-arg v
  571. (lambda (cps v)
  572. (cond
  573. (known?
  574. (with-cps cps
  575. (letv u64)
  576. (letk kunbox
  577. ($kargs ('idx) (u64)
  578. ($continue k src
  579. ($primcall 'vector-set! (var u64 v)))))
  580. ($ (with-cps-constants ((idx idx))
  581. (build-term
  582. ($continue kunbox src
  583. ($primcall 'scm->u64 (idx))))))))
  584. (else
  585. (with-cps cps
  586. ($ (with-cps-constants ((idx idx))
  587. (build-term
  588. ($continue k src
  589. ($primcall 'free-set!
  590. (var idx v)))))))))))))))))))
  591. (define (make-single-closure cps k src kfun)
  592. (let ((free (intmap-ref free-vars kfun)))
  593. (match (vector (well-known? kfun) (intset-count free))
  594. (#(#f 0)
  595. (with-cps cps
  596. (build-term ($continue k src ($closure kfun 0)))))
  597. (#(#t 0)
  598. (with-cps cps
  599. (build-term ($continue k src ($const #f)))))
  600. (#(#t 1)
  601. ;; A well-known closure of one free variable is replaced
  602. ;; at each use with the free variable itself, so we don't
  603. ;; need a binding at all; and yet, the continuation
  604. ;; expects one value, so give it something. DCE should
  605. ;; clean up later.
  606. (with-cps cps
  607. (build-term ($continue k src ($const #f)))))
  608. (#(well-known? nfree)
  609. ;; A bit of a mess, but beta conversion should remove the
  610. ;; final $values if possible.
  611. (with-cps cps
  612. (letv closure)
  613. (letk k* ($kargs () () ($continue k src ($values (closure)))))
  614. (let$ init (init-closure k* src closure well-known? free))
  615. (letk knew ($kargs (#f) (closure) ,init))
  616. ($ (allocate-closure knew src kfun well-known? nfree)))))))
  617. ;; The callee is known, but not necessarily well-known.
  618. (define (convert-known-proc-call cps k src label closure args)
  619. (define (have-closure cps closure)
  620. (convert-args cps args
  621. (lambda (cps args)
  622. (with-cps cps
  623. (build-term
  624. ($continue k src ($callk label closure args)))))))
  625. (cond
  626. ((eq? (intmap-ref free-vars label) empty-intset)
  627. ;; Known call, no free variables; no closure needed.
  628. ;; Pass #f as closure argument.
  629. (with-cps cps
  630. ($ (with-cps-constants ((false #f))
  631. ($ (have-closure false))))))
  632. ((and (well-known? (closure-label label shared bound->label))
  633. (trivial-intset (intmap-ref free-vars label)))
  634. ;; Well-known closures with one free variable are
  635. ;; replaced at their use sites by uses of the one free
  636. ;; variable.
  637. => (lambda (var)
  638. (convert-arg cps var have-closure)))
  639. (else
  640. ;; Otherwise just load the proc.
  641. (convert-arg cps closure have-closure))))
  642. (define (visit-term cps term)
  643. (match term
  644. (($ $continue k src (or ($ $const) ($ $prim)))
  645. (with-cps cps
  646. term))
  647. (($ $continue k src ($ $fun kfun))
  648. (with-cps cps
  649. ($ (make-single-closure k src kfun))))
  650. ;; Remove letrec.
  651. (($ $continue k src ($ $rec names vars (($ $fun kfuns) ...)))
  652. (match (vector names vars kfuns)
  653. (#(() () ())
  654. ;; Trivial empty case.
  655. (with-cps cps
  656. (build-term ($continue k src ($values ())))))
  657. (#((name) (var) (kfun))
  658. ;; Trivial single case. We have already proven that K has
  659. ;; only LABEL as its predecessor, so we have been able
  660. ;; already to rewrite free references to the bound name with
  661. ;; the self name.
  662. (with-cps cps
  663. ($ (make-single-closure k src kfun))))
  664. (#(_ _ (kfun0 . _))
  665. ;; A non-trivial strongly-connected component. Does it have
  666. ;; a shared closure?
  667. (match (intmap-ref shared kfun0 (lambda (_) #f))
  668. (#f
  669. ;; Nope. Allocate closures for each function.
  670. (let lp ((cps (match (intmap-ref cps k)
  671. ;; Steal declarations from the continuation.
  672. (($ $kargs names vals body)
  673. (intmap-replace cps k
  674. (build-cont
  675. ($kargs () () ,body))))))
  676. (in (map vector names vars kfuns))
  677. (init (lambda (cps)
  678. (with-cps cps
  679. (build-term
  680. ($continue k src ($values ())))))))
  681. (match in
  682. (() (init cps))
  683. ((#(name var kfun) . in)
  684. (let* ((known? (well-known? kfun))
  685. (free (intmap-ref free-vars kfun))
  686. (nfree (intset-count free)))
  687. (define (next-init cps)
  688. (with-cps cps
  689. (let$ body (init))
  690. (letk k ($kargs () () ,body))
  691. ($ (init-closure k src var known? free))))
  692. (with-cps cps
  693. (let$ body (lp in next-init))
  694. (letk k ($kargs (name) (var) ,body))
  695. ($ (allocate-closure k src kfun known? nfree))))))))
  696. (shared
  697. ;; If shared is in the bound->var map, that means one of
  698. ;; the functions is not well-known. Otherwise use kfun0
  699. ;; as the function label, but just so make-single-closure
  700. ;; can find the free vars, not for embedding in the
  701. ;; closure.
  702. (let* ((kfun (intmap-ref bound->label shared (lambda (_) kfun0)))
  703. (cps (match (intmap-ref cps k)
  704. ;; Make continuation declare only the shared
  705. ;; closure.
  706. (($ $kargs names vals body)
  707. (intmap-replace cps k
  708. (build-cont
  709. ($kargs (#f) (shared) ,body)))))))
  710. (with-cps cps
  711. ($ (make-single-closure k src kfun)))))))))
  712. (($ $continue k src ($ $call proc args))
  713. (match (intmap-ref bound->label proc (lambda (_) #f))
  714. (#f
  715. (convert-arg cps proc
  716. (lambda (cps proc)
  717. (convert-args cps args
  718. (lambda (cps args)
  719. (with-cps cps
  720. (build-term
  721. ($continue k src ($call proc args)))))))))
  722. (label
  723. (convert-known-proc-call cps k src label proc args))))
  724. (($ $continue k src ($ $callk label proc args))
  725. (convert-known-proc-call cps k src label proc args))
  726. (($ $continue k src ($ $primcall name args))
  727. (convert-args cps args
  728. (lambda (cps args)
  729. (with-cps cps
  730. (build-term
  731. ($continue k src ($primcall name args)))))))
  732. (($ $continue k src ($ $branch kt ($ $primcall name args)))
  733. (convert-args cps args
  734. (lambda (cps args)
  735. (with-cps cps
  736. (build-term
  737. ($continue k src
  738. ($branch kt ($primcall name args))))))))
  739. (($ $continue k src ($ $branch kt ($ $values (arg))))
  740. (convert-arg cps arg
  741. (lambda (cps arg)
  742. (with-cps cps
  743. (build-term
  744. ($continue k src
  745. ($branch kt ($values (arg)))))))))
  746. (($ $continue k src ($ $values args))
  747. (convert-args cps args
  748. (lambda (cps args)
  749. (with-cps cps
  750. (build-term
  751. ($continue k src ($values args)))))))
  752. (($ $continue k src ($ $prompt escape? tag handler))
  753. (convert-arg cps tag
  754. (lambda (cps tag)
  755. (with-cps cps
  756. (build-term
  757. ($continue k src
  758. ($prompt escape? tag handler)))))))))
  759. (intset-fold (lambda (label cps)
  760. (match (intmap-ref cps label (lambda (_) #f))
  761. (($ $kargs names vars term)
  762. (with-cps cps
  763. (let$ term (visit-term term))
  764. (setk label ($kargs names vars ,term))))
  765. (_ cps)))
  766. body
  767. cps)))
  768. (define (convert-closures cps)
  769. "Convert free reference in @var{cps} to primcalls to @code{free-ref},
  770. and allocate and initialize flat closures."
  771. (let* ((kfun 0) ;; Ass-u-me.
  772. ;; label -> body-label...
  773. (functions (compute-function-bodies cps kfun))
  774. (cps (filter-reachable cps functions))
  775. ;; label -> bound-var...
  776. (label->bound (compute-function-names cps functions))
  777. ;; bound-var -> label
  778. (bound->label (invert-partition label->bound))
  779. ;; label...
  780. (well-known (compute-well-known-functions cps bound->label))
  781. ;; label -> closure-var
  782. (shared (compute-shared-closures cps well-known))
  783. (cps (rewrite-shared-closure-calls cps functions label->bound shared
  784. kfun))
  785. ;; label -> free-var...
  786. (free-vars (compute-free-vars cps kfun shared))
  787. (free-vars (prune-free-vars free-vars bound->label well-known shared)))
  788. (let ((free-in-program (intmap-ref free-vars kfun)))
  789. (unless (eq? empty-intset free-in-program)
  790. (error "Expected no free vars in program" free-in-program)))
  791. (with-fresh-name-state cps
  792. (persistent-intmap
  793. (intmap-fold
  794. (lambda (label body cps)
  795. (convert-one cps label body free-vars bound->label well-known shared))
  796. functions
  797. cps)))))
  798. ;;; Local Variables:
  799. ;;; eval: (put 'convert-arg 'scheme-indent-function 2)
  800. ;;; eval: (put 'convert-args 'scheme-indent-function 2)
  801. ;;; End: