cps.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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 is the continuation-passing style (CPS) intermediate language
  19. ;;; (IL) for Guile.
  20. ;;;
  21. ;;; In CPS, a term is a labelled expression that calls a continuation.
  22. ;;; A function is a collection of terms. No term belongs to more than
  23. ;;; one function. The function is identified by the label of its entry
  24. ;;; term, and its body is composed of those terms that are reachable
  25. ;;; from the entry term. A program is a collection of functions,
  26. ;;; identified by the entry label of the entry function.
  27. ;;;
  28. ;;; Terms are themselves wrapped in continuations, which specify how
  29. ;;; predecessors may continue to them. For example, a $kargs
  30. ;;; continuation specifies that the term may be called with a specific
  31. ;;; number of values, and that those values will then be bound to
  32. ;;; lexical variables. $kreceive specifies that some number of values
  33. ;;; will be passed on the stack, as from a multiple-value return. Those
  34. ;;; values will be passed to a $kargs, if the number of values is
  35. ;;; compatible with the $kreceive's arity. $kfun is an entry point to a
  36. ;;; function, and receives arguments according to a well-known calling
  37. ;;; convention (currently, on the stack) and the stack before
  38. ;;; dispatching to a $kclause. A $kclause is a case-lambda clause, and
  39. ;;; only appears within a $kfun; it checks the incoming values for the
  40. ;;; correct arity and dispatches to a $kargs, or to the next clause.
  41. ;;; Finally, $ktail is the tail continuation for a function, and
  42. ;;; contains no term.
  43. ;;;
  44. ;;; Each continuation has a label that is unique in the program. As an
  45. ;;; implementation detail, the labels are integers, which allows us to
  46. ;;; easily sort them topologically. A program is a map from integers to
  47. ;;; continuations, where continuation 0 in the map is the entry point
  48. ;;; for the program, and is a $kfun of no arguments.
  49. ;;;
  50. ;;; $continue nodes call continuations. The expression contained in the
  51. ;;; $continue node determines the value or values that are passed to the
  52. ;;; target continuation: $const to pass a constant value, $values to
  53. ;;; pass multiple named values, etc. $continue nodes also record the
  54. ;;; source location corresponding to the expression.
  55. ;;;
  56. ;;; As mentioned above, a $kargs continuation can bind variables, if it
  57. ;;; receives incoming values. $kfun also binds a value, corresponding
  58. ;;; to the closure being called. A traditional CPS implementation will
  59. ;;; nest terms in each other, binding them in "let" forms, ensuring that
  60. ;;; continuations are declared and bound within the scope of the values
  61. ;;; that they may use. In this way, the scope tree is a proof that
  62. ;;; variables are defined before they are used. However, this proof is
  63. ;;; conservative; it is possible for a variable to always be defined
  64. ;;; before it is used, but not to be in scope:
  65. ;;;
  66. ;;; (letrec ((k1 (lambda (v1) (k2)))
  67. ;;; (k2 (lambda () v1)))
  68. ;;; (k1 0))
  69. ;;;
  70. ;;; This example is invalid, as v1 is used outside its scope. However
  71. ;;; it would be perfectly fine for k2 to use v1 if k2 were nested inside
  72. ;;; k1:
  73. ;;;
  74. ;;; (letrec ((k1 (lambda (v1)
  75. ;;; (letrec ((k2 (lambda () v1)))
  76. ;;; (k2))))
  77. ;;; (k1 0))
  78. ;;;
  79. ;;; Because program transformation usually uses flow-based analysis,
  80. ;;; having to update the scope tree to manifestly prove a transformation
  81. ;;; that has already proven correct is needless overhead, and in the
  82. ;;; worst case can prevent optimizations from occuring. For that
  83. ;;; reason, Guile's CPS language does not nest terms. Instead, we use
  84. ;;; the invariant that definitions must dominate uses. To check the
  85. ;;; validity of a CPS program is thus more involved than checking for a
  86. ;;; well-scoped tree; you have to do flow analysis to determine a
  87. ;;; dominator tree. However the flexibility that this grants us is
  88. ;;; worth the cost of throwing away the embedded proof of the scope
  89. ;;; tree.
  90. ;;;
  91. ;;; This particular formulation of CPS was inspired by Andrew Kennedy's
  92. ;;; 2007 paper, "Compiling with Continuations, Continued". All Guile
  93. ;;; hackers should read that excellent paper! As in Kennedy's paper,
  94. ;;; continuations are second-class, and may be thought of as basic block
  95. ;;; labels. All values are bound to variables using continuation calls:
  96. ;;; even constants!
  97. ;;;
  98. ;;; Finally, note that there are two flavors of CPS: higher-order and
  99. ;;; first-order. By "higher-order", we mean that variables may be free
  100. ;;; across function boundaries. Higher-order CPS contains $fun and $rec
  101. ;;; expressions that declare functions in the scope of their term.
  102. ;;; Closure conversion results in first-order CPS, where closure
  103. ;;; representations have been explicitly chosen, and all variables used
  104. ;;; in a function are bound. Higher-order CPS is good for
  105. ;;; interprocedural optimizations like contification and beta reduction,
  106. ;;; while first-order CPS is better for instruction selection, register
  107. ;;; allocation, and code generation.
  108. ;;;
  109. ;;; See (language tree-il compile-cps) for details on how Tree-IL
  110. ;;; converts to CPS.
  111. ;;;
  112. ;;; Code:
  113. (define-module (language cps)
  114. #:use-module (ice-9 match)
  115. #:use-module (srfi srfi-9)
  116. #:use-module (srfi srfi-9 gnu)
  117. #:use-module (srfi srfi-11)
  118. #:export (;; Helper.
  119. $arity
  120. make-$arity
  121. ;; Continuations.
  122. $kreceive $kargs $kfun $ktail $kclause
  123. ;; Terms.
  124. $continue $branch $prompt $throw
  125. ;; Expressions.
  126. $const $prim $fun $rec $const-fun $code
  127. $call $callk $primcall $values
  128. ;; Building macros.
  129. build-cont build-term build-exp
  130. rewrite-cont rewrite-term rewrite-exp
  131. ;; External representation.
  132. parse-cps unparse-cps))
  133. ;; FIXME: Use SRFI-99, when Guile adds it.
  134. (define-syntax define-record-type*
  135. (lambda (x)
  136. (define (id-append ctx . syms)
  137. (datum->syntax ctx (apply symbol-append (map syntax->datum syms))))
  138. (syntax-case x ()
  139. ((_ name field ...)
  140. (and (identifier? #'name) (and-map identifier? #'(field ...)))
  141. (with-syntax ((cons (id-append #'name #'make- #'name))
  142. (pred (id-append #'name #'name #'?))
  143. ((getter ...) (map (lambda (f)
  144. (id-append f #'name #'- f))
  145. #'(field ...))))
  146. #'(define-record-type name
  147. (cons field ...)
  148. pred
  149. (field getter)
  150. ...))))))
  151. (define-syntax-rule (define-cps-type name field ...)
  152. (begin
  153. (define-record-type* name field ...)
  154. (set-record-type-printer! name print-cps)))
  155. (define (print-cps exp port)
  156. (format port "#<cps ~S>" (unparse-cps exp)))
  157. ;; Helper.
  158. (define-record-type* $arity req opt rest kw allow-other-keys?)
  159. ;; Continuations
  160. (define-cps-type $kreceive arity kbody)
  161. (define-cps-type $kargs names syms term)
  162. (define-cps-type $kfun src meta self ktail kclause)
  163. (define-cps-type $ktail)
  164. (define-cps-type $kclause arity kbody kalternate)
  165. ;; Terms.
  166. (define-cps-type $continue k src exp)
  167. (define-cps-type $branch kf kt src op param args)
  168. (define-cps-type $prompt k kh src escape? tag)
  169. (define-cps-type $throw src op param args)
  170. ;; Expressions.
  171. (define-cps-type $const val)
  172. (define-cps-type $prim name)
  173. (define-cps-type $fun body) ; Higher-order.
  174. (define-cps-type $rec names syms funs) ; Higher-order.
  175. (define-cps-type $const-fun label) ; First-order.
  176. (define-cps-type $code label) ; First-order.
  177. (define-cps-type $call proc args)
  178. (define-cps-type $callk k proc args) ; First-order.
  179. (define-cps-type $primcall name param args)
  180. (define-cps-type $values args)
  181. (define-syntax build-arity
  182. (syntax-rules (unquote)
  183. ((_ (unquote exp)) exp)
  184. ((_ (req opt rest kw allow-other-keys?))
  185. (make-$arity req opt rest kw allow-other-keys?))))
  186. (define-syntax build-cont
  187. (syntax-rules (unquote $kreceive $kargs $kfun $ktail $kclause)
  188. ((_ (unquote exp))
  189. exp)
  190. ((_ ($kreceive req rest kargs))
  191. (make-$kreceive (make-$arity req '() rest '() #f) kargs))
  192. ((_ ($kargs (name ...) (unquote syms) body))
  193. (make-$kargs (list name ...) syms (build-term body)))
  194. ((_ ($kargs (name ...) (sym ...) body))
  195. (make-$kargs (list name ...) (list sym ...) (build-term body)))
  196. ((_ ($kargs names syms body))
  197. (make-$kargs names syms (build-term body)))
  198. ((_ ($kfun src meta self ktail kclause))
  199. (make-$kfun src meta self ktail kclause))
  200. ((_ ($ktail))
  201. (make-$ktail))
  202. ((_ ($kclause arity kbody kalternate))
  203. (make-$kclause (build-arity arity) kbody kalternate))))
  204. (define-syntax build-term
  205. (syntax-rules (unquote $rec $continue)
  206. ((_ (unquote exp))
  207. exp)
  208. ((_ ($continue k src exp))
  209. (make-$continue k src (build-exp exp)))
  210. ((_ ($branch kf kt src op param (unquote args)))
  211. (make-$branch kf kt src op param args))
  212. ((_ ($branch kf kt src op param (arg ...)))
  213. (make-$branch kf kt src op param (list arg ...)))
  214. ((_ ($branch kf kt src op param args))
  215. (make-$branch kf kt src op param args))
  216. ((_ ($prompt k kh src escape? tag))
  217. (make-$prompt k kh src escape? tag))
  218. ((_ ($throw src op param (unquote args)))
  219. (make-$throw src op param args))
  220. ((_ ($throw src op param (arg ...)))
  221. (make-$throw src op param (list arg ...)))
  222. ((_ ($throw src op param args))
  223. (make-$throw src op param args))))
  224. (define-syntax build-exp
  225. (syntax-rules (unquote
  226. $const $prim $fun $rec $const-fun $code
  227. $call $callk $primcall $values)
  228. ((_ (unquote exp)) exp)
  229. ((_ ($const val)) (make-$const val))
  230. ((_ ($prim name)) (make-$prim name))
  231. ((_ ($fun kentry)) (make-$fun kentry))
  232. ((_ ($rec names gensyms funs)) (make-$rec names gensyms funs))
  233. ((_ ($const-fun k)) (make-$const-fun k))
  234. ((_ ($code k)) (make-$code k))
  235. ((_ ($call proc (unquote args))) (make-$call proc args))
  236. ((_ ($call proc (arg ...))) (make-$call proc (list arg ...)))
  237. ((_ ($call proc args)) (make-$call proc args))
  238. ((_ ($callk k proc (unquote args))) (make-$callk k proc args))
  239. ((_ ($callk k proc (arg ...))) (make-$callk k proc (list arg ...)))
  240. ((_ ($callk k proc args)) (make-$callk k proc args))
  241. ((_ ($primcall name param (unquote args))) (make-$primcall name param args))
  242. ((_ ($primcall name param (arg ...))) (make-$primcall name param (list arg ...)))
  243. ((_ ($primcall name param args)) (make-$primcall name param args))
  244. ((_ ($values (unquote args))) (make-$values args))
  245. ((_ ($values (arg ...))) (make-$values (list arg ...)))
  246. ((_ ($values args)) (make-$values args))))
  247. (define-syntax-rule (rewrite-cont x (pat cont) ...)
  248. (match x
  249. (pat (build-cont cont)) ...))
  250. (define-syntax-rule (rewrite-term x (pat term) ...)
  251. (match x
  252. (pat (build-term term)) ...))
  253. (define-syntax-rule (rewrite-exp x (pat body) ...)
  254. (match x
  255. (pat (build-exp body)) ...))
  256. (define (parse-cps exp)
  257. (define (src exp)
  258. (let ((props (source-properties exp)))
  259. (and (pair? props) props)))
  260. (match exp
  261. ;; Continuations.
  262. (('kreceive req rest k)
  263. (build-cont ($kreceive req rest k)))
  264. (('kargs names syms body)
  265. (build-cont ($kargs names syms ,(parse-cps body))))
  266. (('kfun meta self ktail kclause)
  267. (build-cont ($kfun (src exp) meta self ktail kclause)))
  268. (('ktail)
  269. (build-cont ($ktail)))
  270. (('kclause (req opt rest kw allow-other-keys?) kbody)
  271. (build-cont ($kclause (req opt rest kw allow-other-keys?) kbody #f)))
  272. (('kclause (req opt rest kw allow-other-keys?) kbody kalt)
  273. (build-cont ($kclause (req opt rest kw allow-other-keys?) kbody kalt)))
  274. ;; Terms.
  275. (('continue k exp)
  276. (build-term ($continue k (src exp) ,(parse-cps exp))))
  277. (('branch kf kt op param arg ...)
  278. (build-term ($branch kf kt (src exp) op param arg)))
  279. (('prompt k kh escape? tag)
  280. (build-term ($prompt k kh (src exp) escape? tag)))
  281. (('throw op param arg ...)
  282. (build-term ($throw (src exp) op param arg)))
  283. ;; Expressions.
  284. (('unspecified)
  285. (build-exp ($const *unspecified*)))
  286. (('const exp)
  287. (build-exp ($const exp)))
  288. (('prim name)
  289. (build-exp ($prim name)))
  290. (('fun kbody)
  291. (build-exp ($fun kbody)))
  292. (('const-fun k)
  293. (build-exp ($const-fun k)))
  294. (('code k)
  295. (build-exp ($code k)))
  296. (('rec (name sym fun) ...)
  297. (build-exp ($rec name sym (map parse-cps fun))))
  298. (('call proc arg ...)
  299. (build-exp ($call proc arg)))
  300. (('callk k proc arg ...)
  301. (build-exp ($callk k proc arg)))
  302. (('primcall name param arg ...)
  303. (build-exp ($primcall name param arg)))
  304. (('values arg ...)
  305. (build-exp ($values arg)))
  306. (_
  307. (error "unexpected cps" exp))))
  308. (define (unparse-cps exp)
  309. (match exp
  310. ;; Continuations.
  311. (($ $kreceive ($ $arity req () rest () #f) k)
  312. `(kreceive ,req ,rest ,k))
  313. (($ $kargs names syms body)
  314. `(kargs ,names ,syms ,(unparse-cps body)))
  315. (($ $kfun src meta self ktail kclause)
  316. `(kfun ,meta ,self ,ktail ,kclause))
  317. (($ $ktail)
  318. `(ktail))
  319. (($ $kclause ($ $arity req opt rest kw allow-other-keys?) kbody kalternate)
  320. `(kclause (,req ,opt ,rest ,kw ,allow-other-keys?) ,kbody
  321. . ,(if kalternate (list kalternate) '())))
  322. ;; Terms.
  323. (($ $continue k src exp)
  324. `(continue ,k ,(unparse-cps exp)))
  325. (($ $branch kf kt src op param args)
  326. `(branch ,kf ,kt ,op ,param ,@args))
  327. (($ $prompt k kh src escape? tag)
  328. `(prompt ,k ,kh ,escape? ,tag))
  329. (($ $throw src op param args)
  330. `(throw ,op ,param ,@args))
  331. ;; Expressions.
  332. (($ $const val)
  333. (if (unspecified? val)
  334. '(unspecified)
  335. `(const ,val)))
  336. (($ $prim name)
  337. `(prim ,name))
  338. (($ $fun kbody)
  339. `(fun ,kbody))
  340. (($ $const-fun k)
  341. `(const-fun ,k))
  342. (($ $code k)
  343. `(code ,k))
  344. (($ $rec names syms funs)
  345. `(rec ,@(map (lambda (name sym fun)
  346. (list name sym (unparse-cps fun)))
  347. names syms funs)))
  348. (($ $call proc args)
  349. `(call ,proc ,@args))
  350. (($ $callk k proc args)
  351. `(callk ,k ,proc ,@args))
  352. (($ $primcall name param args)
  353. `(primcall ,name ,param ,@args))
  354. (($ $values args)
  355. `(values ,@args))
  356. (_
  357. (error "unexpected cps" exp))))