dce.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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 kills dead expressions: code that has no side effects, and
  19. ;;; whose value is unused. It does so by marking all live values, and
  20. ;;; then discarding other values as dead. This happens recursively
  21. ;;; through procedures, so it should be possible to elide dead
  22. ;;; procedures as well.
  23. ;;;
  24. ;;; Code:
  25. (define-module (language cps dce)
  26. #:use-module (ice-9 match)
  27. #:use-module (srfi srfi-1)
  28. #:use-module (language cps)
  29. #:use-module (language cps effects-analysis)
  30. #:use-module (language cps renumber)
  31. #:use-module (language cps type-checks)
  32. #:use-module (language cps utils)
  33. #:use-module (language cps intmap)
  34. #:use-module (language cps intset)
  35. #:export (eliminate-dead-code))
  36. (define (fold-local-conts proc conts label seed)
  37. (match (intmap-ref conts label)
  38. (($ $kfun src meta self tail clause)
  39. (let lp ((label label) (seed seed))
  40. (if (<= label tail)
  41. (lp (1+ label) (proc label (intmap-ref conts label) seed))
  42. seed)))))
  43. (define (postorder-fold-local-conts2 proc conts label seed0 seed1)
  44. (match (intmap-ref conts label)
  45. (($ $kfun src meta self tail clause)
  46. (let ((start label))
  47. (let lp ((label tail) (seed0 seed0) (seed1 seed1))
  48. (if (<= start label)
  49. (let ((cont (intmap-ref conts label)))
  50. (call-with-values (lambda () (proc label cont seed0 seed1))
  51. (lambda (seed0 seed1)
  52. (lp (1- label) seed0 seed1))))
  53. (values seed0 seed1)))))))
  54. (define (compute-known-allocations conts effects)
  55. "Compute the variables bound in CONTS that have known allocation
  56. sites."
  57. ;; Compute the set of conts that are called with freshly allocated
  58. ;; values, and subtract from that set the conts that might be called
  59. ;; with values with unknown allocation sites. Then convert that set
  60. ;; of conts into a set of bound variables.
  61. (call-with-values
  62. (lambda ()
  63. (intmap-fold (lambda (label cont known unknown)
  64. ;; Note that we only need to add labels to the
  65. ;; known/unknown sets if the labels can bind
  66. ;; values. So there's no need to add tail,
  67. ;; clause, branch alternate, or prompt handler
  68. ;; labels, as they bind no values.
  69. (match cont
  70. (($ $kargs _ _ ($ $continue k))
  71. (let ((fx (intmap-ref effects label)))
  72. (if (and (not (causes-all-effects? fx))
  73. (causes-effect? fx &allocation))
  74. (values (intset-add! known k) unknown)
  75. (values known (intset-add! unknown k)))))
  76. (($ $kreceive arity kargs)
  77. (values known (intset-add! unknown kargs)))
  78. (($ $kfun src meta self tail clause)
  79. (values known unknown))
  80. (($ $kclause arity body alt)
  81. (values known (intset-add! unknown body)))
  82. (($ $ktail)
  83. (values known unknown))))
  84. conts
  85. empty-intset
  86. empty-intset))
  87. (lambda (known unknown)
  88. (persistent-intset
  89. (intset-fold (lambda (label vars)
  90. (match (intmap-ref conts label)
  91. (($ $kargs (_) (var)) (intset-add! vars var))
  92. (_ vars)))
  93. (intset-subtract (persistent-intset known)
  94. (persistent-intset unknown))
  95. empty-intset)))))
  96. (define (compute-live-code conts)
  97. (let* ((effects (compute-effects/elide-type-checks conts))
  98. (known-allocations (compute-known-allocations conts effects)))
  99. (define (adjoin-var var set)
  100. (intset-add set var))
  101. (define (adjoin-vars vars set)
  102. (match vars
  103. (() set)
  104. ((var . vars) (adjoin-vars vars (adjoin-var var set)))))
  105. (define (var-live? var live-vars)
  106. (intset-ref live-vars var))
  107. (define (any-var-live? vars live-vars)
  108. (match vars
  109. (() #f)
  110. ((var . vars)
  111. (or (var-live? var live-vars)
  112. (any-var-live? vars live-vars)))))
  113. (define (cont-defs k)
  114. (match (intmap-ref conts k)
  115. (($ $kargs _ vars) vars)
  116. (_ #f)))
  117. (define (visit-live-exp label k exp live-labels live-vars)
  118. (match exp
  119. ((or ($ $const) ($ $prim))
  120. (values live-labels live-vars))
  121. (($ $fun body)
  122. (values (intset-add live-labels body) live-vars))
  123. (($ $closure body)
  124. (values (intset-add live-labels body) live-vars))
  125. (($ $rec names vars (($ $fun kfuns) ...))
  126. (let lp ((vars vars) (kfuns kfuns)
  127. (live-labels live-labels) (live-vars live-vars))
  128. (match (vector vars kfuns)
  129. (#(() ()) (values live-labels live-vars))
  130. (#((var . vars) (kfun . kfuns))
  131. (lp vars kfuns
  132. (if (var-live? var live-vars)
  133. (intset-add live-labels kfun)
  134. live-labels)
  135. live-vars)))))
  136. (($ $prompt escape? tag handler)
  137. (values live-labels (adjoin-var tag live-vars)))
  138. (($ $call proc args)
  139. (values live-labels (adjoin-vars args (adjoin-var proc live-vars))))
  140. (($ $callk kfun proc args)
  141. (values (intset-add live-labels kfun)
  142. (adjoin-vars args (adjoin-var proc live-vars))))
  143. (($ $primcall name args)
  144. (values live-labels (adjoin-vars args live-vars)))
  145. (($ $branch k ($ $primcall name args))
  146. (values live-labels (adjoin-vars args live-vars)))
  147. (($ $branch k ($ $values (arg)))
  148. (values live-labels (adjoin-var arg live-vars)))
  149. (($ $values args)
  150. (values live-labels
  151. (match (cont-defs k)
  152. (#f (adjoin-vars args live-vars))
  153. (defs (fold (lambda (use def live-vars)
  154. (if (var-live? def live-vars)
  155. (adjoin-var use live-vars)
  156. live-vars))
  157. live-vars args defs)))))))
  158. (define (visit-exp label k exp live-labels live-vars)
  159. (cond
  160. ((intset-ref live-labels label)
  161. ;; Expression live already.
  162. (visit-live-exp label k exp live-labels live-vars))
  163. ((let ((defs (cont-defs k))
  164. (fx (intmap-ref effects label)))
  165. (or
  166. ;; No defs; perhaps continuation is $ktail.
  167. (not defs)
  168. ;; We don't remove branches.
  169. (match exp (($ $branch) #t) (_ #f))
  170. ;; Do we have a live def?
  171. (any-var-live? defs live-vars)
  172. ;; Does this expression cause all effects? If so, it's
  173. ;; definitely live.
  174. (causes-all-effects? fx)
  175. ;; Does it cause a type check, but we weren't able to prove
  176. ;; that the types check?
  177. (causes-effect? fx &type-check)
  178. ;; We might have a setter. If the object being assigned to
  179. ;; is live or was not created by us, then this expression is
  180. ;; live. Otherwise the value is still dead.
  181. (and (causes-effect? fx &write)
  182. (match exp
  183. (($ $primcall
  184. (or 'vector-set! 'vector-set!/immediate
  185. 'set-car! 'set-cdr!
  186. 'box-set!)
  187. (obj . _))
  188. (or (var-live? obj live-vars)
  189. (not (intset-ref known-allocations obj))))
  190. (_ #t)))))
  191. ;; Mark expression as live and visit.
  192. (visit-live-exp label k exp (intset-add live-labels label) live-vars))
  193. (else
  194. ;; Still dead.
  195. (values live-labels live-vars))))
  196. (define (visit-fun label live-labels live-vars)
  197. ;; Visit uses before definitions.
  198. (postorder-fold-local-conts2
  199. (lambda (label cont live-labels live-vars)
  200. (match cont
  201. (($ $kargs _ _ ($ $continue k src exp))
  202. (visit-exp label k exp live-labels live-vars))
  203. (($ $kreceive arity kargs)
  204. (values live-labels live-vars))
  205. (($ $kclause arity kargs kalt)
  206. (values live-labels (adjoin-vars (cont-defs kargs) live-vars)))
  207. (($ $kfun src meta self)
  208. (values live-labels (adjoin-var self live-vars)))
  209. (($ $ktail)
  210. (values live-labels live-vars))))
  211. conts label live-labels live-vars))
  212. (fixpoint (lambda (live-labels live-vars)
  213. (let lp ((label 0)
  214. (live-labels live-labels)
  215. (live-vars live-vars))
  216. (match (intset-next live-labels label)
  217. (#f (values live-labels live-vars))
  218. (label
  219. (call-with-values
  220. (lambda ()
  221. (match (intmap-ref conts label)
  222. (($ $kfun)
  223. (visit-fun label live-labels live-vars))
  224. (_ (values live-labels live-vars))))
  225. (lambda (live-labels live-vars)
  226. (lp (1+ label) live-labels live-vars)))))))
  227. (intset 0)
  228. empty-intset)))
  229. (define-syntax adjoin-conts
  230. (syntax-rules ()
  231. ((_ (exp ...) clause ...)
  232. (let ((cps (exp ...)))
  233. (adjoin-conts cps clause ...)))
  234. ((_ cps (label cont) clause ...)
  235. (adjoin-conts (intmap-add! cps label (build-cont cont))
  236. clause ...))
  237. ((_ cps)
  238. cps)))
  239. (define (process-eliminations conts live-labels live-vars)
  240. (define (label-live? label)
  241. (intset-ref live-labels label))
  242. (define (value-live? var)
  243. (intset-ref live-vars var))
  244. (define (make-adaptor k src defs)
  245. (let* ((names (map (lambda (_) 'tmp) defs))
  246. (vars (map (lambda (_) (fresh-var)) defs))
  247. (live (filter-map (lambda (def var)
  248. (and (value-live? def) var))
  249. defs vars)))
  250. (build-cont
  251. ($kargs names vars
  252. ($continue k src ($values live))))))
  253. (define (visit-term label term cps)
  254. (match term
  255. (($ $continue k src exp)
  256. (if (label-live? label)
  257. (match exp
  258. (($ $fun body)
  259. (values cps
  260. term))
  261. (($ $closure body nfree)
  262. (values cps
  263. term))
  264. (($ $rec names vars funs)
  265. (match (filter-map (lambda (name var fun)
  266. (and (value-live? var)
  267. (list name var fun)))
  268. names vars funs)
  269. (()
  270. (values cps
  271. (build-term ($continue k src ($values ())))))
  272. (((names vars funs) ...)
  273. (values cps
  274. (build-term ($continue k src
  275. ($rec names vars funs)))))))
  276. (_
  277. (match (intmap-ref conts k)
  278. (($ $kargs ())
  279. (values cps term))
  280. (($ $kargs names ((? value-live?) ...))
  281. (values cps term))
  282. (($ $kargs names vars)
  283. (match exp
  284. (($ $values args)
  285. (let ((args (filter-map (lambda (use def)
  286. (and (value-live? def) use))
  287. args vars)))
  288. (values cps
  289. (build-term
  290. ($continue k src ($values args))))))
  291. (_
  292. (let-fresh (adapt) ()
  293. (values (adjoin-conts cps
  294. (adapt ,(make-adaptor k src vars)))
  295. (build-term
  296. ($continue adapt src ,exp)))))))
  297. (_
  298. (values cps term)))))
  299. (values cps
  300. (build-term
  301. ($continue k src ($values ()))))))))
  302. (define (visit-cont label cont cps)
  303. (match cont
  304. (($ $kargs names vars term)
  305. (match (filter-map (lambda (name var)
  306. (and (value-live? var)
  307. (cons name var)))
  308. names vars)
  309. (((names . vars) ...)
  310. (call-with-values (lambda () (visit-term label term cps))
  311. (lambda (cps term)
  312. (adjoin-conts cps
  313. (label ($kargs names vars ,term))))))))
  314. (($ $kreceive ($ $arity req () rest () #f) kargs)
  315. (let ((defs (match (intmap-ref conts kargs)
  316. (($ $kargs names vars) vars))))
  317. (if (and-map value-live? defs)
  318. (adjoin-conts cps (label ,cont))
  319. (let-fresh (adapt) ()
  320. (adjoin-conts cps
  321. (adapt ,(make-adaptor kargs #f defs))
  322. (label ($kreceive req rest adapt)))))))
  323. (_
  324. (adjoin-conts cps (label ,cont)))))
  325. (with-fresh-name-state conts
  326. (persistent-intmap
  327. (intmap-fold (lambda (label cont cps)
  328. (match cont
  329. (($ $kfun)
  330. (if (label-live? label)
  331. (fold-local-conts visit-cont conts label cps)
  332. cps))
  333. (_ cps)))
  334. conts
  335. empty-intmap))))
  336. (define (eliminate-dead-code conts)
  337. ;; We work on a renumbered program so that we can easily visit uses
  338. ;; before definitions just by visiting higher-numbered labels before
  339. ;; lower-numbered labels. Renumbering is also a precondition for type
  340. ;; inference.
  341. (let ((conts (renumber conts)))
  342. (call-with-values (lambda () (compute-live-code conts))
  343. (lambda (live-labels live-vars)
  344. (process-eliminations conts live-labels live-vars)))))
  345. ;;; Local Variables:
  346. ;;; eval: (put 'adjoin-conts 'scheme-indent-function 1)
  347. ;;; End: