Remove $void CPS expression type
[bpt/guile.git] / module / language / cps / dfg.scm
CommitLineData
6e8ad823
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
a9ec16f9 3;; Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc.
6e8ad823
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;;; Many passes rely on a local or global static analysis of a function.
22;;; This module implements a simple data-flow graph (DFG) analysis,
23;;; tracking the definitions and uses of variables and continuations.
f22979db 24;;; It also builds a table of continuations and scope links, to be able
6e8ad823
AW
25;;; to easily determine if one continuation is in the scope of another,
26;;; and to get to the expression inside a continuation.
27;;;
28;;; Note that the data-flow graph of continuation labels is a
29;;; control-flow graph.
30;;;
31;;; We currently don't expose details of the DFG type outside this
32;;; module, preferring to only expose accessors. That may change in the
33;;; future but it seems to work for now.
34;;;
35;;; Code:
36
37(define-module (language cps dfg)
38 #:use-module (ice-9 match)
fb512cac 39 #:use-module (ice-9 format)
6e8ad823
AW
40 #:use-module (srfi srfi-1)
41 #:use-module (srfi srfi-9)
42 #:use-module (srfi srfi-26)
43 #:use-module (language cps)
e9808c14 44 #:use-module (language cps intset)
6e8ad823 45 #:export (build-cont-table
6e8ad823
AW
46 lookup-cont
47
48 compute-dfg
49 dfg-cont-table
a8430ab1
AW
50 dfg-min-label
51 dfg-label-count
52 dfg-min-var
53 dfg-var-count
3e1b97c1 54 with-fresh-name-state-from-dfg
6e8ad823
AW
55 lookup-def
56 lookup-uses
f22979db
AW
57 lookup-predecessors
58 lookup-successors
c8ad7426 59 lookup-block-scope
6e8ad823
AW
60 find-call
61 call-expression
62 find-expression
63 find-defining-expression
64 find-constant-value
f22979db 65 continuation-bound-in?
d51fb1e6 66 variable-free-in?
6e8ad823 67 constant-needs-allocation?
e636f424 68 control-point?
db11440d
AW
69 lookup-bound-syms
70
38c7bd0e
AW
71 compute-idoms
72 compute-dom-edges
73
db11440d
AW
74 ;; Data flow analysis.
75 compute-live-variables
76 dfa-k-idx dfa-k-sym dfa-k-count dfa-k-in dfa-k-out
29619661 77 dfa-var-idx dfa-var-sym dfa-var-count
db11440d 78 print-dfa))
6e8ad823 79
48c2a539
AW
80;; These definitions are here because currently we don't do cross-module
81;; inlining. They can be removed once that restriction is gone.
82(define-inlinable (for-each f l)
83 (unless (list? l)
84 (scm-error 'wrong-type-arg "for-each" "Not a list: ~S" (list l) #f))
85 (let for-each1 ((l l))
86 (unless (null? l)
87 (f (car l))
88 (for-each1 (cdr l)))))
89
90(define-inlinable (for-each/2 f l1 l2)
91 (unless (= (length l1) (length l2))
92 (scm-error 'wrong-type-arg "for-each" "List of wrong length: ~S"
93 (list l2) #f))
94 (let for-each2 ((l1 l1) (l2 l2))
95 (unless (null? l1)
96 (f (car l1) (car l2))
97 (for-each2 (cdr l1) (cdr l2)))))
98
6e8ad823 99(define (build-cont-table fun)
fbdb69b2
AW
100 (let ((max-k (fold-conts (lambda (k cont max-k) (max k max-k))
101 -1 fun)))
102 (fold-conts (lambda (k cont table)
103 (vector-set! table k cont)
104 table)
105 (make-vector (1+ max-k) #f)
106 fun)))
107
6e8ad823
AW
108;; Data-flow graph for CPS: both for values and continuations.
109(define-record-type $dfg
4bf757b8 110 (make-dfg conts preds defs uses scopes scope-levels
3e1b97c1
AW
111 min-label max-label label-count
112 min-var max-var var-count)
6e8ad823 113 dfg?
59258f7c 114 ;; vector of label -> $kargs, etc
6e8ad823 115 (conts dfg-cont-table)
5fc40391 116 ;; vector of label -> (pred-label ...)
21d6d183 117 (preds dfg-preds)
5fc40391 118 ;; vector of var -> def-label
98c5b69f 119 (defs dfg-defs)
5fc40391 120 ;; vector of var -> (use-label ...)
98c5b69f 121 (uses dfg-uses)
5fc40391
AW
122 ;; vector of label -> label
123 (scopes dfg-scopes)
124 ;; vector of label -> int
125 (scope-levels dfg-scope-levels)
5e897908
AW
126
127 (min-label dfg-min-label)
3e1b97c1 128 (max-label dfg-max-label)
a8430ab1 129 (label-count dfg-label-count)
3e1b97c1 130
5e897908 131 (min-var dfg-min-var)
3e1b97c1 132 (max-var dfg-max-var)
a8430ab1 133 (var-count dfg-var-count))
6e8ad823 134
9002277d
AW
135(define-inlinable (vector-push! vec idx val)
136 (let ((v vec) (i idx))
137 (vector-set! v i (cons val (vector-ref v i)))))
138
16af91e8 139(define (compute-reachable dfg min-label label-count)
4ec3ded0 140 "Compute and return the continuations that may be reached if flow
5ded8498 141reaches a continuation N. Returns a vector of intsets, whose first
4ec3ded0 142index corresponds to MIN-LABEL, and so on."
e9808c14 143 (let (;; Vector of intsets, indicating that continuation N can
16af91e8
AW
144 ;; reach a set M...
145 (reachable (make-vector label-count #f)))
146
147 (define (label->idx label) (- label min-label))
9002277d 148
4ec3ded0 149 ;; Iterate labels backwards, to converge quickly.
e9808c14
AW
150 (let lp ((label (+ min-label label-count)) (changed? #f))
151 (cond
152 ((= label min-label)
153 (if changed?
154 (lp (+ min-label label-count) #f)
155 reachable))
156 (else
157 (let* ((label (1- label))
158 (idx (label->idx label))
159 (old (vector-ref reachable idx))
160 (new (fold (lambda (succ set)
161 (cond
162 ((vector-ref reachable (label->idx succ))
163 => (lambda (succ-set)
164 (intset-union set succ-set)))
165 (else set)))
166 (or (vector-ref reachable idx)
167 (intset-add empty-intset label))
168 (visit-cont-successors list
169 (lookup-cont label dfg)))))
170 (cond
171 ((eq? old new)
172 (lp label changed?))
173 (else
174 (vector-set! reachable idx new)
175 (lp label #t)))))))))
9002277d 176
16af91e8
AW
177(define (find-prompts dfg min-label label-count)
178 "Find the prompts in DFG between MIN-LABEL and MIN-LABEL +
179LABEL-COUNT, and return them as a list of PROMPT-LABEL, HANDLER-LABEL
180pairs."
181 (let lp ((label min-label) (prompts '()))
9002277d 182 (cond
16af91e8 183 ((= label (+ min-label label-count))
9002277d
AW
184 (reverse prompts))
185 (else
16af91e8 186 (match (lookup-cont label dfg)
9002277d
AW
187 (($ $kargs names syms body)
188 (match (find-expression body)
189 (($ $prompt escape? tag handler)
16af91e8
AW
190 (lp (1+ label) (acons label handler prompts)))
191 (_ (lp (1+ label) prompts))))
192 (_ (lp (1+ label) prompts)))))))
9002277d 193
16af91e8 194(define (compute-interval reachable min-label label-count start end)
9002277d 195 "Compute and return the set of continuations that may be reached from
e9808c14
AW
196START, inclusive, but not reached by END, exclusive. Returns an
197intset."
198 (intset-subtract (vector-ref reachable (- start min-label))
199 (vector-ref reachable (- end min-label))))
9002277d 200
16af91e8
AW
201(define (find-prompt-bodies dfg min-label label-count)
202 "Find all the prompts in DFG from the LABEL-COUNT continuations
203starting at MIN-LABEL, and compute the set of continuations that is
204reachable from the prompt bodies but not from the corresponding handler.
e9808c14
AW
205Returns a list of PROMPT, HANDLER, BODY lists, where the BODY is an
206intset."
16af91e8 207 (match (find-prompts dfg min-label label-count)
9002277d
AW
208 (() '())
209 (((prompt . handler) ...)
16af91e8 210 (let ((reachable (compute-reachable dfg min-label label-count)))
9002277d
AW
211 (map (lambda (prompt handler)
212 ;; FIXME: It isn't correct to use all continuations
213 ;; reachable from the prompt, because that includes
214 ;; continuations outside the prompt body. This point is
215 ;; moot if the handler's control flow joins with the the
216 ;; body, as is usually but not always the case.
217 ;;
218 ;; One counter-example is when the handler contifies an
219 ;; infinite loop; in that case we compute a too-large
16af91e8
AW
220 ;; prompt body. This error is currently innocuous, but we
221 ;; should fix it at some point.
9002277d
AW
222 ;;
223 ;; The fix is to end the body at the corresponding "pop"
224 ;; primcall, if any.
16af91e8
AW
225 (let ((body (compute-interval reachable min-label label-count
226 prompt handler)))
9002277d
AW
227 (list prompt handler body)))
228 prompt handler)))))
229
16af91e8 230(define* (visit-prompt-control-flow dfg min-label label-count f #:key complete?)
4ec3ded0
AW
231 "For all prompts in DFG in the range [MIN-LABEL, MIN-LABEL +
232LABEL-COUNT), invoke F with arguments PROMPT, HANDLER, and BODY for each
233body continuation in the prompt."
16af91e8
AW
234 (define (label->idx label) (- label min-label))
235 (define (idx->label idx) (+ idx min-label))
9002277d
AW
236 (for-each
237 (match-lambda
238 ((prompt handler body)
e9808c14 239 (define (out-or-back-edge? label)
9002277d
AW
240 ;; Most uses of visit-prompt-control-flow don't need every body
241 ;; continuation, and would be happy getting called only for
242 ;; continuations that postdominate the rest of the body. Unless
243 ;; you pass #:complete? #t, we only invoke F on continuations
244 ;; that can leave the body, or on back-edges in loops.
245 ;;
246 ;; You would think that looking for the final "pop" primcall
247 ;; would be sufficient, but that is incorrect; it's possible for
248 ;; a loop in the prompt body to be contified, and that loop need
249 ;; not continue to the pop if it never terminates. The pop could
250 ;; even be removed by DCE, in that case.
251 (or-map (lambda (succ)
e9808c14
AW
252 (or (not (intset-ref body succ))
253 (<= succ label)))
254 (lookup-successors label dfg)))
255 (let lp ((label min-label))
256 (let ((label (intset-next body label)))
257 (when label
258 (when (or complete? (out-or-back-edge? label))
259 (f prompt handler label))
260 (lp (1+ label)))))))
16af91e8
AW
261 (find-prompt-bodies dfg min-label label-count)))
262
a7324faf
AW
263(define (analyze-reverse-control-flow fun dfg min-label label-count)
264 (define (compute-reverse-control-flow-order ktail dfg)
21a528fd 265 (let ((label-map (make-vector label-count #f))
16af91e8
AW
266 (next -1))
267 (define (label->idx label) (- label min-label))
268 (define (idx->label idx) (+ idx min-label))
269
270 (let visit ((k ktail))
271 ;; Mark this label as visited.
272 (vector-set! label-map (label->idx k) #t)
273 (for-each (lambda (k)
274 ;; Visit predecessors unless they are already visited.
275 (unless (vector-ref label-map (label->idx k))
276 (visit k)))
277 (lookup-predecessors k dfg))
278 ;; Add to reverse post-order chain.
279 (vector-set! label-map (label->idx k) next)
280 (set! next k))
281
282 (let lp ((n 0) (head next))
283 (if (< head 0)
284 ;; Add nodes that are not reachable from the tail.
285 (let lp ((n n) (m label-count))
286 (unless (= n label-count)
287 (let find-unvisited ((m (1- m)))
288 (if (vector-ref label-map m)
289 (find-unvisited (1- m))
290 (begin
291 (vector-set! label-map m n)
292 (lp (1+ n) m))))))
293 ;; Pop the head off the chain, give it its
294 ;; reverse-post-order numbering, and continue.
295 (let ((next (vector-ref label-map (label->idx head))))
296 (vector-set! label-map (label->idx head) n)
297 (lp (1+ n) next))))
298
21a528fd 299 label-map))
16af91e8 300
a7324faf 301 (define (convert-successors k-map)
16af91e8
AW
302 (define (idx->label idx) (+ idx min-label))
303 (define (renumber label)
304 (vector-ref k-map (- label min-label)))
305 (let ((succs (make-vector (vector-length k-map) #f)))
306 (let lp ((n 0))
307 (when (< n (vector-length succs))
308 (vector-set! succs (vector-ref k-map n)
309 (map renumber
310 (lookup-successors (idx->label n) dfg)))
311 (lp (1+ n))))
312 succs))
313
a7324faf 314 (match fun
6bc36ca5 315 (($ $cont kfun ($ $kfun src meta self ($ $cont ktail tail)))
21a528fd
AW
316 (let* ((k-map (compute-reverse-control-flow-order ktail dfg))
317 (succs (convert-successors k-map)))
318 ;; Any expression in the prompt body could cause an abort to
319 ;; the handler. This code adds links from every block in the
320 ;; prompt body to the handler. This causes all values used
321 ;; by the handler to be seen as live in the prompt body, as
322 ;; indeed they are.
323 (visit-prompt-control-flow
324 dfg min-label label-count
325 (lambda (prompt handler body)
326 (define (renumber label)
327 (vector-ref k-map (- label min-label)))
328 (vector-push! succs (renumber body) (renumber handler))))
329
330 (values k-map succs)))))
dda5fd94 331
38c7bd0e
AW
332(define (compute-idoms dfg min-label label-count)
333 (define preds (dfg-preds dfg))
4ec3ded0
AW
334 (define (label->idx label) (- label min-label))
335 (define (idx->label idx) (+ idx min-label))
38c7bd0e
AW
336 (define (idx->dfg-idx idx) (- (idx->label idx) (dfg-min-label dfg)))
337 (let ((idoms (make-vector label-count #f)))
3aee6cfd
AW
338 (define (common-idom d0 d1)
339 ;; We exploit the fact that a reverse post-order is a topological
340 ;; sort, and so the idom of a node is always numerically less than
341 ;; the node itself.
342 (cond
343 ((= d0 d1) d0)
38c7bd0e
AW
344 ((< d0 d1) (common-idom d0 (vector-ref idoms (label->idx d1))))
345 (else (common-idom (vector-ref idoms (label->idx d0)) d1))))
3aee6cfd 346 (define (compute-idom preds)
38c7bd0e
AW
347 (define (has-idom? pred)
348 (vector-ref idoms (label->idx pred)))
3aee6cfd 349 (match preds
38c7bd0e 350 (() min-label)
3aee6cfd 351 ((pred . preds)
38c7bd0e
AW
352 (if (has-idom? pred)
353 (let lp ((idom pred) (preds preds))
354 (match preds
355 (() idom)
356 ((pred . preds)
357 (lp (if (has-idom? pred)
358 (common-idom idom pred)
359 idom)
360 preds))))
361 (compute-idom preds)))))
3aee6cfd
AW
362 ;; This is the iterative O(n^2) fixpoint algorithm, originally from
363 ;; Allen and Cocke ("Graph-theoretic constructs for program flow
364 ;; analysis", 1972). See the discussion in Cooper, Harvey, and
365 ;; Kennedy's "A Simple, Fast Dominance Algorithm", 2001.
366 (let iterate ((n 0) (changed? #f))
367 (cond
4ec3ded0 368 ((< n label-count)
3aee6cfd 369 (let ((idom (vector-ref idoms n))
38c7bd0e 370 (idom* (compute-idom (vector-ref preds (idx->dfg-idx n)))))
3aee6cfd
AW
371 (cond
372 ((eqv? idom idom*)
373 (iterate (1+ n) changed?))
374 (else
375 (vector-set! idoms n idom*)
376 (iterate (1+ n) #t)))))
377 (changed?
378 (iterate 0 #f))
366eb4d7
AW
379 (else idoms)))))
380
96b8027c
AW
381;; Compute a vector containing, for each node, a list of the nodes that
382;; it immediately dominates. These are the "D" edges in the DJ tree.
38c7bd0e
AW
383(define (compute-dom-edges idoms min-label)
384 (define (label->idx label) (- label min-label))
385 (define (idx->label idx) (+ idx min-label))
96b8027c
AW
386 (let ((doms (make-vector (vector-length idoms) '())))
387 (let lp ((n 0))
388 (when (< n (vector-length idoms))
389 (let ((idom (vector-ref idoms n)))
38c7bd0e 390 (vector-push! doms (label->idx idom) (idx->label n)))
96b8027c
AW
391 (lp (1+ n))))
392 doms))
393
38c7bd0e
AW
394;; There used to be some loop detection code here, but it bitrotted.
395;; We'll need it again eventually but for now it can be found in the git
396;; history.
db11440d 397
db11440d
AW
398;; Data-flow analysis.
399(define-record-type $dfa
21a528fd 400 (make-dfa min-label min-var var-count in out)
db11440d 401 dfa?
21a528fd 402 ;; Minimum label in this function.
a57f6e1e 403 (min-label dfa-min-label)
7c4977e6
AW
404 ;; Minimum var in this function.
405 (min-var dfa-min-var)
21a528fd 406 ;; Var count in this function.
7c4977e6 407 (var-count dfa-var-count)
5ded8498 408 ;; Vector of k-idx -> intset
db11440d 409 (in dfa-in)
5ded8498 410 ;; Vector of k-idx -> intset
db11440d
AW
411 (out dfa-out))
412
413(define (dfa-k-idx dfa k)
21a528fd 414 (- k (dfa-min-label dfa)))
db11440d
AW
415
416(define (dfa-k-sym dfa idx)
21a528fd 417 (+ idx (dfa-min-label dfa)))
db11440d
AW
418
419(define (dfa-k-count dfa)
21a528fd 420 (vector-length (dfa-in dfa)))
db11440d
AW
421
422(define (dfa-var-idx dfa var)
7c4977e6
AW
423 (let ((idx (- var (dfa-min-var dfa))))
424 (unless (< -1 idx (dfa-var-count dfa))
425 (error "var out of range" var))
426 idx))
db11440d 427
db11440d 428(define (dfa-var-sym dfa idx)
7c4977e6
AW
429 (unless (< -1 idx (dfa-var-count dfa))
430 (error "idx out of range" idx))
431 (+ idx (dfa-min-var dfa)))
db11440d
AW
432
433(define (dfa-k-in dfa idx)
434 (vector-ref (dfa-in dfa) idx))
435
436(define (dfa-k-out dfa idx)
437 (vector-ref (dfa-out dfa) idx))
438
5bff3125 439(define (compute-live-variables fun dfg)
5ded8498
AW
440 ;; Compute the maximum fixed point of the data-flow constraint problem.
441 ;;
442 ;; This always completes, as the graph is finite and the in and out sets
443 ;; are complete semi-lattices. If the graph is reducible and the blocks
444 ;; are sorted in reverse post-order, this completes in a maximum of LC +
445 ;; 2 iterations, where LC is the loop connectedness number. See Hecht
446 ;; and Ullman, "Analysis of a simple algorithm for global flow
447 ;; problems", POPL 1973, or the recent summary in "Notes on graph
448 ;; algorithms used in optimizing compilers", Offner 2013.
449 (define (compute-maximum-fixed-point preds inv outv killv genv)
450 (define (fold f seed l)
451 (if (null? l) seed (fold f (f (car l) seed) (cdr l))))
452 (let lp ((n 0) (changed? #f))
453 (cond
454 ((< n (vector-length preds))
455 (let* ((in (vector-ref inv n))
456 (in* (or
457 (fold (lambda (pred set)
458 (cond
459 ((vector-ref outv pred)
460 => (lambda (out)
461 (if set
462 (intset-union set out)
463 out)))
464 (else set)))
465 in
466 (vector-ref preds n))
467 empty-intset)))
468 (if (eq? in in*)
469 (lp (1+ n) changed?)
470 (let ((out* (fold (lambda (gen set)
471 (intset-add set gen))
472 (fold (lambda (kill set)
473 (intset-remove set kill))
474 in*
475 (vector-ref killv n))
476 (vector-ref genv n))))
477 (vector-set! inv n in*)
478 (vector-set! outv n out*)
479 (lp (1+ n) #t)))))
480 (changed?
481 (lp 0 #f)))))
482
7c4977e6
AW
483 (unless (and (= (vector-length (dfg-uses dfg)) (dfg-var-count dfg))
484 (= (vector-length (dfg-cont-table dfg)) (dfg-label-count dfg)))
485 (error "function needs renumbering"))
a7324faf
AW
486 (let* ((min-label (dfg-min-label dfg))
487 (nlabels (dfg-label-count dfg))
488 (min-var (dfg-min-var dfg))
a8430ab1 489 (nvars (dfg-var-count dfg))
a7324faf
AW
490 (usev (make-vector nlabels '()))
491 (defv (make-vector nlabels '()))
492 (live-in (make-vector nlabels #f))
493 (live-out (make-vector nlabels #f)))
494 (call-with-values
495 (lambda ()
496 (analyze-reverse-control-flow fun dfg min-label nlabels))
21a528fd 497 (lambda (k-map succs)
a7324faf
AW
498 (define (var->idx var) (- var min-var))
499 (define (idx->var idx) (+ idx min-var))
500 (define (label->idx label)
501 (vector-ref k-map (- label min-label)))
502
503 ;; Initialize defv and usev.
504 (let ((defs (dfg-defs dfg))
505 (uses (dfg-uses dfg)))
506 (let lp ((n 0))
507 (when (< n (vector-length defs))
508 (let ((def (vector-ref defs n)))
509 (unless def
510 (error "internal error -- var array not packed"))
511 (for-each (lambda (def)
512 (vector-push! defv (label->idx def) n))
513 (lookup-predecessors def dfg))
514 (for-each (lambda (use)
515 (vector-push! usev (label->idx use) n))
516 (vector-ref uses n))
517 (lp (1+ n))))))
518
a7324faf
AW
519 ;; Liveness is a reverse data-flow problem, so we give
520 ;; compute-maximum-fixed-point a reversed graph, swapping in for
521 ;; out, usev for defv, and using successors instead of
522 ;; predecessors. Continuation 0 is ktail.
5ded8498 523 (compute-maximum-fixed-point succs live-out live-in defv usev)
a7324faf 524
21a528fd
AW
525 ;; Now rewrite the live-in and live-out sets to be indexed by
526 ;; (LABEL - MIN-LABEL).
527 (let ((live-in* (make-vector nlabels #f))
528 (live-out* (make-vector nlabels #f)))
529 (let lp ((idx 0))
530 (when (< idx nlabels)
531 (let ((dfa-idx (vector-ref k-map idx)))
532 (vector-set! live-in* idx (vector-ref live-in dfa-idx))
533 (vector-set! live-out* idx (vector-ref live-out dfa-idx))
534 (lp (1+ idx)))))
535
536 (make-dfa min-label min-var nvars live-in* live-out*))))))
db11440d
AW
537
538(define (print-dfa dfa)
539 (match dfa
21a528fd 540 (($ $dfa min-label min-var var-count in out)
db11440d
AW
541 (define (print-var-set bv)
542 (let lp ((n 0))
5ded8498 543 (let ((n (intset-next bv n)))
db11440d 544 (when n
7c4977e6 545 (format #t " ~A" (+ n min-var))
db11440d
AW
546 (lp (1+ n))))))
547 (let lp ((n 0))
21a528fd
AW
548 (when (< n (vector-length in))
549 (format #t "~A:\n" (+ n min-label))
db11440d
AW
550 (format #t " in:")
551 (print-var-set (vector-ref in n))
552 (newline)
553 (format #t " out:")
554 (print-var-set (vector-ref out n))
555 (newline)
556 (lp (1+ n)))))))
557
5e897908
AW
558(define (compute-label-and-var-ranges fun global?)
559 (define (min* a b)
560 (if b (min a b) a))
405805fb
AW
561 (define-syntax-rule (do-fold make-cont-folder)
562 ((make-cont-folder min-label max-label label-count
545274a0
AW
563 min-var max-var var-count)
564 (lambda (label cont
565 min-label max-label label-count
566 min-var max-var var-count)
567 (let ((min-label (min* label min-label))
568 (max-label (max label max-label)))
569 (define (visit-letrec body min-var max-var var-count)
570 (match body
571 (($ $letk conts body)
572 (visit-letrec body min-var max-var var-count))
573 (($ $letrec names vars funs body)
574 (visit-letrec body
575 (cond (min-var (fold min min-var vars))
576 ((pair? vars) (fold min (car vars) (cdr vars)))
577 (else min-var))
578 (fold max max-var vars)
579 (+ var-count (length vars))))
580 (($ $continue) (values min-var max-var var-count))))
581 (match cont
582 (($ $kargs names vars body)
583 (call-with-values
584 (lambda ()
585 (if global?
586 (visit-letrec body min-var max-var var-count)
587 (values min-var max-var var-count)))
588 (lambda (min-var max-var var-count)
589 (values min-label max-label (1+ label-count)
590 (cond (min-var (fold min min-var vars))
591 ((pair? vars) (fold min (car vars) (cdr vars)))
592 (else min-var))
593 (fold max max-var vars)
594 (+ var-count (length vars))))))
8320f504 595 (($ $kfun src meta self)
545274a0
AW
596 (values min-label max-label (1+ label-count)
597 (min* self min-var) (max self max-var) (1+ var-count)))
598 (_ (values min-label max-label (1+ label-count)
599 min-var max-var var-count)))))
600 fun
601 #f -1 0 #f -1 0))
602 (if global?
405805fb
AW
603 (do-fold make-global-cont-folder)
604 (do-fold make-local-cont-folder)))
5e897908 605
6e8ad823 606(define* (compute-dfg fun #:key (global? #t))
a16af113
AW
607 (call-with-values (lambda () (compute-label-and-var-ranges fun global?))
608 (lambda (min-label max-label label-count min-var max-var var-count)
609 (when (or (zero? label-count) (zero? var-count))
610 (error "internal error (no vars or labels for fun?)"))
611 (let* ((nlabels (- (1+ max-label) min-label))
612 (nvars (- (1+ max-var) min-var))
613 (conts (make-vector nlabels #f))
614 (preds (make-vector nlabels '()))
615 (defs (make-vector nvars #f))
616 (uses (make-vector nvars '()))
617 (scopes (make-vector nlabels #f))
618 (scope-levels (make-vector nlabels #f)))
619 (define (var->idx var) (- var min-var))
620 (define (label->idx label) (- label min-label))
621
622 (define (add-def! var def-k)
623 (vector-set! defs (var->idx var) def-k))
624 (define (add-use! var use-k)
625 (vector-push! uses (var->idx var) use-k))
626
627 (define* (declare-block! label cont parent
628 #:optional (level
629 (1+ (vector-ref
630 scope-levels
631 (label->idx parent)))))
632 (vector-set! conts (label->idx label) cont)
633 (vector-set! scopes (label->idx label) parent)
634 (vector-set! scope-levels (label->idx label) level))
635
636 (define (link-blocks! pred succ)
637 (vector-push! preds (label->idx succ) pred))
638
639 (define (visit-cont cont label)
640 (match cont
641 (($ $kargs names syms body)
642 (for-each (cut add-def! <> label) syms)
643 (visit-term body label))
a16af113
AW
644 (($ $kreceive arity k)
645 (link-blocks! label k))))
646
647 (define (visit-term term label)
648 (match term
649 (($ $letk (($ $cont k cont) ...) body)
650 ;; Set up recursive environment before visiting cont bodies.
651 (for-each/2 (lambda (cont k)
652 (declare-block! k cont label))
653 cont k)
654 (for-each/2 visit-cont cont k)
655 (visit-term body label))
656 (($ $letrec names syms funs body)
657 (unless global?
658 (error "$letrec should not be present when building a local DFG"))
659 (for-each (cut add-def! <> label) syms)
660 (for-each (lambda (fun)
661 (match fun
662 (($ $fun free body)
663 (visit-fun body))))
664 funs)
665 (visit-term body label))
666 (($ $continue k src exp)
667 (link-blocks! label k)
668 (visit-exp exp label))))
669
670 (define (visit-exp exp label)
671 (define (use! sym)
672 (add-use! sym label))
673 (match exp
a9ec16f9 674 ((or ($ $const) ($ $prim) ($ $closure)) #f)
a16af113
AW
675 (($ $call proc args)
676 (use! proc)
677 (for-each use! args))
678 (($ $callk k proc args)
679 (use! proc)
680 (for-each use! args))
681 (($ $primcall name args)
682 (for-each use! args))
92805e21
AW
683 (($ $branch kt exp)
684 (link-blocks! label kt)
685 (visit-exp exp label))
a16af113
AW
686 (($ $values args)
687 (for-each use! args))
688 (($ $prompt escape? tag handler)
689 (use! tag)
690 (link-blocks! label handler))
691 (($ $fun free body)
692 (when global?
693 (visit-fun body)))))
694
695 (define (visit-clause clause kfun)
696 (match clause
697 (#f #t)
698 (($ $cont kclause
699 (and clause ($ $kclause arity ($ $cont kbody body)
700 alternate)))
701 (declare-block! kclause clause kfun)
702 (link-blocks! kfun kclause)
703
704 (declare-block! kbody body kclause)
705 (link-blocks! kclause kbody)
706
707 (visit-cont body kbody)
708 (visit-clause alternate kfun))))
709
710 (define (visit-fun fun)
711 (match fun
712 (($ $cont kfun
713 (and cont
714 ($ $kfun src meta self ($ $cont ktail tail) clause)))
715 (declare-block! kfun cont #f 0)
716 (add-def! self kfun)
717 (declare-block! ktail tail kfun)
718 (visit-clause clause kfun))))
719
720 (visit-fun fun)
721
722 (make-dfg conts preds defs uses scopes scope-levels
723 min-label max-label label-count
724 min-var max-var var-count)))))
3e1b97c1 725
fb512cac
AW
726(define* (dump-dfg dfg #:optional (port (current-output-port)))
727 (let ((min-label (dfg-min-label dfg))
728 (min-var (dfg-min-var dfg)))
729 (define (label->idx label) (- label min-label))
730 (define (idx->label idx) (+ idx min-label))
731 (define (var->idx var) (- var min-var))
732 (define (idx->var idx) (+ idx min-var))
733
734 (let lp ((label (dfg-min-label dfg)))
51177f35 735 (when (<= label (dfg-max-label dfg))
fb512cac
AW
736 (let ((cont (vector-ref (dfg-cont-table dfg) (label->idx label))))
737 (when cont
738 (unless (equal? (lookup-predecessors label dfg) (list (1- label)))
739 (newline port))
740 (format port "k~a:~8t" label)
741 (match cont
fb512cac
AW
742 (($ $kreceive arity k)
743 (format port "$kreceive ~a k~a\n" arity k))
744 (($ $kfun src meta self tail clause)
745 (format port "$kfun ~a ~a v~a\n" src meta self))
746 (($ $ktail)
747 (format port "$ktail\n"))
748 (($ $kclause arity ($ $cont kbody) alternate)
749 (format port "$kclause ~a k~a" arity kbody)
750 (match alternate
751 (#f #f)
752 (($ $cont kalt) (format port " -> k~a" kalt)))
753 (newline port))
754 (($ $kargs names vars term)
755 (unless (null? vars)
756 (format port "v~a[~a]~:{ v~a[~a]~}: "
757 (car vars) (car names) (map list (cdr vars) (cdr names))))
758 (match (find-call term)
92805e21
AW
759 (($ $continue kf src ($ $branch kt exp))
760 (format port "if ")
761 (match exp
762 (($ $primcall name args)
763 (format port "(~a~{ v~a~})" name args))
764 (($ $values (arg))
765 (format port "v~a" arg)))
766 (format port " k~a k~a\n" kt kf))
fb512cac
AW
767 (($ $continue k src exp)
768 (match exp
fb512cac
AW
769 (($ $const val) (format port "const ~@y" val))
770 (($ $prim name) (format port "prim ~a" name))
771 (($ $fun free ($ $cont kbody)) (format port "fun k~a" kbody))
772 (($ $closure label nfree) (format port "closure k~a (~a free)" label nfree))
773 (($ $call proc args) (format port "call~{ v~a~}" (cons proc args)))
774 (($ $callk k proc args) (format port "callk k~a~{ v~a~}" k (cons proc args)))
775 (($ $primcall name args) (format port "~a~{ v~a~}" name args))
776 (($ $values args) (format port "values~{ v~a~}" args))
777 (($ $prompt escape? tag handler) (format port "prompt ~a v~a k~a" escape? tag handler)))
778 (unless (= k (1+ label))
779 (format port " -> k~a" k))
780 (newline port))))))
781 (lp (1+ label)))))))
782
3e1b97c1
AW
783(define-syntax-rule (with-fresh-name-state-from-dfg dfg body ...)
784 (parameterize ((label-counter (1+ (dfg-max-label dfg)))
785 (var-counter (1+ (dfg-max-var dfg))))
786 body ...))
5e897908 787
f49e994b
AW
788(define (lookup-cont label dfg)
789 (let ((res (vector-ref (dfg-cont-table dfg) (- label (dfg-min-label dfg)))))
790 (unless res
791 (error "Unknown continuation!" label))
792 res))
793
5fc40391
AW
794(define (lookup-predecessors k dfg)
795 (vector-ref (dfg-preds dfg) (- k (dfg-min-label dfg))))
796
797(define (lookup-successors k dfg)
2c3c086e
AW
798 (let ((cont (vector-ref (dfg-cont-table dfg) (- k (dfg-min-label dfg)))))
799 (visit-cont-successors list cont)))
6e8ad823 800
5e897908 801(define (lookup-def var dfg)
f49e994b 802 (vector-ref (dfg-defs dfg) (- var (dfg-min-var dfg))))
6e8ad823 803
5e897908 804(define (lookup-uses var dfg)
f49e994b 805 (vector-ref (dfg-uses dfg) (- var (dfg-min-var dfg))))
6e8ad823 806
c8ad7426 807(define (lookup-block-scope k dfg)
5fc40391 808 (vector-ref (dfg-scopes dfg) (- k (dfg-min-label dfg))))
f22979db 809
5fc40391
AW
810(define (lookup-scope-level k dfg)
811 (vector-ref (dfg-scope-levels dfg) (- k (dfg-min-label dfg))))
f22979db 812
6e8ad823 813(define (find-defining-term sym dfg)
f22979db 814 (match (lookup-predecessors (lookup-def sym dfg) dfg)
6e8ad823 815 ((def-exp-k)
fbdb69b2 816 (lookup-cont def-exp-k dfg))
6e8ad823
AW
817 (else #f)))
818
819(define (find-call term)
820 (match term
821 (($ $kargs names syms body) (find-call body))
822 (($ $letk conts body) (find-call body))
823 (($ $letrec names syms funs body) (find-call body))
824 (($ $continue) term)))
825
826(define (call-expression call)
827 (match call
6e422a35 828 (($ $continue k src exp) exp)))
6e8ad823
AW
829
830(define (find-expression term)
831 (call-expression (find-call term)))
832
833(define (find-defining-expression sym dfg)
834 (match (find-defining-term sym dfg)
835 (#f #f)
36527695 836 (($ $kreceive) #f)
f22979db 837 (($ $kclause) #f)
6e8ad823
AW
838 (term (find-expression term))))
839
840(define (find-constant-value sym dfg)
841 (match (find-defining-expression sym dfg)
842 (($ $const val)
843 (values #t val))
6e8ad823
AW
844 (else
845 (values #f #f))))
846
36aeda5b 847(define (constant-needs-allocation? var val dfg)
607fe5a6
AW
848 (define (immediate-u8? val)
849 (and (integer? val) (exact? val) (<= 0 val 255)))
850
6e8ad823
AW
851 (define (find-exp term)
852 (match term
36aeda5b 853 (($ $kargs names vars body) (find-exp body))
6e8ad823
AW
854 (($ $letk conts body) (find-exp body))
855 (else term)))
f49e994b
AW
856
857 (or-map
858 (lambda (use)
859 (match (find-expression (lookup-cont use dfg))
860 (($ $call) #f)
861 (($ $callk) #f)
862 (($ $values) #f)
863 (($ $primcall 'free-ref (closure slot))
36aeda5b 864 (eq? var closure))
f49e994b 865 (($ $primcall 'free-set! (closure slot value))
36aeda5b 866 (or (eq? var closure) (eq? var value)))
f49e994b 867 (($ $primcall 'cache-current-module! (mod . _))
36aeda5b 868 (eq? var mod))
f49e994b
AW
869 (($ $primcall 'cached-toplevel-box _)
870 #f)
871 (($ $primcall 'cached-module-box _)
872 #f)
873 (($ $primcall 'resolve (name bound?))
36aeda5b 874 (eq? var name))
f49e994b 875 (($ $primcall 'make-vector/immediate (len init))
36aeda5b 876 (eq? var init))
f49e994b 877 (($ $primcall 'vector-ref/immediate (v i))
36aeda5b 878 (eq? var v))
f49e994b 879 (($ $primcall 'vector-set!/immediate (v i x))
36aeda5b 880 (or (eq? var v) (eq? var x)))
f49e994b 881 (($ $primcall 'allocate-struct/immediate (vtable nfields))
36aeda5b 882 (eq? var vtable))
f49e994b 883 (($ $primcall 'struct-ref/immediate (s n))
36aeda5b 884 (eq? var s))
f49e994b 885 (($ $primcall 'struct-set!/immediate (s n x))
36aeda5b 886 (or (eq? var s) (eq? var x)))
f49e994b
AW
887 (($ $primcall 'builtin-ref (idx))
888 #f)
889 (_ #t)))
36aeda5b 890 (vector-ref (dfg-uses dfg) (- var (dfg-min-var dfg)))))
6e8ad823 891
5e897908
AW
892(define (continuation-scope-contains? scope-k k dfg)
893 (let ((scope-level (lookup-scope-level scope-k dfg)))
f22979db
AW
894 (let lp ((k k))
895 (or (eq? scope-k k)
5fc40391
AW
896 (and (< scope-level (lookup-scope-level k dfg))
897 (lp (lookup-block-scope k dfg)))))))
f22979db 898
f22979db 899(define (continuation-bound-in? k use-k dfg)
21d6d183 900 (continuation-scope-contains? (lookup-block-scope k dfg) use-k dfg))
d51fb1e6
AW
901
902(define (variable-free-in? var k dfg)
5e897908
AW
903 (or-map (lambda (use)
904 (continuation-scope-contains? k use dfg))
905 (lookup-uses var dfg)))
6e8ad823 906
e636f424 907;; A continuation is a control point if it has multiple predecessors, or
a3a45279 908;; if its single predecessor does not have a single successor.
e636f424
AW
909(define (control-point? k dfg)
910 (match (lookup-predecessors k dfg)
911 ((pred)
2c3c086e
AW
912 (let ((cont (vector-ref (dfg-cont-table dfg)
913 (- pred (dfg-min-label dfg)))))
914 (visit-cont-successors (case-lambda
915 (() #t)
916 ((succ0) #f)
917 ((succ1 succ2) #t))
918 cont)))
e636f424 919 (_ #t)))
6e8ad823
AW
920
921(define (lookup-bound-syms k dfg)
fbdb69b2
AW
922 (match (lookup-cont k dfg)
923 (($ $kargs names syms body)
924 syms)))