split-rec.scm 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. ;;; 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 ($ $continue k src exp))
  69. (values
  70. (add-defs vars defs)
  71. (match exp
  72. ((or ($ $const) ($ $prim)) uses)
  73. (($ $fun kfun)
  74. (intset-union (persistent-intset uses)
  75. (intmap-ref free kfun)))
  76. (($ $rec names vars (($ $fun kfun) ...))
  77. (fold (lambda (kfun uses)
  78. (intset-union (persistent-intset uses)
  79. (intmap-ref free kfun)))
  80. uses kfun))
  81. (($ $values args)
  82. (add-uses args uses))
  83. (($ $call proc args)
  84. (add-use proc (add-uses args uses)))
  85. (($ $branch kt ($ $values (arg)))
  86. (add-use arg uses))
  87. (($ $branch kt ($ $primcall name args))
  88. (add-uses args uses))
  89. (($ $primcall name args)
  90. (add-uses args uses))
  91. (($ $prompt escape? tag handler)
  92. (add-use tag uses)))))
  93. (($ $kfun src meta self)
  94. (values (add-def self defs) uses))
  95. (_ (values defs uses))))
  96. body empty-intset empty-intset))
  97. (lambda (defs uses)
  98. (intmap-add free kfun (intset-subtract
  99. (persistent-intset uses)
  100. (persistent-intset defs)))))))
  101. (visit-fun kfun))
  102. (define (compute-split fns free-vars)
  103. (define (get-free kfun)
  104. ;; It's possible for a fun to have been skipped by
  105. ;; compute-free-vars, if the fun isn't reachable. Fall back to
  106. ;; empty-intset for the fun's free vars, in that case.
  107. (intmap-ref free-vars kfun (lambda (_) empty-intset)))
  108. (let* ((vars (intmap-keys fns))
  109. (edges (intmap-map
  110. (lambda (var kfun)
  111. (intset-intersect (get-free kfun) vars))
  112. fns)))
  113. (compute-sorted-strongly-connected-components edges)))
  114. (define (intmap-acons k v map)
  115. (intmap-add map k v))
  116. (define (split-rec conts)
  117. (let ((free (compute-free-vars conts 0)))
  118. (with-fresh-name-state conts
  119. (persistent-intmap
  120. (intmap-fold
  121. (lambda (label cont out)
  122. (match cont
  123. (($ $kargs cont-names cont-vars
  124. ($ $continue k src ($ $rec names vars (($ $fun kfuns) ...))))
  125. (let ((fns (fold intmap-acons empty-intmap vars kfuns))
  126. (fn-names (fold intmap-acons empty-intmap vars names)))
  127. (match (compute-split fns free)
  128. (()
  129. ;; Remove trivial $rec.
  130. (with-cps out
  131. (setk label ($kargs cont-names cont-vars
  132. ($continue k src ($values ()))))))
  133. ((_)
  134. ;; Bound functions already form a strongly-connected
  135. ;; component.
  136. out)
  137. (components
  138. ;; Multiple components. Split them into separate $rec
  139. ;; expressions.
  140. (define (build-body out components)
  141. (match components
  142. (()
  143. (match (intmap-ref out k)
  144. (($ $kargs names vars term)
  145. (with-cps (intmap-remove out k)
  146. term))))
  147. ((vars . components)
  148. (match (intset-fold
  149. (lambda (var out)
  150. (let ((name (intmap-ref fn-names var))
  151. (fun (build-exp
  152. ($fun (intmap-ref fns var)))))
  153. (cons (list name var fun) out)))
  154. vars '())
  155. (((name var fun) ...)
  156. (with-cps out
  157. (let$ body (build-body components))
  158. (letk kbody ($kargs name var ,body))
  159. (build-term
  160. ($continue kbody src ($rec name var fun)))))))))
  161. (with-cps out
  162. (let$ body (build-body components))
  163. (setk label ($kargs cont-names cont-vars ,body)))))))
  164. (_ out)))
  165. conts
  166. conts)))))