Initial revision
authorChris Hanson <org/chris-hanson/cph>
Tue, 9 Jun 1987 19:56:56 +0000 (19:56 +0000)
committerChris Hanson <org/chris-hanson/cph>
Tue, 9 Jun 1987 19:56:56 +0000 (19:56 +0000)
v7/src/compiler/fgopt/folcon.scm [new file with mode: 0644]
v7/src/compiler/fgopt/outer.scm [new file with mode: 0644]
v7/src/compiler/fgopt/simapp.scm [new file with mode: 0644]
v7/src/compiler/rtlopt/rcse2.scm [new file with mode: 0644]

diff --git a/v7/src/compiler/fgopt/folcon.scm b/v7/src/compiler/fgopt/folcon.scm
new file mode 100644 (file)
index 0000000..fafbed6
--- /dev/null
@@ -0,0 +1,136 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/fgopt/folcon.scm,v 1.1 1987/06/09 19:53:48 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. |#
+
+;;;; Dataflow Analysis: Constant Folding
+
+(declare (usual-integrations))
+\f
+(package (fold-constants)
+
+;;;; Fold constants
+
+(define-export (fold-constants vnodes combinations receiver)
+  (define (loop vnodes combinations)
+    (let ((unknown-vnodes (eliminate-known-nodes vnodes)))
+      (fold-combinations combinations
+       (lambda (any-folded? not-folded)
+         (if any-folded?
+             (loop unknown-vnodes not-folded)
+             (receiver unknown-vnodes not-folded))))))
+  (loop vnodes combinations))
+
+(define (eliminate-known-nodes vnodes)
+  (let ((knowable-nodes
+        (list-transform-positive vnodes
+          (lambda (vnode)
+            (and (not (or (vnode-unknowable? vnode)
+                          ;; Does this really matter?  Seems like it
+                          ;; should be a noop if there is only one
+                          ;; value.
+                          (and (variable? vnode)
+                               (variable-assigned? vnode))))
+                 (let ((procedures (vnode-procedures vnode))
+                       (values (vnode-values vnode)))
+                   (if (null? values)
+                       (and (not (null? procedures))
+                            (null? (cdr procedures)))
+                       (and (null? procedures)
+                            (null? (cdr values))
+                            (let ((value (car values)))
+                              (or (block? value)
+                                  (and (constant? value)
+                                       (object-immutable?
+                                        (constant-value value)))))))))))))
+    (for-each vnode-knowable! knowable-nodes)
+    (transitive-closure delete-if-known! knowable-nodes))
+  ;; **** Could flush KNOWABLE? and UNKNOWABLE? marks at this point.
+  (list-transform-negative vnodes vnode-known?))
+
+(define (delete-if-known! vnode)
+  (if (and (not (vnode-known? vnode))
+          (null? (vnode-backward-links vnode)))
+      (let ((value (car (if (null? (vnode-procedures vnode))
+                           (vnode-values vnode)
+                           (vnode-procedures vnode))))
+           (forward-links (vnode-forward-links vnode)))
+       (vnode-delete! vnode)
+       (for-each (lambda (vnode*)
+                   ;; This is needed because, previously, VNODE*
+                   ;; inherited this value from VNODE.
+                   (vnode-connect! vnode* value)
+                   (if (vnode-knowable? vnode*)
+                       (enqueue-node! vnode*)))
+                 forward-links)
+       (set-vnode-known-value! vnode value))))
+\f
+(define (fold-combinations combinations receiver)
+  (if (null? combinations)
+      (receiver false '())
+      (fold-combinations (cdr combinations)
+       (lambda (any-folded? not-folded)
+         (if (fold-combination (car combinations))
+             (receiver true not-folded)
+             (receiver any-folded? (cons (car combinations) not-folded)))))))
+
+(define (fold-combination combination)
+  (let ((operator (combination-operator combination))
+       (operands (combination-operands combination)))
+    (and (subproblem-known-constant? operator)
+        (all-known-constants? operands)
+        (let ((operator (subproblem-constant-value operator)))
+          (and (operator-constant-foldable? operator)
+               (begin (let ((value
+                             (make-constant
+                              (apply operator
+                                     (map subproblem-constant-value
+                                          operands))))
+                            (cvalue (combination-value combination)))
+                        (vnode-known! cvalue value)
+                        (set-vnode-known-value! cvalue value))
+                      (set-combination-constant?! combination true)
+                      ;; Discard useless information to save space.
+                      (let ((block (combination-block combination)))
+                        (set-block-combinations!
+                         block
+                         (delq! combination (block-combinations block))))
+                      (set-combination-operator! combination false)
+                      (set-combination-operands! combination '())
+                      (set-combination-procedures! combination '())
+                      (set-combination-known-operator! combination false)
+                      true))))))
+
+(define all-known-constants?
+  (for-all? subproblem-known-constant?))
+
+)
\ No newline at end of file
diff --git a/v7/src/compiler/fgopt/outer.scm b/v7/src/compiler/fgopt/outer.scm
new file mode 100644 (file)
index 0000000..d4ea406
--- /dev/null
@@ -0,0 +1,146 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/fgopt/outer.scm,v 1.1 1987/06/09 19:53:18 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. |#
+
+;;;; Dataflow Analysis: Outer Analysis
+
+(declare (usual-integrations))
+\f
+(package (outer-analysis)
+
+;;;; Outer analysis
+
+;;; When this pass is completed, any combination which is known to
+;;; call only known procedures contains all of the procedural
+;;; arguments in its COMBINATION-PROCEDURES slot.  This is taken
+;;; advantage of by the closure analysis.
+
+(define more-unknowable-vnodes?)
+
+(define-export (outer-analysis blocks vnodes combinations procedures
+                              quotations)
+  (fluid-let ((more-unknowable-vnodes? false))
+    (define (loop)
+      (if more-unknowable-vnodes?
+         (begin (set! more-unknowable-vnodes? false)
+                (for-each check-combination combinations)
+                (loop))))
+    (for-each analyze-block blocks)
+    ;; Don't bother to analyze ACCESSes now.
+    (for-each (lambda (vnode)
+               (if (access? vnode) (make-vnode-unknowable! vnode)))
+             vnodes)
+    (for-each (lambda (quotation)
+               (let ((value (quotation-value quotation)))
+                 (if (vnode? value)
+                     (for-each make-procedure-externally-visible!
+                               (vnode-procedures value)))))
+             quotations)
+    (for-each prepare-combination combinations)
+    (loop)))
+
+(define (analyze-block block)
+  (if (ic-block? block)
+      (begin (if (block-outer? block)
+                (for-each make-vnode-externally-visible!
+                          (block-free-variables block)))
+            (for-each make-vnode-externally-visible!
+                      (block-bound-variables block)))))
+\f
+(define (prepare-combination combination)
+  (set-combination-procedures!
+   combination
+   (mapcan (lambda (operand)
+            (list-copy (subproblem-procedures operand)))
+          (combination-operands combination)))
+  (if (not (null? (subproblem-values (combination-operator combination))))
+      (begin (combination-operator-unknowable! combination)
+            (make-vnode-unknowable! (combination-value combination)))))
+
+(define any-primitives?
+  (there-exists? primitive-procedure-constant?))
+
+(define (check-combination combination)
+  (if (subproblem-unknowable? (combination-operator combination))
+      (begin (combination-operator-unknowable! combination)
+            (make-vnode-unknowable! (combination-value combination))))
+  (if (any-unknowable-subproblems? (combination-operands combination))
+      (make-vnode-unknowable! (combination-value combination))))
+
+(define any-unknowable-subproblems?
+  (there-exists? subproblem-unknowable?))
+
+(define (combination-operator-unknowable! combination)
+  (let ((procedures (combination-procedures combination)))
+    (set-combination-procedures! combination '())
+    (for-each make-procedure-externally-visible! procedures)))
+\f
+(define (make-vnode-externally-visible! vnode)
+  (if (not (vnode-externally-visible? vnode))
+      (begin (set! more-unknowable-vnodes? true)
+            (vnode-externally-visible! vnode)
+            (vnode-unknowable! vnode)
+            (make-vnode-forward-links-unknowable! vnode)
+            (for-each make-procedure-externally-visible!
+                      (vnode-procedures vnode)))))
+
+(define (make-procedure-externally-visible! procedure)
+  (if (not (procedure-externally-visible? procedure))
+      (begin (procedure-externally-visible! procedure)
+            (closure-procedure! procedure)
+            (for-each make-vnode-unknowable! (procedure-required procedure))
+            (for-each make-vnode-unknowable! (procedure-optional procedure))
+            (if (procedure-rest procedure)
+                ;; This is not really unknowable -- it is a list
+                ;; whose length and elements are unknowable.
+                (make-vnode-unknowable! (procedure-rest procedure)))
+            (for-each make-procedure-externally-visible!
+                      (rvalue-procedures (procedure-value procedure))))))
+
+(define (make-vnode-unknowable! vnode)
+  (if (not (vnode-unknowable? vnode))
+      (begin (set! more-unknowable-vnodes? true)
+            (vnode-unknowable! vnode)
+            (make-vnode-forward-links-unknowable! vnode))))
+
+(define (make-vnode-forward-links-unknowable! vnode)
+  ;; No recursion is needed here because the graph is transitively
+  ;; closed, and thus the forward links of a node's forward links are
+  ;; a subset of the node's forward links.
+  (for-each (lambda (vnode)
+             (if (not (vnode-unknowable? vnode))
+                 (begin (set! more-unknowable-vnodes? true)
+                        (vnode-unknowable! vnode))))
+           (vnode-forward-links vnode)))
+
+)
\ No newline at end of file
diff --git a/v7/src/compiler/fgopt/simapp.scm b/v7/src/compiler/fgopt/simapp.scm
new file mode 100644 (file)
index 0000000..7079b6b
--- /dev/null
@@ -0,0 +1,144 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/fgopt/simapp.scm,v 1.1 1987/06/09 19:52:58 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. |#
+
+;;;; Dataflow Analysis: Simulate Application
+
+(declare (usual-integrations))
+\f
+(package (simulate-application)
+
+;;;; Simulate Application
+
+(define-export (simulate-application vnodes combinations)
+  (for-each (lambda (vnode)
+             (set-vnode-procedures-cache! vnode
+                                          (vnode-initial-procedures vnode)))
+           vnodes)
+  (for-each (lambda (combination)
+             (set-combination-procedures! combination '()))
+           combinations)
+  (transitive-closure process-combination combinations)
+  (for-each (lambda (vnode)
+             (set-vnode-procedures-cache! vnode 'NOT-CACHED))
+           vnodes))
+\f
+(define (process-combination combination)
+  (set-combination-procedures!
+   combination
+   (let ((operator (subproblem-value (combination-operator combination)))
+        (old (combination-procedures combination))
+        (apply-procedure
+         (procedure-applicator (combination-operands combination)
+                               (combination-value combination))))
+     (define (process-vnode vnode)
+       (let ((new (vnode-procedures-cache vnode)))
+        (define (loop procedures)
+          ;; We can use `eq?' here because we assume that
+          ;; (eq? (list-tail (eq-set-union x y) n) y) for some n.
+          ;; This is also noted at the definition of `eq-set-union'.
+          (if (eq? procedures old)
+              new
+              (begin (apply-procedure (car procedures))
+                     (loop (cdr procedures)))))
+        (loop new)))
+     (cond ((vnode? operator)
+           (process-vnode operator))
+          ((reference? operator)
+           (process-vnode (reference-variable operator)))
+          ((not (null? old))
+           (error "Encountered constant-operator combination twice"
+                  combination))
+          (else
+           (if (procedure? operator)
+               (apply-procedure operator))
+           true)))))
+
+(define (procedure-applicator operands combination-value)
+  (let ((number-supplied (length operands)))
+    (lambda (procedure)
+      (let ((number-required (length (procedure-required procedure)))
+           (number-optional (length (procedure-optional procedure)))
+           (rest (procedure-rest procedure)))
+       (cond ((< number-supplied number-required)
+              (warn "Too few arguments" procedure operands))
+             (rest
+              (if (<= number-supplied (+ number-required number-optional))
+                  ((vnode-connect!:constant (make-constant '())) rest)
+                  ;; Can make this a LIST rvalue when that is implemented.
+                  (vnode-unknowable! rest)))
+             ((> number-supplied (+ number-required number-optional))
+              (warn "Too many arguments" procedure operands))))
+      (for-each vnode-connect!
+               (append (procedure-required procedure)
+                       (procedure-optional procedure))
+               operands)
+      ((vnode-connect!:vnode (procedure-value procedure)) combination-value))))
+\f
+(define-integrable (vnode-connect! vnode operand)
+  ((&vnode-connect! (subproblem-value operand)) vnode))
+
+(define ((vnode-connect!:procedure procedure) vnode)
+  (let ((procedures (vnode-initial-procedures vnode)))
+    (if (not (memq procedure procedures))
+       (set-vnode-initial-procedures! vnode (cons procedure procedures))))
+  (let ((procedures (vnode-procedures-cache vnode)))
+    (if (not (memq procedure procedures))
+       (begin (enqueue-nodes! (vnode-combinations vnode))
+              (set-vnode-procedures-cache! vnode
+                                           (cons procedure procedures))))))
+
+(define (vnode-connect!:vnode from)
+  (define (self to)
+    (if (not (memq from (vnode-backward-links to)))
+       (begin (enqueue-nodes! (vnode-combinations to))
+              (set-vnode-backward-links! to
+                                         (cons from
+                                               (vnode-backward-links to)))
+              (set-vnode-forward-links! from
+                                        (cons to (vnode-forward-links from)))
+              (set-vnode-procedures-cache!
+               to
+               (eq-set-union (vnode-procedures-cache from)
+                             (vnode-procedures-cache to)))
+              (for-each (lambda (backward)
+                          ((vnode-connect!:vnode backward) to))
+                        (vnode-backward-links from))
+              (for-each self (vnode-forward-links to)))))
+  self)
+
+(define &vnode-connect!
+  (standard-rvalue-operation vnode-connect!:constant vnode-connect!:procedure
+                            vnode-connect!:vnode))
+
+)
\ No newline at end of file
diff --git a/v7/src/compiler/rtlopt/rcse2.scm b/v7/src/compiler/rtlopt/rcse2.scm
new file mode 100644 (file)
index 0000000..cd04597
--- /dev/null
@@ -0,0 +1,275 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/compiler/rtlopt/rcse2.scm,v 1.1 1987/06/09 19:56:56 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. |#
+
+;;;; RTL Common Subexpression Elimination
+;;;  Based on the GNU C Compiler
+
+(declare (usual-integrations))
+\f
+;;;; Canonicalization
+
+(define (expression-replace! statement-expression set-statement-expression!
+                            statement receiver)
+  ;; Replace the expression by its cheapest equivalent.  Returns two
+  ;; values: (1) a flag which is true iff the expression is volatile;
+  ;; and (2) a thunk which, when called, will insert the expression in
+  ;; the hash table, returning the element.  Do not call the thunk if
+  ;; the expression is volatile.
+  (let ((expression
+        (expression-canonicalize (statement-expression statement))))
+    (full-expression-hash expression
+      (lambda (hash volatile? in-memory?)
+       (let ((element
+              (find-cheapest-valid-element expression hash volatile?)))
+         (define (finish expression hash volatile? in-memory?)
+           (set-statement-expression! statement expression)
+           (receiver
+            volatile?
+            (expression-inserter expression element hash in-memory?)))
+         (if element
+             (let ((expression (element-expression element)))
+               (full-expression-hash expression
+                 (lambda (hash volatile? in-memory?)
+                   (finish expression hash volatile? in-memory?))))
+             (finish expression hash volatile? in-memory?)))))))
+
+(define ((expression-inserter expression element hash in-memory?))
+  (or element
+      (begin (if (rtl:register? expression)
+                (set-register-expression! (rtl:register-number expression)
+                                          expression)
+                (mention-registers! expression))
+            (let ((element* (hash-table-insert! hash expression false)))
+              (set-element-in-memory?! element* in-memory?)
+              (element-first-value element*)))))
+
+(define (expression-canonicalize expression)
+  (if (rtl:register? expression)
+      (or (register-expression
+          (quantity-first-register
+           (get-register-quantity (rtl:register-number expression))))
+         expression)
+      (rtl:map-subexpressions expression expression-canonicalize)))
+\f
+;;;; Invalidation
+
+(define (non-object-invalidate!)
+  (hash-table-delete-class!
+   (lambda (element)
+     (memq (rtl:expression-type (element-expression element))
+          '(OBJECT->ADDRESS OBJECT->DATUM OBJECT->TYPE)))))
+
+(define (element-address-varies? element)
+  (and (element-in-memory? element)
+       (expression-address-varies? (element-expression element))))
+
+(define (expression-address-varies? expression)
+  (if (memq (rtl:expression-type expression)
+           '(OFFSET PRE-INCREMENT POST-INCREMENT))
+      (let ((expression (rtl:address-register expression)))
+       (not (or (= regnum:regs-pointer (rtl:register-number expression))
+                (= regnum:frame-pointer (rtl:register-number expression)))))
+      (rtl:any-subexpression? expression expression-address-varies?)))
+
+(define (expression-invalidate! expression)
+  ;; Delete any expression which refers to this expression from the
+  ;; table.
+  (if (rtl:register? expression)
+      (register-expression-invalidate! expression)
+      (hash-table-delete-class!
+       (lambda (element)
+        (expression-refers-to? (element-expression element) expression)))))
+
+(define-integrable (stack-pointer-invalidate!)
+  (register-expression-invalidate! (interpreter-stack-pointer)))
+
+(define (register-expression-invalidate! expression)
+  ;; Invalidate a register expression.  These expressions are handled
+  ;; specially for efficiency -- the register is marked invalid but we
+  ;; delay searching the hash table for relevant expressions.
+  (let ((hash (expression-hash expression)))
+    (register-invalidate! (rtl:register-number expression))
+    (hash-table-delete! hash (hash-table-lookup hash expression))))
+
+(define (register-invalidate! register)
+  (let ((next (register-next-equivalent register))
+       (previous (register-previous-equivalent register))
+       (quantity (get-register-quantity register)))
+    (set-register-tick! register (1+ (register-tick register)))
+    (if next
+       (set-register-previous-equivalent! next previous)
+       (set-quantity-last-register! quantity previous))
+    (if previous
+       (set-register-next-equivalent! previous next)
+       (set-quantity-first-register! quantity next))
+    (set-register-quantity! register (new-quantity register))
+    (set-register-next-equivalent! register false)
+    (set-register-previous-equivalent! register false)))
+\f
+;;;; Destination Insertion
+
+(define (insert-register-destination! expression element)
+  ;; Insert EXPRESSION, which should be a register expression, into
+  ;; the hash table as the destination of an assignment.  ELEMENT is
+  ;; the hash table element for the value being assigned to
+  ;; EXPRESSION.
+  (let ((class (element->class element))
+       (register (rtl:register-number expression)))
+    (define (register-equivalence! quantity)
+      (set-register-quantity! register quantity)
+      (let ((last (quantity-last-register quantity)))
+       (if last
+           (begin (set-register-next-equivalent! last register)
+                  (set-register-previous-equivalent! register last))
+           (begin (set-quantity-first-register! quantity register)
+                  (set-quantity-last-register! quantity register))))
+      (set-register-next-equivalent! register false)
+      (set-quantity-last-register! quantity register))
+
+    (set-register-expression! register expression)
+    (if class
+       (let ((expression (element-expression class)))
+         (cond ((rtl:register? expression)
+                (register-equivalence!
+                 (get-register-quantity (rtl:register-number expression)))))))
+    (set-element-in-memory?!
+     (hash-table-insert! (expression-hash expression) expression class)
+     false)))
+
+(define (insert-memory-destination! expression element hash)
+  (let ((class (element->class element)))
+    (mention-registers! expression)
+    (set-element-in-memory?! (hash-table-insert! hash expression class) true)))
+
+(define (mention-registers! expression)
+  (if (rtl:register? expression)
+      (let ((register (rtl:register-number expression)))
+       (remove-invalid-references! register)
+       (set-register-in-table! register (register-tick register)))
+      (rtl:for-each-subexpression expression mention-registers!)))
+
+(define (remove-invalid-references! register)
+  ;; If REGISTER is invalid, delete all expressions which refer to it
+  ;; from the hash table.
+  (if (let ((in-table (register-in-table register)))
+       (and (not (negative? in-table))
+            (not (= in-table (register-tick register)))))
+      (let ((expression (register-expression register)))
+       (hash-table-delete-class!
+        (lambda (element)
+          (let ((expression* (element-expression element)))
+            (and (not (rtl:register? expression*))
+                 (expression-refers-to? expression* expression))))))))
+\f
+;;;; Table Search
+
+(define (find-cheapest-expression expression hash volatile?)
+  ;; Find the cheapest equivalent expression for EXPRESSION.
+  (let ((element (find-cheapest-valid-element expression hash volatile?)))
+    (if element
+       (element-expression element)
+       expression)))
+
+(define (find-cheapest-valid-element expression hash volatile?)
+  ;; Find the cheapest valid hash table element for EXPRESSION.
+  ;; Returns false if no such element exists or if EXPRESSION is
+  ;; VOLATILE?.
+  (and (not volatile?)
+       (let ((element (hash-table-lookup hash expression)))
+        (and element
+             (let ((element* (element-first-value element)))
+               (if (eq? element element*)
+                   element
+                   (let loop ((element element*))
+                     (and element
+                          (let ((expression (element-expression element)))
+                            (if (or (rtl:register? expression)
+                                    (expression-valid? expression))
+                                element
+                                (loop (element-next-value element))))))))))))
+
+(define (expression-valid? expression)
+  ;; True iff all registers mentioned in EXPRESSION have valid values
+  ;; in the hash table.
+  (if (rtl:register? expression)
+      (let ((register (rtl:register-number expression)))
+       (= (register-in-table register) (register-tick register)))
+      (rtl:all-subexpressions? expression expression-valid?)))
+
+(define (element->class element)
+  ;; Return the cheapest element in the hash table which has the same
+  ;; value as ELEMENT.  This is necessary because ELEMENT may have
+  ;; been deleted due to register or memory invalidation.
+  (and element
+       ;; If ELEMENT has been deleted from the hash table,
+       ;; CLASS will be false.  [ref crock-1]
+       (or (element-first-value element)
+          (element->class (element-next-value element)))))
+\f
+;;;; Expression Hash
+
+(define (expression-hash expression)
+  (full-expression-hash expression
+    (lambda (hash do-not-record? hash-arg-in-memory?)
+      hash)))
+
+(define (full-expression-hash expression receiver)
+  (let ((do-not-record? false)
+       (hash-arg-in-memory? false))
+    (define (loop expression)
+      (let ((type (rtl:expression-type expression)))
+       (+ (symbol-hash type)
+          (case type
+            ((REGISTER)
+             (quantity-number
+              (get-register-quantity (rtl:register-number expression))))
+            ((OFFSET)
+             (set! hash-arg-in-memory? true)
+             (continue expression))
+            ((PRE-INCREMENT POST-INCREMENT)
+             (set! hash-arg-in-memory? true)
+             (set! do-not-record? true)
+             0)
+            (else (continue expression))))))
+
+    (define (continue expression)
+      (rtl:reduce-subparts expression + 0 loop
+       (lambda (object)
+         (cond ((integer? object) object)
+               ((symbol? object) (symbol-hash object))
+               ((string? object) (string-hash object))
+               (else (hash object))))))
+
+    (let ((hash (loop expression)))
+      (receiver (modulo hash n-buckets) do-not-record? hash-arg-in-memory?))))
\ No newline at end of file