dce.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013, 2014, 2015, 2017, 2018 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. (($ $kargs _ _ (or ($ $branch) ($ $prompt) ($ $throw)))
  77. ;; Branches and prompts pass no values to
  78. ;; their continuations, and throw terms don't
  79. ;; continue at all.
  80. (values known unknown))
  81. (($ $kreceive arity kargs)
  82. (values known (intset-add! unknown kargs)))
  83. (($ $kfun src meta self tail clause)
  84. (values known unknown))
  85. (($ $kclause arity body alt)
  86. (values known (intset-add! unknown body)))
  87. (($ $ktail)
  88. (values known unknown))))
  89. conts
  90. empty-intset
  91. empty-intset))
  92. (lambda (known unknown)
  93. (persistent-intset
  94. (intset-fold (lambda (label vars)
  95. (match (intmap-ref conts label)
  96. (($ $kargs (_) (var)) (intset-add! vars var))
  97. (_ vars)))
  98. (intset-subtract (persistent-intset known)
  99. (persistent-intset unknown))
  100. empty-intset)))))
  101. (define (compute-live-code conts)
  102. (let* ((effects (compute-effects/elide-type-checks conts))
  103. (known-allocations (compute-known-allocations conts effects)))
  104. (define (adjoin-var var set)
  105. (intset-add set var))
  106. (define (adjoin-vars vars set)
  107. (match vars
  108. (() set)
  109. ((var . vars) (adjoin-vars vars (adjoin-var var set)))))
  110. (define (var-live? var live-vars)
  111. (intset-ref live-vars var))
  112. (define (any-var-live? vars live-vars)
  113. (match vars
  114. (() #f)
  115. ((var . vars)
  116. (or (var-live? var live-vars)
  117. (any-var-live? vars live-vars)))))
  118. (define (cont-defs k)
  119. (match (intmap-ref conts k)
  120. (($ $kargs _ vars) vars)
  121. (_ #f)))
  122. (define (visit-live-exp label k exp live-labels live-vars)
  123. (match exp
  124. ((or ($ $const) ($ $prim))
  125. (values live-labels live-vars))
  126. (($ $fun body)
  127. (values (intset-add live-labels body) live-vars))
  128. (($ $const-fun body)
  129. (values (intset-add live-labels body) live-vars))
  130. (($ $code body)
  131. (values (intset-add live-labels body) live-vars))
  132. (($ $rec names vars (($ $fun kfuns) ...))
  133. (let lp ((vars vars) (kfuns kfuns)
  134. (live-labels live-labels) (live-vars live-vars))
  135. (match (vector vars kfuns)
  136. (#(() ()) (values live-labels live-vars))
  137. (#((var . vars) (kfun . kfuns))
  138. (lp vars kfuns
  139. (if (var-live? var live-vars)
  140. (intset-add live-labels kfun)
  141. live-labels)
  142. live-vars)))))
  143. (($ $call proc args)
  144. (values live-labels (adjoin-vars args (adjoin-var proc live-vars))))
  145. (($ $callk kfun proc args)
  146. (values (intset-add live-labels kfun)
  147. (adjoin-vars args (adjoin-var proc live-vars))))
  148. (($ $primcall name param args)
  149. (values live-labels (adjoin-vars args live-vars)))
  150. (($ $values args)
  151. (values live-labels
  152. (match (cont-defs k)
  153. (#f (adjoin-vars args live-vars))
  154. (defs (fold (lambda (use def live-vars)
  155. (if (var-live? def live-vars)
  156. (adjoin-var use live-vars)
  157. live-vars))
  158. live-vars args defs)))))))
  159. (define (visit-exp label k exp live-labels live-vars)
  160. (cond
  161. ((intset-ref live-labels label)
  162. ;; Expression live already.
  163. (visit-live-exp label k exp live-labels live-vars))
  164. ((let ((defs (cont-defs k))
  165. (fx (intmap-ref effects label)))
  166. (or
  167. ;; No defs; perhaps continuation is $ktail.
  168. (not defs)
  169. ;; Do we have a live def?
  170. (any-var-live? defs live-vars)
  171. ;; Does this expression cause all effects? If so, it's
  172. ;; definitely live.
  173. (causes-all-effects? fx)
  174. ;; Does it cause a type check, but we weren't able to prove
  175. ;; that the types check?
  176. (causes-effect? fx &type-check)
  177. ;; We might have a setter. If the object being assigned to
  178. ;; is live or was not created by us, then this expression is
  179. ;; live. Otherwise the value is still dead.
  180. (and (causes-effect? fx &write)
  181. (match exp
  182. (($ $primcall
  183. (or 'scm-set! 'scm-set!/tag 'scm-set!/immediate
  184. 'word-set! 'word-set!/immediate) _
  185. (obj . _))
  186. (or (var-live? obj live-vars)
  187. (not (intset-ref known-allocations obj))))
  188. (_ #t)))))
  189. ;; Mark expression as live and visit.
  190. (visit-live-exp label k exp (intset-add live-labels label) live-vars))
  191. (else
  192. ;; Still dead.
  193. (values live-labels live-vars))))
  194. (define (visit-branch label kf kt args live-labels live-vars)
  195. (define (next-live-term k)
  196. ;; FIXME: For a chain of dead branches, this is quadratic.
  197. (let lp ((seen empty-intset) (k k))
  198. (cond
  199. ((intset-ref live-labels k) k)
  200. ((intset-ref seen k) k)
  201. (else
  202. (match (intmap-ref conts k)
  203. (($ $kargs _ _ ($ $continue k*))
  204. (lp (intset-add seen k) k*))
  205. (_ k))))))
  206. (cond
  207. ((intset-ref live-labels label)
  208. ;; Branch live already.
  209. (values live-labels (adjoin-vars args live-vars)))
  210. ((or (causes-effect? (intmap-ref effects label) &type-check)
  211. (not (eqv? (next-live-term kf) (next-live-term kt))))
  212. ;; The branch is live if its continuations are not the same, or
  213. ;; if the branch itself causes type checks.
  214. (values (intset-add live-labels label)
  215. (adjoin-vars args live-vars)))
  216. (else
  217. ;; Still dead.
  218. (values live-labels live-vars))))
  219. (define (visit-fun label live-labels live-vars)
  220. ;; Visit uses before definitions.
  221. (postorder-fold-local-conts2
  222. (lambda (label cont live-labels live-vars)
  223. (match cont
  224. (($ $kargs _ _ ($ $continue k src exp))
  225. (visit-exp label k exp live-labels live-vars))
  226. (($ $kargs _ _ ($ $branch kf kt src op param args))
  227. (visit-branch label kf kt args live-labels live-vars))
  228. (($ $kargs _ _ ($ $prompt k kh src escape? tag))
  229. ;; Prompts need special elision passes that would contify
  230. ;; aborts and remove corresponding "unwind" primcalls.
  231. (values (intset-add live-labels label)
  232. (adjoin-var tag live-vars)))
  233. (($ $kargs _ _ ($ $throw src op param args))
  234. ;; A reachable "throw" is always live.
  235. (values (intset-add live-labels label)
  236. (adjoin-vars args live-vars)))
  237. (($ $kreceive arity kargs)
  238. (values live-labels live-vars))
  239. (($ $kclause arity kargs kalt)
  240. (values live-labels (adjoin-vars (cont-defs kargs) live-vars)))
  241. (($ $kfun src meta self)
  242. (values live-labels (adjoin-var self live-vars)))
  243. (($ $ktail)
  244. (values live-labels live-vars))))
  245. conts label live-labels live-vars))
  246. (fixpoint (lambda (live-labels live-vars)
  247. (let lp ((label 0)
  248. (live-labels live-labels)
  249. (live-vars live-vars))
  250. (match (intset-next live-labels label)
  251. (#f (values live-labels live-vars))
  252. (label
  253. (call-with-values
  254. (lambda ()
  255. (match (intmap-ref conts label)
  256. (($ $kfun)
  257. (visit-fun label live-labels live-vars))
  258. (_ (values live-labels live-vars))))
  259. (lambda (live-labels live-vars)
  260. (lp (1+ label) live-labels live-vars)))))))
  261. (intset 0)
  262. empty-intset)))
  263. (define-syntax adjoin-conts
  264. (syntax-rules ()
  265. ((_ (exp ...) clause ...)
  266. (let ((cps (exp ...)))
  267. (adjoin-conts cps clause ...)))
  268. ((_ cps (label cont) clause ...)
  269. (adjoin-conts (intmap-add! cps label (build-cont cont))
  270. clause ...))
  271. ((_ cps)
  272. cps)))
  273. (define (process-eliminations conts live-labels live-vars)
  274. (define (label-live? label)
  275. (intset-ref live-labels label))
  276. (define (value-live? var)
  277. (intset-ref live-vars var))
  278. (define (make-adaptor k src defs)
  279. (let* ((names (map (lambda (_) 'tmp) defs))
  280. (vars (map (lambda (_) (fresh-var)) defs))
  281. (live (filter-map (lambda (def var)
  282. (and (value-live? def) var))
  283. defs vars)))
  284. (build-cont
  285. ($kargs names vars
  286. ($continue k src ($values live))))))
  287. (define (visit-term label term cps)
  288. (match term
  289. (($ $continue k src exp)
  290. (if (label-live? label)
  291. (match exp
  292. (($ $fun body)
  293. (values cps
  294. term))
  295. (($ $const-fun body)
  296. (values cps
  297. term))
  298. (($ $rec names vars funs)
  299. (match (filter-map (lambda (name var fun)
  300. (and (value-live? var)
  301. (list name var fun)))
  302. names vars funs)
  303. (()
  304. (values cps
  305. (build-term ($continue k src ($values ())))))
  306. (((names vars funs) ...)
  307. (values cps
  308. (build-term ($continue k src
  309. ($rec names vars funs)))))))
  310. (_
  311. (match (intmap-ref conts k)
  312. (($ $kargs ())
  313. (values cps term))
  314. (($ $kargs names ((? value-live?) ...))
  315. (values cps term))
  316. (($ $kargs names vars)
  317. (match exp
  318. (($ $values args)
  319. (let ((args (filter-map (lambda (use def)
  320. (and (value-live? def) use))
  321. args vars)))
  322. (values cps
  323. (build-term
  324. ($continue k src ($values args))))))
  325. (_
  326. (let-fresh (adapt) ()
  327. (values (adjoin-conts cps
  328. (adapt ,(make-adaptor k src vars)))
  329. (build-term
  330. ($continue adapt src ,exp)))))))
  331. (_
  332. (values cps term)))))
  333. (values cps
  334. (build-term
  335. ($continue k src ($values ()))))))
  336. (($ $branch kf kt src op param args)
  337. (if (label-live? label)
  338. (values cps term)
  339. ;; Dead branches continue to the same continuation
  340. ;; (eventually).
  341. (values cps (build-term ($continue kf src ($values ()))))))
  342. (($ $prompt)
  343. (values cps term))
  344. (($ $throw)
  345. (values cps term))))
  346. (define (visit-cont label cont cps)
  347. (match cont
  348. (($ $kargs names vars term)
  349. (match (filter-map (lambda (name var)
  350. (and (value-live? var)
  351. (cons name var)))
  352. names vars)
  353. (((names . vars) ...)
  354. (call-with-values (lambda () (visit-term label term cps))
  355. (lambda (cps term)
  356. (adjoin-conts cps
  357. (label ($kargs names vars ,term))))))))
  358. (($ $kreceive ($ $arity req () rest () #f) kargs)
  359. (let ((defs (match (intmap-ref conts kargs)
  360. (($ $kargs names vars) vars))))
  361. (if (and-map value-live? defs)
  362. (adjoin-conts cps (label ,cont))
  363. (let-fresh (adapt) ()
  364. (adjoin-conts cps
  365. (adapt ,(make-adaptor kargs #f defs))
  366. (label ($kreceive req rest adapt)))))))
  367. (_
  368. (adjoin-conts cps (label ,cont)))))
  369. (with-fresh-name-state conts
  370. (persistent-intmap
  371. (intmap-fold (lambda (label cont cps)
  372. (match cont
  373. (($ $kfun)
  374. (if (label-live? label)
  375. (fold-local-conts visit-cont conts label cps)
  376. cps))
  377. (_ cps)))
  378. conts
  379. empty-intmap))))
  380. (define (eliminate-dead-code conts)
  381. ;; We work on a renumbered program so that we can easily visit uses
  382. ;; before definitions just by visiting higher-numbered labels before
  383. ;; lower-numbered labels. Renumbering is also a precondition for type
  384. ;; inference.
  385. (let ((conts (renumber conts)))
  386. (call-with-values (lambda () (compute-live-code conts))
  387. (lambda (live-labels live-vars)
  388. (process-eliminations conts live-labels live-vars)))))
  389. ;;; Local Variables:
  390. ;;; eval: (put 'adjoin-conts 'scheme-indent-function 1)
  391. ;;; End: