simplify.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013-2015, 2017-2019 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. ;;; The fundamental lambda calculus reductions, like beta and eta
  19. ;;; reduction and so on. Pretty lame currently.
  20. ;;;
  21. ;;; Code:
  22. (define-module (language cps simplify)
  23. #:use-module (ice-9 match)
  24. #:use-module (srfi srfi-1)
  25. #:use-module (srfi srfi-11)
  26. #:use-module (srfi srfi-26)
  27. #:use-module (language cps)
  28. #:use-module (language cps utils)
  29. #:use-module (language cps intset)
  30. #:use-module (language cps intmap)
  31. #:export (simplify))
  32. (define (intset-maybe-add! set k add?)
  33. (if add? (intset-add! set k) set))
  34. (define (intset-add*! set k*)
  35. (fold1 (lambda (k set) (intset-add! set k)) k* set))
  36. (define (fold2* f l1 l2 seed)
  37. (let lp ((l1 l1) (l2 l2) (seed seed))
  38. (match (cons l1 l2)
  39. ((() . ()) seed)
  40. (((x1 . l1) . (x2 . l2)) (lp l1 l2 (f x1 x2 seed))))))
  41. (define (transform-conts f conts)
  42. (persistent-intmap
  43. (intmap-fold (lambda (k v out)
  44. (let ((v* (f k v)))
  45. (cond
  46. ((equal? v v*) out)
  47. (v* (intmap-replace! out k v*))
  48. (else (intmap-remove out k)))))
  49. conts
  50. conts)))
  51. (define (compute-singly-referenced-vars conts)
  52. (define (visit label cont single multiple)
  53. (define (add-ref var single multiple)
  54. (if (intset-ref single var)
  55. (values single (intset-add! multiple var))
  56. (values (intset-add! single var) multiple)))
  57. (define (ref var) (add-ref var single multiple))
  58. (define (ref* vars) (fold2 add-ref vars single multiple))
  59. (match cont
  60. (($ $kargs _ _ ($ $continue _ _ exp))
  61. (match exp
  62. ((or ($ $const) ($ $prim) ($ $fun) ($ $rec) ($ $const-fun) ($ $code))
  63. (values single multiple))
  64. (($ $call proc args)
  65. (ref* (cons proc args)))
  66. (($ $callk k proc args)
  67. (ref* (if proc (cons proc args) args)))
  68. (($ $primcall name param args)
  69. (ref* args))
  70. (($ $values args)
  71. (ref* args))))
  72. (($ $kargs _ _ ($ $branch kf kt src op param args))
  73. (ref* args))
  74. (($ $kargs _ _ ($ $prompt k kh src escape? tag))
  75. (ref tag))
  76. (($ $kargs _ _ ($ $throw src op param args))
  77. (ref* args))
  78. (_
  79. (values single multiple))))
  80. (let*-values (((single multiple) (values empty-intset empty-intset))
  81. ((single multiple) (intmap-fold visit conts single multiple)))
  82. (intset-subtract (persistent-intset single)
  83. (persistent-intset multiple))))
  84. ;;; Continuations whose values are simply forwarded to another and not
  85. ;;; used in any other way may be elided via eta reduction over labels.
  86. ;;;
  87. ;;; There is an exception however: we must exclude strongly-connected
  88. ;;; components (SCCs). The only kind of SCC we can build out of $values
  89. ;;; expressions are infinite loops.
  90. ;;;
  91. ;;; Condition A below excludes single-node SCCs. Single-node SCCs
  92. ;;; cannot be reduced.
  93. ;;;
  94. ;;; Condition B conservatively excludes edges to labels already marked
  95. ;;; as candidates. This prevents back-edges and so breaks SCCs, and is
  96. ;;; optimal if labels are sorted. If the labels aren't sorted it's
  97. ;;; suboptimal but cheap.
  98. (define (compute-eta-reductions conts kfun singly-used)
  99. (define (singly-used? vars)
  100. (match vars
  101. (() #t)
  102. ((var . vars)
  103. (and (intset-ref singly-used var) (singly-used? vars)))))
  104. (define (visit-fun kfun body eta)
  105. (define (visit-cont label eta)
  106. (match (intmap-ref conts label)
  107. (($ $kargs names vars ($ $continue k src ($ $values vars)))
  108. (intset-maybe-add! eta label
  109. (match (intmap-ref conts k)
  110. (($ $kargs)
  111. (and (not (eqv? label k)) ; A
  112. (not (intset-ref eta label)) ; B
  113. (singly-used? vars)))
  114. (_ #f))))
  115. (_
  116. eta)))
  117. (intset-fold visit-cont body eta))
  118. (persistent-intset
  119. (intmap-fold visit-fun
  120. (compute-reachable-functions conts kfun)
  121. empty-intset)))
  122. (define (eta-reduce conts kfun)
  123. (let* ((singly-used (compute-singly-referenced-vars conts))
  124. (label-set (compute-eta-reductions conts kfun singly-used)))
  125. ;; Replace any continuation to a label in LABEL-SET with the label's
  126. ;; continuation. The label will denote a $kargs continuation, so
  127. ;; only terms that can continue to $kargs need be taken into
  128. ;; account.
  129. (define (subst label)
  130. (if (intset-ref label-set label)
  131. (match (intmap-ref conts label)
  132. (($ $kargs _ _ ($ $continue k)) (subst k)))
  133. label))
  134. (transform-conts
  135. (lambda (label cont)
  136. (and (not (intset-ref label-set label))
  137. (rewrite-cont cont
  138. (($ $kargs names syms ($ $branch kf kt src op param args))
  139. ($kargs names syms
  140. ($branch (subst kf) (subst kt) src op param args)))
  141. (($ $kargs names syms ($ $prompt k kh src escape? tag))
  142. ($kargs names syms
  143. ($prompt (subst k) (subst kh) src escape? tag)))
  144. (($ $kargs names syms ($ $continue k src ($ $const val)))
  145. ,(match (intmap-ref conts k)
  146. (($ $kargs (_)
  147. ((? (lambda (var) (intset-ref singly-used var))
  148. var))
  149. ($ $branch kf kt _ 'false? #f (var)))
  150. (build-cont
  151. ($kargs names syms
  152. ($continue (subst (if val kf kt)) src ($values ())))))
  153. (_
  154. (build-cont
  155. ($kargs names syms
  156. ($continue (subst k) src ($const val)))))))
  157. (($ $kargs names syms ($ $continue k src exp))
  158. ($kargs names syms
  159. ($continue (subst k) src ,exp)))
  160. (($ $kreceive ($ $arity req () rest () #f) k)
  161. ($kreceive req rest (subst k)))
  162. (($ $kclause arity body alt)
  163. ($kclause ,arity (subst body) alt))
  164. (_ ,cont))))
  165. conts)))
  166. (define (compute-singly-referenced-labels conts body)
  167. (define (add-ref label single multiple)
  168. (define (ref k single multiple)
  169. (if (intset-ref single k)
  170. (values single (intset-add! multiple k))
  171. (values (intset-add! single k) multiple)))
  172. (define (ref0) (values single multiple))
  173. (define (ref1 k) (ref k single multiple))
  174. (define (ref2 k k*)
  175. (if k*
  176. (let-values (((single multiple) (ref k single multiple)))
  177. (ref k* single multiple))
  178. (ref1 k)))
  179. (match (intmap-ref conts label)
  180. (($ $kreceive arity k) (ref1 k))
  181. (($ $kfun src meta self ktail kclause) (ref2 ktail kclause))
  182. (($ $ktail) (ref0))
  183. (($ $kclause arity kbody kalt) (ref2 kbody kalt))
  184. (($ $kargs names syms ($ $continue k)) (ref1 k))
  185. (($ $kargs names syms ($ $branch kf kt)) (ref2 kf kt))
  186. (($ $kargs names syms ($ $prompt k kh)) (ref2 k kh))
  187. (($ $kargs names syms ($ $throw)) (ref0))))
  188. (let*-values (((single multiple) (values empty-intset empty-intset))
  189. ((single multiple) (intset-fold add-ref body single multiple)))
  190. (intset-subtract (persistent-intset single)
  191. (persistent-intset multiple))))
  192. (define (compute-beta-reductions conts kfun)
  193. (define (visit-fun kfun body beta)
  194. (let ((single (compute-singly-referenced-labels conts body)))
  195. (define (visit-cont label beta)
  196. (match (intmap-ref conts label)
  197. ;; A continuation's body can be inlined in place of a $values
  198. ;; expression if the continuation is a $kargs. It should only
  199. ;; be inlined if it is used only once, and not recursively.
  200. (($ $kargs _ _ ($ $continue k src ($ $values)))
  201. (intset-maybe-add! beta label
  202. (and (intset-ref single k)
  203. (match (intmap-ref conts k)
  204. (($ $kargs) #t)
  205. (_ #f)))))
  206. (_
  207. beta)))
  208. (intset-fold visit-cont body beta)))
  209. (persistent-intset
  210. (intmap-fold visit-fun
  211. (compute-reachable-functions conts kfun)
  212. empty-intset)))
  213. (define (compute-beta-var-substitutions conts label-set)
  214. (define (add-var-substs label var-map)
  215. (match (intmap-ref conts label)
  216. (($ $kargs _ _ ($ $continue k _ ($ $values vals)))
  217. (match (intmap-ref conts k)
  218. (($ $kargs names vars)
  219. (fold2* (lambda (var val var-map)
  220. (intmap-add! var-map var val))
  221. vars vals var-map))))))
  222. (intset-fold add-var-substs label-set empty-intmap))
  223. (define (beta-reduce conts kfun)
  224. (let* ((label-set (compute-beta-reductions conts kfun))
  225. (var-map (compute-beta-var-substitutions conts label-set)))
  226. (define (subst var)
  227. (match (intmap-ref var-map var (lambda (_) #f))
  228. (#f var)
  229. (val (subst val))))
  230. (define (transform-term label term)
  231. (if (intset-ref label-set label)
  232. (match term
  233. (($ $continue k)
  234. (match (intmap-ref conts k)
  235. (($ $kargs _ _ term)
  236. (transform-term k term)))))
  237. (rewrite-term term
  238. (($ $continue k src exp)
  239. ($continue k src
  240. ,(rewrite-exp exp
  241. ((or ($ $const) ($ $prim) ($ $fun) ($ $rec) ($ $const-fun)
  242. ($ $code))
  243. ,exp)
  244. (($ $call proc args)
  245. ($call (subst proc) ,(map subst args)))
  246. (($ $callk k proc args)
  247. ($callk k (and proc (subst proc)) ,(map subst args)))
  248. (($ $primcall name param args)
  249. ($primcall name param ,(map subst args)))
  250. (($ $values args)
  251. ($values ,(map subst args))))))
  252. (($ $branch kf kt src op param args)
  253. ($branch kf kt src op param ,(map subst args)))
  254. (($ $prompt k kh src escape? tag)
  255. ($prompt k kh src escape? (subst tag)))
  256. (($ $throw src op param args)
  257. ($throw src op param ,(map subst args))))))
  258. (transform-conts
  259. (lambda (label cont)
  260. (rewrite-cont cont
  261. (($ $kargs names syms term)
  262. ($kargs names syms ,(transform-term label term)))
  263. (_ ,cont)))
  264. conts)))
  265. (define (simplify conts)
  266. (eta-reduce (beta-reduce conts 0) 0))