X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fir1opt.lisp;h=a5a8969ffac0b6a798a5a05c0e6b569f3e05680e;hb=dcd86042bba514f5dfc39246de9cdbb030648569;hp=6da6828f7fb89fc50b9beec3a227bb1c0f385385;hpb=3d6751d99d2bf224ccbc18e133f23aff72fb708f;p=sbcl.git diff --git a/src/compiler/ir1opt.lisp b/src/compiler/ir1opt.lisp index 6da6828..a5a8969 100644 --- a/src/compiler/ir1opt.lisp +++ b/src/compiler/ir1opt.lisp @@ -57,9 +57,10 @@ (values-type-union (node-derived-type (first current)) res)) (current (rest uses) (rest current))) - ((null current) res))) + ((or (null current) (eq res *wild-type*)) + res))) (t - (node-derived-type (lvar-uses lvar)))))) + (node-derived-type uses))))) ;;; Return the derived type for LVAR's first value. This is guaranteed ;;; not to be a VALUES or FUNCTION type. @@ -181,7 +182,7 @@ (lambda-var-p (ref-leaf node))) (let ((type (single-value-type int))) (when (and (member-type-p type) - (null (rest (member-type-members type)))) + (eql 1 (member-type-size type))) (change-ref-leaf node (find-constant (first (member-type-members type))))))) (reoptimize-lvar lvar))))) @@ -305,6 +306,9 @@ (when value (derive-node-type node (lvar-derived-type value))))) (cset + ;; PROPAGATE-FROM-SETS can do a better job if NODE-REOPTIMIZE + ;; is accurate till the node actually has been reoptimized. + (setf (node-reoptimize node) t) (ir1-optimize-set node)) (cast (ir1-optimize-cast node))))) @@ -696,7 +700,7 @@ (when (and fun ;; If somebody is really sure that they want to modify ;; constants, let them. - (policy node (> safety 0))) + (policy node (> check-constant-modification 0))) (let ((destroyed-constant-args (funcall fun args))) (when destroyed-constant-args (let ((*compiler-error-context* node)) @@ -754,6 +758,14 @@ (values)) +(defun xep-tail-combination-p (node) + (and (combination-p node) + (let* ((lvar (combination-lvar node)) + (dest (when (lvar-p lvar) (lvar-dest lvar))) + (lambda (when (return-p dest) (return-lambda dest)))) + (and (lambda-p lambda) + (eq :external (lambda-kind lambda)))))) + ;;; If NODE doesn't return (i.e. return type is NIL), then terminate ;;; the block there, and link it to the component tail. ;;; @@ -779,7 +791,10 @@ (declare (ignore lvar)) (unless (or (and (eq node (block-last block)) (eq succ tail)) (block-delete-p block)) - (when (eq (node-derived-type node) *empty-type*) + ;; Even if the combination will never return, don't terminate if this + ;; is the tail call of a XEP: doing that would inhibit TCO. + (when (and (eq (node-derived-type node) *empty-type*) + (not (xep-tail-combination-p node))) (cond (ir1-converting-not-optimizing-p (cond ((block-last block) @@ -843,22 +858,20 @@ (:inline t) (:no-chance nil) ((nil :maybe-inline) (policy call (zerop space)))) - ;; FIXME & KLUDGE: This LET-CONVERSION check was added as a - ;; half-assed workaround for the bug for which the test - ;; case :HIGH-DEBUG-KNOWN-FUNCTION-INLINING checks in - ;; compiler.pure.lisp. The _real_ culprit seems to be - ;; the insertion of BIND/UNBIND-SENTINEL vops. - (policy call (plusp let-conversion)) (defined-fun-p leaf) (defined-fun-inline-expansion leaf) - (let ((fun (defined-fun-functional leaf))) - (or (not fun) - (and (eq inlinep :inline) (functional-kind fun)))) (inline-expansion-ok call)) - (flet (;; FIXME: Is this what the old CMU CL internal documentation - ;; called semi-inlining? A more descriptive name would - ;; be nice. -- WHN 2002-01-07 - (frob () + ;; Inline: if the function has already been converted at another call + ;; site in this component, we point this REF to the functional. If not, + ;; we convert the expansion. + ;; + ;; For :INLINE case local call analysis will copy the expansion later, + ;; but for :MAYBE-INLINE and NIL cases we only get one copy of the + ;; expansion per component. + ;; + ;; FIXME: We also convert in :INLINE & FUNCTIONAL-KIND case below. What + ;; is it for? + (flet ((frob () (let* ((name (leaf-source-name leaf)) (res (ir1-convert-inline-expansion name @@ -870,14 +883,18 @@ ;; following top level forms (setf (defined-fun-functional leaf) res) (change-ref-leaf ref res)))) - (if ir1-converting-not-optimizing-p - (frob) - (with-ir1-environment-from-node call - (frob) - (locall-analyze-component *current-component*)))) - - (values (ref-leaf (lvar-uses (basic-combination-fun call))) - nil)) + (let ((fun (defined-fun-functional leaf))) + (if (or (not fun) + (and (eq inlinep :inline) (functional-kind fun))) + ;; Convert. + (if ir1-converting-not-optimizing-p + (frob) + (with-ir1-environment-from-node call + (frob) + (locall-analyze-component *current-component*))) + ;; If we've already converted, change ref to the converted functional. + (change-ref-leaf ref fun)))) + (values (ref-leaf ref) nil)) (t (let ((info (info :function :info (leaf-source-name leaf)))) (if info @@ -894,12 +911,22 @@ ;;; syntax check, arg/result type processing, but still call ;;; RECOGNIZE-KNOWN-CALL, since the call might be to a known lambda, ;;; and that checking is done by local call analysis. -(defun validate-call-type (call type ir1-converting-not-optimizing-p) +(defun validate-call-type (call type defined-type ir1-converting-not-optimizing-p) (declare (type combination call) (type ctype type)) (cond ((not (fun-type-p type)) (aver (multiple-value-bind (val win) (csubtypep type (specifier-type 'function)) (or val (not win)))) + ;; In the commonish case where the function has been defined + ;; in another file, we only get FUNCTION for the type; but we + ;; can check whether the current call is valid for the + ;; existing definition, even if only to STYLE-WARN about it. + (when defined-type + (valid-fun-use call defined-type + :argument-test #'always-subtypep + :result-test nil + :lossage-fun #'compiler-style-warn + :unwinnage-fun #'compiler-notify)) (recognize-known-call call ir1-converting-not-optimizing-p)) ((valid-fun-use call type :argument-test #'always-subtypep @@ -949,7 +976,7 @@ (derive-node-type call (tail-set-type (lambda-tail-set fun)))))) (:full (multiple-value-bind (leaf info) - (validate-call-type call (lvar-type fun-lvar) nil) + (validate-call-type call (lvar-type fun-lvar) nil nil) (cond ((functional-p leaf) (convert-call-if-possible (lvar-uses (basic-combination-fun call)) @@ -1125,9 +1152,24 @@ (aver (and (legal-fun-name-p source-name) (not (eql source-name '.anonymous.)))) (node-ends-block call) + ;; The internal variables of a transform are not going to be + ;; interesting to the debugger, so there's no sense in + ;; suppressing the substitution of variables with only one use + ;; (the extra variables can slow down constraint propagation). + ;; + ;; This needs to be done before the WITH-IR1-ENVIRONMENT-FROM-NODE, + ;; so that it will bind *LEXENV* to the right environment. + (setf (combination-lexenv call) + (make-lexenv :default (combination-lexenv call) + :policy (process-optimize-decl + '(optimize + (preserve-single-use-debug-variables 0)) + (lexenv-policy + (combination-lexenv call))))) (with-ir1-environment-from-node call (with-component-last-block (*current-component* (block-next (node-block call))) + (let ((new-fun (ir1-convert-inline-lambda res :debug-name (debug-name 'lambda-inlined source-name) @@ -1135,17 +1177,6 @@ (ref (lvar-use (combination-fun call)))) (change-ref-leaf ref new-fun) (setf (combination-kind call) :full) - ;; The internal variables of a transform are not going to be - ;; interesting to the debugger, so there's no sense in - ;; suppressing the substitution of variables with only one use - ;; (the extra variables can slow down constraint propagation). - (setf (combination-lexenv call) - (make-lexenv :default (combination-lexenv call) - :policy (process-optimize-decl - '(optimize - (preserve-single-use-debug-variables 0)) - (lexenv-policy - (combination-lexenv call))))) (locall-analyze-component *current-component*)))) (values)) @@ -1241,12 +1272,13 @@ (let ((int (type-approx-intersection2 var-type type))) (when (type/= int var-type) (setf (leaf-type leaf) int) - (dolist (ref (leaf-refs leaf)) - (derive-node-type ref (make-single-value-type int)) - ;; KLUDGE: LET var substitution - (let* ((lvar (node-lvar ref))) - (when (and lvar (combination-p (lvar-dest lvar))) - (reoptimize-lvar lvar)))))) + (let ((s-int (make-single-value-type int))) + (dolist (ref (leaf-refs leaf)) + (derive-node-type ref s-int) + ;; KLUDGE: LET var substitution + (let* ((lvar (node-lvar ref))) + (when (and lvar (combination-p (lvar-dest lvar))) + (reoptimize-lvar lvar))))))) (values)))) ;;; Iteration variable: exactly one SETQ of the form: @@ -1342,17 +1374,22 @@ ;;; the union of the INITIAL-TYPE and the types of all the set ;;; values and to a PROPAGATE-TO-REFS with this type. (defun propagate-from-sets (var initial-type) - (collect ((res initial-type type-union)) - (dolist (set (basic-var-sets var)) + (let ((changes (not (csubtypep (lambda-var-last-initial-type var) initial-type))) + (types nil)) + (dolist (set (lambda-var-sets var)) (let ((type (lvar-type (set-value set)))) - (res type) + (push type types) (when (node-reoptimize set) - (derive-node-type set (make-single-value-type type)) + (let ((old-type (node-derived-type set))) + (unless (values-subtypep old-type type) + (derive-node-type set (make-single-value-type type)) + (setf changes t))) (setf (node-reoptimize set) nil)))) - (let ((res (res))) - (awhen (maybe-infer-iteration-var-type var initial-type) - (setq res it)) - (propagate-to-refs var res))) + (when changes + (setf (lambda-var-last-initial-type var) initial-type) + (let ((res-type (or (maybe-infer-iteration-var-type var initial-type) + (apply #'type-union initial-type types)))) + (propagate-to-refs var res-type)))) (values)) ;;; If a LET variable, find the initial value's type and do @@ -1368,9 +1405,9 @@ (initial-type (lvar-type initial-value))) (setf (lvar-reoptimize initial-value) nil) (propagate-from-sets var initial-type)))))) - (derive-node-type node (make-single-value-type (lvar-type (set-value node)))) + (setf (node-reoptimize node) nil) (values)) ;;; Return true if the value of REF will always be the same (and is @@ -1445,8 +1482,8 @@ *policy*))) (setf (cast-type-to-check cast) *wild-type*) (substitute-lvar-uses value arg - ;; FIXME - t) + ;; FIXME + t) (%delete-lvar-use ref) (add-lvar-use cast lvar))))) (setf (node-derived-type ref) *wild-type*) @@ -1551,7 +1588,6 @@ ;;; right here. (defun propagate-local-call-args (call fun) (declare (type combination call) (type clambda fun)) - (unless (or (functional-entry-fun fun) (lambda-optional-dispatch fun)) (let* ((vars (lambda-vars fun)) @@ -1719,10 +1755,13 @@ (with-ir1-environment-from-node node (let* ((dums (make-gensym-list count)) (ignore (gensym)) + (leaf (ref-leaf ref)) (fun (ir1-convert-lambda `(lambda (&optional ,@dums &rest ,ignore) (declare (ignore ,ignore)) - (funcall ,(ref-leaf ref) ,@dums))))) + (%funcall ,leaf ,@dums)) + :source-name (leaf-%source-name leaf) + :debug-name (leaf-%debug-name leaf)))) (change-ref-leaf ref fun) (aver (eq (basic-combination-kind node) :full)) (locall-analyze-component *current-component*)