split-rec.scm 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013-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. ;;; Split functions bound in $rec expressions into strongly-connected
  19. ;;; components. The result will be that each $rec binds a
  20. ;;; strongly-connected component of mutually recursive functions.
  21. ;;;
  22. ;;; Code:
  23. (define-module (language cps split-rec)
  24. #:use-module (ice-9 match)
  25. #:use-module ((srfi srfi-1) #:select (fold))
  26. #:use-module (language cps)
  27. #:use-module (language cps utils)
  28. #:use-module (language cps with-cps)
  29. #:use-module (language cps intmap)
  30. #:use-module (language cps intset)
  31. #:export (split-rec))
  32. (define (compute-free-vars conts kfun)
  33. "Compute a FUN-LABEL->FREE-VAR... map describing all free variable
  34. references."
  35. (define (add-def var defs) (intset-add! defs var))
  36. (define (add-defs vars defs)
  37. (match vars
  38. (() defs)
  39. ((var . vars) (add-defs vars (add-def var defs)))))
  40. (define (add-use var uses) (intset-add! uses var))
  41. (define (add-uses vars uses)
  42. (match vars
  43. (() uses)
  44. ((var . vars) (add-uses vars (add-use var uses)))))
  45. (define (visit-nested-funs body)
  46. (intset-fold
  47. (lambda (label out)
  48. (match (intmap-ref conts label)
  49. (($ $kargs _ _ ($ $continue _ _
  50. ($ $fun kfun)))
  51. (intmap-union out (visit-fun kfun)))
  52. (($ $kargs _ _ ($ $continue _ _
  53. ($ $rec _ _ (($ $fun kfun) ...))))
  54. (fold (lambda (kfun out)
  55. (intmap-union out (visit-fun kfun)))
  56. out kfun))
  57. (_ out)))
  58. body
  59. empty-intmap))
  60. (define (visit-fun kfun)
  61. (let* ((body (compute-function-body conts kfun))
  62. (free (visit-nested-funs body)))
  63. (call-with-values
  64. (lambda ()
  65. (intset-fold
  66. (lambda (label defs uses)
  67. (match (intmap-ref conts label)
  68. (($ $kargs names vars term)
  69. (values
  70. (add-defs vars defs)
  71. (match term
  72. (($ $continue k src exp)
  73. (match exp
  74. ((or ($ $const) ($ $prim)) uses)
  75. (($ $fun kfun)
  76. (intset-union (persistent-intset uses)
  77. (intmap-ref free kfun)))
  78. (($ $rec names vars (($ $fun kfun) ...))
  79. (fold (lambda (kfun uses)
  80. (intset-union (persistent-intset uses)
  81. (intmap-ref free kfun)))
  82. uses kfun))
  83. (($ $values args)
  84. (add-uses args uses))
  85. (($ $call proc args)
  86. (add-use proc (add-uses args uses)))
  87. (($ $primcall name param args)
  88. (add-uses args uses))))
  89. (($ $branch kf kt src op param args)
  90. (add-uses args uses))
  91. (($ $prompt k kh src escape? tag)
  92. (add-use tag uses))
  93. (($ $throw src op param args)
  94. (add-uses args uses)))))
  95. (($ $kfun src meta (and self (not #f)))
  96. (values (add-def self defs) uses))
  97. (_ (values defs uses))))
  98. body empty-intset empty-intset))
  99. (lambda (defs uses)
  100. (intmap-add free kfun (intset-subtract
  101. (persistent-intset uses)
  102. (persistent-intset defs)))))))
  103. (visit-fun kfun))
  104. (define (compute-split fns free-vars)
  105. (define (get-free kfun)
  106. ;; It's possible for a fun to have been skipped by
  107. ;; compute-free-vars, if the fun isn't reachable. Fall back to
  108. ;; empty-intset for the fun's free vars, in that case.
  109. (intmap-ref free-vars kfun (lambda (_) empty-intset)))
  110. (let* ((vars (intmap-keys fns))
  111. (edges (intmap-map
  112. (lambda (var kfun)
  113. (intset-intersect (get-free kfun) vars))
  114. fns)))
  115. (compute-sorted-strongly-connected-components edges)))
  116. (define (intmap-acons k v map)
  117. (intmap-add map k v))
  118. (define (split-rec conts)
  119. (let ((free (compute-free-vars conts 0)))
  120. (with-fresh-name-state conts
  121. (persistent-intmap
  122. (intmap-fold
  123. (lambda (label cont out)
  124. (match cont
  125. (($ $kargs cont-names cont-vars
  126. ($ $continue k src ($ $rec names vars (($ $fun kfuns) ...))))
  127. (let ((fns (fold intmap-acons empty-intmap vars kfuns))
  128. (fn-names (fold intmap-acons empty-intmap vars names)))
  129. (match (compute-split fns free)
  130. (()
  131. ;; Remove trivial $rec.
  132. (with-cps out
  133. (setk label ($kargs cont-names cont-vars
  134. ($continue k src ($values ()))))))
  135. ((_)
  136. ;; Bound functions already form a strongly-connected
  137. ;; component.
  138. out)
  139. (components
  140. ;; Multiple components. Split them into separate $rec
  141. ;; expressions.
  142. (define (build-body out components)
  143. (match components
  144. (()
  145. (match (intmap-ref out k)
  146. (($ $kargs names vars term)
  147. (with-cps (intmap-remove out k)
  148. term))))
  149. ((vars . components)
  150. (match (intset-fold
  151. (lambda (var out)
  152. (let ((name (intmap-ref fn-names var))
  153. (fun (build-exp
  154. ($fun (intmap-ref fns var)))))
  155. (cons (list name var fun) out)))
  156. vars '())
  157. (((name var fun) ...)
  158. (with-cps out
  159. (let$ body (build-body components))
  160. (letk kbody ($kargs name var ,body))
  161. (build-term
  162. ($continue kbody src ($rec name var fun)))))))))
  163. (with-cps out
  164. (let$ body (build-body components))
  165. (setk label ($kargs cont-names cont-vars ,body)))))))
  166. (_ out)))
  167. conts
  168. conts)))))