Initial revision
authorStephen Adams <edu/mit/csail/zurich/adams>
Wed, 1 Mar 1995 14:02:52 +0000 (14:02 +0000)
committerStephen Adams <edu/mit/csail/zurich/adams>
Wed, 1 Mar 1995 14:02:52 +0000 (14:02 +0000)
v8/src/compiler/midend/ea2.scm [new file with mode: 0644]

diff --git a/v8/src/compiler/midend/ea2.scm b/v8/src/compiler/midend/ea2.scm
new file mode 100644 (file)
index 0000000..5064dc6
--- /dev/null
@@ -0,0 +1,1061 @@
+#| -*-Scheme-*-
+
+$Id: ea2.scm,v 1.1 1995/03/01 14:02:52 adams Exp $
+
+Copyright (c) 1995 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. |#
+
+;;;; Early generic arithmetic rewrite
+;;; package: (compiler midend)
+
+(declare (usual-integrations))
+\f
+
+;; Affects how careful we are to maintain exactness:
+(define *earlyrew/maximize-exactness?* #T)
+
+
+(define (earlyrew/top-level program)
+  ;; 1. Copy the program, doing some expansions and constant folding
+  ;; 2. Figure out some types and do some rewrites based on that
+  (let ((copy (earlyrew/expr program)))
+    (earlyrew/typeinf copy)
+    copy))
+
+(define-macro (define-early-rewriter keyword bindings . body)
+  (let ((proc-name (symbol-append 'EARLYREW/ keyword)))
+    (call-with-values
+       (lambda () (%matchup bindings '(handler) '(cdr form)))
+      (lambda (names code)
+       `(DEFINE ,proc-name
+          (LET ((HANDLER (LAMBDA ,names ,@body)))
+            (NAMED-LAMBDA (,proc-name FORM)
+              (EARLYREW/REMEMBER ,code FORM))))))))
+
+(define-early-rewriter LOOKUP (name)
+  `(LOOKUP ,name))
+
+(define-early-rewriter LAMBDA (lambda-list body)
+  `(LAMBDA ,lambda-list
+     ,(earlyrew/expr body)))
+
+(define-early-rewriter CALL (rator cont #!rest rands)
+  (define (default)
+    `(CALL ,(earlyrew/expr rator)
+          ,(earlyrew/expr cont)
+          ,@(earlyrew/expr* rands)))
+  (cond ((and (QUOTE/? rator)
+             (rewrite-operator/early? (quote/text rator)))
+        => (lambda (handler)
+             (if (not (equal? cont '(QUOTE #F)))
+                 (internal-error "Early rewrite done after CPS conversion?"
+                                 cont))
+             (apply handler (earlyrew/expr* rands))))
+       (else
+        (default))))
+
+(define-early-rewriter LET (bindings body)
+  `(LET ,(map (lambda (binding)
+               (list (car binding)
+                     (earlyrew/expr (cadr binding))))
+             bindings)
+     ,(earlyrew/expr body)))
+
+(define-early-rewriter LETREC (bindings body)
+  `(LETREC ,(map (lambda (binding)
+                  (list (car binding)
+                        (earlyrew/expr (cadr binding))))
+                bindings)
+     ,(earlyrew/expr body)))
+
+(define-early-rewriter QUOTE (object)
+  `(QUOTE ,object))
+
+(define-early-rewriter DECLARE (#!rest anything)
+  `(DECLARE ,@anything))
+
+(define-early-rewriter BEGIN (#!rest actions)
+  `(BEGIN ,@(earlyrew/expr* actions)))
+
+(define-early-rewriter IF (pred conseq alt)
+  `(IF ,(earlyrew/expr pred)
+       ,(earlyrew/expr conseq)
+       ,(earlyrew/expr alt)))
+\f
+(define (earlyrew/expr expr)
+  (if (not (pair? expr))
+      (illegal expr))
+  (case (car expr)
+    ((QUOTE)    (earlyrew/quote expr))
+    ((LOOKUP)   (earlyrew/lookup expr))
+    ((LAMBDA)   (earlyrew/lambda expr))
+    ((LET)      (earlyrew/let expr))
+    ((DECLARE)  (earlyrew/declare expr))
+    ((CALL)     (earlyrew/call expr))
+    ((BEGIN)    (earlyrew/begin expr))
+    ((IF)       (earlyrew/if expr))
+    ((LETREC)   (earlyrew/letrec expr))
+    (else       (illegal expr))))
+
+(define (earlyrew/expr* exprs)
+  (map earlyrew/expr exprs))
+
+(define (earlyrew/remember new old)
+  (code-rewrite/remember new old))
+
+(define (earlyrew/new-name prefix)
+  (new-variable prefix))
+\f
+(define *early-rewritten-operators*
+  (make-eq-hash-table))
+
+(define-integrable (rewrite-operator/early? rator)
+  (hash-table/get *early-rewritten-operators* rator false))
+
+(define (define-rewrite/early operator-name-or-object handler)
+  (hash-table/put! *early-rewritten-operators*
+                  (if (hash-table/get *operator-properties*
+                                      operator-name-or-object
+                                      false)
+                      operator-name-or-object
+                      (make-primitive-procedure operator-name-or-object))
+                  handler))
+\f
+;;;; Rewrites of unary operations in terms of binary operations
+
+(let ((unary-rewrite
+       (lambda (binary-name rand2)
+        (let ((binary-operation (make-primitive-procedure binary-name)))
+          (lambda (rand1)
+            `(CALL (QUOTE ,binary-operation)
+                   (QUOTE #F)
+                   ,rand1
+                   (QUOTE ,rand2))))))
+      (special-rewrite
+       (lambda (binary-name rand2)
+        (let ((binary-operation (make-primitive-procedure binary-name)))
+          (lambda (rand1)
+            `(CALL (QUOTE ,binary-operation)
+                   (QUOTE #F)
+                   ,rand1
+                   (QUOTE ,rand2))))))
+      (special-rewrite/left
+       (lambda (binary-name rand1)
+        (let ((binary-operation (make-primitive-procedure binary-name)))
+          (lambda (rand2)
+            `(CALL (QUOTE ,binary-operation)
+                   (QUOTE #F)
+                   (QUOTE ,rand1)
+                   ,rand2))))))
+
+  (define-rewrite/early 'ZERO?     (unary-rewrite '&= 0))
+  (define-rewrite/early 'POSITIVE? (unary-rewrite '&> 0))
+  (define-rewrite/early 'NEGATIVE? (unary-rewrite '&< 0))
+  (define-rewrite/early '1+        (unary-rewrite '&+ 1))
+  (define-rewrite/early '-1+       (unary-rewrite '&- 1))
+
+  (define-rewrite/early 'ZERO-FIXNUM?
+    (special-rewrite 'EQUAL-FIXNUM? 0))
+  (define-rewrite/early 'NEGATIVE-FIXNUM?
+    (special-rewrite 'LESS-THAN-FIXNUM? 0))
+  (define-rewrite/early 'POSITIVE-FIXNUM?
+    (special-rewrite 'GREATER-THAN-FIXNUM? 0))
+  (define-rewrite/early 'ONE-PLUS-FIXNUM
+    (special-rewrite 'PLUS-FIXNUM 1))
+  (define-rewrite/early 'MINUS-ONE-PLUS-FIXNUM
+    (special-rewrite 'MINUS-FIXNUM 1))
+
+  (define-rewrite/early 'FLONUM-ZERO?     (special-rewrite 'FLONUM-EQUAL? 0.))
+  (define-rewrite/early 'FLONUM-NEGATIVE? (special-rewrite 'FLONUM-LESS? 0.))
+  (define-rewrite/early 'FLONUM-POSITIVE? (special-rewrite 'FLONUM-GREATER? 0.))
+
+  (define-rewrite/early 'FLONUM-NEGATE
+    (special-rewrite/left 'FLONUM-SUBTRACT 0.)))
+
+#|
+;; Some machines have an ABS instruction.
+;; This should be enabled according to the back end.
+
+(define-rewrite/early 'FLONUM-ABS
+  (let ((flo:> (make-primitive-procedure 'FLONUM-GREATER?))
+       (flo:- (make-primitive-procedure 'FLONUM-SUBTRACT)))
+    (lambda (x)
+      (let ((x-name (earlyrew/new-name 'X)))
+       (bind x-name x
+             `(IF (CALL (QUOTE ,flo:>) (QUOTE #F) (QUOTE 0.) (LOOKUP ,x-name))
+                  (CALL (QUOTE ,flo:-) (QUOTE #F) (QUOTE 0.) (LOOKUP ,x-name))
+                  (LOOKUP ,x-name)))))))
+|#
+\f
+;;;; *** Special, for now ***
+;; This is done this way because of current rtl generator 
+
+(let ((allocation-rewriter
+       (lambda (name out-of-line limit)
+        (let ((primitive (make-primitive-procedure name)))
+          (lambda (size)
+            (define (default)
+              `(CALL (QUOTE ,out-of-line) (QUOTE #F) ,size))
+            (cond ((form/number? size)
+                   => (lambda (nbytes)
+                        (if (not (and (exact-nonnegative-integer? nbytes)
+                                      (<= nbytes limit)))
+                            (default)
+                            `(CALL (QUOTE ,primitive) (QUOTE #F) ,size))))
+                  (else
+                   (default))))))))
+  (define-rewrite/early 'STRING-ALLOCATE
+    (allocation-rewriter 'STRING-ALLOCATE %string-allocate
+                        *string-allocate-max-open-coded-length*))
+  (define-rewrite/early 'FLOATING-VECTOR-CONS
+    (allocation-rewriter 'FLOATING-VECTOR-CONS %floating-vector-cons 
+                        *floating-vector-cons-max-open-coded-length*)))
+
+;; *** This can be improved by using %vector-allocate,
+;; and a non-marked header moved through the vector as it is filled. ***
+
+(define-rewrite/early 'VECTOR-CONS
+  (let ((primitive (make-primitive-procedure 'VECTOR-CONS)))
+    (lambda (size fill)
+      (define (default)
+       `(CALL (QUOTE ,%vector-cons) (QUOTE #F) ,size ,fill))
+      (cond ((form/number? size)
+            => (lambda (nbytes)
+                 (if (or (not (exact-nonnegative-integer? nbytes))
+                         (> nbytes *vector-cons-max-open-coded-length*))
+                     (default)
+                     `(CALL (QUOTE ,primitive) (QUOTE #F) ,size ,fill))))
+           (else
+            (default))))))
+
+
+(define-rewrite/early 'GENERAL-CAR-CDR
+  (let ((prim-general-car-cdr (make-primitive-procedure 'GENERAL-CAR-CDR))
+        (prim-car             (make-primitive-procedure 'CAR))
+        (prim-cdr             (make-primitive-procedure 'CDR)))
+    (lambda (term pattern)
+      (define (default)
+       `(CALL (QUOTE ,prim-general-car-cdr) (QUOTE #f) ,term ,pattern))
+      (cond ((form/number? pattern)
+            => (lambda (pattern)
+                 (if (and (integer? pattern) (> pattern 0))
+                     (let walk-bits ((num  pattern)
+                                     (text term))
+                       (if (= num 1)
+                           text
+                           (walk-bits (quotient num 2)
+                                      `(CALL (QUOTE ,(if (odd? num)
+                                                         prim-car
+                                                         prim-cdr))
+                                             (QUOTE #f)
+                                             ,text))))
+                     (default))))
+           (else (default))))))
+
+
+#|
+(define (define-rewrite/early/global name arity handler)
+  (let ((slot (hash-table/get *early-rewritten-operators* name '())))
+    (hash-table/put! *early-rewritten-operators*
+                    name
+                    (cons (cons arity handler) slot))))
+
+(define-rewrite/early %invoke-remote-cache 
+  (lambda (descriptor operator-cache . values)
+    (define (default values)
+      `(CALL (QUOTE ,%invoke-remote-cache)
+            (QUOTE #f)
+            ,descriptor
+            ,operator-cache
+            ,@values))
+    (let* ((descriptor* (quote/text descriptor))
+          (name  (first descriptor*))
+          (arity (second descriptor*)))
+      (cond ((rewrite-operator/early? name)
+            => (lambda (alist)
+                 (cond ((assq arity alist)
+                        => (lambda (arity.handler)
+                             (apply (cdr arity.handler) default values)))
+                       (else (default values)))))
+           (else
+            (default values))))))
+|#
+
+\f
+;;______________________________________________________________________
+;;
+;; Type-aware rewriting for generic arithmetic,
+;;  . Traverse the program and compute type information.  At this time a
+;;    rewrite may be decided and `posted'.
+;;  . Traverse the program again, applying posted and other rewrites in some
+;;    depth first ordering.
+
+
+(define *earlyrew/typemap*)
+(define *earlyrew/posted-rewrites*)
+
+(define (earlyrew/typeinf program)
+  (fluid-let ((*earlyrew/typemap* (make-eq-hash-table))
+             (*earlyrew/posted-rewrites* (make-eq-hash-table)))
+    (earlyrew/typeinf/expr *earlyrew/typemap* program)
+    (earlyrew/rewrite!/top-level program)
+    unspecific))
+
+(define-macro (define-early-type-inferencer keyword bindings . body)
+  (let ((proc-name (symbol-append 'EARLYREW/TYPEINF/ keyword)))
+    (call-with-values
+       (lambda () (%matchup (cdr bindings) '(handler env) '(cdr form)))
+      (lambda (names code)
+       `(DEFINE ,proc-name
+          (NAMED-LAMBDA (,proc-name ENV FORM)
+            ;; FORM is in scope in HANDLER
+            (LET ((HANDLER (LAMBDA ,(cons (car bindings) names) ,@body)))
+              ,code)))))))
+
+
+(define-early-type-inferencer LOOKUP (env name)
+  (earlyrew/typeinf/env/lookup env name))
+
+(define-early-type-inferencer LAMBDA (env lambda-list body)
+  (let* ((names  (lambda-list->names lambda-list))
+        (types  (make-list (length names) earlyrew/type/*unknown))
+        (env*   (earlyrew/typeinf/env/extend env names types)))
+    (earlyrew/typeinf/expr env* body))
+  earlyrew/type/*procedure)
+
+(define-early-type-inferencer CALL (env rator cont #!rest rands)
+  (let ((rand-types  (earlyrew/typeinf/expr* env rands))
+       (rand-count  (length rands)))
+    (define (default) earlyrew/type/*unknown)
+    (define (apply-handler handler rand-types)
+      (if (not (equal? cont '(QUOTE #F)))
+         (internal-error "Early rewrite done after CPS conversion?"
+                         cont))
+      (apply handler form rand-types))
+    (cond ((QUOTE/? rator)
+          (cond ((earlyrew/type-method? (quote/text rator) rand-count)
+                 => (lambda (handler)
+                      (apply-handler handler rand-types)))
+                ((eq? (quote/text rator) %invoke-remote-cache)
+                 (let ((descriptor  (quote/text (first rands))))
+                   (cond ((earlyrew/type-method? (first descriptor)
+                                                 (second descriptor))
+                          => (lambda (handler)
+                               (apply-handler handler (cddr rand-types))))
+                         (else (default)))))
+                (else (default))))
+         ((LAMBDA/? rator)
+          (hash-table/put! *earlyrew/typemap* rator earlyrew/type/*procedure)
+          (let* ((names  (cdr (lambda/formals rator)))
+                 (env*   (earlyrew/typeinf/env/extend env names rand-types)))
+            (earlyrew/typeinf/expr env* (lambda/body rator))))
+         (else
+          (earlyrew/typeinf/expr env rator)
+          (default)))))
+
+(define-early-type-inferencer LET (env bindings body)
+  (let* ((names  (map first bindings))
+        (types  (map (lambda (binding)
+                       (earlyrew/typeinf/expr env (cadr binding)))
+                     bindings))
+        (env*   (earlyrew/typeinf/env/extend env names types)))
+    (earlyrew/typeinf/expr env* body)))
+
+(define-early-type-inferencer LETREC (env bindings body)
+  (let* ((names (map first bindings))
+        (types (map (lambda (ignored) ignored earlyrew/type/*procedure)
+                    bindings))
+        (env*  (earlyrew/typeinf/env/extend env names types)))
+    (earlyrew/typeinf/expr* env* (map second bindings))
+    (earlyrew/typeinf/expr env* body)))
+
+(define-early-type-inferencer QUOTE (env object)
+  env ; ignored
+  (earlyrew/typeinf/type-of-constant object))
+
+(define-early-type-inferencer DECLARE (env #!rest anything)
+  env anything                         ; ignored
+  earlyrew/type/*illegal-type)
+
+(define-early-type-inferencer BEGIN (env #!rest actions)
+  (let  ((types (earlyrew/typeinf/expr* env actions)))
+    (if (equal? (first actions) '(DECLARE (RESULT-TYPE FLONUM)))
+       earlyrew/type/*flonum
+       (car (last-pair types)))))
+
+(define-early-type-inferencer IF (env pred conseq alt)
+  (earlyrew/typeinf/expr env pred)
+  (earlyrew/type/lub  (earlyrew/typeinf/expr env conseq)
+                     (earlyrew/typeinf/expr env alt)))
+\f
+(define (earlyrew/typeinf/expr env expr)
+  (if (not (pair? expr))
+      (illegal expr))
+  (let ((type
+        (case (car expr)
+          ((QUOTE)     (earlyrew/typeinf/quote   env expr))
+          ((LOOKUP)    (earlyrew/typeinf/lookup  env expr))
+          ((LAMBDA)    (earlyrew/typeinf/lambda  env expr))
+          ((LET)       (earlyrew/typeinf/let     env expr))
+          ((DECLARE)   (earlyrew/typeinf/declare env expr))
+          ((CALL)      (earlyrew/typeinf/call    env expr))
+          ((BEGIN)     (earlyrew/typeinf/begin   env expr))
+          ((IF)        (earlyrew/typeinf/if      env expr))
+          ((LETREC)    (earlyrew/typeinf/letrec  env expr))
+          (else        (illegal expr)))))
+    ;;(if (not (fixnum? type))
+    ;; (internal-error "Not a type" type expr))
+    ;;Remove complex numbers:
+    ;;(set! type (fix:and type (fix:not (fix:or earlyrew/type/*exact-recnum earlyrew/type/*inexact-recnum))))
+    (hash-table/put! *earlyrew/typemap* expr type)
+    type))
+
+(define (earlyrew/typeinf/expr* env exprs)
+  (map (lambda (expr)
+        (earlyrew/typeinf/expr env expr))
+       exprs))
+
+(define (earlyrew/typeinf/env/lookup env name)
+  (cond ((hash-table/get env name #F))
+       (else (free-var-error name))))
+
+(define (earlyrew/typeinf/env/extend env names0 types0)
+  (define (extend! name type)
+    (cond ((hash-table/get env name #F)
+          (internal-error "Not alpha-converted? Name already defined:" name))
+         (else
+          (hash-table/put! env name type))))
+  (let loop ((names names0) (types types0) (optionals? #F))
+    (cond ((and (null? names) (null? types))
+          env)
+         ((and optionals? (null? types))
+          env)
+         ((or (null? names) (null? types))
+          (internal-error "Mismatch" names0 types0))
+         ((eq? (car names) '#!optional)
+          (loop (cdr names) types #T))
+         ((eq? (car names) '#!aux)
+          (loop (cdr names) types #T))
+         ((eq? (car names) '#!rest)
+          (extend! (second names) earlyrew/type/*unknown)
+          env)
+         (else
+          (extend! (car names) (car types))
+          (loop (cdr names) (cdr types) optionals?)))))
+
+(define (earlyrew/form/type form)
+  (let ((type (hash-table/get *earlyrew/typemap* form #F)))
+    (or type
+       (internal-warning "Form not annotated with type:" form))))
+
+(let-syntax ((primitive-types
+             (macro names0
+               (define (definer name value)
+                 `(DEFINE ,(symbol-append 'EARLYREW/TYPE/ name) ',value))
+               (let loop ((names names0) (value 1) (defs '()))
+                 (if (null? names)
+                     `(BEGIN ,(definer '*UNKNOWN (- value 1))
+                             (DEFINE EARLYREW/TYPE/TYPE-NAMES
+                               ',(list->vector names0))
+                             ,@defs)
+                     (loop (cdr names)
+                           (* value 2)
+                           (cons (definer (car names) value) defs)))))))
+  (primitive-types  *exact-zero                ; special numbers...
+                   *exact-one
+                   *exact-minus-one
+                   *small-fixnum>1     ; numbers which won't overflow
+                   *small-fixnum<-1    ;  if added or subtracted
+                   *big-fixnum+ve      ; other fixnums
+                   *big-fixnum-ve      ; other fixnums
+                   *bignum
+                   *ratnum
+                   *flonum
+                   *exact-recnum
+                   *inexact-recnum
+                   *other              ; anything else
+                   ))
+
+(define (earlyrew/type/union . ts)
+  (reduce fix:or 0 ts))
+
+(let-syntax ((alias
+             (macro (name . parts)
+               (define (->name name)
+                 (symbol-append 'EARLYREW/TYPE/ name))
+               `(DEFINE ,(->name name)
+                  (EARLYREW/TYPE/UNION ,@(map ->name parts))))))
+  (alias *empty)
+  (alias *small-fixnum+ve  *exact-one *small-fixnum>1)
+  (alias *small-fixnum-ve  *exact-minus-one *small-fixnum<-1)
+  (alias *small-fixnum            *exact-zero *small-fixnum-ve *small-fixnum+ve)
+  (alias *big-fixnum       *big-fixnum-ve *big-fixnum+ve)
+  (alias *fixnum           *small-fixnum *big-fixnum)
+  (alias *exact-integer    *fixnum *bignum)
+  (alias *exact-real       *fixnum *bignum *ratnum)
+  (alias *inexact-real     *flonum)
+  (alias *real             *exact-real *inexact-real)
+  (alias *recnum           *exact-recnum *inexact-recnum)
+  (alias *exact-number     *exact-real *exact-recnum)
+  (alias *inexact-number   *inexact-real *inexact-recnum)
+  (alias *number           *real *recnum)
+
+  (alias *small-non-negative-fixnum  *exact-zero *small-fixnum+ve)
+  (alias *non-negative-fixnum  *exact-zero *small-fixnum+ve *big-fixnum+ve)
+  (alias *unsigned-byte        *exact-zero *exact-one *small-fixnum>1)
+  (alias *procedure *other)
+  (alias *boolean *other)
+  (alias *vector-length  *exact-zero *small-fixnum+ve)
+  (alias *string-length  *non-negative-fixnum))
+
+(define earlyrew/type/*illegal-type 'ILLEGAL-TYPE)
+
+(define (earlyrew/typeinf/type->description t)
+  (cond ((eq? t earlyrew/type/*unknown)    '(*unknown))
+       ((eq? t earlyrew/type/*number)     '(*number))
+       ((eq? t earlyrew/type/*fixnum)     '(*fixnum))
+       (else
+        (let loop ((bit 1) (index 0))
+          (if (< bit earlyrew/type/*unknown)
+              (if (zero? (fix:and t bit))
+                  (loop (* bit 2) (+ index 1))
+                  (cons (vector-ref earlyrew/type/type-names index)
+                        (loop (* bit 2) (+ index 1))))
+              '())))))
+
+
+(define-structure ea/pp/annotation
+  text
+  type)
+
+(define (pp/ann/ty program)
+  (let ((old-browser:print browser:print))
+    (let ((ht (make-eq-hash-table)))
+      (define (ppt form)
+       (let  ((ann (hash-table/get ht form #F)))
+         (pp form)
+         (if (ea/pp/annotation? ann)
+             (let  ((type  (ea/pp/annotation-type ann)))
+               (newline)
+               (display (unsigned-integer->bit-string 16 type))
+               (pp (earlyrew/typeinf/type->description type)))
+             (pp type))))
+      (hash-table/for-each *earlyrew/typemap*
+       (lambda (node type)
+         (if (pair? node)
+             (hash-table/put! ht node (make-ea/pp/annotation node type)))))
+      (fluid-let
+         ((browser:print
+           (lambda (object)
+             (if (ea/pp/annotation? object)
+                 (let ((form (ea/pp/annotation-text object)))
+                   (fluid-let ((*unparser-list-depth-limit* 4))
+                     (pp form))
+                   (newline)
+                   (fluid-let ((*unparser-list-depth-limit* 1))
+                     (if (call/? form)
+                         (begin
+                           (display "\n<H2>Argument types</H2>\n")
+                           (for-each (lambda (part)
+                                       (ppt part)
+                                       (display "\n"))
+                             (if (call/%invoke-remote-cache? form)
+                                 (cddr (cdddr form))
+                                 (cdddr form)))))
+                     (display "\n\n<H2>Result type</H2>\n")
+                     (ppt form)))
+                 (old-browser:print object)))))
+       (pp/ann program ht)))))
+         
+                  
+(define earlyrew/typeinf/type-of-constant
+  (let* ((max-fixnum        (object-new-type 0 -1))
+        (max-small-fixnum  (quotient max-fixnum 2))
+        (min-small-fixnum  (- -1 max-small-fixnum)))
+    (lambda (value)
+      (cond ((fixnum? value)
+            (cond ((eqv? value 0)   earlyrew/type/*exact-zero)
+                  ((eqv? value 1)   earlyrew/type/*exact-one)
+                  ((eqv? value -1)  earlyrew/type/*exact-minus-one)
+                  ((<= 2 value max-small-fixnum)
+                   earlyrew/type/*small-fixnum>1)
+                  ((<= min-small-fixnum value -2)
+                   earlyrew/type/*small-fixnum<-1)
+                  ((< value 0)
+                   earlyrew/type/*big-fixnum-ve)
+                  (else earlyrew/type/*big-fixnum+ve)))
+           ((exact-integer? value)
+            earlyrew/type/*bignum)
+           ((exact-rational? value)
+            earlyrew/type/*ratnum)
+           ((flo:flonum? value)
+            earlyrew/type/*flonum)
+           ((complex? value)
+            (if (exact? value)
+                earlyrew/type/*exact-recnum
+                earlyrew/type/*inexact-recnum))
+           (else
+            earlyrew/type/*other)))))
+
+(define (earlyrew/type/lub t1 t2)
+  (if (and (fixnum? t1)
+          (fixnum? t2))
+      (fix:or t1 t2)
+      (internal-error "LUB:" t1 t2)))
+
+(define (earlyrew/type/intersection t1 t2)
+  (if (and (fixnum? t1)
+          (fixnum? t2))
+      (fix:and t1 t2)
+      (internal-error "INTERSECTION:" t1 t2)))
+
+(define (earlyrew/subtype? sub super)
+  (if (and (fixnum? sub)
+          (fixnum? super))
+      (fix:= super (fix:or sub super))
+      (internal-error "SUBTYPE:" sub super)))
+
+(define (earlyrew/type=? t1 t2) (fix:= t1 t2))
+
+(define (earlyrew/type/not t)
+  (if (fixnum? t)
+      (fix:andc earlyrew/type/*unknown t)
+      (internal-error "SUBTYPE:" sub super)))
+  
+(define (earlyrew/closed-on closed-type tu tv subject-type)
+  (if (and (earlyrew/subtype? tu closed-type)
+          (earlyrew/subtype? tv closed-type))
+      (earlyrew/type/intersection subject-type closed-type)
+      subject-type))
+
+(define (earlyrew/binary-exactness-contagion tu tv subject-type)
+  (cond
+   ((and (earlyrew/subtype? tu earlyrew/type/*exact-number)
+        (earlyrew/subtype? tv earlyrew/type/*exact-number))
+    (earlyrew/type/intersection subject-type earlyrew/type/*exact-number))
+   ((or (earlyrew/subtype? tu earlyrew/type/*inexact-number)
+       (earlyrew/subtype? tv earlyrew/type/*inexact-number))
+    (earlyrew/type/intersection subject-type earlyrew/type/*inexact-number))
+   (else
+    subject-type)))
+  
+(define *earlyrew-typeinf-operators* (make-eq-hash-table))
+
+(define (earlyrew/type-method? operator arity)
+  (cond ((hash-table/get *earlyrew-typeinf-operators* operator #F)
+        => (lambda (alist)
+             (cond ((assq arity alist) => cdr)
+                   (else #F))))
+       (else #F)))
+
+(define (define-early-type-method name arity handler)
+  (let ((slot  (hash-table/get *earlyrew-typeinf-operators* name '())))
+    (hash-table/put! *earlyrew-typeinf-operators*
+                    name
+                    (cons (cons arity handler) slot)))
+  name)
+
+
+(let* ((unary-result
+       (lambda (type #!optional arg-type)
+         (default-object? arg-type)    ; ignored
+         (lambda (op)
+           (define-early-type-method op 1
+             (lambda (form u) form u  type)))))
+       (binary-result
+       (lambda (type #!optional arg1-type arg2-type)
+         (default-object? arg1-type)   ; ignored
+         (default-object? arg2-type)   ; ignored
+         (lambda (op)
+           (define-early-type-method op 2
+             (lambda (form u v) form u v  type)))))
+       (do-each
+       (lambda (op . args) (for-each op args))))
+
+  (do-each (unary-result earlyrew/type/*fixnum)
+          fix:-1+ fix:1+ fix:not)
+  (do-each (binary-result earlyrew/type/*fixnum)
+          fix:+ fix:- fix:* fix:quotient fix:remainder
+          fix:andc fix:and fix:or fix:xor fix:lsh)
+  (do-each (unary-result earlyrew/type/*flonum)
+          flo:negate flo:abs flo:sqrt
+          flo:floor flo:ceiling flo:truncate flo:round
+          flo:exp flo:log flo:sin flo:cos flo:tan flo:asin
+          flo:acos flo:atan)
+  (do-each (binary-result earlyrew/type/*flonum)
+          flo:+ flo:- flo:* flo:/ flo:atan2 flo:expt)
+
+  (do-each (unary-result earlyrew/type/*boolean)
+          not eq? null? false?
+          boolean? cell? pair? vector? %record? string?
+          fixnum? index-fixnum? flo:flonum?)
+
+  (do-each (binary-result earlyrew/type/*boolean)
+          (make-primitive-procedure '&=)
+          (make-primitive-procedure '&<)
+          (make-primitive-procedure '&>)
+          fix:= fix:> fix:< fix:<= fix:>=
+          flo:= flo:> flo:<
+          object-type?)
+
+  (do-each (unary-result earlyrew/type/*unsigned-byte)
+          char-code char->ascii)
+
+  (do-each (binary-result earlyrew/type/*unsigned-byte)
+          vector-8b-ref)
+
+  (do-each (binary-result earlyrew/type/*flonum)
+          flo:vector-ref)
+
+  (do-each (unary-result earlyrew/type/*small-fixnum+ve)
+          char->integer)
+
+  (do-each (unary-result earlyrew/type/*vector-length)
+          vector-length  flo:vector-length  length)
+
+  ;;((unary-result earlyrew/type/*small-non-negative-fixnum) string-length)
+  ((unary-result earlyrew/type/*string-length) string-length)
+
+  ((unary-result earlyrew/type/*small-fixnum) object-type)
+  )
+
+
+(define (earlyrew/rewrite-operator! replacement-op)
+  (lambda (form)
+    (form/rewrite! (call/operator form) `(QUOTE ,replacement-op))))
+
+(define (earlyrew/rewrite-diamond  gen-test-x gen-x-type
+                                  gen-test-y gen-y-type
+                                  cheap-op costly-op)
+  (define (test-will-fail? type type-test-checks-for)
+    (earlyrew/subtype? type (earlyrew/type/not type-test-checks-for)))
+  (define (test-will-succeed? type type-test-checks-for)
+    (earlyrew/subtype? type type-test-checks-for))
+
+  (define (generate-test var t gen-test gen-type)
+    (cond ((test-will-fail? t gen-type)  `(QUOTE ,#F))
+         ((test-will-succeed? t gen-type) `(QUOTE ,#T))
+         (else (gen-test `(LOOKUP ,var)))))
+  (let ((rewrite-costly (earlyrew/rewrite-operator! costly-op))
+       (rewrite-cheap  (earlyrew/rewrite-operator! cheap-op)))
+    (lambda (form tx ty)
+      form                             ; ignored
+      (cond ((or (test-will-fail? tx gen-x-type)
+                (test-will-fail? ty gen-y-type))
+            (rewrite-costly form))
+           ((and (test-will-succeed? tx gen-x-type)
+                 (test-will-succeed? ty gen-y-type))
+            (rewrite-cheap form))
+           (else
+            (let* ((x-name  (earlyrew/new-name 'X))
+                   (y-name  (earlyrew/new-name 'Y))
+                   (x-test  (generate-test x-name tx gen-test-x gen-x-type))
+                   (y-test  (generate-test y-name ty gen-test-y gen-y-type)))
+              (form/rewrite! form
+                (bind x-name (first (call/operands form))
+                      (bind y-name (second (call/operands form))
+                            `(IF ,(andify x-test y-test)
+                                 (CALL (QUOTE ,cheap-op)
+                                       (QUOTE #F)
+                                       (LOOKUP ,x-name)
+                                       (LOOKUP ,y-name))
+                                 (CALL (QUOTE ,costly-op)
+                                       (QUOTE #F)
+                                       (LOOKUP ,x-name)
+                                       (LOOKUP ,y-name))))))))))))
+
+
+(let ()
+  (define (plus/minus-pre form tu tv)
+    form                               ; ignored
+    (cond ((and (earlyrew/subtype? tu earlyrew/type/*small-fixnum)
+               (earlyrew/subtype? tv earlyrew/type/*small-fixnum))
+          earlyrew/type/*fixnum)
+         (else
+          earlyrew/type/*number)))
+
+  (define (standard-binary-method name pre post)
+    (define-early-type-method name 2
+      (lambda (form tu tv)
+       (let* ((result  (pre form tu tv))
+              (result*
+               (earlyrew/binary-exactness-contagion
+                tu tv
+                (earlyrew/closed-on earlyrew/type/*real tu tv result)))
+              (result** 
+               (or (and post (post form result* tu tv)) result*)))
+         result**))))
+
+  (define (number-pre form tu tv) form tu tv  earlyrew/type/*number)
+  (define (*-post form result tu tv)
+    form ; ignored
+    (if (or (earlyrew/subtype? earlyrew/type/*exact-zero tu)
+           (earlyrew/subtype? earlyrew/type/*exact-zero tv))
+       (fix:or earlyrew/type/*exact-zero result)
+       result))
+
+  (standard-binary-method (make-primitive-procedure '&+)  plus/minus-pre #F)
+  (standard-binary-method (make-primitive-procedure '&-)  plus/minus-pre #F)
+  (standard-binary-method (make-primitive-procedure '&*)  number-pre *-post)
+  (standard-binary-method (make-primitive-procedure '&/)  number-pre #F)
+  )
+
+
+(define-early-type-method 'EXACT->INEXACT 1
+  (lambda (form arg-type)
+    form                               ; ignored
+    (cond ((earlyrew/subtype? arg-type earlyrew/type/*real)
+          earlyrew/type/*inexact-real)
+         ((earlyrew/subtype? arg-type earlyrew/type/*recnum)
+          earlyrew/type/*inexact-recnum)
+         (else
+          earlyrew/type/*inexact-number))))
+
+(define-early-type-method 'SQRT 1
+  (lambda (form arg-type)
+    form                               ; ignored
+    (cond ((earlyrew/subtype? arg-type earlyrew/type/*non-negative-fixnum)
+          earlyrew/type/*real)
+         ((earlyrew/subtype? arg-type earlyrew/type/*inexact-number)
+          earlyrew/type/*inexact-number)
+         (else
+          earlyrew/type/*number))))
+
+(define-early-type-method 'EXPT 2
+  (let ((type:+1/-1 (earlyrew/type/union earlyrew/type/*exact-one
+                                        earlyrew/type/*exact-minus-one)))
+    (lambda (form t-base t-exponent)
+      form                             ; ignored
+      (cond ((and (earlyrew/subtype? t-base earlyrew/type/*exact-minus-one)
+                 (earlyrew/subtype? t-exponent earlyrew/type/*exact-integer))
+            type:+1/-1)
+           ((earlyrew/subtype? t-exponent earlyrew/type/*exact-integer)
+            (fix:or earlyrew/type/*exact-one t-base))
+           (else
+            earlyrew/type/*number)))))
+
+(let ()
+  (define (unary/2 name input1 output1 input2 output2)
+    (define-early-type-method name 1
+      (lambda (form arg-type)
+       form                            ; ignored
+       (cond ((earlyrew/subtype arg-type input1)    output1)
+             ((earlyrew/subtype arg-type input2)    output2)
+             (else                                  earlyrew/type/*number)))))
+  (define (unary/3 name input1 output1 input2 output2 input3 output3)
+    (define-early-type-method name 1
+      (lambda (form arg-type)
+       form                            ; ignored
+       (cond ((earlyrew/subtype arg-type input1)    output1)
+             ((earlyrew/subtype arg-type input2)    output2)
+             ((earlyrew/subtype arg-type input3)    output3)
+             (else                                  earlyrew/type/*number)))))
+  (unary/2 'SIN
+          earlyrew/type/*exact-zero earlyrew/type/*exact-zero
+          earlyrew/type/*real       earlyrew/type/*flonum)
+  (unary/2 'COS
+          earlyrew/type/*exact-zero earlyrew/type/*exact-one
+          earlyrew/type/*real       earlyrew/type/*flonum)
+  (unary/2 'TAN
+          earlyrew/type/*exact-zero earlyrew/type/*exact-zero
+          earlyrew/type/*real       earlyrew/type/*flonum)
+  (unary/2 'ACOS
+          earlyrew/type/*exact-one  earlyrew/type/*exact-zero
+          earlyrew/type/*unknown    earlyrew/type/*inexact-number)
+  (unary/2 'ASIN
+          earlyrew/type/*exact-zero earlyrew/type/*exact-zero
+          earlyrew/type/*unknown    earlyrew/type/*inexact-number)
+  (unary/3 'EXP
+          earlyrew/type/*recnum     earlyrew/type/*inexact-recnum
+          earlyrew/type/*exact-zero earlyrew/type/*exact-one
+          earlyrew/type/*real       earlyrew/type/*inexact-real)
+  (unary/2 'LOG
+          earlyrew/type/*exact-one  earlyrew/type/*exact-zero
+          earlyrew/type/*number     earlyrew/type/*inexact-number)  )
+
+      
+#|
+(define-early-type-method 'EXPT 2
+  (let ((&* (make-primitive-procedure '&*))
+       (max-multiplies 3))
+    (lambda (form base exponent)
+      (define (make-product x y)
+       `(CALL (QUOTE ,&*)
+              (QUOTE #F)
+              ,x ,y))
+      (define (count-multiplies n)
+       (cond ((= n 1) 0)
+             ((= n 2) 1)
+             ((even? n) (+ (count-multiplies (/ n 2)) 1))
+             ((odd? n)  (+ (count-multiplies (- n 1)) 1))))
+      (define (power variable n)
+       (cond ((= n 1) variable)
+             ((= n 2) (make-product variable variable))
+             ((even? n)
+              (let ((square (earlyrew/new-name 'X)))
+                (bind square (make-product variable variable)
+                      (power `(LOOKUP ,square) (/ n 2)))))
+             ((odd? n)
+              (make-product variable (power variable (- n 1))))))             
+                      
+      (cond ((form/number? exponent)
+            => (lambda (exponent)
+                 (cond ((form/number? base)
+                        => (lambda (base)
+                             `(QUOTE ,(expt base exponent))))
+                       ((eqv? exponent 0)
+                        `(QUOTE 1))
+                       ((eqv? exponent 1)
+                        base)
+                       ((and (exact-integer? exponent)
+                             (>= exponent 2)
+                             (<= (count-multiplies exponent) max-multiplies))
+                        (let* ((base-name  (earlyrew/new-name 'X))
+                               (expression (power `(LOOKUP ,base-name) exponent)))
+                          (bind base-name base
+                                expressions)))
+                       (else (default)))))
+           (else
+            (default))))))
+|#
+
+(define (earlyrew/post-rewrite form rewrite)
+  (hash-table/put! *earlyrew/posted-rewrites* form rewrite))
+
+(define (earlyrew/posted-rewrite? form)
+  (hash-table/get *earlyrew/posted-rewrites* form #F))
+
+(define (earlyrew/rewrite!/top-level form)
+  (earlyrew/rewrite! form))
+
+(define (earlyrew/rewrite! form)
+  (define (rewrite* forms)
+    (for-each earlyrew/rewrite! forms))
+  (define (let&rec bindings body)
+    (for-each (lambda (bindings) (earlyrew/rewrite! (second bindings)))
+      bindings)
+    (earlyrew/rewrite! body))
+  (cond ((QUOTE/? form))
+       ((LOOKUP/? form))
+       ((CALL/? form)
+        (let ((operator  (call/operator form))
+              (operands  (call/operands form)))
+          (define (try name arity rands)
+            (let ((handler  (earlyrew/type-rewrite? name arity)))
+              (if handler
+                  (apply handler form rands))))
+          (earlyrew/rewrite! operator)
+          (rewrite* (call/cont-and-operands form))
+          (cond ((earlyrew/posted-rewrite? form)
+                 => (lambda (rewrite!) (rewrite! form)))
+                ((not (QUOTE/? operator)) #F)
+                ((eq? (quote/text operator) %invoke-remote-cache)
+                 (try (first  (quote/text (first operands)))
+                      (second (quote/text (first operands)))
+                      (cddr operands)))
+                (else
+                 (try (quote/text operator) (length operands) operands)))))
+       ((LAMBDA/? form)  (earlyrew/rewrite! (lambda/body form)))
+       ((IF/? form)      (rewrite* (cdr form)))
+       ((LET/? form)     (let&rec (let/bindings form) (let/body form)))
+       ((LETREC/? form)  (let&rec (letrec/bindings form) (letrec/body form)))
+       ((BEGIN/? form)   (rewrite* (begin/exprs form)))
+       ((DECLARE/? form))
+       (else (illegal form))))
+
+
+(define *earlyrew/type-rewrites* (make-eq-hash-table))
+
+(define (define-type-rewrite name arity handler)
+  (let ((alist (hash-table/get *earlyrew/type-rewrites* name '())))
+    (hash-table/put! *earlyrew/type-rewrites*
+                    name
+                    (cons (cons arity handler) alist)))
+  name)
+
+(define (earlyrew/type-rewrite? name arity)
+  (let ((alist (hash-table/get *earlyrew/type-rewrites* name '())))
+    (and alist
+        (let ((pair (or (assq arity alist)  (assq 'any alist))))
+          (and pair
+               (cdr pair))))))
+
+(define earlyrew/flonum-test
+  (let ((flonum?  (make-primitive-procedure 'FLONUM?)))
+    (lambda (subject)
+      `(CALL (QUOTE ,flonum?) '#F ,subject))))
+
+(let ()
+  (define (small-fixnum-test/1 subject)
+    `(CALL (QUOTE ,%small-fixnum?) '#F ,subject '1))
+  (define (additive fix:op flo:op out-of-line:op)
+    (let ((fix:diamond (earlyrew/rewrite-diamond
+                       small-fixnum-test/1 earlyrew/type/*small-fixnum
+                       small-fixnum-test/1 earlyrew/type/*small-fixnum
+                       fix:op out-of-line:op))
+         (flo:diamond (earlyrew/rewrite-diamond
+                       earlyrew/flonum-test earlyrew/type/*flonum
+                       earlyrew/flonum-test earlyrew/type/*flonum
+                       flo:op out-of-line:op)))
+      (lambda (form x y)
+       (let  ((tx  (earlyrew/form/type x))
+              (ty  (earlyrew/form/type y)))
+         (cond ((or (earlyrew/subtype? tx earlyrew/type/*flonum)
+                    (earlyrew/subtype? ty earlyrew/type/*flonum))
+                (flo:diamond form tx ty))
+               (else
+                (fix:diamond form tx ty)))))))
+
+  (define (define-additive name fix:op flo:op out:op)
+    (define-type-rewrite (make-primitive-procedure name) 2
+      (additive fix:op flo:op out:op)))
+
+  (define-additive '&+ fix:+ flo:+ %+)
+  (define-additive '&- fix:- flo:- %-)
+
+  (define-additive '&< fix:< flo:< %<)
+  (define-additive '&= fix:= flo:= %=)
+  (define-additive '&> fix:> flo:> %>))
+
+(define-type-rewrite (make-primitive-procedure '&*) 2
+  (let ((rewrite-out-of-line (earlyrew/rewrite-operator! %*))
+       (flo:diamond (earlyrew/rewrite-diamond
+                     earlyrew/flonum-test earlyrew/type/*flonum
+                     earlyrew/flonum-test earlyrew/type/*flonum
+                     flo:* %*)))
+    (lambda (form x y)
+      (let  ((tx  (earlyrew/form/type x))
+            (ty  (earlyrew/form/type y)))
+       (cond ((or (earlyrew/subtype? tx earlyrew/type/*flonum)
+                  (earlyrew/subtype? ty earlyrew/type/*flonum))
+              (flo:diamond form tx ty))
+             (else
+              (rewrite-out-of-line form)))))))
+