Speed up compute-label-and-var-ranges
[bpt/guile.git] / module / language / cps / dfg.scm
index 551b80e..4f32fce 100644 (file)
   #:use-module (srfi srfi-26)
   #:use-module (language cps)
   #:export (build-cont-table
-            build-local-cont-table
             lookup-cont
 
             compute-dfg
             dfg-cont-table
+            dfg-min-label
+            dfg-label-count
+            dfg-min-var
+            dfg-var-count
             lookup-def
             lookup-uses
             lookup-predecessors
             ;; Data flow analysis.
             compute-live-variables
             dfa-k-idx dfa-k-sym dfa-k-count dfa-k-in dfa-k-out
-            dfa-var-idx dfa-var-name dfa-var-sym dfa-var-count
+            dfa-var-idx dfa-var-sym dfa-var-count
             print-dfa))
 
+;; These definitions are here because currently we don't do cross-module
+;; inlining.  They can be removed once that restriction is gone.
+(define-inlinable (for-each f l)
+  (unless (list? l)
+    (scm-error 'wrong-type-arg "for-each" "Not a list: ~S" (list l) #f))
+  (let for-each1 ((l l))
+    (unless (null? l)
+      (f (car l))
+      (for-each1 (cdr l)))))
+
+(define-inlinable (for-each/2 f l1 l2)
+  (unless (= (length l1) (length l2))
+    (scm-error 'wrong-type-arg "for-each" "List of wrong length: ~S"
+               (list l2) #f))
+  (let for-each2 ((l1 l1) (l2 l2))
+    (unless (null? l1)
+      (f (car l1) (car l2))
+      (for-each2 (cdr l1) (cdr l2)))))
+
 (define (build-cont-table fun)
-  (fold-conts (lambda (k cont table)
-                (hashq-set! table k cont)
-                table)
-              (make-hash-table)
-              fun))
-
-(define (build-local-cont-table cont)
-  (fold-local-conts (lambda (k cont table)
-                      (hashq-set! table k cont)
-                      table)
-                    (make-hash-table)
-                    cont))
-
-(define (lookup-cont sym conts)
-  (let ((res (hashq-ref conts sym)))
-    (unless res
-      (error "Unknown continuation!" sym (hash-fold acons '() conts)))
-    res))
+  (let ((max-k (fold-conts (lambda (k cont max-k) (max k max-k))
+                           -1 fun)))
+    (fold-conts (lambda (k cont table)
+                  (vector-set! table k cont)
+                  table)
+                (make-vector (1+ max-k) #f)
+                fun)))
 
 ;; Data-flow graph for CPS: both for values and continuations.
 (define-record-type $dfg
-  (make-dfg conts blocks use-maps)
+  (make-dfg conts preds defs uses scopes scope-levels
+            min-label label-count min-var var-count)
   dfg?
-  ;; hash table of sym -> $kif, $kargs, etc
+  ;; vector of label -> $kif, $kargs, etc
   (conts dfg-cont-table)
-  ;; hash table of sym -> $block
-  (blocks dfg-blocks)
-  ;; hash table of sym -> $use-map
-  (use-maps dfg-use-maps))
-
-(define-record-type $use-map
-  (make-use-map name sym def uses)
-  use-map?
-  (name use-map-name)
-  (sym use-map-sym)
-  (def use-map-def)
-  (uses use-map-uses set-use-map-uses!))
-
-(define-record-type $block
-  (%make-block scope scope-level preds succs)
-  block?
-  (scope block-scope set-block-scope!)
-  (scope-level block-scope-level set-block-scope-level!)
-  (preds block-preds set-block-preds!)
-  (succs block-succs set-block-succs!))
-
-(define (make-block scope scope-level)
-  (%make-block scope scope-level '() '()))
+  ;; vector of label -> (pred-label ...)
+  (preds dfg-preds)
+  ;; vector of var -> def-label
+  (defs dfg-defs)
+  ;; vector of var -> (use-label ...)
+  (uses dfg-uses)
+  ;; vector of label -> label
+  (scopes dfg-scopes)
+  ;; vector of label -> int
+  (scope-levels dfg-scope-levels)
+
+  (min-label dfg-min-label)
+  (label-count dfg-label-count)
+  (min-var dfg-min-var)
+  (var-count dfg-var-count))
 
 ;; Some analyses assume that the only relevant set of nodes is the set
 ;; that is reachable from some start node.  Others need to include nodes
@@ -218,8 +222,7 @@ for quickest convergence."
       (when (< n k-count)
         (for-each (lambda (succ)
                     (vector-push! succs n (cfa-k-idx cfa succ)))
-                  (block-succs (lookup-block (cfa-k-sym cfa n)
-                                             (dfg-blocks dfg))))
+                  (lookup-successors (cfa-k-sym cfa n) dfg))
         (lp (1+ n))))
 
     ;; Iterate cfa backwards, to converge quickly.
@@ -253,7 +256,7 @@ HANDLER-INDEX pairs."
      ((= n (cfa-k-count cfa))
       (reverse prompts))
      (else
-      (match (lookup-cont (cfa-k-sym cfa n) (dfg-cont-table dfg))
+      (match (lookup-cont (cfa-k-sym cfa n) dfg)
         (($ $kargs names syms body)
          (match (find-expression body)
            (($ $prompt escape? tag handler)
@@ -319,8 +322,7 @@ BODY for each body continuation in the prompt."
                  (let ((succ (cfa-k-idx cfa succ)))
                    (or (not (bitvector-ref body succ))
                        (<= succ n))))
-               (block-succs (lookup-block (cfa-k-sym cfa n)
-                                          (dfg-blocks dfg)))))
+               (lookup-successors (cfa-k-sym cfa n) dfg)))
      (let lp ((n 0))
        (let ((n (bit-position #t body n)))
          (when n
@@ -330,19 +332,24 @@ BODY for each body continuation in the prompt."
    (find-prompt-bodies cfa dfg)))
 
 (define* (analyze-control-flow fun dfg #:key reverse? add-handler-preds?)
-  (define (build-cfa kentry block-succs block-preds forward-cfa)
-    (define (block-accessor accessor)
-      (lambda (k)
-        (accessor (lookup-block k (dfg-blocks dfg)))))
-    (define (reachable-preds mapping accessor)
+  (define (build-cfa kentry lookup-succs lookup-preds forward-cfa)
+    (define (reachable-preds mapping)
       ;; It's possible for a predecessor to not be in the mapping, if
       ;; the predecessor is not reachable from the entry node.
       (lambda (k)
-        (filter-map (cut hashq-ref mapping <>)
-                    ((block-accessor accessor) k))))
+        (filter-map (cut hashq-ref mapping <>) (lookup-preds k dfg))))
     (let* ((order (reverse-post-order
                    kentry
-                   (block-accessor block-succs)
+                   (lambda (k)
+                     ;; RPO numbering is going to visit this list of
+                     ;; successors in the order that we give it.  Sort
+                     ;; it so that all things being equal, we preserve
+                     ;; the existing numbering order.  This also has the
+                     ;; effect of preserving clause order.
+                     (let ((succs (lookup-succs k dfg)))
+                       (if (or (null? succs) (null? (cdr succs)))
+                           succs
+                           (sort succs >))))
                    (if forward-cfa
                        (lambda (f seed)
                          (let lp ((n (cfa-k-count forward-cfa)) (seed seed))
@@ -352,8 +359,7 @@ BODY for each body continuation in the prompt."
                                    (f (cfa-k-sym forward-cfa (1- n)) seed)))))
                        (lambda (f seed) seed))))
            (k-map (make-block-mapping order))
-           (preds (convert-predecessors order
-                                        (reachable-preds k-map block-preds)))
+           (preds (convert-predecessors order (reachable-preds k-map)))
            (cfa (make-cfa k-map order preds)))
       (when add-handler-preds?
         ;; Any expression in the prompt body could cause an abort to the
@@ -378,13 +384,12 @@ BODY for each body continuation in the prompt."
   (match fun
     (($ $fun src meta free
         ($ $cont kentry
-           (and entry
-                ($ $kentry self ($ $cont ktail tail) clauses))))
+           (and entry ($ $kentry self ($ $cont ktail tail)))))
      (if reverse?
-         (build-cfa ktail block-preds block-succs
+         (build-cfa ktail lookup-predecessors lookup-successors
                     (analyze-control-flow fun dfg #:reverse? #f
                                           #:add-handler-preds? #f))
-         (build-cfa kentry block-succs block-preds #f)))))
+         (build-cfa kentry lookup-successors lookup-predecessors #f)))))
 
 ;; Dominator analysis.
 (define-record-type $dominator-analysis
@@ -654,16 +659,14 @@ BODY for each body continuation in the prompt."
 
 ;; Data-flow analysis.
 (define-record-type $dfa
-  (make-dfa cfa var-map names syms in out)
+  (make-dfa cfa min-var var-count in out)
   dfa?
   ;; CFA, for its reverse-post-order numbering
   (cfa dfa-cfa)
-  ;; Hash table mapping var-sym -> var-idx
-  (var-map dfa-var-map)
-  ;; Vector of var-idx -> name
-  (names dfa-names)
-  ;; Vector of var-idx -> var-sym
-  (syms dfa-syms)
+  ;; Minimum var in this function.
+  (min-var dfa-min-var)
+  ;; Minimum var in this function.
+  (var-count dfa-var-count)
   ;; Vector of k-idx -> bitvector
   (in dfa-in)
   ;; Vector of k-idx -> bitvector
@@ -679,17 +682,15 @@ BODY for each body continuation in the prompt."
   (cfa-k-count (dfa-cfa dfa)))
 
 (define (dfa-var-idx dfa var)
-  (or (hashq-ref (dfa-var-map dfa) var)
-      (error "unknown var" var)))
-
-(define (dfa-var-name dfa idx)
-  (vector-ref (dfa-names dfa) idx))
+  (let ((idx (- var (dfa-min-var dfa))))
+    (unless (< -1 idx (dfa-var-count dfa))
+      (error "var out of range" var))
+    idx))
 
 (define (dfa-var-sym dfa idx)
-  (vector-ref (dfa-syms dfa) idx))
-
-(define (dfa-var-count dfa)
-  (vector-length (dfa-syms dfa)))
+  (unless (< -1 idx (dfa-var-count dfa))
+    (error "idx out of range" idx))
+  (+ idx (dfa-min-var dfa)))
 
 (define (dfa-k-in dfa idx)
   (vector-ref (dfa-in dfa) idx))
@@ -698,66 +699,61 @@ BODY for each body continuation in the prompt."
   (vector-ref (dfa-out dfa) idx))
 
 (define (compute-live-variables fun dfg)
-  (define (make-variable-mapping use-maps)
-    (let ((mapping (make-hash-table))
-          (n 0))
-      (hash-for-each (lambda (sym use-map)
-                       (hashq-set! mapping sym n)
-                       (set! n (1+ n)))
-                     use-maps)
-      (values mapping n)))
-  (call-with-values (lambda () (make-variable-mapping (dfg-use-maps dfg)))
-    (lambda (var-map nvars)
-      (let* ((cfa (analyze-control-flow fun dfg #:reverse? #t
-                                        #:add-handler-preds? #t))
-             (syms (make-vector nvars #f))
-             (names (make-vector nvars #f))
-             (usev (make-vector (cfa-k-count cfa) '()))
-             (defv (make-vector (cfa-k-count cfa) '()))
-             (live-in (make-vector (cfa-k-count cfa) #f))
-             (live-out (make-vector (cfa-k-count cfa) #f)))
-        ;; Initialize syms, names, defv, and usev.
-        (hash-for-each
-         (lambda (sym use-map)
-           (match use-map
-             (($ $use-map name sym def uses)
-              (let ((v (or (hashq-ref var-map sym)
-                           (error "unknown var" sym))))
-                (vector-set! syms v sym)
-                (vector-set! names v name)
-                (for-each (lambda (def)
-                            (vector-push! defv (cfa-k-idx cfa def) v))
-                          (block-preds (lookup-block def (dfg-blocks dfg))))
-                (for-each (lambda (use)
-                            (vector-push! usev (cfa-k-idx cfa use) v))
-                          uses)))))
-         (dfg-use-maps dfg))
-
-        ;; Initialize live-in and live-out sets.
-        (let lp ((n 0))
-          (when (< n (vector-length live-out))
-            (vector-set! live-in n (make-bitvector nvars #f))
-            (vector-set! live-out n (make-bitvector nvars #f))
-            (lp (1+ n))))
-
-        ;; Liveness is a reverse data-flow problem, so we give
-        ;; compute-maximum-fixed-point a reversed graph, swapping in
-        ;; for out, and usev for defv.  Note that since we are using
-        ;; a reverse CFA, cfa-preds are actually successors, and
-        ;; continuation 0 is ktail.
-        (compute-maximum-fixed-point (cfa-preds cfa)
-                                     live-out live-in defv usev #t)
-
-        (make-dfa cfa var-map names syms live-in live-out)))))
+  (unless (and (= (vector-length (dfg-uses dfg)) (dfg-var-count dfg))
+               (= (vector-length (dfg-cont-table dfg)) (dfg-label-count dfg)))
+    (error "function needs renumbering"))
+  (let* ((min-var (dfg-min-var dfg))
+         (nvars (dfg-var-count dfg))
+         (cfa (analyze-control-flow fun dfg #:reverse? #t
+                                    #:add-handler-preds? #t))
+         (usev (make-vector (cfa-k-count cfa) '()))
+         (defv (make-vector (cfa-k-count cfa) '()))
+         (live-in (make-vector (cfa-k-count cfa) #f))
+         (live-out (make-vector (cfa-k-count cfa) #f)))
+    (define (var->idx var) (- var min-var))
+    (define (idx->var idx) (+ idx min-var))
+
+    ;; Initialize defv and usev.
+    (let ((defs (dfg-defs dfg))
+          (uses (dfg-uses dfg)))
+      (let lp ((n 0))
+        (when (< n (vector-length defs))
+          (let ((def (vector-ref defs n)))
+            (unless def
+              (error "internal error -- var array not packed"))
+            (for-each (lambda (def)
+                        (vector-push! defv (cfa-k-idx cfa def) n))
+                      (lookup-predecessors def dfg))
+            (for-each (lambda (use)
+                        (vector-push! usev (cfa-k-idx cfa use) n))
+                      (vector-ref uses n))
+            (lp (1+ n))))))
+
+    ;; Initialize live-in and live-out sets.
+    (let lp ((n 0))
+      (when (< n (vector-length live-out))
+        (vector-set! live-in n (make-bitvector nvars #f))
+        (vector-set! live-out n (make-bitvector nvars #f))
+        (lp (1+ n))))
+
+    ;; Liveness is a reverse data-flow problem, so we give
+    ;; compute-maximum-fixed-point a reversed graph, swapping in
+    ;; for out, and usev for defv.  Note that since we are using
+    ;; a reverse CFA, cfa-preds are actually successors, and
+    ;; continuation 0 is ktail.
+    (compute-maximum-fixed-point (cfa-preds cfa)
+                                 live-out live-in defv usev #t)
+
+    (make-dfa cfa min-var nvars live-in live-out)))
 
 (define (print-dfa dfa)
   (match dfa
-    (($ $dfa cfa var-map names syms in out)
+    (($ $dfa cfa min-var in out)
      (define (print-var-set bv)
        (let lp ((n 0))
          (let ((n (bit-position #t bv n)))
            (when n
-             (format #t " ~A" (vector-ref syms n))
+             (format #t " ~A" (+ n min-var))
              (lp (1+ n))))))
      (let lp ((n 0))
        (when (< n (cfa-k-count cfa))
@@ -770,35 +766,29 @@ BODY for each body continuation in the prompt."
          (newline)
          (lp (1+ n)))))))
 
-(define (visit-fun fun conts blocks use-maps global?)
-  (define (add-def! name sym def-k)
-    (unless def-k
-      (error "Term outside labelled continuation?"))
-    (hashq-set! use-maps sym (make-use-map name sym def-k '())))
+(define (visit-fun fun conts preds defs uses scopes scope-levels
+                   min-label min-var global?)
+  (define (add-def! var def-k)
+    (vector-set! defs (- var min-var) def-k))
 
-  (define (add-use! sym use-k)
-    (match (hashq-ref use-maps sym)
-      (#f (error "Symbol out of scope?" sym))
-      ((and use-map ($ $use-map name sym def uses))
-       (set-use-map-uses! use-map (cons use-k uses)))))
+  (define (add-use! var use-k)
+    (vector-push! uses (- var min-var) use-k))
 
   (define* (declare-block! label cont parent
                            #:optional (level
-                                       (1+ (lookup-scope-level parent blocks))))
-    (hashq-set! conts label cont)
-    (hashq-set! blocks label (make-block parent level)))
+                                       (1+ (vector-ref
+                                            scope-levels
+                                            (- parent min-label)))))
+    (vector-set! conts (- label min-label) cont)
+    (vector-set! scopes (- label min-label) parent)
+    (vector-set! scope-levels (- label min-label) level))
 
   (define (link-blocks! pred succ)
-    (let ((pred-block (hashq-ref blocks pred))
-          (succ-block (hashq-ref blocks succ)))
-      (unless (and pred-block succ-block)
-        (error "internal error" pred-block succ-block))
-      (set-block-succs! pred-block (cons succ (block-succs pred-block)))
-      (set-block-preds! succ-block (cons pred (block-preds succ-block)))))
+    (vector-push! preds (- succ min-label) pred))
 
   (define (visit exp exp-k)
-    (define (def! name sym)
-      (add-def! name sym exp-k))
+    (define (def! sym)
+      (add-def! sym exp-k))
     (define (use! sym)
       (add-use! sym exp-k))
     (define (use-k! k)
@@ -808,14 +798,14 @@ BODY for each body continuation in the prompt."
     (match exp
       (($ $letk (($ $cont k cont) ...) body)
        ;; Set up recursive environment before visiting cont bodies.
-       (for-each (lambda (cont k)
-                   (declare-block! k cont exp-k))
-                 cont k)
-       (for-each visit cont k)
+       (for-each/2 (lambda (cont k)
+                     (declare-block! k cont exp-k))
+                   cont k)
+       (for-each/2 visit cont k)
        (recur body))
 
       (($ $kargs names syms body)
-       (for-each def! names syms)
+       (for-each def! syms)
        (recur body))
 
       (($ $kif kt kf)
@@ -828,8 +818,11 @@ BODY for each body continuation in the prompt."
       (($ $letrec names syms funs body)
        (unless global?
          (error "$letrec should not be present when building a local DFG"))
-       (for-each def! names syms)
-       (for-each (cut visit-fun <> conts blocks use-maps global?) funs)
+       (for-each def! syms)
+       (for-each
+        (cut visit-fun <> conts preds defs uses scopes scope-levels
+             min-label min-var global?)
+        funs)
        (visit body exp-k))
 
       (($ $continue k src exp)
@@ -855,7 +848,8 @@ BODY for each body continuation in the prompt."
 
          (($ $fun)
           (when global?
-            (visit-fun exp conts blocks use-maps global?)))
+            (visit-fun exp conts preds defs uses scopes scope-levels
+                       min-label min-var global?)))
 
          (_ #f)))))
 
@@ -863,77 +857,123 @@ BODY for each body continuation in the prompt."
     (($ $fun src meta free
         ($ $cont kentry
            (and entry
-                ($ $kentry self ($ $cont ktail tail) clauses))))
+                ($ $kentry self ($ $cont ktail tail) clause))))
      (declare-block! kentry entry #f 0)
-     (add-def! #f self kentry)
+     (add-def! self kentry)
 
      (declare-block! ktail tail kentry)
 
-     (for-each
-      (match-lambda
-       (($ $cont kclause
-           (and clause ($ $kclause arity ($ $cont kbody body))))
-        (declare-block! kclause clause kentry)
-        (link-blocks! kentry kclause)
-
-        (declare-block! kbody body kclause)
-        (link-blocks! kclause kbody)
-
-        (visit body kbody)))
-      clauses))))
+     (let lp ((clause clause))
+       (match clause
+         (#f #t)
+         (($ $cont kclause
+             (and clause ($ $kclause arity ($ $cont kbody body)
+                            alternate)))
+          (declare-block! kclause clause kentry)
+          (link-blocks! kentry kclause)
+
+          (declare-block! kbody body kclause)
+          (link-blocks! kclause kbody)
+
+          (visit body kbody)
+          (lp alternate)))))))
+
+(define (compute-label-and-var-ranges fun global?)
+  (define (min* a b)
+    (if b (min a b) a))
+  (define-syntax-rule (do-fold global?)
+    ((make-cont-folder global?
+                       min-label max-label label-count
+                       min-var max-var var-count)
+     (lambda (label cont
+                    min-label max-label label-count
+                    min-var max-var var-count)
+       (let ((min-label (min* label min-label))
+             (max-label (max label max-label)))
+         (define (visit-letrec body min-var max-var var-count)
+           (match body
+             (($ $letk conts body)
+              (visit-letrec body min-var max-var var-count))
+             (($ $letrec names vars funs body)
+              (visit-letrec body
+                            (cond (min-var (fold min min-var vars))
+                                  ((pair? vars) (fold min (car vars) (cdr vars)))
+                                  (else min-var))
+                            (fold max max-var vars)
+                            (+ var-count (length vars))))
+             (($ $continue) (values min-var max-var var-count))))
+         (match cont
+           (($ $kargs names vars body)
+            (call-with-values
+                (lambda ()
+                  (if global?
+                      (visit-letrec body min-var max-var var-count)
+                      (values min-var max-var var-count)))
+              (lambda (min-var max-var var-count)
+                (values min-label max-label (1+ label-count)
+                        (cond (min-var (fold min min-var vars))
+                              ((pair? vars) (fold min (car vars) (cdr vars)))
+                              (else min-var))
+                        (fold max max-var vars)
+                        (+ var-count (length vars))))))
+           (($ $kentry self)
+            (values min-label max-label (1+ label-count)
+                    (min* self min-var) (max self max-var) (1+ var-count)))
+           (_ (values min-label max-label (1+ label-count)
+                      min-var max-var var-count)))))
+     fun
+     #f -1 0 #f -1 0))
+  (if global?
+      (do-fold #t)
+      (do-fold #f)))
 
 (define* (compute-dfg fun #:key (global? #t))
-  (let* ((conts (make-hash-table))
-         (blocks (make-hash-table))
-         (use-maps (make-hash-table)))
-    (visit-fun fun conts blocks use-maps global?)
-    (make-dfg conts blocks use-maps)))
-
-(define (lookup-block k blocks)
-  (let ((res (hashq-ref blocks k)))
+  (call-with-values (lambda () (compute-label-and-var-ranges fun global?))
+    (lambda (min-label max-label label-count min-var max-var var-count)
+      (when (or (zero? label-count) (zero? var-count))
+        (error "internal error (no vars or labels for fun?)"))
+      (let* ((nlabels (- (1+ max-label) min-label))
+             (nvars (- (1+ max-var) min-var))
+             (conts (make-vector nlabels #f))
+             (preds (make-vector nlabels '()))
+             (defs (make-vector nvars #f))
+             (uses (make-vector nvars '()))
+             (scopes (make-vector nlabels #f))
+             (scope-levels (make-vector nlabels #f)))
+        (visit-fun fun conts preds defs uses scopes scope-levels
+                   min-label min-var global?)
+        (make-dfg conts preds defs uses scopes scope-levels
+                  min-label label-count min-var var-count)))))
+
+(define (lookup-cont label dfg)
+  (let ((res (vector-ref (dfg-cont-table dfg) (- label (dfg-min-label dfg)))))
     (unless res
-      (error "Unknown continuation!" k (hash-fold acons '() blocks)))
+      (error "Unknown continuation!" label))
     res))
 
-(define (lookup-scope-level k blocks)
-  (match (lookup-block k blocks)
-    (($ $block _ scope-level) scope-level)))
+(define (lookup-predecessors k dfg)
+  (vector-ref (dfg-preds dfg) (- k (dfg-min-label dfg))))
 
-(define (lookup-use-map sym use-maps)
-  (let ((res (hashq-ref use-maps sym)))
-    (unless res
-      (error "Unknown lexical!" sym (hash-fold acons '() use-maps)))
-    res))
+(define (lookup-successors k dfg)
+  (let ((cont (vector-ref (dfg-cont-table dfg) (- k (dfg-min-label dfg)))))
+    (visit-cont-successors list cont)))
 
-(define (lookup-def sym dfg)
-  (match dfg
-    (($ $dfg conts blocks use-maps)
-     (match (lookup-use-map sym use-maps)
-       (($ $use-map name sym def uses)
-        def)))))
+(define (lookup-def var dfg)
+  (vector-ref (dfg-defs dfg) (- var (dfg-min-var dfg))))
 
-(define (lookup-uses sym dfg)
-  (match dfg
-    (($ $dfg conts blocks use-maps)
-     (match (lookup-use-map sym use-maps)
-       (($ $use-map name sym def uses)
-        uses)))))
+(define (lookup-uses var dfg)
+  (vector-ref (dfg-uses dfg) (- var (dfg-min-var dfg))))
 
 (define (lookup-block-scope k dfg)
-  (block-scope (lookup-block k (dfg-blocks dfg))))
-
-(define (lookup-predecessors k dfg)
-  (match (lookup-block k (dfg-blocks dfg))
-    (($ $block _ _ preds succs) preds)))
+  (vector-ref (dfg-scopes dfg) (- k (dfg-min-label dfg))))
 
-(define (lookup-successors k dfg)
-  (match (lookup-block k (dfg-blocks dfg))
-    (($ $block _ _ preds succs) succs)))
+(define (lookup-scope-level k dfg)
+  (vector-ref (dfg-scope-levels dfg) (- k (dfg-min-label dfg))))
 
 (define (find-defining-term sym dfg)
   (match (lookup-predecessors (lookup-def sym dfg) dfg)
     ((def-exp-k)
-     (lookup-cont def-exp-k (dfg-cont-table dfg)))
+     (lookup-cont def-exp-k dfg))
     (else #f)))
 
 (define (find-call term)
@@ -975,83 +1015,72 @@ BODY for each body continuation in the prompt."
       (($ $kargs names syms body) (find-exp body))
       (($ $letk conts body) (find-exp body))
       (else term)))
-  (match dfg
-    (($ $dfg conts blocks use-maps)
-     (match (lookup-use-map sym use-maps)
-       (($ $use-map _ _ def uses)
-        (or-map
-         (lambda (use)
-           (match (find-expression (lookup-cont use conts))
-             (($ $call) #f)
-             (($ $callk) #f)
-             (($ $values) #f)
-             (($ $primcall 'free-ref (closure slot))
-              (not (eq? sym slot)))
-             (($ $primcall 'free-set! (closure slot value))
-              (not (eq? sym slot)))
-             (($ $primcall 'cache-current-module! (mod . _))
-              (eq? sym mod))
-             (($ $primcall 'cached-toplevel-box _)
-              #f)
-             (($ $primcall 'cached-module-box _)
-              #f)
-             (($ $primcall 'resolve (name bound?))
-              (eq? sym name))
-             (($ $primcall 'make-vector/immediate (len init))
-              (not (eq? sym len)))
-             (($ $primcall 'vector-ref/immediate (v i))
-              (not (eq? sym i)))
-             (($ $primcall 'vector-set!/immediate (v i x))
-              (not (eq? sym i)))
-             (($ $primcall 'allocate-struct/immediate (vtable nfields))
-              (not (eq? sym nfields)))
-             (($ $primcall 'struct-ref/immediate (s n))
-              (not (eq? sym n)))
-             (($ $primcall 'struct-set!/immediate (s n x))
-              (not (eq? sym n)))
-             (($ $primcall 'builtin-ref (idx))
-              #f)
-             (_ #t)))
-         uses))))))
-
-(define (continuation-scope-contains? scope-k k blocks)
-  (let ((scope-level (lookup-scope-level scope-k blocks)))
+
+  (or-map
+   (lambda (use)
+     (match (find-expression (lookup-cont use dfg))
+       (($ $call) #f)
+       (($ $callk) #f)
+       (($ $values) #f)
+       (($ $primcall 'free-ref (closure slot))
+        (not (eq? sym slot)))
+       (($ $primcall 'free-set! (closure slot value))
+        (not (eq? sym slot)))
+       (($ $primcall 'cache-current-module! (mod . _))
+        (eq? sym mod))
+       (($ $primcall 'cached-toplevel-box _)
+        #f)
+       (($ $primcall 'cached-module-box _)
+        #f)
+       (($ $primcall 'resolve (name bound?))
+        (eq? sym name))
+       (($ $primcall 'make-vector/immediate (len init))
+        (not (eq? sym len)))
+       (($ $primcall 'vector-ref/immediate (v i))
+        (not (eq? sym i)))
+       (($ $primcall 'vector-set!/immediate (v i x))
+        (not (eq? sym i)))
+       (($ $primcall 'allocate-struct/immediate (vtable nfields))
+        (not (eq? sym nfields)))
+       (($ $primcall 'struct-ref/immediate (s n))
+        (not (eq? sym n)))
+       (($ $primcall 'struct-set!/immediate (s n x))
+        (not (eq? sym n)))
+       (($ $primcall 'builtin-ref (idx))
+        #f)
+       (_ #t)))
+   (vector-ref (dfg-uses dfg) (- sym (dfg-min-var dfg)))))
+
+(define (continuation-scope-contains? scope-k k dfg)
+  (let ((scope-level (lookup-scope-level scope-k dfg)))
     (let lp ((k k))
       (or (eq? scope-k k)
-          (match (lookup-block k blocks)
-            (($ $block scope level)
-             (and (< scope-level level)
-                  (lp scope))))))))
+          (and (< scope-level (lookup-scope-level k dfg))
+               (lp (lookup-block-scope k dfg)))))))
 
 (define (continuation-bound-in? k use-k dfg)
-  (match dfg
-    (($ $dfg conts blocks use-maps)
-     (match (lookup-block k blocks)
-       (($ $block def-k)
-        (continuation-scope-contains? def-k use-k blocks))))))
+  (continuation-scope-contains? (lookup-block-scope k dfg) use-k dfg))
 
 (define (variable-free-in? var k dfg)
-  (match dfg
-    (($ $dfg conts blocks use-maps)
-     (or-map (lambda (use)
-               (continuation-scope-contains? k use blocks))
-             (match (lookup-use-map var use-maps)
-               (($ $use-map name sym def uses)
-                uses))))))
+  (or-map (lambda (use)
+            (continuation-scope-contains? k use dfg))
+          (lookup-uses var dfg)))
 
 ;; A continuation is a control point if it has multiple predecessors, or
-;; if its single predecessor has multiple successors.
+;; if its single predecessor does not have a single successor.
 (define (control-point? k dfg)
   (match (lookup-predecessors k dfg)
     ((pred)
-     (match (lookup-successors pred dfg)
-       ((_) #f)
-       (_ #t)))
+     (let ((cont (vector-ref (dfg-cont-table dfg)
+                             (- pred (dfg-min-label dfg)))))
+       (visit-cont-successors (case-lambda
+                                (() #t)
+                                ((succ0) #f)
+                                ((succ1 succ2) #t))
+                              cont)))
     (_ #t)))
 
 (define (lookup-bound-syms k dfg)
-  (match dfg
-    (($ $dfg conts blocks use-maps)
-     (match (lookup-cont k conts)
-       (($ $kargs names syms body)
-        syms)))))
+  (match (lookup-cont k dfg)
+    (($ $kargs names syms body)
+     syms)))