temporarily disable elisp exception tests
[bpt/guile.git] / module / language / cps / simplify.scm
CommitLineData
22a79b55
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
a9ec16f9 3;; Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc.
22a79b55
AW
4
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19;;; Commentary:
20;;;
21;;; The fundamental lambda calculus reductions, like beta and eta
22;;; reduction and so on. Pretty lame currently.
23;;;
24;;; Code:
25
26(define-module (language cps simplify)
27 #:use-module (ice-9 match)
28 #:use-module (srfi srfi-1)
b9e601d2 29 #:use-module (srfi srfi-11)
22a79b55
AW
30 #:use-module (srfi srfi-26)
31 #:use-module (language cps)
32 #:use-module (language cps dfg)
c79c02d6 33 #:use-module (language cps renumber)
22a79b55
AW
34 #:export (simplify))
35
4b3d7a2b
AW
36(define (compute-eta-reductions fun)
37 (let ((table (make-hash-table)))
38 (define (visit-cont cont)
39 (match cont
40 (($ $cont sym ($ $kargs names syms body))
41 (visit-term body sym syms))
8320f504 42 (($ $cont sym ($ $kfun src meta self tail clause))
90dce16d
AW
43 (when clause (visit-cont clause)))
44 (($ $cont sym ($ $kclause arity body alternate))
45 (visit-cont body)
46 (when alternate (visit-cont alternate)))
4b3d7a2b
AW
47 (($ $cont sym _) #f)))
48 (define (visit-term term term-k term-args)
49 (match term
50 (($ $letk conts body)
51 (for-each visit-cont conts)
52 (visit-term body term-k term-args))
4b3d7a2b
AW
53 (($ $continue k src ($ $values args))
54 (when (and (equal? term-args args) (not (eq? k term-k)))
55 (hashq-set! table term-k k)))
56 (($ $continue k src (and fun ($ $fun)))
57 (visit-fun fun))
34ff3af9
AW
58 (($ $continue k src ($ $rec names syms funs))
59 (for-each visit-fun funs))
4b3d7a2b
AW
60 (($ $continue k src _)
61 #f)))
62 (define (visit-fun fun)
63 (match fun
50fcdfec 64 (($ $fun body)
4b3d7a2b 65 (visit-cont body))))
a0329d01 66 (visit-cont fun)
4b3d7a2b
AW
67 table))
68
22a79b55
AW
69(define (eta-reduce fun)
70 (let ((table (compute-eta-reductions fun))
a0329d01 71 (dfg (compute-dfg fun)))
22a79b55
AW
72 (define (reduce* k scope values?)
73 (match (hashq-ref table k)
74 (#f k)
75 (k*
76 (if (and (continuation-bound-in? k* scope dfg)
77 (or values?
fbdb69b2 78 (match (lookup-cont k* dfg)
22a79b55
AW
79 (($ $kargs) #t)
80 (_ #f))))
81 (reduce* k* scope values?)
82 k))))
83 (define (reduce k scope)
84 (reduce* k scope #f))
85 (define (reduce-values k scope)
86 (reduce* k scope #t))
b9a5bac6
AW
87 (define (reduce-const k src scope const)
88 (let lp ((k k) (seen '()) (const const))
89 (match (lookup-cont k dfg)
90 (($ $kargs (_) (arg) term)
91 (match (find-call term)
92 (($ $continue k* src* ($ $values (arg*)))
93 (and (eqv? arg arg*)
94 (not (memq k* seen))
95 (lp k* (cons k seen) const)))
96 (($ $continue k* src* ($ $primcall 'not (arg*)))
97 (and (eqv? arg arg*)
98 (not (memq k* seen))
99 (lp k* (cons k seen) (not const))))
100 (($ $continue k* src* ($ $branch kt ($ $values (arg*))))
101 (and (eqv? arg arg*)
102 (let ((k* (if const kt k*)))
103 (and (continuation-bound-in? k* scope dfg)
104 (build-cps-term
105 ($continue k* src ($values ())))))))
106 (_
107 (and (continuation-bound-in? k scope dfg)
108 (build-cps-term
109 ($continue k src ($const const)))))))
110 (_ #f))))
22a79b55
AW
111 (define (visit-cont cont scope)
112 (rewrite-cps-cont cont
113 (($ $cont sym ($ $kargs names syms body))
114 (sym ($kargs names syms ,(visit-term body sym))))
8320f504
AW
115 (($ $cont sym ($ $kfun src meta self tail clause))
116 (sym ($kfun src meta self ,tail
24b611e8 117 ,(and clause (visit-cont clause sym)))))
90dce16d
AW
118 (($ $cont sym ($ $kclause arity body alternate))
119 (sym ($kclause ,arity ,(visit-cont body sym)
120 ,(and alternate (visit-cont alternate sym)))))
36527695 121 (($ $cont sym ($ $kreceive ($ $arity req () rest () #f) kargs))
59258f7c 122 (sym ($kreceive req rest (reduce kargs scope))))))
22a79b55
AW
123 (define (visit-term term scope)
124 (rewrite-cps-term term
125 (($ $letk conts body)
126 ($letk ,(map (cut visit-cont <> scope) conts)
127 ,(visit-term body scope)))
22a79b55
AW
128 (($ $continue k src ($ $values args))
129 ($continue (reduce-values k scope) src ($values args)))
130 (($ $continue k src (and fun ($ $fun)))
131 ($continue (reduce k scope) src ,(visit-fun fun)))
34ff3af9
AW
132 (($ $continue k src ($ $rec names syms funs))
133 ($continue k src ($rec names syms (map visit-fun funs))))
b9a5bac6
AW
134 (($ $continue k src ($ $const const))
135 ,(let ((k (reduce k scope)))
136 (or (reduce-const k src scope const)
137 (build-cps-term ($continue k src ($const const))))))
22a79b55
AW
138 (($ $continue k src exp)
139 ($continue (reduce k scope) src ,exp))))
140 (define (visit-fun fun)
4b3d7a2b 141 (rewrite-cps-exp fun
50fcdfec
AW
142 (($ $fun body)
143 ($fun ,(visit-cont body #f)))))
a0329d01 144 (visit-cont fun #f)))
22a79b55
AW
145
146(define (compute-beta-reductions fun)
147 ;; A continuation's body can be inlined in place of a $values
148 ;; expression if the continuation is a $kargs. It should only be
149 ;; inlined if it is used only once, and not recursively.
b9e601d2
AW
150 (let ((var-table (make-hash-table))
151 (k-table (make-hash-table))
a0329d01 152 (dfg (compute-dfg fun)))
22a79b55
AW
153 (define (visit-cont cont)
154 (match cont
155 (($ $cont sym ($ $kargs names syms body))
156 (visit-term body))
8320f504 157 (($ $cont sym ($ $kfun src meta self tail clause))
90dce16d
AW
158 (when clause (visit-cont clause)))
159 (($ $cont sym ($ $kclause arity body alternate))
160 (visit-cont body)
161 (when alternate (visit-cont alternate)))
59258f7c 162 (($ $cont sym (or ($ $ktail) ($ $kreceive)))
22a79b55
AW
163 #f)))
164 (define (visit-term term)
165 (match term
166 (($ $letk conts body)
167 (for-each visit-cont conts)
168 (visit-term body))
22a79b55 169 (($ $continue k src ($ $values args))
fbdb69b2 170 (match (lookup-cont k dfg)
22a79b55
AW
171 (($ $kargs names syms body)
172 (match (lookup-predecessors k dfg)
173 ((_)
174 ;; There is only one use, and it is this use. We assume
175 ;; it's not recursive, as there would to be some other
176 ;; use for control flow to reach this loop. Store the k
177 ;; -> body mapping in the table. Also store the
178 ;; substitutions for the variables bound by the inlined
179 ;; continuation.
b9e601d2
AW
180 (for-each (cut hashq-set! var-table <> <>) syms args)
181 (hashq-set! k-table k body))
22a79b55
AW
182 (_ #f)))
183 (_ #f)))
184 (($ $continue k src (and fun ($ $fun)))
185 (visit-fun fun))
34ff3af9
AW
186 (($ $continue k src ($ $rec names syms funs))
187 (for-each visit-fun funs))
22a79b55
AW
188 (($ $continue k src _)
189 #f)))
190 (define (visit-fun fun)
191 (match fun
50fcdfec 192 (($ $fun body)
22a79b55 193 (visit-cont body))))
a0329d01 194 (visit-cont fun)
b9e601d2 195 (values var-table k-table)))
22a79b55
AW
196
197(define (beta-reduce fun)
b9e601d2 198 (let-values (((var-table k-table) (compute-beta-reductions fun)))
22a79b55 199 (define (subst var)
b9e601d2 200 (cond ((hashq-ref var-table var) => subst)
22a79b55
AW
201 (else var)))
202 (define (must-visit-cont cont)
203 (or (visit-cont cont)
204 (error "continuation must not be inlined" cont)))
205 (define (visit-cont cont)
206 (match cont
207 (($ $cont sym cont)
b9e601d2 208 (and (not (hashq-ref k-table sym))
22a79b55
AW
209 (rewrite-cps-cont cont
210 (($ $kargs names syms body)
211 (sym ($kargs names syms ,(visit-term body))))
8320f504
AW
212 (($ $kfun src meta self tail clause)
213 (sym ($kfun src meta self ,tail
90dce16d
AW
214 ,(and clause (must-visit-cont clause)))))
215 (($ $kclause arity body alternate)
216 (sym ($kclause ,arity ,(must-visit-cont body)
217 ,(and alternate (must-visit-cont alternate)))))
59258f7c 218 (($ $kreceive)
22a79b55
AW
219 (sym ,cont)))))))
220 (define (visit-term term)
221 (match term
222 (($ $letk conts body)
223 (match (filter-map visit-cont conts)
224 (() (visit-term body))
225 (conts (build-cps-term
226 ($letk ,conts ,(visit-term body))))))
22a79b55
AW
227 (($ $continue k src exp)
228 (cond
b9e601d2 229 ((hashq-ref k-table k) => visit-term)
22a79b55 230 (else
92805e21
AW
231 (build-cps-term ($continue k src ,(visit-exp exp))))))))
232 (define (visit-exp exp)
233 (match exp
a9ec16f9 234 ((or ($ $const) ($ $prim)) exp)
92805e21 235 (($ $fun) (visit-fun exp))
34ff3af9
AW
236 (($ $rec names syms funs)
237 (build-cps-exp ($rec names (map subst syms) (map visit-fun funs))))
92805e21
AW
238 (($ $call proc args)
239 (let ((args (map subst args)))
240 (build-cps-exp ($call (subst proc) args))))
241 (($ $callk k proc args)
242 (let ((args (map subst args)))
243 (build-cps-exp ($callk k (subst proc) args))))
244 (($ $primcall name args)
245 (let ((args (map subst args)))
246 (build-cps-exp ($primcall name args))))
247 (($ $values args)
248 (let ((args (map subst args)))
249 (build-cps-exp ($values args))))
250 (($ $branch kt exp)
251 (build-cps-exp ($branch kt ,(visit-exp exp))))
252 (($ $prompt escape? tag handler)
253 (build-cps-exp ($prompt escape? (subst tag) handler)))))
22a79b55
AW
254 (define (visit-fun fun)
255 (rewrite-cps-exp fun
50fcdfec
AW
256 (($ $fun body)
257 ($fun ,(must-visit-cont body)))))
a0329d01 258 (must-visit-cont fun)))
22a79b55 259
44954194
AW
260;; Rewrite the scope tree to reflect the dominator tree. Precondition:
261;; the fun has been renumbered, its min-label is 0, and its labels are
262;; packed.
263(define (redominate fun)
264 (let* ((dfg (compute-dfg fun))
265 (idoms (compute-idoms dfg 0 (dfg-label-count dfg)))
266 (doms (compute-dom-edges idoms 0)))
267 (define (visit-fun-cont cont)
268 (rewrite-cps-cont cont
269 (($ $cont label ($ $kfun src meta self tail clause))
270 (label ($kfun src meta self ,tail
271 ,(and clause (visit-fun-cont clause)))))
272 (($ $cont label ($ $kclause arity ($ $cont kbody body) alternate))
273 (label ($kclause ,arity ,(visit-cont kbody body)
274 ,(and alternate (visit-fun-cont alternate)))))))
275
276 (define (visit-cont label cont)
277 (rewrite-cps-cont cont
278 (($ $kargs names vars body)
279 (label ($kargs names vars ,(visit-term body label))))
280 (_ (label ,cont))))
281
34ff3af9
AW
282 (define (visit-fun fun)
283 (rewrite-cps-exp fun
50fcdfec
AW
284 (($ $fun body)
285 ($fun ,(visit-fun-cont body)))))
34ff3af9 286
44954194
AW
287 (define (visit-exp k src exp)
288 (rewrite-cps-term exp
50fcdfec 289 (($ $fun body)
34ff3af9
AW
290 ($continue k src ,(visit-fun exp)))
291 (($ $rec names syms funs)
292 ($continue k src ($rec names syms (map visit-fun funs))))
44954194
AW
293 (_
294 ($continue k src ,exp))))
295
296 (define (visit-term term label)
297 (define (visit-dom-conts label)
298 (let ((cont (lookup-cont label dfg)))
299 (match cont
300 (($ $ktail) '())
301 (($ $kargs) (list (visit-cont label cont)))
302 (else
303 (cons (visit-cont label cont)
304 (visit-dom-conts* (vector-ref doms label)))))))
305
306 (define (visit-dom-conts* labels)
307 (match labels
308 (() '())
309 ((label . labels)
310 (append (visit-dom-conts label)
311 (visit-dom-conts* labels)))))
312
313 (rewrite-cps-term term
314 (($ $letk conts body)
315 ,(visit-term body label))
44954194
AW
316 (($ $continue k src exp)
317 ,(let ((conts (visit-dom-conts* (vector-ref doms label))))
318 (if (null? conts)
319 (visit-exp k src exp)
320 (build-cps-term
321 ($letk ,conts ,(visit-exp k src exp))))))))
322
323 (visit-fun-cont fun)))
324
22a79b55 325(define (simplify fun)
c79c02d6
AW
326 ;; Renumbering prunes continuations that are made unreachable by
327 ;; eta/beta reductions.
44954194 328 (redominate (renumber (eta-reduce (beta-reduce fun)))))