Initial revision
authorChris Hanson <org/chris-hanson/cph>
Sat, 13 Jun 1987 21:18:20 +0000 (21:18 +0000)
committerChris Hanson <org/chris-hanson/cph>
Sat, 13 Jun 1987 21:18:20 +0000 (21:18 +0000)
v7/src/compiler/back/lapgn2.scm [new file with mode: 0644]
v7/src/compiler/back/lapgn3.scm [new file with mode: 0644]
v7/src/compiler/base/cfg2.scm [new file with mode: 0644]
v7/src/compiler/base/cfg3.scm [new file with mode: 0644]

diff --git a/v7/src/compiler/back/lapgn2.scm b/v7/src/compiler/back/lapgn2.scm
new file mode 100644 (file)
index 0000000..2f6fa7f
--- /dev/null
@@ -0,0 +1,207 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/back/lapgn2.scm,v 1.1 1987/06/13 21:18:05 cph Exp $
+
+Copyright (c) 1987 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. |#
+
+;;;; LAP Generator
+
+(declare (usual-integrations))
+\f
+(define *register-map*)
+(define *prefix-instructions*)
+(define *needed-registers*)
+
+(define-integrable (prefix-instructions! instructions)
+  (set! *prefix-instructions* (append! *prefix-instructions* instructions)))
+
+(define-integrable (need-register! register)
+  (set! *needed-registers* (cons register *needed-registers*)))
+
+(define-integrable (need-registers! registers)
+  ;; **** Assume EQ? works on registers here. ****
+  (set! *needed-registers* (eq-set-union registers *needed-registers*)))
+
+(define (maybe-need-register! register)
+  (if register (need-register! register))
+  register)
+
+(define (register-has-alias? register type)
+  (if (machine-register? register)
+      (register-type? register type)
+      (pseudo-register-alias *register-map* type register)))
+
+(define-integrable (register-alias register type)
+  (maybe-need-register! (pseudo-register-alias *register-map* type register)))
+
+(define-integrable (register-alias-alternate register type)
+  (maybe-need-register! (machine-register-alias *register-map* type register)))
+
+(define-integrable (register-type? register type)
+  (or (not type)
+      (eq? (register-type register) type)))
+
+(define ((register-type-predicate type) register)
+  (register-type? register type))
+
+(define-integrable (dead-register? register)
+  (memv register *dead-registers*))
+\f
+(define (guarantee-machine-register! register type)
+  (if (and (machine-register? register)
+          (register-type? register type))
+      register
+      (load-alias-register! register type)))
+
+(define (load-alias-register! register type)
+  (bind-allocator-values (load-alias-register *register-map* type
+                                             *needed-registers* register)
+    store-allocator-values!))
+
+(define (allocate-alias-register! register type)
+  (bind-allocator-values (allocate-alias-register *register-map* type
+                                                 *needed-registers* register)
+    (lambda (alias map instructions)
+      (store-allocator-values! alias
+                              (delete-other-locations map alias)
+                              instructions))))
+
+(define (allocate-assignment-alias! target type)
+  (let ((target (allocate-alias-register! target type)))
+    (delete-dead-registers!)
+    target))
+
+(define (allocate-temporary-register! type)
+  (bind-allocator-values (allocate-temporary-register *register-map* type
+                                                     *needed-registers*)
+    store-allocator-values!))
+
+(define (store-allocator-values! alias map instructions)
+  (need-register! alias)
+  (set! *register-map* map)
+  (prefix-instructions! instructions)
+  alias)
+
+(define-integrable (reference-alias-register! register type)
+  (register-reference (allocate-alias-register! register type)))
+
+(define-integrable (reference-assignment-alias! register type)
+  (register-reference (allocate-assignment-alias! register type)))
+
+(define-integrable (reference-temporary-register! type)
+  (register-reference (allocate-temporary-register! type)))
+\f
+(define (move-to-alias-register! source type target)
+  (reuse-pseudo-register-alias! source type
+    (lambda (reusable-alias)
+      (add-pseudo-register-alias! target reusable-alias false))
+    (lambda ()
+      (allocate-alias-register! target type))))
+
+(define (move-to-temporary-register! source type)
+  (reuse-pseudo-register-alias! source type
+    need-register!
+    (lambda ()
+      (allocate-temporary-register! type))))
+
+(define (reuse-pseudo-register-alias! source type if-reusable if-not)
+  ;; IF-NOT is assumed to return a machine register.
+  (let ((reusable-alias
+        (and (dead-register? source)
+             (register-alias source type))))
+    (if reusable-alias
+       (begin (delete-dead-registers!)
+              (if-reusable reusable-alias)
+              (register-reference reusable-alias))
+       (let ((alias (if (machine-register? source)
+                        source
+                        (register-alias source false))))
+         (delete-dead-registers!)
+         (let ((target (if-not)))
+           (prefix-instructions!
+           (cond ((not alias) (home->register-transfer source target))
+                 ((= alias target) '())
+                 (else (register->register-transfer alias target))))
+           (register-reference target))))))
+\f
+(define (add-pseudo-register-alias! register alias saved-into-home?)
+  (set! *register-map*
+       (add-pseudo-register-alias *register-map* register alias
+                                  saved-into-home?))
+  (need-register! alias))
+
+(define (clear-map!)
+  (delete-dead-registers!)
+  (let ((instructions (clear-map)))
+    (set! *register-map* (empty-register-map))
+    (set! *needed-registers* '())
+    instructions))
+
+(define-integrable (clear-map)
+  (clear-map-instructions *register-map*))
+
+(define (clear-registers! . registers)
+  (if (null? registers)
+      '()
+      (let loop ((map *register-map*) (registers registers))
+       (save-machine-register map (car registers)
+         (lambda (map instructions)
+           (let ((map (delete-machine-register map (car registers))))
+             (if (null? (cdr registers))
+                 (begin (set! *register-map* map)
+                        instructions)
+                 (append! instructions (loop map (cdr registers))))))))))
+
+(define (save-machine-register! register)
+  (let ((contents (machine-register-contents *register-map* register)))
+    (if contents
+       (save-pseudo-register! contents))))
+
+(define (save-pseudo-register! register)
+  (if (not (dead-register? register))
+      (save-pseudo-register *register-map* register
+       (lambda (map instructions)
+         (set! *register-map* map)
+         (prefix-instructions! instructions)))))
+
+(define (delete-machine-register! register)
+  (set! *register-map* (delete-machine-register *register-map* register))
+  (set! *needed-registers* (eqv-set-delete *needed-registers* register)))
+
+(package (delete-pseudo-register! delete-dead-registers!)
+  (define-export (delete-pseudo-register! register)
+    (delete-pseudo-register *register-map* register delete-registers!))
+  (define-export (delete-dead-registers!)
+    (delete-pseudo-registers *register-map* *dead-registers* delete-registers!)
+    (set! *dead-registers* '()))
+  (define (delete-registers! map aliases)
+    (set! *register-map* map)
+    (set! *needed-registers* (eqv-set-difference *needed-registers* aliases))))
\ No newline at end of file
diff --git a/v7/src/compiler/back/lapgn3.scm b/v7/src/compiler/back/lapgn3.scm
new file mode 100644 (file)
index 0000000..4b8b38e
--- /dev/null
@@ -0,0 +1,142 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/back/lapgn3.scm,v 1.1 1987/06/13 21:18:20 cph Exp $
+
+Copyright (c) 1987 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. |#
+
+;;;; LAP Generator
+
+(declare (usual-integrations))
+\f
+;;;; Constants
+
+(define *next-constant*)
+(define *interned-constants*)
+(define *interned-variables*)
+(define *interned-uuo-links*)
+
+(define (allocate-constant-label)
+  (let ((label
+        (string->symbol
+         (string-append "CONSTANT-" (write-to-string *next-constant*)))))
+    (set! *next-constant* (1+ *next-constant*))
+    label))
+
+(define (constant->label constant)
+  (let ((entry (assv constant *interned-constants*)))
+    (if entry
+       (cdr entry)
+       (let ((label (allocate-constant-label)))
+         (set! *interned-constants*
+               (cons (cons constant label)
+                     *interned-constants*))
+         label))))
+
+(define (free-reference-label name)
+  (let ((entry (assq name *interned-variables*)))
+    (if entry
+       (cdr entry)
+       (let ((label (allocate-constant-label)))
+         (set! *interned-variables*
+               (cons (cons name label)
+                     *interned-variables*))
+         label))))
+
+(define (free-uuo-link-label name)
+  (let ((entry (assq name *interned-uuo-links*)))
+    (if entry
+       (cdr entry)
+       (let ((label (allocate-constant-label)))
+         (set! *interned-uuo-links*
+               (cons (cons name label)
+                     *interned-uuo-links*))
+         label))))
+
+(define-integrable (set-current-branches! consequent alternative)
+  (set-rtl-pnode-consequent-lap-generator! *current-rnode* consequent)
+  (set-rtl-pnode-alternative-lap-generator! *current-rnode* alternative))
+\f
+;;;; Frame Pointer
+
+(define *frame-pointer-offset*)
+
+(define (disable-frame-pointer-offset! instructions)
+  (set! *frame-pointer-offset* false)
+  instructions)
+
+(define (enable-frame-pointer-offset! offset)
+  (if (not offset) (error "Null frame-pointer offset"))
+  (set! *frame-pointer-offset* offset))
+
+(define (record-push! instructions)
+  (if *frame-pointer-offset*
+      (set! *frame-pointer-offset* (1+ *frame-pointer-offset*)))
+  instructions)
+
+(define (record-pop!)
+  (if *frame-pointer-offset*
+      (set! *frame-pointer-offset* (-1+ *frame-pointer-offset*))))
+
+(define (decrement-frame-pointer-offset! n instructions)
+  (if *frame-pointer-offset*
+      (set! *frame-pointer-offset*
+           (and (<= n *frame-pointer-offset*) (- *frame-pointer-offset* n))))
+  instructions)
+
+(define (guarantee-frame-pointer-offset!)
+  (if (not *frame-pointer-offset*) (error "Frame pointer not initialized")))
+
+(define (increment-frame-pointer-offset! n instructions)
+  (guarantee-frame-pointer-offset!)
+  (set! *frame-pointer-offset* (+ *frame-pointer-offset* n))
+  instructions)
+
+(define (frame-pointer-offset)
+  (guarantee-frame-pointer-offset!)
+  *frame-pointer-offset*)
+
+(define (record-continuation-frame-pointer-offset! label)
+  (let ((continuation (label->continuation label)))
+    (guarantee-frame-pointer-offset!)
+    (if (continuation-frame-pointer-offset continuation)
+       (if (not (= (continuation-frame-pointer-offset continuation)
+                   *frame-pointer-offset*))
+           (error "Continuation frame-pointer offset mismatch" continuation
+                  *frame-pointer-offset*))
+       (set-continuation-frame-pointer-offset! continuation
+                                               *frame-pointer-offset*))
+    (enqueue! *continuation-queue* continuation)))
+
+(define (record-rnode-frame-pointer-offset! rnode offset)
+  (if (rnode-frame-pointer-offset rnode)
+      (if (not (and offset (= (rnode-frame-pointer-offset rnode) offset)))
+         (error "RNode frame-pointer offset mismatch" rnode offset))
+      (set-rnode-frame-pointer-offset! rnode offset)))
\ No newline at end of file
diff --git a/v7/src/compiler/base/cfg2.scm b/v7/src/compiler/base/cfg2.scm
new file mode 100644 (file)
index 0000000..0b34b47
--- /dev/null
@@ -0,0 +1,205 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/base/cfg2.scm,v 1.1 1987/06/13 21:16:51 cph Exp $
+
+Copyright (c) 1987 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. |#
+
+;;;; Control Flow Graph Abstraction
+
+(declare (usual-integrations))
+\f
+;;;; Editing
+
+;;; BBlock information is preserved only for deletions.  Doing the
+;;; same for insertions is more difficult and not currently needed.
+
+(define (snode-delete! snode)
+  (let ((bblock (node-bblock snode)))
+    (if (and bblock
+            (eq? snode (bblock-exit bblock))
+            (not (eq? snode (bblock-entry bblock))))
+       (set-bblock-exit! bblock (node-previous-first snode))))
+  (let ((previous-edges (node-previous-edges snode))
+       (next-edge (snode-next-edge snode)))
+    (let ((node (edge-right-node next-edge)))
+      (edges-disconnect-right! previous-edges)
+      (edge-disconnect! next-edge)
+      (edges-connect-right! previous-edges node))))
+
+(define (edge-insert-snode! edge snode)
+  (let ((next (edge-right-node edge)))
+    (edge-disconnect-right! edge)
+    (edge-connect-right! edge snode)
+    (create-edge! snode set-snode-next-edge! next)))
+
+(define (node-insert-snode! node snode)
+  (let ((previous-edges (node-previous-edges node)))
+    (edges-disconnect-right! previous-edges)
+    (edges-connect-right! previous-edges snode)
+    (create-edge! snode set-snode-next-edge! node)))
+
+(define (node->edge node)
+  (let ((edge (make-edge false false false)))
+    (edge-connect-right! edge node)
+    edge))
+
+(define-integrable (cfg-entry-edge cfg)
+  (node->edge (cfg-entry-node cfg)))\f
+;;;; Previous Connections
+
+(define-integrable (node-previous=0? node)
+  (edges=0? (node-previous-edges node)))
+
+(define (edges=0? edges)
+  (cond ((null? edges) true)
+       ((edge-left-node (car edges)) false)
+       (else (edges=0? (cdr edges)))))
+
+(define-integrable (node-previous>0? node)
+  (edges>0? (node-previous-edges node)))
+
+(define (edges>0? edges)
+  (cond ((null? edges) false)
+       ((edge-left-node (car edges)) true)
+       (else (edges>0? (cdr edges)))))
+
+(define-integrable (node-previous=1? node)
+  (edges=1? (node-previous-edges node)))
+
+(define (edges=1? edges)
+  (if (null? edges)
+      false
+      ((if (edge-left-node (car edges)) edges=0? edges=1?) (cdr edges))))
+
+(define-integrable (node-previous>1? node)
+  (edges>1? (node-previous-edges node)))
+
+(define (edges>1? edges)
+  (if (null? edges)
+      false
+      ((if (edge-left-node (car edges)) edges>0? edges>1?) (cdr edges))))
+
+(define-integrable (node-previous-first node)
+  (edges-first-node (node-previous-edges node)))
+
+(define (edges-first-node edges)
+  (if (null? edges)
+      (error "No first hook")
+      (or (edge-left-node (car edges))
+         (edges-first-node (cdr edges)))))
+
+(define (for-each-previous-node node procedure)
+  (for-each (lambda (edge)
+             (let ((node (edge-left-node edge)))
+               (if node
+                   (procedure node))))
+           (node-previous-edges node)))
+\f
+;;;; Noops
+
+(define noop-node-tag (make-vector-tag snode-tag 'NOOP))
+(define *noop-nodes*)
+
+(define-integrable (make-noop-node)
+  (let ((node (make-snode noop-node-tag)))
+    (set! *noop-nodes* (cons node *noop-nodes*))
+    node))
+
+(define (delete-noop-nodes!)
+  (for-each snode-delete! *noop-nodes*)
+  (set! *noop-nodes* '()))
+
+(define (constant->pcfg value)
+  ((if value make-true-pcfg make-false-pcfg)))
+
+(define (make-false-pcfg)
+  (let ((node (make-noop-node)))
+    (make-pcfg node
+              '()
+              (list (make-hook node set-snode-next-edge!)))))
+
+(define (make-true-pcfg)
+  (let ((node (make-noop-node)))
+    (make-pcfg node
+              (list (make-hook node set-snode-next-edge!))
+              '())))
+\f
+;;;; Miscellaneous
+
+(package (with-new-node-marks
+         node-marked?
+         node-mark!)
+
+(define *generation*)
+
+(define-export (with-new-node-marks thunk)
+  (fluid-let ((*generation* (make-generation)))
+    (thunk)))
+
+(define make-generation
+  (let ((generation 0))
+    (named-lambda (make-generation)
+      (let ((value generation))
+       (set! generation (1+ generation))
+       value))))
+
+(define-export (node-marked? node)
+  (eq? (node-generation node) *generation*))
+
+(define-export (node-mark! node)
+  (set-node-generation! node *generation*))
+
+)
+
+(define (node-property-get node key)
+  (let ((entry (assq key (node-alist node))))
+    (and entry (cdr entry))))
+
+(define (node-property-put! node key item)
+  (let ((entry (assq key (node-alist node))))
+    (if entry
+       (set-cdr! entry item)
+       (set-node-alist! node (cons (cons key item) (node-alist node))))))
+
+(define (node-property-remove! node key)
+  (set-node-alist! node (del-assq! key (node-alist node))))
+
+(define (node-label node)
+  (or (node-labelled? node)
+      (let ((label (generate-label)))
+       (set-node-label! node label)
+       label)))
+
+(define-integrable (node-labelled? node)
+  (node-property-get node node-label))
+
+(define-integrable (set-node-label! node label)
+  (node-property-put! node node-label label))
\ No newline at end of file
diff --git a/v7/src/compiler/base/cfg3.scm b/v7/src/compiler/base/cfg3.scm
new file mode 100644 (file)
index 0000000..617c35f
--- /dev/null
@@ -0,0 +1,318 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/base/cfg3.scm,v 1.1 1987/06/13 21:16:37 cph Exp $
+
+Copyright (c) 1987 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. |#
+
+;;;; Control Flow Graph Abstraction
+
+(declare (usual-integrations))
+\f
+;;;; CFG Datatypes
+
+;;; A CFG is a compound CFG-node, so there are different types of CFG
+;;; corresponding to the (connective-wise) different types of
+;;; CFG-node.  One may insert a particular type of CFG anywhere in a
+;;; graph that its corresponding node may be inserted.
+
+(define-integrable (make-scfg node next-hooks)
+  (vector 'SNODE-CFG node next-hooks))
+
+(define-integrable (make-scfg* node consequent-hooks alternative-hooks)
+  (make-scfg node (hooks-union consequent-hooks alternative-hooks)))
+
+(define-integrable (make-pcfg node consequent-hooks alternative-hooks)
+  (vector 'PNODE-CFG node consequent-hooks alternative-hooks))
+
+(define-integrable (cfg-tag cfg)
+  (vector-ref cfg 0))
+
+(define-integrable (cfg-entry-node cfg)
+  (vector-ref cfg 1))
+
+(define-integrable (scfg-next-hooks scfg)
+  (vector-ref scfg 2))
+
+(define-integrable (pcfg-consequent-hooks pcfg)
+  (vector-ref pcfg 2))
+
+(define-integrable (pcfg-alternative-hooks pcfg)
+  (vector-ref pcfg 3))
+
+(define-integrable (make-null-cfg) false)
+(define-integrable cfg-null? false?)
+(define-integrable (snode->scfg snode)
+  (node->scfg snode set-snode-next-edge!))
+
+(define (node->scfg node set-node-next!)
+  (make-scfg node
+            (list (make-hook node set-node-next!))))
+
+(define-integrable (pnode->pcfg pnode)
+  (node->pcfg pnode
+             set-pnode-consequent-edge!
+             set-pnode-alternative-edge!))
+
+(define (node->pcfg node set-node-consequent! set-node-alternative!)
+  (make-pcfg node
+            (list (make-hook node set-node-consequent!))
+            (list (make-hook node set-node-alternative!))))
+\f
+;;;; Hook Datatype
+
+(define-integrable make-hook cons)
+(define-integrable hook-node car)
+(define-integrable hook-connect cdr)
+
+(define (hook=? x y)
+  (and (eq? (hook-node x) (hook-node y))
+       (eq? (hook-connect x) (hook-connect y))))
+
+(define hook-member?
+  (member-procedure hook=?))
+
+(define (hooks-union x y)
+  (let loop ((x x))
+    (cond ((null? x) y)
+         ((hook-member? (car x) y) (loop (cdr x)))
+         (else (cons (car x) (loop (cdr x)))))))
+
+(define (hooks-connect! hooks node)
+  (for-each (lambda (hook)
+             (hook-connect! hook node))
+           hooks))
+
+(define (hook-connect! hook node)
+  (create-edge! (hook-node hook) (hook-connect hook) node))
+
+(define (scfg*node->node! scfg next-node)
+  (if (cfg-null? scfg)
+      next-node
+      (begin (if next-node
+                (hooks-connect! (scfg-next-hooks scfg) next-node))
+            (cfg-entry-node scfg))))
+
+(define (pcfg*node->node! pcfg consequent-node alternative-node)
+  (if (cfg-null? pcfg)
+      (error "PCFG*NODE->NODE!: Can't have null predicate"))
+  (if consequent-node
+      (hooks-connect! (pcfg-consequent-hooks pcfg) consequent-node))
+  (if alternative-node
+      (hooks-connect! (pcfg-alternative-hooks pcfg) alternative-node))
+  (cfg-entry-node pcfg))
+\f
+;;;; CFG Construction
+
+(define-integrable (scfg-next-connect! scfg cfg)
+  (hooks-connect! (scfg-next-hooks scfg) (cfg-entry-node cfg)))
+
+(define-integrable (pcfg-consequent-connect! pcfg cfg)
+  (hooks-connect! (pcfg-consequent-hooks pcfg) (cfg-entry-node cfg)))
+
+(define-integrable (pcfg-alternative-connect! pcfg cfg)
+  (hooks-connect! (pcfg-alternative-hooks pcfg) (cfg-entry-node cfg)))
+
+(define (scfg*scfg->scfg! scfg scfg*)
+  (cond ((not scfg) scfg*)
+       ((not scfg*) scfg)
+       (else
+        (scfg-next-connect! scfg scfg*)
+        (make-scfg (cfg-entry-node scfg) (scfg-next-hooks scfg*)))))
+
+(define (scfg-append! . scfgs)
+  (scfg*->scfg! scfgs))
+
+(define scfg*->scfg!
+  (let ()
+    (define (loop first second rest)
+      (scfg-next-connect! first second)
+      (if (null? rest)
+         second
+         (loop second (car rest) (find-non-null (cdr rest)))))
+
+    (define (find-non-null scfgs)
+      (if (or (null? scfgs)
+             (car scfgs))
+         scfgs
+         (find-non-null (cdr scfgs))))
+
+    (named-lambda (scfg*->scfg! scfgs)
+      (let ((first (find-non-null scfgs)))
+       (and (not (null? first))
+            (let ((second (find-non-null (cdr first))))
+              (if (null? second)
+                  (car first)
+                  (make-scfg (cfg-entry-node (car first))
+                             (scfg-next-hooks
+                              (loop (car first)
+                                    (car second)
+                                    (find-non-null (cdr second))))))))))))
+\f
+(define (pcfg->scfg! pcfg)
+  (make-scfg* (cfg-entry-node pcfg)
+             (pcfg-consequent-hooks pcfg)
+             (pcfg-alternative-hooks pcfg)))
+
+(package (scfg*pcfg->pcfg! scfg*pcfg->scfg!)
+
+(define ((scfg*pcfg->cfg! transformer constructor) scfg pcfg)
+  (cond ((not pcfg) (error "SCFG*PCFG->CFG!: Can't have null predicate"))
+       ((not scfg) (transformer pcfg))
+       (else
+        (scfg-next-connect! scfg pcfg)
+        (constructor (cfg-entry-node scfg)
+                     (pcfg-consequent-hooks pcfg)
+                     (pcfg-alternative-hooks pcfg)))))
+
+(define scfg*pcfg->pcfg!
+  (scfg*pcfg->cfg! identity-procedure make-pcfg))
+
+(define scfg*pcfg->scfg!
+  (scfg*pcfg->cfg! pcfg->scfg! make-scfg*))
+
+)
+
+(package (pcfg*scfg->pcfg! pcfg*scfg->scfg!)
+
+(define ((pcfg*scfg->cfg! transformer constructor) pcfg consequent alternative)
+  (cond ((not pcfg) (error "PCFG*SCFG->CFG!: Can't have null predicate"))
+       ((not consequent)
+        (if (not alternative)
+            (transformer pcfg)
+            (begin (pcfg-alternative-connect! pcfg alternative)
+                   (constructor (cfg-entry-node pcfg)
+                                (pcfg-consequent-hooks pcfg)
+                                (scfg-next-hooks alternative)))))
+       ((not alternative)
+        (pcfg-consequent-connect! pcfg consequent)
+        (constructor (cfg-entry-node pcfg)
+                     (scfg-next-hooks consequent)
+                     (pcfg-alternative-hooks pcfg)))
+       (else
+        (pcfg-consequent-connect! pcfg consequent)
+        (pcfg-alternative-connect! pcfg alternative)
+        (constructor (cfg-entry-node pcfg)
+                     (scfg-next-hooks consequent)
+                     (scfg-next-hooks alternative)))))
+
+(define pcfg*scfg->pcfg!
+  (pcfg*scfg->cfg! identity-procedure make-pcfg))
+
+(define pcfg*scfg->scfg!
+  (pcfg*scfg->cfg! pcfg->scfg! make-scfg*))
+
+)
+\f
+(package (pcfg*pcfg->pcfg! pcfg*pcfg->scfg!)
+
+(define ((pcfg*pcfg->cfg! transformer constructor) pcfg consequent alternative)
+  (cond ((not pcfg)
+        (error "PCFG*PCFG->CFG!: Can't have null predicate"))
+       ((not consequent)
+        (if (not alternative)
+            (transformer pcfg)
+            (begin (pcfg-alternative-connect! pcfg alternative)
+                   (constructor
+                    (cfg-entry-node pcfg)
+                    (hooks-union (pcfg-consequent-hooks pcfg)
+                                 (pcfg-consequent-hooks alternative))
+                    (pcfg-alternative-hooks alternative)))))
+       ((not alternative)
+        (pcfg-consequent-connect! pcfg consequent)
+        (constructor (cfg-entry-node pcfg)
+                     (pcfg-consequent-hooks consequent)
+                     (hooks-union (pcfg-alternative-hooks consequent)
+                                  (pcfg-alternative-hooks pcfg))))
+       (else
+        (pcfg-consequent-connect! pcfg consequent)
+        (pcfg-alternative-connect! pcfg alternative)
+        (constructor (cfg-entry-node pcfg)
+                     (hooks-union (pcfg-consequent-hooks consequent)
+                                  (pcfg-consequent-hooks alternative))
+                     (hooks-union (pcfg-alternative-hooks consequent)
+                                  (pcfg-alternative-hooks alternative))))))
+
+(define pcfg*pcfg->pcfg!
+  (pcfg*pcfg->cfg! identity-procedure make-pcfg))
+
+(define pcfg*pcfg->scfg!
+  (pcfg*pcfg->cfg! pcfg->scfg! make-scfg*))
+
+)
+\f
+(define (scfg*cfg->cfg! scfg cfg)
+  (if (not scfg)
+      cfg
+      (begin (scfg-next-connect! scfg cfg)
+            (case (cfg-tag cfg)
+              ((SNODE-CFG)
+               (make-scfg (cfg-entry-node scfg) (scfg-next-hooks cfg)))
+              ((PNODE-CFG)
+               (make-pcfg (cfg-entry-node scfg)
+                          (pcfg-consequent-hooks cfg)
+                          (pcfg-alternative-hooks cfg)))
+              (else
+               (error "Unknown CFG tag" cfg))))))
+
+(define (pcfg*cfg->pcfg! pcfg consequent alternative)
+  (pcfg-consequent-connect! pcfg consequent)
+  (pcfg-alternative-connect! pcfg alternative)
+  (case (cfg-tag consequent)
+    ((SNODE-CFG)
+     (case (cfg-tag alternative)
+       ((SNODE-CFG)
+       (make-pcfg (cfg-entry-node pcfg)
+                  (scfg-next-hooks consequent)
+                  (scfg-next-hooks alternative)))
+       ((PNODE-CFG)
+       (make-pcfg (cfg-entry-node pcfg)
+                  (hooks-union (scfg-next-hooks consequent)
+                               (pcfg-consequent-hooks alternative))
+                  (pcfg-alternative-hooks alternative)))
+       (else
+       (error "Unknown CFG tag" alternative))))
+    ((PNODE-CFG)
+     (case (cfg-tag alternative)
+       ((SNODE-CFG)
+       (make-pcfg (cfg-entry-node pcfg)
+                  (pcfg-consequent-hooks consequent)
+                  (hooks-union (pcfg-alternative-hooks consequent)
+                               (scfg-next-hooks alternative))))
+       ((PNODE-CFG)
+       (make-pcfg (cfg-entry-node pcfg)
+                  (hooks-union (pcfg-consequent-hooks consequent)
+                               (pcfg-consequent-hooks alternative))
+                  (hooks-union (pcfg-alternative-hooks consequent)
+                               (pcfg-alternative-hooks alternative))))
+       (else
+       (error "Unknown CFG tag" alternative))))
+    (else
+     (error "Unknown CFG tag" consequent))))
\ No newline at end of file