Block sorting to keep loop bodies together
[bpt/guile.git] / module / language / cps / renumber.scm
CommitLineData
f05517b2
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
3;; Copyright (C) 2014 Free Software Foundation, Inc.
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;;; A pass to renumber variables and continuation labels so that they
09220d21
AW
22;;; are contiguous within each function and, in the case of labels,
23;;; topologically sorted.
f05517b2
AW
24;;;
25;;; Code:
26
27(define-module (language cps renumber)
28 #:use-module (ice-9 match)
f9bceb77 29 #:use-module (srfi srfi-1)
f05517b2
AW
30 #:use-module (language cps)
31 #:export (renumber))
32
09220d21
AW
33;; Topologically sort the continuation tree starting at k0, using
34;; reverse post-order numbering.
6d7b6a17 35(define (sort-conts k0 conts new-k0 path-lengths)
09220d21
AW
36 (let ((next -1))
37 (let visit ((k k0))
6d7b6a17
AW
38 (define (maybe-visit k)
39 (let ((entry (vector-ref conts k)))
40 ;; Visit the successor if it has not been
41 ;; visited yet.
42 (when (and entry (not (exact-integer? entry)))
43 (visit k))))
44
09220d21
AW
45 (let ((cont (vector-ref conts k)))
46 ;; Clear the cont table entry to mark this continuation as
47 ;; visited.
48 (vector-set! conts k #f)
6d7b6a17
AW
49
50 (match cont
51 (($ $kargs names syms body)
52 (let lp ((body body))
53 (match body
54 (($ $letk conts body) (lp body))
55 (($ $letrec names syms funs body) (lp body))
56 (($ $continue k src exp)
57 (match exp
58 (($ $prompt escape? tag handler)
59 (maybe-visit handler)
60 (maybe-visit k))
61 (($ $branch kt)
62 ;; Visit the successor with the shortest path length
63 ;; to the tail first, so that if the branches are
64 ;; unsorted, the longer path length will appear
65 ;; first. This will move a loop exit out of a loop.
66 (let ((k-len (vector-ref path-lengths k))
67 (kt-len (vector-ref path-lengths kt)))
68 (cond
69 ((and k-len kt-len (< k-len kt-len))
70 (maybe-visit k)
71 (maybe-visit kt))
72 (else
73 (maybe-visit kt)
74 (maybe-visit k)))))
75 (_
76 (maybe-visit k)))))))
77 (($ $kreceive arity k) (maybe-visit k))
78 (($ $kclause arity ($ $cont kbody) alt)
79 (match alt
80 (($ $cont kalt) (maybe-visit kalt))
81 (_ #f))
82 (maybe-visit kbody))
83 (($ $kfun src meta self tail clause)
84 (match clause
85 (($ $cont kclause) (maybe-visit kclause))
86 (_ #f)))
87 (_ #f))
88
09220d21
AW
89 ;; Chain this label to the label that will follow it in the sort
90 ;; order, and record this label as the new head of the order.
91 (vector-set! conts k next)
92 (set! next k)))
93
94 ;; Finally traverse the label chain, giving each label its final
95 ;; name.
96 (let lp ((n new-k0) (head next))
97 (if (< head 0)
98 n
99 (let ((next (vector-ref conts head)))
100 (vector-set! conts head n)
101 (lp (1+ n) next))))))
102
6d7b6a17
AW
103(define (compute-tail-path-lengths preds ktail path-lengths)
104 (let visit ((k ktail) (length-in 0))
105 (let ((length (vector-ref path-lengths k)))
106 (unless (and length (<= length length-in))
107 (vector-set! path-lengths k length-in)
108 (let lp ((preds (vector-ref preds k)))
109 (match preds
110 (() #t)
111 ((pred . preds)
112 (visit pred (1+ length-in))
113 (lp preds))))))))
114
f05517b2 115(define (compute-new-labels-and-vars fun)
a0329d01 116 (call-with-values (lambda () (compute-max-label-and-var fun))
f05517b2 117 (lambda (max-label max-var)
09220d21 118 (let ((labels (make-vector (1+ max-label) #f))
f05517b2 119 (next-label 0)
09220d21 120 (vars (make-vector (1+ max-var) #f))
6d7b6a17
AW
121 (next-var 0)
122 (preds (make-vector (1+ max-label) '()))
123 (path-lengths (make-vector (1+ max-label) #f)))
124 (define (add-predecessor! pred succ)
125 (vector-set! preds succ (cons pred (vector-ref preds succ))))
f05517b2
AW
126 (define (rename! var)
127 (vector-set! vars var next-var)
128 (set! next-var (1+ next-var)))
09220d21
AW
129
130 (define (collect-conts fun)
f05517b2
AW
131 (define (visit-cont cont)
132 (match cont
133 (($ $cont label cont)
09220d21 134 (vector-set! labels label cont)
f05517b2
AW
135 (match cont
136 (($ $kargs names vars body)
6d7b6a17 137 (visit-term body label))
8320f504 138 (($ $kfun src meta self tail clause)
f05517b2 139 (visit-cont tail)
6d7b6a17
AW
140 (match clause
141 (($ $cont kclause)
142 (add-predecessor! label kclause)
143 (visit-cont clause))
144 (#f #f)))
145 (($ $kclause arity (and body ($ $cont kbody)) alternate)
146 (add-predecessor! label kbody)
90dce16d 147 (visit-cont body)
6d7b6a17
AW
148 (match alternate
149 (($ $cont kalt)
150 (add-predecessor! label kalt)
151 (visit-cont alternate))
152 (#f #f)))
153 (($ $kreceive arity kargs)
154 (add-predecessor! label kargs))
155 (($ $ktail) #f)))))
156 (define (visit-term term label)
f05517b2
AW
157 (match term
158 (($ $letk conts body)
6d7b6a17
AW
159 (let lp ((conts conts))
160 (unless (null? conts)
161 (visit-cont (car conts))
162 (lp (cdr conts))))
163 (visit-term body label))
f05517b2 164 (($ $letrec names syms funs body)
6d7b6a17
AW
165 (visit-term body label))
166 (($ $continue k src exp)
167 (add-predecessor! label k)
168 (match exp
169 (($ $branch kt)
170 (add-predecessor! label kt))
171 (($ $prompt escape? tag handler)
172 (add-predecessor! label handler))
173 (_ #f)))))
a0329d01 174 (visit-cont fun))
f05517b2 175
09220d21 176 (define (compute-names-in-fun fun)
f9bceb77 177 (define queue '())
09220d21
AW
178 (define (visit-cont cont)
179 (match cont
180 (($ $cont label cont)
181 (let ((reachable? (exact-integer? (vector-ref labels label))))
182 ;; This cont is reachable if it was given a number.
183 ;; Otherwise the cont table entry still contains the
184 ;; cont itself; clear it out to indicate that the cont
185 ;; should not be residualized.
186 (unless reachable?
187 (vector-set! labels label #f))
188 (match cont
189 (($ $kargs names vars body)
190 (when reachable?
191 (for-each rename! vars))
192 (visit-term body reachable?))
8320f504 193 (($ $kfun src meta self tail clause)
f9bceb77
AW
194 (unless reachable? (error "entry should be reachable"))
195 (rename! self)
09220d21
AW
196 (visit-cont tail)
197 (when clause
198 (visit-cont clause)))
199 (($ $kclause arity body alternate)
f9bceb77 200 (unless reachable? (error "clause should be reachable"))
09220d21
AW
201 (visit-cont body)
202 (when alternate
203 (visit-cont alternate)))
204 (($ $ktail)
205 (unless reachable?
206 ;; It's possible for the tail to be unreachable,
207 ;; if all paths contify to infinite loops. Make
208 ;; sure we mark as reachable.
209 (vector-set! labels label next-label)
210 (set! next-label (1+ next-label))))
59258f7c 211 (($ $kreceive)
09220d21
AW
212 #f))))))
213 (define (visit-term term reachable?)
214 (match term
215 (($ $letk conts body)
216 (for-each visit-cont conts)
217 (visit-term body reachable?))
218 (($ $letrec names syms funs body)
219 (when reachable?
f9bceb77 220 (for-each rename! syms)
a0329d01
AW
221 (set! queue (fold (lambda (fun queue)
222 (match fun
223 (($ $fun free body)
224 (cons body queue))))
225 queue
226 funs)))
09220d21 227 (visit-term body reachable?))
a0329d01 228 (($ $continue k src ($ $fun free body))
f9bceb77 229 (when reachable?
a0329d01 230 (set! queue (cons body queue))))
f9bceb77 231 (($ $continue) #f)))
09220d21 232
09220d21 233 (match fun
6d7b6a17 234 (($ $cont kfun ($ $kfun src meta self ($ $cont ktail)))
cf8bb037 235 (collect-conts fun)
6d7b6a17
AW
236 (compute-tail-path-lengths preds ktail path-lengths)
237 (set! next-label (sort-conts kfun labels next-label path-lengths))
a0329d01 238 (visit-cont fun)
cf8bb037
AW
239 (for-each compute-names-in-fun (reverse queue)))
240 (($ $program conts)
241 (for-each compute-names-in-fun conts))))
09220d21 242
f9bceb77 243 (compute-names-in-fun fun)
cc8eb195 244 (values labels vars next-label next-var)))))
f05517b2 245
cf8bb037
AW
246(define (apply-renumbering term labels vars)
247 (define (relabel label) (vector-ref labels label))
248 (define (rename var) (vector-ref vars var))
249 (define (rename-kw-arity arity)
250 (match arity
251 (($ $arity req opt rest kw aok?)
252 (make-$arity req opt rest
253 (map (match-lambda
254 ((kw kw-name kw-var)
255 (list kw kw-name (rename kw-var))))
256 kw)
257 aok?))))
258 (define (must-visit-cont cont)
259 (or (visit-cont cont)
260 (error "internal error -- failed to visit cont")))
261 (define (visit-conts conts)
262 (match conts
263 (() '())
264 ((cont . conts)
265 (cond
266 ((visit-cont cont)
267 => (lambda (cont)
268 (cons cont (visit-conts conts))))
269 (else (visit-conts conts))))))
270 (define (visit-cont cont)
271 (match cont
272 (($ $cont label cont)
273 (let ((label (relabel label)))
274 (and
275 label
276 (rewrite-cps-cont cont
277 (($ $kargs names vars body)
278 (label ($kargs names (map rename vars) ,(visit-term body))))
279 (($ $kfun src meta self tail clause)
280 (label
281 ($kfun src meta (rename self) ,(must-visit-cont tail)
282 ,(and clause (must-visit-cont clause)))))
283 (($ $ktail)
284 (label ($ktail)))
285 (($ $kclause arity body alternate)
286 (label
287 ($kclause ,(rename-kw-arity arity) ,(must-visit-cont body)
288 ,(and alternate (must-visit-cont alternate)))))
289 (($ $kreceive ($ $arity req () rest () #f) kargs)
59258f7c 290 (label ($kreceive req rest (relabel kargs))))))))))
cf8bb037
AW
291 (define (visit-term term)
292 (rewrite-cps-term term
293 (($ $letk conts body)
294 ,(match (visit-conts conts)
295 (() (visit-term body))
296 (conts (build-cps-term ($letk ,conts ,(visit-term body))))))
297 (($ $letrec names vars funs body)
298 ($letrec names (map rename vars) (map visit-fun funs)
299 ,(visit-term body)))
300 (($ $continue k src exp)
301 ($continue (relabel k) src ,(visit-exp exp)))))
302 (define (visit-exp exp)
303 (match exp
304 ((or ($ $void) ($ $const) ($ $prim))
305 exp)
306 (($ $closure k nfree)
307 (build-cps-exp ($closure (relabel k) nfree)))
308 (($ $fun)
309 (visit-fun exp))
310 (($ $values args)
311 (let ((args (map rename args)))
312 (build-cps-exp ($values args))))
313 (($ $call proc args)
314 (let ((args (map rename args)))
315 (build-cps-exp ($call (rename proc) args))))
316 (($ $callk k proc args)
317 (let ((args (map rename args)))
318 (build-cps-exp ($callk (relabel k) (rename proc) args))))
92805e21
AW
319 (($ $branch kt exp)
320 (build-cps-exp ($branch (relabel kt) ,(visit-exp exp))))
cf8bb037
AW
321 (($ $primcall name args)
322 (let ((args (map rename args)))
323 (build-cps-exp ($primcall name args))))
324 (($ $prompt escape? tag handler)
325 (build-cps-exp
326 ($prompt escape? (rename tag) (relabel handler))))))
327 (define (visit-fun fun)
328 (rewrite-cps-exp fun
329 (($ $fun free body)
330 ($fun (map rename free) ,(must-visit-cont body)))))
331
332 (match term
333 (($ $cont)
334 (must-visit-cont term))
335 (($ $program conts)
336 (build-cps-term
337 ($program ,(map must-visit-cont conts))))))
338
339(define (renumber term)
340 (call-with-values (lambda () (compute-new-labels-and-vars term))
a0329d01 341 (lambda (labels vars nlabels nvars)
cf8bb037 342 (values (apply-renumbering term labels vars) nlabels nvars))))