Update of /project/movitz/cvsroot/movitz In directory common-lisp.net:/tmp/cvs-serv10944
Modified Files: compiler.lisp Log Message: Changed (and hopefully improved) the type-inference logic quite a bit.
Date: Thu Aug 12 10:25:07 2004 Author: ffjeld
Index: movitz/compiler.lisp diff -u movitz/compiler.lisp:1.92 movitz/compiler.lisp:1.93 --- movitz/compiler.lisp:1.92 Tue Aug 10 05:56:12 2004 +++ movitz/compiler.lisp Thu Aug 12 10:25:06 2004 @@ -8,7 +8,7 @@ ;;;; Created at: Wed Oct 25 12:30:49 2000 ;;;; Distribution: See the accompanying file COPYING. ;;;; -;;;; $Id: compiler.lisp,v 1.92 2004/08/10 12:56:12 ffjeld Exp $ +;;;; $Id: compiler.lisp,v 1.93 2004/08/12 17:25:06 ffjeld Exp $ ;;;; ;;;;------------------------------------------------------------------
@@ -74,6 +74,8 @@ (defvar *compiler-produce-defensive-code* t "Try make code be extra cautious.")
+(defvar *compiler-trust-user-type-declarations-p* t) + (defvar *compiling-function-name*) (defvar muerte.cl:*compile-file-pathname* nil)
@@ -360,25 +362,36 @@ (thunks) (binding-types) (encoded-type - (multiple-value-list (type-specifier-encode nil)))) + (multiple-value-list (type-specifier-encode nil))) + (declared-encoded-type + (multiple-value-list (type-specifier-encode t)))) + +(defun make-type-analysis-with-declaration (binding) + (let ((declared-type + (if (not (and *compiler-trust-user-type-declarations-p* + (movitz-env-get (binding-name binding) :variable-type + nil (binding-env binding) nil))) + (multiple-value-list (type-specifier-encode t)) + (multiple-value-list + (type-specifier-encode (movitz-env-get (binding-name binding) :variable-type + t (binding-env binding) nil)))))) + ;; (warn "~S decl: ~A" binding (apply #'encoded-type-decode declared-type)) + (make-type-analysis :declared-encoded-type declared-type)))
(defun analyze-bindings (toplevel-funobj) "Figure out usage of bindings in a toplevel funobj. Side-effects each binding's binding-store-type." (when *compiler-do-type-inference* - (let ((more-binding-references-p nil) - (binding-usage (make-hash-table :test 'eq))) + (let ((binding-usage (make-hash-table :test 'eq))) (labels ((binding-resolved-p (binding) (let ((analysis (gethash binding binding-usage))) (and analysis - (null (type-analysis-binding-types analysis)) (null (type-analysis-thunks analysis))))) (binding-resolve (binding) (if (not (bindingp binding)) binding (let ((analysis (gethash binding binding-usage))) (assert (and (and analysis - (null (type-analysis-binding-types analysis)) (null (type-analysis-thunks analysis)))) (binding) "Can't resolve unresolved binding ~S." binding) @@ -395,49 +408,63 @@ (assert (or (typep type 'binding) (eql 1 (type-specifier-num-values type))) () "store-lexical with multiple-valued type: ~S for ~S" type binding) + ;; (warn "store ~S type ~S, thunk ~S" binding type thunk) (let ((analysis (or (gethash binding binding-usage) (setf (gethash binding binding-usage) - (make-type-analysis))))) + (make-type-analysis-with-declaration binding))))) (cond (thunk (assert (some #'bindingp thunk-args)) +;;; (assert (notany (lambda (arg) +;;; (and (bindingp arg) +;;; (binding-eql arg binding))) +;;; thunk-args) +;;; () "A thunk on itself for ~S?" binding) (push (cons thunk thunk-args) (type-analysis-thunks analysis))) - ((typep binding 'function-argument) - (setf (type-analysis-encoded-type analysis) - (multiple-value-list - (type-specifier-encode (etypecase binding - (rest-function-argument 'list) - (supplied-p-function-argument 'boolean) - (function-argument t)))))) - ((and (consp type) (eq 'binding-type (car type))) - (let ((target-binding (binding-target (cadr type)))) - (cond - ((eq binding target-binding)) - ((typep binding 'constant-object-binding) - (setf (type-analysis-encoded-type analysis) - (multiple-value-list - (multiple-value-call - #'encoded-types-or - (values-list (type-analysis-encoded-type analysis)) - (member-type-encode (constant-object target-binding)))))) - (t (pushnew target-binding (type-analysis-binding-types analysis)) - (setf more-binding-references-p t))))) +;;; ((typep binding 'function-argument) +;;; (setf (type-analysis-encoded-type analysis) +;;; (multiple-value-list +;;; (type-specifier-encode (etypecase binding +;;; (rest-function-argument 'list) +;;; (supplied-p-function-argument 'boolean) +;;; (function-argument t)))))) +;;; ((and (consp type) (eq 'binding-type (car type))) +;;; (break "Got binding-type.") +;;; (let ((target-binding (binding-target (cadr type)))) +;;; (cond +;;; ((eq binding target-binding)) +;;; ((typep binding 'constant-object-binding) +;;; (setf (type-analysis-encoded-type analysis) +;;; (multiple-value-list +;;; (multiple-value-call +;;; #'encoded-types-or +;;; (values-list (type-analysis-encoded-type analysis)) +;;; (member-type-encode (constant-object target-binding)))))) +;;; (t (pushnew target-binding (type-analysis-binding-types analysis)) +;;; )))) ((and (bindingp type) (binding-eql type binding)) + (break "got binding type") nil) (t (setf (type-analysis-encoded-type analysis) (multiple-value-list (multiple-value-call #'encoded-types-or (values-list (type-analysis-encoded-type analysis)) - (type-specifier-encode type)))))))) + (type-specifier-encode type))))))) + #+ignore + (when (typep binding 'forwarding-binding) + (analyze-store (forwarding-binding-target binding) type thunk thunk-args))) (analyze-code (code) (dolist (instruction code) (when (listp instruction) (multiple-value-bind (store-binding store-type thunk thunk-args) (find-written-binding-and-type instruction) (when store-binding - (analyze-store (binding-target store-binding) store-type thunk thunk-args))) + #+ignore + (warn "store: ~S binding ~S type ~S thunk ~S" + instruction store-binding store-type thunk) + (analyze-store store-binding store-type thunk thunk-args))) (analyze-code (instruction-sub-program instruction))))) (analyze-funobj (funobj) (loop for (nil . function-env) in (function-envs funobj) @@ -448,88 +475,78 @@ ;; 1. Examine each store to lexical bindings. (analyze-funobj toplevel-funobj) ;; 2. - (loop repeat 10 while more-binding-references-p - doing - (setf more-binding-references-p nil) - (maphash (lambda (binding analysis) - (setf (type-analysis-thunks analysis) - (remove-if (lambda (x) - (destructuring-bind (thunk . thunk-args) x - (when (every (lambda (arg) - (or (not (bindingp arg)) - (binding-resolved-p arg))) - thunk-args) - (setf more-binding-references-p t) - (setf (type-analysis-encoded-type analysis) + (flet ((resolve-thunks () + (loop with more-thunks-p = t + repeat 20 + finally (return t) + do (unless more-thunks-p + (return nil)) + (setf more-thunks-p nil) + (maphash (lambda (binding analysis) + (declare (ignore binding)) + (setf (type-analysis-thunks analysis) + (loop for (thunk . thunk-args) in (type-analysis-thunks analysis) + if (not (every #'binding-resolved-p thunk-args)) + collect (cons thunk thunk-args) + else + do (setf (type-analysis-encoded-type analysis) (multiple-value-list (multiple-value-call - #'encoded-types-or + #'encoded-types-and (values-list - (type-analysis-encoded-type analysis)) - (type-specifier-encode - (apply thunk (mapcar #'binding-resolve - thunk-args))))))))) - (type-analysis-thunks analysis))) - (dolist (target-binding (type-analysis-binding-types analysis)) - (let* ((target-analysis - (or (gethash target-binding binding-usage) - (and (typep target-binding 'function-argument) - (make-type-analysis - :encoded-type (multiple-value-list - (type-specifier-encode t)))) - (error "Type-reference by ~S to unknown binding ~S" - binding target-binding))) - (new-type (setf (type-analysis-encoded-type analysis) - (multiple-value-list - (multiple-value-call - #'encoded-types-or - (values-list - (type-analysis-encoded-type analysis)) - (values-list - (type-analysis-encoded-type target-analysis))))))) - (cond - ((apply #'encoded-allp new-type) - ;; If the type is already T, no need to look further. - (setf (type-analysis-binding-types analysis) nil)) - ((setf (type-analysis-binding-types analysis) - (remove target-binding - (remove binding - (union (type-analysis-binding-types analysis) - (type-analysis-binding-types target-analysis))))) - (setf more-binding-references-p t)))))) - binding-usage)) - (when more-binding-references-p - (warn "Unable to remove all binding-references during lexical type analysis.")) + (type-analysis-declared-encoded-type analysis)) + (multiple-value-call + #'encoded-types-or + (values-list + (type-analysis-encoded-type analysis)) + (type-specifier-encode + (apply thunk (mapcar #'binding-resolve + thunk-args))))))) + (setf more-thunks-p t)))) + binding-usage)))) + (when (and (resolve-thunks) + *compiler-trust-user-type-declarations-p*) + ;; For each unresolved binding, just use the declared type. + (maphash (lambda (binding analysis) + (declare (ignore binding)) + (when (and (not (null (type-analysis-thunks analysis))) + (not (apply #'encoded-allp + (type-analysis-declared-encoded-type analysis)))) + (setf (type-analysis-encoded-type analysis) + (type-analysis-declared-encoded-type analysis)) + (setf (type-analysis-thunks analysis) nil))) ; Ignore remaining thunks. + binding-usage) + ;; Try one more time to resolve thunks. + (resolve-thunks))) + #+ignore + (maphash (lambda (binding analysis) + (when (type-analysis-thunks analysis) + (warn "Unable to infer type for ~S: ~S" binding + (type-analysis-thunks analysis)))) + binding-usage) ;; 3. (maphash (lambda (binding analysis) -;;; (loop for (nil . thunk-args) in (type-analysis-thunks analysis) -;;; do (warn "Unable to thunk ~S with args ~S." binding thunk-args)) - (assert (null (type-analysis-binding-types analysis)) () - "binding ~S type ~S still refers to ~S" - binding - (apply #'encoded-type-decode (type-analysis-encoded-type analysis)) - (type-analysis-binding-types analysis)) (setf (binding-store-type binding) (cond + ((and (not (null (type-analysis-thunks analysis))) + *compiler-trust-user-type-declarations-p* + (movitz-env-get (binding-name binding) :variable-type nil + (binding-env binding) nil)) + (multiple-value-list + (type-specifier-encode (movitz-env-get (binding-name binding) :variable-type + t (binding-env binding) nil)))) + ((and *compiler-trust-user-type-declarations-p* + (movitz-env-get (binding-name binding) :variable-type nil + (binding-env binding) nil)) + (multiple-value-list + (multiple-value-call #'encoded-types-and + (type-specifier-encode (movitz-env-get (binding-name binding) :variable-type + t (binding-env binding) nil)) + (values-list (type-analysis-encoded-type analysis))))) ((not (null (type-analysis-thunks analysis))) -;;; (when (not (rest (type-analysis-thunks analysis))) -;;; (warn "One thunk: ~S for ~S" binding (first (type-analysis-thunks analysis)))) (multiple-value-list (type-specifier-encode t))) (t (type-analysis-encoded-type analysis)))) - #+ignore - (when (apply #'encoded-type-singleton (type-analysis-encoded-type analysis)) - (warn "Singleton: ~A" binding)) - #+ignore - (when (or t #+ignore (not (apply #'encoded-allp (type-analysis-encoded-type analysis))) - #+ignore (multiple-value-call #'encoded-subtypep - (values-list (type-analysis-encoded-type analysis)) - (type-specifier-encode 'list))) - (warn "Type: ~S => ~A (~A)" - binding - (apply #'encoded-type-decode (type-analysis-encoded-type analysis)) - (multiple-value-call #'encoded-subtypep - (values-list (type-analysis-encoded-type analysis)) - (type-specifier-encode 'list))))) + #+ignore (warn "Finally: ~S" binding)) binding-usage)))) toplevel-funobj)
@@ -555,10 +572,9 @@ 'forwarding-binding) (change-class (borrowed-binding-target borrowing-binding) 'located-binding)) - #+ignore - (warn "binding ~S of ~S is not local to ~S, replacing with ~S of ~S." - binding (binding-env binding) funobj - borrowing-binding (binding-env borrowing-binding)) +;;; (warn "binding ~S of ~S is not local to ~S, replacing with ~S of ~S." +;;; binding (binding-env binding) funobj +;;; borrowing-binding (binding-env borrowing-binding)) (pushnew borrowing-binding (getf (binding-lended-p binding) :lended-to)) (dolist (usage usages) @@ -5821,24 +5837,28 @@ (list extended-instruction) (let* ((operator (car extended-instruction)) (expander (gethash operator *extended-code-expanders*))) - (if expander - (funcall expander extended-instruction funobj frame-map) - (list extended-instruction))))) + (if (not expander) + (list extended-instruction) + (let ((expansion (funcall expander extended-instruction funobj frame-map))) + (mapcan (lambda (e) + (expand-extended-code e funobj frame-map)) + expansion))))))
(defun ensure-local-binding (binding funobj) "When referencing binding in funobj, ensure we have the binding local to funobj." (if (not (typep binding 'binding)) binding - (let ((binding (binding-target binding))) + (let ((target-binding (binding-target binding))) (cond - ((eq funobj (binding-funobj binding)) + ((eq funobj (binding-funobj target-binding)) binding) - (t (or (find binding (borrowed-bindings funobj) + (t (or (find target-binding (borrowed-bindings funobj) :key (lambda (binding) (borrowed-binding-target binding))) (error "Can't install non-local binding ~W." binding)))))))
(defun binding-type-specifier (binding) + (break "nix binding-type-specifier: ~S" binding) (etypecase binding (forwarding-binding (binding-type-specifier (forwarding-binding-target binding))) @@ -5867,7 +5887,10 @@ (destructuring-bind (source destination &key &allow-other-keys) (cdr instruction) (when (typep destination 'binding) - (values destination (binding-type-specifier source))))) + (values destination t #+ignore (binding-type-specifier source) + (lambda (source-type) + source-type) + (list source)))))
(define-find-read-bindings :load-lexical (source destination &key &allow-other-keys) (declare (ignore destination)) @@ -5927,8 +5950,13 @@ (declare (ignore protect-registers protect-carry)) (cond (init-with-register - (assert init-with-type) - (values binding init-with-type)) + (cond + ((not (typep init-with-register 'binding)) + (assert init-with-type) + (values binding init-with-type) ) + (t (values binding t + (lambda (x) x) + (list init-with-register))))) ((not (typep binding 'temporary-name)) (values binding t)))))
@@ -5942,8 +5970,6 @@ init-with-register init-with-type) (cdr instruction) (declare (ignore protect-carry)) ; nothing modifies carry anyway. - (when (string= (binding-name binding) 'reader-function) - (break "init: ~S" instruction)) ;; (assert (eq binding (ensure-local-binding binding funobj))) (assert (eq funobj (binding-funobj binding))) (cond @@ -6049,6 +6075,8 @@ (:movl ,tmp-register (:ebp ,(stack-frame-offset (new-binding-location binding frame-map)))))))) + ((typep init-with-register 'lexical-binding) + (make-load-lexical init-with-register binding funobj nil frame-map)) (init-with-register (make-store-lexical binding init-with-register nil frame-map))))))))
@@ -6239,41 +6267,59 @@ (bindingp term1) (member (result-mode-type destination) '(:lexical-binding :function :multple-values :eax :ebx :ecx :edx)))) - (let* ((term0 (binding-target term0)) - (term1 (binding-target term1)) - (destination (if (or (not (bindingp destination)) - (not (symbolp (new-binding-location destination frame-map :default 0)))) - destination - (new-binding-location destination frame-map))) + (let* ((destination (ensure-local-binding destination funobj)) + (term0 (ensure-local-binding term0 funobj)) + (term1 (ensure-local-binding term1 funobj)) + (destination-location (if (or (not (bindingp destination)) + (typep destination 'borrowed-binding)) + destination + (new-binding-location (binding-target destination) frame-map))) (type0 (apply #'encoded-type-decode (binding-store-type term0))) (type1 (apply #'encoded-type-decode (binding-store-type term1))) (result-type (multiple-value-call #'encoded-integer-types-add (values-list (binding-store-type term0)) (values-list (binding-store-type term1))))) - ;; (warn "add for: ~S is ~A." destination result-type) (let ((loc0 (new-binding-location term0 frame-map :default nil)) (loc1 (new-binding-location term1 frame-map :default nil))) +;;; (warn "add: ~A" instruction) +;;; (warn "add for: ~S is ~A, from ~A/~A and ~A/~A." +;;; destination result-type +;;; term0 loc0 +;;; term1 loc1) (cond ((type-specifier-singleton result-type) ;; (break "constant add: ~S" instruction) (make-load-constant (car (type-specifier-singleton result-type)) destination funobj frame-map)) - ((and (movitz-subtypep type1 'fixnum) + ((and (movitz-subtypep type0 'fixnum) (movitz-subtypep type1 'fixnum) (movitz-subtypep result-type 'fixnum)) (cond ((and (type-specifier-singleton type0) - (eq loc1 destination)) + (eq loc1 destination-location)) (cond - ((member destination '(:eax :ebx :ecx :edx)) + ((member destination-location '(:eax :ebx :ecx :edx)) `((:addl ,(movitz-immediate-value (car (type-specifier-singleton type0))) ,destination))) (t (assert (integerp loc1)) (break "check that this is correct..") `((:addl ,(movitz-immediate-value (car (type-specifier-singleton type0))) (:ebp ,(stack-frame-offset loc1))))))) + ((and (type-specifier-singleton type0) + (eq term1 destination) + (integerp destination-location)) + (break "untested") + `((:addl ,(movitz-immediate-value (car (type-specifier-singleton type0))) + (:ebp ,(stack-frame-offset destination-location))))) + ((and (type-specifier-singleton type0) + (symbolp loc1) + (integerp destination-location)) + `((:addl ,(movitz-immediate-value (car (type-specifier-singleton type0))) + ,loc1) + (:movl ,loc1 (:ebp ,(stack-frame-offset destination-location))))) (t -;;; (warn "ADD: ~S = ~A/~S + ~A/~S,~%~A ~A" +;;; (warn "ADD: ~A/~S = ~A/~S + ~A/~S,~%~A ~A" +;;; destination-location ;;; destination ;;; loc0 term0 ;;; loc1 term1 @@ -6281,24 +6327,24 @@ ;;; (eq loc1 destination)) ;;; (warn "ADDI: ~S" instruction) (append (cond - ((and (eq :eax loc0) (eq :ebx loc1)) - nil) - ((and (eq :ebx loc0) (eq :eax loc1)) - nil) ; terms order isn't important - ((eq :eax loc1) - (append - (make-load-lexical term0 :ebx funobj nil frame-map))) - (t (append - (make-load-lexical term0 :eax funobj nil frame-map) - (make-load-lexical term1 :ebx funobj nil frame-map)))) - `((:movl (:edi ,(global-constant-offset '+)) :esi)) - (make-compiled-funcall-by-esi 2) - (etypecase destination - (symbol - (unless (eq destination :eax) - `((:movl :eax ,destination)))) - (binding - (make-store-lexical destination :eax nil frame-map))))))) + ((and (eq :eax loc0) (eq :ebx loc1)) + nil) + ((and (eq :ebx loc0) (eq :eax loc1)) + nil) ; terms order isn't important + ((eq :eax loc1) + (append + (make-load-lexical term0 :ebx funobj nil frame-map))) + (t (append + (make-load-lexical term0 :eax funobj nil frame-map) + (make-load-lexical term1 :ebx funobj nil frame-map)))) + `((:movl (:edi ,(global-constant-offset '+)) :esi)) + (make-compiled-funcall-by-esi 2) + (etypecase destination + (symbol + (unless (eq destination :eax) + `((:movl :eax ,destination)))) + (binding + (make-store-lexical destination :eax nil frame-map))))))) (t (append (cond ((and (eq :eax loc0) (eq :ebx loc1)) nil)