Initial revision
authorStephen Adams <edu/mit/csail/zurich/adams>
Thu, 30 Mar 1995 15:11:40 +0000 (15:11 +0000)
committerStephen Adams <edu/mit/csail/zurich/adams>
Thu, 30 Mar 1995 15:11:40 +0000 (15:11 +0000)
v8/src/compiler/midend/frag.scm [new file with mode: 0644]

diff --git a/v8/src/compiler/midend/frag.scm b/v8/src/compiler/midend/frag.scm
new file mode 100644 (file)
index 0000000..6de62f4
--- /dev/null
@@ -0,0 +1,574 @@
+#| -*-Scheme-*-
+
+$Id: frag.scm,v 1.1 1995/03/30 15:11:40 adams Exp $
+
+Copyright (c) 1994 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. |#
+
+;;;; Constant folder for closure and stack closure indices
+;;; package: (compiler midend)
+
+(declare (usual-integrations))
+
+(define (frag/top-level program)
+  (frag/expr program))
+
+(define-macro (define-fragmenter keyword bindings . body)
+  (let ((proc-name (symbol-append 'FRAG/ 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)
+              (FRAG/REMEMBER ,code FORM))))))))
+
+(define-fragmenter LOOKUP (name)
+  `(LOOKUP ,name))
+
+(define (frag/embody expr)
+  (cond ((LOOKUP/? expr) (frag/expr expr))
+       ((QUOTE/? expr)  (frag/expr expr))
+       ((LAMBDA/? expr) (frag/expr expr))
+       ((form/static? expr) (form/copy expr))
+       (else
+        (let ((body-var  (new-variable 'BODY)))
+          `(LET ((,body-var
+                  (LAMBDA  (,(frag/ignored-continuation))
+                    ,(frag/expr expr))))
+             (CALL (LOOKUP ,body-var) '#F))))))
+
+(define-fragmenter LAMBDA (lambda-list body)
+  `(LAMBDA ,lambda-list
+     ,(frag/embody body)))
+
+(define-fragmenter LET (bindings body)
+  `(LET ,(map (lambda (binding)
+               (list (car binding)
+                     (frag/expr (cadr binding))))
+             bindings)
+     ,(if (for-all? bindings
+           (lambda (b)
+             (or (pseudo-static-variable? (car b))
+                 (form/static? (cadr b)))))
+         (frag/expr body)
+         (frag/embody body))))
+
+(define-fragmenter LETREC (bindings body)
+  `(LETREC ,(map (lambda (binding)
+                  (list (car binding)
+                        (frag/expr (cadr binding))))
+                bindings)
+     ,(frag/embody body)))
+
+(define-fragmenter IF (pred conseq alt)
+  (frag* (list pred conseq alt)
+        (lambda (parts*)
+          `(IF ,@parts*))))
+
+(define-fragmenter QUOTE (object)
+  `(QUOTE ,object))
+
+(define-fragmenter DECLARE (#!rest anything)
+  `(DECLARE ,@anything))
+
+(define-fragmenter BEGIN (#!rest actions)
+  (frag* actions
+        (lambda (actions*)
+          `(BEGIN ,@actions*))))
+
+(define-fragmenter CALL (rator cont #!rest rands)
+  (let ((parts  (cons* rator cont rands)))
+    (frag* parts
+          (lambda (parts*)
+            `(CALL ,@parts*)))))
+
+(define (frag* exprs receiver)
+  (let* ((names  (map (lambda (e)
+                      (if (or (QUOTE/? e) (LOOKUP/? e) (LAMBDA/? e)
+                              (form/static? e))
+                          #F
+                          (new-variable 'FRAG)))
+                    exprs))
+       (bds (list-transform-positive
+                (map (lambda (n r)
+                       (and n
+                            `(,n (LAMBDA (,(frag/ignored-continuation))
+                                   ,(frag/expr r)))))
+                     names exprs)
+              identity-procedure))
+       (exprs*  (map (lambda (n r)
+                       (if n
+                           `(CALL (LOOKUP ,n) '#F)
+                           (frag/expr r)))
+                     names exprs)))
+    (if (null? bds)
+       (receiver exprs*)
+       `(LET ,bds ,(receiver exprs*)))))
+
+
+(define (frag/expr expr)
+  (if (not (pair? expr))
+      (illegal expr))
+  (case (car expr)
+    ((QUOTE)    (frag/quote expr))
+    ((LOOKUP)   (frag/lookup expr))
+    ((LAMBDA)   (frag/lambda expr))
+    ((LET)      (frag/let expr))
+    ((DECLARE)  (frag/declare expr))
+    ((CALL)     (frag/call expr))
+    ((BEGIN)    (frag/begin expr))
+    ((IF)       (frag/if expr))
+    ((LETREC)   (frag/letrec expr))
+    (else       (illegal expr))))
+
+(define (frag/expr* exprs)
+  (lmap (lambda (expr)
+         (frag/expr expr))
+       exprs))
+
+(define (frag/remember new old)
+  (code-rewrite/remember new old))
+
+(define (frag/ignored-continuation)
+  (new-continuation-variable))
+
+
+(define (frag/worth-while? expr)
+  (define (worth-while? expr)
+    (if (not (pair? expr))
+       (illegal expr))
+    (case (car expr)
+      ((QUOTE)    #F)
+      ((LOOKUP)   #F)
+      ((DECLARE)  #F)
+      ((LAMBDA)   (or (hairy-lambda-list? (lambda/formals expr))
+                     (worth-while? (lambda/body expr))))
+      ((LET)      (let-like (let/bindings expr) (let/body expr)))
+      ((LETREC)   (let-like (letrec/bindings expr) (letrec/body expr)))
+      ((CALL)     (worth-while?* (cdr expr)))
+      ((BEGIN)    (worth-while?* (cdr expr)))
+      ((IF)       (worth-while?* (cdr expr)))
+      (else       (illegal expr))))
+  (define (let-like bindings body)
+    (or        (worth-while? body)
+       (there-exists? bindings (lambda (b) (worth-while? (second b))))))
+  (define (worth-while?* exprs)
+    (there-exists? exprs worth-while?))
+  (worth-while? expr))
+
+
+;;;; Specialization
+;;
+;; We use a new form, (PLACEHOLDER <value>) where <value> is a scheme
+;; value containing placeholder objects.
+
+(define-structure
+    (specializer/info
+     (conc-name specializer/info/)
+     (constructor specializer/info/make (name lambda)))
+  (name #F read-only true)             ; binding in top level LETREC
+  (lambda #F read-only true)           ; lambda expression in top level LETREC
+  (specializations '())                        ; list((key name lambda*))
+  )
+
+(define *specialization-table*) ; label->specializer/info
+(define *lambda-queue*)
+
+
+
+(define (specialize/enqueue-lambda! form)
+  (pp `(queue-lambda: ,form))
+  (queue/enqueue! *lambda-queue* form))
+
+(define-macro (define-specializer keyword bindings . body)
+  (let ((proc-name (symbol-append 'SPECIALIZER/ keyword)))
+    (call-with-values
+       (lambda () (%matchup bindings '(handler) '(cdr form)))
+      (lambda (names code)
+       `(DEFINE ,proc-name
+          (NAMED-LAMBDA (,proc-name ENV FORM)
+            ENV                        ; in case not used
+            (LET ((HANDLER (LAMBDA ,names ,@body)))
+              ,code)))))))
+
+(define-specializer QUOTE (object)
+  object
+  unspecific)
+
+(define-specializer LOOKUP (name)
+  name
+  (let  ((place (assq name env)))
+    (if place
+       (form/rewrite! form (cdr place))))
+  unspecific)
+
+(define-specializer LAMBDA (lambda-list body)
+  (let ((env*
+        (map* env (lambda (name) (cons name `(LOOKUP ,name)))
+              (lambda-list->names lambda-list))))
+    (specialize/expr! env* body))
+  (if (hairy-lambda-list? lambda-list)
+      (specialize/enqueue-lambda! form)))
+
+(define-specializer LET (bindings body)
+  (let ((env*
+        (map* env (lambda (b) (cons (car b) `(LOOKUP ,(car b)))) bindings)))
+    (for-each (lambda (binding)
+               (specialize/expr! env (cadr binding)))
+      bindings)
+    (specialize/expr! env* body)))
+
+(define-specializer LETREC (bindings body)
+  (let ((env*
+        (map* env (lambda (b) (cons (car b) `(LOOKUP ,(car b)))) bindings)))
+    (for-each (lambda (binding)
+               (specialize/expr! env* (cadr binding)))
+      bindings)
+    (specialize/expr! env* body)
+    (if (specialize/simple? body)
+       (form/rewrite! form body))))
+
+(define-specializer IF (pred conseq alt)
+  (specialize/expr! env pred)
+  (cond ((equal? pred '(QUOTE #F))
+        (specialize/expr! env alt)
+        (form/rewrite! form alt))
+       ((QUOTE/? pred)
+        (specialize/expr! env conseq)
+        (form/rewrite! form conseq))
+       (else
+        (specialize/expr! env conseq)
+        (specialize/expr! env alt))))
+
+(define-specializer DECLARE (#!rest anything)
+  anything
+  unspecific)
+
+(define-specializer BEGIN (#!rest actions)
+  (for-each (lambda (action)
+             (specialize/expr! env action))
+    actions))
+
+(define-specializer CALL (rator cont #!rest rands)
+  cont
+  (specialize/expr! env rator)
+  (for-each (lambda (expr)
+             (specialize/expr! env expr))
+    rands)
+  (cond ((and (QUOTE/? rator)
+             (specializer/rewrite? (quote/text rator)))
+        => (lambda (handler!)
+             (apply handler! form rands)))
+       ((and (LOOKUP/? rator)
+             (hash-table/get *specialization-table* (lookup/name rator) #F))
+        => (lambda (info)
+             (specialize-call! info env form rands)))
+       (else unspecific)))
+
+(define (specialize-call! info env form rands)
+  (define (extract-placeholders form so-far)
+    (cond ((placeholder? form) (cons form so-far))
+         ((pair? form)
+          (extract-placeholders (cdr form)
+                                (extract-placeholders (car form) so-far)))
+         (else so-far)))
+  (define (substitute? form)
+    (define (immutable? v)
+      (or (number? v) (object-type? v (object-type #F)) (char? v)))
+    (or (PLACEHOLDER-QUOTE/? form)
+       (and (QUOTE/? form)
+            (immutable? (quote/text form)))))
+  (let* ((lam-expr  (specializer/info/lambda info))
+        (formals   (lambda/formals lam-expr))
+        (body      (lambda/body lam-expr)))
+    (if (and (contains-placeholder? rands) ; depends on specialization params
+            (not (hairy-lambda-list? formals)))
+       (let* ((names*  (map variable/rename formals))
+              (ph*     (map (lambda (p)
+                              (cons p `(LOOKUP ,(new-variable (placeholder/name p)))))
+                            (extract-placeholders rands '())))
+              (env*    (map* ph*
+                             (lambda (f n v)
+                               (if (substitute? v)
+                                   (cons f v)
+                                   (cons f `(LOOKUP ,n))))
+                             (cdr formals)
+                             (cdr names*)
+                             rands))
+              (body*   (specialize/expr! env* (form/copy body))))
+         (cond ((QUOTE/? body*)
+                (form/rewrite! form body*))
+               ((PLACEHOLDER-QUOTE/? body*)
+                (form/rewrite! form body*))
+               (else
+                (let* ((procedure-name
+                        (variable/rename (specializer/info/name info)))
+                       (placeholders (remove-placeholders! env* body*))
+                       ;; make new lambda list & call expressions
+                       (actuals
+                        (append (list-transform-negative rands substitute?)
+                                 (map (lambda (p) (cdr (assq p env)))
+                                      placeholders)))
+                       (new-formals
+                        (let loop ((rs rands) (fs names*))
+                           (cond ((null? rs)
+                                  (map (lambda (p) (cdr (assq p env*)))
+                                       placeholders))
+                                 ((substitute? (car rs))
+                                  (loop (cdr rs) (cdr fs)))
+                                 (else
+                                  (cons (car fs) (loop (cdr rs) (cdr fs))))))))
+                  (form/rewrite! form
+                    `(CALL (LOOKUP ,procedure-name)
+                           '#F
+                           ,@actuals))
+                  (remember-specialization!
+                   info
+                   procedure-name
+                   `(LAMBDA ,new-formals ,body*)))))))))
+
+
+(define (remove-placeholders! env form) ; -> list (placeholder)
+  ;; remove placeholders, replacing with new names.
+  ;;  Return alist from placeholders to name
+  (let walk ((form form) (ps '()))
+    (cond ((PLACEHOLDER-QUOTE/? form)
+          (let ((text (placeholder-quote/text form)))
+            (if (placeholder? text)
+                (let ((pair  (assq text env)))
+                  (if (not pair)
+                      (internal-error "Not bound" form env))
+                  (form/rewrite! form `(LOOKUP ,(cdr pair)))
+                  (if (memq text ps) ps (cons text ps)))
+                (nasty-residual))))
+         ((QUOTE/? form) ps)
+         ((LOOKUP/? form) ps)
+         ((LAMBDA/? form) (walk (lambda/formals form) ps))
+         ((or (LET/? form) (LETREC/? form))
+          (let loop ((bds (second form)) (ps ps))
+            (if (null? bds)
+                (walk (third form) ps)
+                (loop (cdr bds) (walk (cadr (first bds)) ps)))))
+         (else
+          (let loop ((forms (cdr form)) (ps ps))
+            (if (null? forms)
+                ps
+                (loop (cdr forms) (walk (car forms) ps))))))))
+
+(define (PLACEHOLDER-QUOTE/? expr)
+  (and (pair? expr)
+       (eq? (car expr) 'PLACEHOLDER-QUOTE)))
+
+(define (placeholder-quote/text expr) (second expr))
+
+(define (contains-placeholder? datum)
+  (cond ((placeholder? datum)  #T)
+       ((pair? datum)
+        (or (contains-placeholder? (car datum))
+            (contains-placeholder? (cdr datum))))
+       ((eq? datum '())        #F)
+       ((eq? datum #F)         #F)
+       ((eq? datum #T)         #F)
+       ((eq? datum unspecific) #F)
+       ((number? datum)        #F)
+       ((symbol? datum)        #F)
+       ((string? datum)        #F)
+       (else #T)))                     ; conservative approximation
+
+(define (make-placeholder-quote value)
+  (if (contains-placeholder? value)
+      `(PLACEHOLDER-QUOTE ,value)
+      `(QUOTE ,value)))
+
+(define (specialize/simple? expr)
+  (or (QUOTE/? expr)
+      (PLACEHOLDER-QUOTE/? expr)))
+
+(define (specialize/expr! env expr)
+  ;; Rewrite EXPR.
+  (if (not (pair? expr))
+      (illegal expr))
+  (case (car expr)
+    ((PLACEHOLDER-QUOTE))
+    ((QUOTE)    (specializer/quote env expr))
+    ((LOOKUP)   (specializer/lookup env expr))
+    ((LAMBDA)   (specializer/lambda env expr))
+    ((LET)      (specializer/let env expr))
+    ((DECLARE)  (specializer/declare env expr))
+    ((CALL)     (specializer/call env expr))
+    ((BEGIN)    (specializer/begin env expr))
+    ((IF)       (specializer/if env expr))
+    ((LETREC)   (specializer/letrec env expr))
+    (else       (illegal expr))))
+
+(define-structure
+    (placeholder
+     (conc-name placeholder/)
+     (constructor make-placeholder))
+  (name  #F read-only true))
+
+
+(define (arity/top-level program)
+  ;; These should be put in a fluid-let when debugging is done.
+  (set! *specialization-table* (make-eq-hash-table))
+  (set! *lambda-queue* (queue/make))
+  (let walk ((expr program))
+    (cond ((LETREC/? expr)
+          (for-each
+              (lambda (binding)
+                (hash-table/put! *specialization-table*
+                                 (car binding)
+                                 (specializer/info/make (car binding)
+                                                        (cadr binding))))
+            (letrec/bindings expr))
+          (walk (letrec/body expr)))
+         ((LET/? expr) (walk (let/body expr)))
+         ((QUOTE/? expr))
+         ((LOOKUP/? expr))
+         ((LAMBDA/? expr)
+          (if (hairy-lambda-list? (lambda/formals expr))
+              (specialize/enqueue-lambda! expr))
+          (walk (lambda/body expr)))
+         (else (for-each walk (cdr expr))))
+    (queue/drain *lambda-queue* arity/specialize-lambda))
+
+
+(define (arity/specialize-lambda form)
+  (let ((body    (lambda/body form))
+       (formals (lambda/formals form)))
+    (call-with-values
+       (lambda () (lambda-list/parse formals))
+      (lambda (required optional rest aux)
+       ;; required includes continuation.
+       (pp form)
+       (let* ((low   (length required))
+              (high  (if rest
+                         (+ low (length optional) 5)
+                         (+ low (length optional)))))
+         (let loop ((arity low))
+           (if (<= arity high)
+               (begin
+                 (arity/generate-specialization form arity #F)
+                 (loop (+ arity 1))))))))))
+
+
+(define (arity/generate-specialization lam-expr arity rest?)
+  ; ARITY is at least enough to satisfy the requireds
+  (define (generate new-ll env)
+    (pp `(lambda-list: ,new-ll env: ,env)))
+
+  (let ((formals (lambda/formals lam-expr)))
+    (let loop ((env '()) (old-ll formals) (new-ll '()) (position 0))
+      (cond ((= position arity)
+            (let loop ((env env) (old-ll old-ll))
+              (cond ((null? old-ll)
+                     (generate (reverse new-ll) env))
+                    ((eq? (car old-ll) '#!optional)
+                     (loop env (cdr old-ll)))
+                    ((eq? (car old-ll) '#!rest)
+                     (generate (reverse new-ll)
+                               (cons (cons (second old-ll) `(QUOTE ())) env)))
+                    (else
+                     (loop (cons (cons (car old-ll) `(QUOTE ,%unassigned)) env)
+                           (cdr old-ll))))))
+           ((eq? (car old-ll) '#!optional)
+            (loop env (cdr old-ll) new-ll position))
+           ((eq? (car old-ll) '#!rest)
+            (let* ((rest           (second old-ll))
+
+*** I was making rest? work
+
+                   (rest-list-args (make-initialized-list (- arity position)
+                                     (lambda (i) i (variable/rename rest))))
+                   (placeholders   (map make-placeholder rest-list-args))
+                   (rest-list-value (if rest?
+                                        (append (list-head placeholders (- new-name-count 1))
+                                                (car (last-pair placeholders)))
+                                        placeholders)))
+              (generate (append (reverse new-ll) rest-list-args)
+                        (map* (cons (cons rest
+                                          `(PLACEHOLDER-QUOTE ,rest-list-value))
+                                    env)
+                              (lambda (ph name) (cons ph `(LOOKUP ,name)))
+                              placeholders
+                              rest-list-args))))
+           (else
+            (let* ((name   (car old-ll))
+                   (name*  (variable/rename name)))
+              (loop (cons (cons name `(LOOKUP ,name*)) env)
+                    (cdr old-ll)
+                    (cons name* new-ll)
+                    (+ position 1))))))))
+
+
+
+(define *specializer/rewriters* (make-eq-hash-table))
+
+(define (specializer/rewrite? operator)
+  (hash-table/get *specializer/rewriters* operator #F))
+
+(define (define-specializer-rewriter name handler)
+  (hash-table/put! *specializer/rewriters* name handler))
+
+(define-specializer-rewriter (make-primitive-procedure 'CAR)
+  (lambda (form arg)
+    (cond ((PLACEHOLDER-QUOTE/? arg)
+          (if (pair? (placeholder-quote/text arg))
+              (form/rewrite! form
+                (make-placeholder-quote (car (placeholder-quote/text arg))))
+              (user-error "Run time error detected during specialization"
+                          form)))
+         (else unspecific))))
+
+(define-specializer-rewriter (make-primitive-procedure 'CDR)
+  (lambda (form arg)
+    (cond ((PLACEHOLDER-QUOTE/? arg)
+          (if (pair? (placeholder-quote/text arg))
+              (form/rewrite! form
+                (make-placeholder-quote (cdr (placeholder-quote/text arg))))
+              (user-error "Run time error detected during specialization"
+                          form)))
+         (else unspecific))))
+
+
+(let ()
+  (define (safe-unary-predicate name pred)
+    (define-specializer-rewriter name
+      (lambda (form arg)
+       (cond ((PLACEHOLDER-QUOTE/? arg)
+              (form/rewrite! form
+                `(QUOTE ,(pred (placeholder-quote/text arg)))))
+             ((QUOTE/? arg)
+              (from/rewrite! form `(QUOTE ,(pred (quote/text arg)))))
+             (else unspecific)))))
+
+  (safe-unary-predicate  (make-primitive-procedure 'NULL?) null?)
+  (safe-unary-predicate  %unassigned? (lambda (x) (eq? x %unassigned))))