X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fir1opt.lisp;h=2e64da8e0f7d7b3491769da48e9672ffc29756f1;hb=a7c2a16d0c2be6709becc962be1cb5e0aeda68c6;hp=2dcfc4dd3a560c8145e2bd73670007e30a0e3aec;hpb=ea1fd7753b7dc1277a7d250fed317300fe1e5772;p=sbcl.git diff --git a/src/compiler/ir1opt.lisp b/src/compiler/ir1opt.lisp index 2dcfc4d..2e64da8 100644 --- a/src/compiler/ir1opt.lisp +++ b/src/compiler/ir1opt.lisp @@ -138,8 +138,9 @@ ;; FUN-TYPE might be (AND FUNCTION (SATISFIES ...)). (fun-type-wild-args fun-type)) (progn (dolist (arg args) - (setf (continuation-%externally-checkable-type arg) - *wild-type*)) + (when arg + (setf (continuation-%externally-checkable-type arg) + *wild-type*))) *wild-type*) (let* ((arg-types (append (fun-type-required fun-type) (fun-type-optional fun-type) @@ -150,14 +151,15 @@ (loop for arg of-type continuation in args and type of-type ctype in arg-types - do (setf (continuation-%externally-checkable-type arg) - type)) + do (when arg + (setf (continuation-%externally-checkable-type arg) + type))) (continuation-%externally-checkable-type cont))))))) ;;;; interface routines used by optimizers ;;; This function is called by optimizers to indicate that something -;;; interesting has happened to the value of Cont. Optimizers must +;;; interesting has happened to the value of CONT. Optimizers must ;;; make sure that they don't call for reoptimization when nothing has ;;; happened, since optimization will fail to terminate. ;;; @@ -166,7 +168,7 @@ ;;; is deleted (in which case we do nothing.) ;;; ;;; Since this can get called during IR1 conversion, we have to be -;;; careful not to fly into space when the Dest's Prev is missing. +;;; careful not to fly into space when the DEST's PREV is missing. (defun reoptimize-continuation (cont) (declare (type continuation cont)) (unless (member (continuation-kind cont) '(:deleted :unused)) @@ -187,15 +189,15 @@ (setf (block-type-check (node-block node)) t))) (values)) -;;; Annotate Node to indicate that its result has been proven to be -;;; typep to RType. After IR1 conversion has happened, this is the +;;; Annotate NODE to indicate that its result has been proven to be +;;; TYPEP to RTYPE. After IR1 conversion has happened, this is the ;;; only correct way to supply information discovered about a node's -;;; type. If you screw with the Node-Derived-Type directly, then +;;; type. If you screw with the NODE-DERIVED-TYPE directly, then ;;; information may be lost and reoptimization may not happen. ;;; -;;; What we do is intersect Rtype with Node's Derived-Type. If the +;;; What we do is intersect RTYPE with NODE's DERIVED-TYPE. If the ;;; intersection is different from the old type, then we do a -;;; Reoptimize-Continuation on the Node-Cont. +;;; REOPTIMIZE-CONTINUATION on the NODE-CONT. (defun derive-node-type (node rtype) (declare (type node node) (type ctype rtype)) (let ((node-type (node-derived-type node))) @@ -214,23 +216,34 @@ (reoptimize-continuation (node-cont node)))))) (values)) +(defun set-continuation-type-assertion (cont atype ctype) + (declare (type continuation cont) (type ctype atype ctype)) + (when (eq atype *wild-type*) + (return-from set-continuation-type-assertion)) + (let* ((old-atype (continuation-asserted-type cont)) + (old-ctype (continuation-type-to-check cont)) + (new-atype (values-type-intersection old-atype atype)) + (new-ctype (values-type-intersection old-ctype ctype))) + (when (or (type/= old-atype new-atype) + (type/= old-ctype new-ctype)) + (setf (continuation-asserted-type cont) new-atype) + (setf (continuation-type-to-check cont) new-ctype) + (do-uses (node cont) + (setf (block-attributep (block-flags (node-block node)) + type-check type-asserted) + t)) + (reoptimize-continuation cont))) + (values)) + ;;; This is similar to DERIVE-NODE-TYPE, but asserts that it is an ;;; error for CONT's value not to be TYPEP to TYPE. If we improve the ;;; assertion, we set TYPE-CHECK and TYPE-ASSERTED to guarantee that ;;; the new assertion will be checked. -(defun assert-continuation-type (cont type) +(defun assert-continuation-type (cont type policy) (declare (type continuation cont) (type ctype type)) - (let ((cont-type (continuation-asserted-type cont))) - (unless (eq cont-type type) - (let ((int (values-type-intersection cont-type type))) - (when (type/= cont-type int) - (setf (continuation-asserted-type cont) int) - (do-uses (node cont) - (setf (block-attributep (block-flags (node-block node)) - type-check type-asserted) - t)) - (reoptimize-continuation cont))))) - (values)) + (when (eq type *wild-type*) + (return-from assert-continuation-type)) + (set-continuation-type-assertion cont type (maybe-weaken-check type policy))) ;;; Assert that CALL is to a function of the specified TYPE. It is ;;; assumed that the call is legal and has only constants in the @@ -238,20 +251,21 @@ (defun assert-call-type (call type) (declare (type combination call) (type fun-type type)) (derive-node-type call (fun-type-returns type)) - (let ((args (combination-args call))) + (let ((args (combination-args call)) + (policy (lexenv-policy (node-lexenv call)))) (dolist (req (fun-type-required type)) (when (null args) (return-from assert-call-type)) (let ((arg (pop args))) - (assert-continuation-type arg req))) + (assert-continuation-type arg req policy))) (dolist (opt (fun-type-optional type)) (when (null args) (return-from assert-call-type)) (let ((arg (pop args))) - (assert-continuation-type arg opt))) + (assert-continuation-type arg opt policy))) (let ((rest (fun-type-rest type))) (when rest (dolist (arg args) - (assert-continuation-type arg rest)))) + (assert-continuation-type arg rest policy)))) (dolist (key (fun-type-keywords type)) (let ((name (key-info-name key))) @@ -259,7 +273,8 @@ ((null arg)) (when (eq (continuation-value (first arg)) name) (assert-continuation-type - (second arg) (key-info-type key))))))) + (second arg) (key-info-type key) + policy)))))) (values)) ;;;; IR1-OPTIMIZE @@ -273,53 +288,47 @@ (setf (component-reoptimize component) nil) (do-blocks (block component) (cond - ((or (block-delete-p block) - (null (block-pred block))) - (delete-block block)) - ((eq (functional-kind (block-home-lambda block)) :deleted) - ;; Preserve the BLOCK-SUCC invariant that almost every block has - ;; one successor (and a block with DELETE-P set is an acceptable - ;; exception). - (labels ((mark-blocks (block) - (dolist (pred (block-pred block)) - (when (and (not (block-delete-p pred)) - (eq (functional-kind (block-home-lambda pred)) - :deleted)) - (setf (block-delete-p pred) t) - (mark-blocks pred))))) - (mark-blocks block) - (delete-block block))) - (t - (loop - (let ((succ (block-succ block))) - (unless (and succ (null (rest succ))) - (return))) - - (let ((last (block-last block))) - (typecase last - (cif - (flush-dest (if-test last)) - (when (unlink-node last) - (return))) - (exit - (when (maybe-delete-exit last) - (return))))) - - (unless (join-successor-if-possible block) - (return))) - - (when (and (block-reoptimize block) (block-component block)) - (aver (not (block-delete-p block))) - (ir1-optimize-block block)) - ;; We delete blocks when there is either no predecessor or the ;; block is in a lambda that has been deleted. These blocks ;; would eventually be deleted by DFO recomputation, but doing ;; it here immediately makes the effect available to IR1 ;; optimization. - (when (and (block-flush-p block) (block-component block)) - (aver (not (block-delete-p block))) - (flush-dead-code block))))) + ((or (block-delete-p block) + (null (block-pred block))) + (delete-block block)) + ((eq (functional-kind (block-home-lambda block)) :deleted) + ;; Preserve the BLOCK-SUCC invariant that almost every block has + ;; one successor (and a block with DELETE-P set is an acceptable + ;; exception). + (mark-for-deletion block) + (delete-block block)) + (t + (loop + (let ((succ (block-succ block))) + (unless (and succ (null (rest succ))) + (return))) + + (let ((last (block-last block))) + (typecase last + (cif + (flush-dest (if-test last)) + (when (unlink-node last) + (return))) + (exit + (when (maybe-delete-exit last) + (return))))) + + (unless (join-successor-if-possible block) + (return))) + + (when (and (block-reoptimize block) (block-component block)) + (aver (not (block-delete-p block))) + (ir1-optimize-block block)) + + (cond ((block-delete-p block) + (delete-block block)) + ((and (block-flush-p block) (block-component block)) + (flush-dead-code block)))))) (values)) @@ -369,6 +378,7 @@ (derive-node-type node (continuation-derived-type value))))) (cset (ir1-optimize-set node))))) + (values)) ;;; Try to join with a successor block. If we succeed, we return true, @@ -1175,15 +1185,21 @@ (values)) ;;; Replace a call to a foldable function of constant arguments with -;;; the result of evaluating the form. We insert the resulting -;;; constant node after the call, stealing the call's continuation. We -;;; give the call a continuation with no DEST, which should cause it -;;; and its arguments to go away. If there is an error during the +;;; the result of evaluating the form. If there is an error during the ;;; evaluation, we give a warning and leave the call alone, making the ;;; call a :ERROR call. ;;; ;;; If there is more than one value, then we transform the call into a ;;; VALUES form. +;;; +;;; An old commentary also said: +;;; +;;; We insert the resulting constant node after the call, stealing +;;; the call's continuation. We give the call a continuation with no +;;; DEST, which should cause it and its arguments to go away. +;;; +;;; This seems to be more efficient, than the current code. Maybe we +;;; should really implement it? -- APD, 2002-12-23 (defun constant-fold-call (call) (let ((args (mapcar #'continuation-value (combination-args call))) (fun-name (combination-fun-source-name call))) @@ -1217,22 +1233,35 @@ ;; when the compiler tries to constant-fold (<= ;; END SIZE). ;; - ;; So, with or without bug 173, it'd be + ;; So, with or without bug 173, it'd be ;; unnecessarily evil to do a full ;; COMPILER-WARNING (and thus return FAILURE-P=T ;; from COMPILE-FILE) for legal code, so we we ;; use a wimpier COMPILE-STYLE-WARNING instead. #'compiler-style-warn "constant folding") - (if (not win) - (setf (combination-kind call) :error) - (let ((dummies (make-gensym-list (length args)))) - (transform-call - call - `(lambda ,dummies - (declare (ignore ,@dummies)) - (values ,@(mapcar (lambda (x) `',x) values))) - fun-name))))) + (cond ((not win) + (setf (combination-kind call) :error)) + ((and (proper-list-of-length-p values 1) + (eq (continuation-kind (node-cont call)) :inside-block)) + (with-ir1-environment-from-node call + (let* ((cont (node-cont call)) + (next (continuation-next cont)) + (prev (make-continuation))) + (delete-continuation-use call) + (add-continuation-use call prev) + (reference-constant prev cont (first values)) + (setf (continuation-next cont) next) + ;; FIXME: type checking? + (reoptimize-continuation cont) + (reoptimize-continuation prev)))) + (t (let ((dummies (make-gensym-list (length args)))) + (transform-call + call + `(lambda ,dummies + (declare (ignore ,@dummies)) + (values ,@(mapcar (lambda (x) `',x) values))) + fun-name)))))) (values)) ;;;; local call optimization @@ -1253,13 +1282,16 @@ (values)))) ;;; Figure out the type of a LET variable that has sets. We compute -;;; the union of the initial value Type and the types of all the set +;;; the union of the initial value TYPE and the types of all the set ;;; values and to a PROPAGATE-TO-REFS with this type. (defun propagate-from-sets (var type) (collect ((res type type-union)) (dolist (set (basic-var-sets var)) - (res (continuation-type (set-value set))) - (setf (node-reoptimize set) nil)) + (let ((type (continuation-type (set-value set)))) + (res type) + (when (node-reoptimize set) + (derive-node-type set type) + (setf (node-reoptimize set) nil)))) (propagate-to-refs var (res))) (values)) @@ -1290,9 +1322,12 @@ (null (lambda-var-sets leaf))) (defined-fun (not (eq (defined-fun-inlinep leaf) :notinline))) + #!+(and (not sb-fluid) (not sb-xc-host)) (global-var (case (global-var-kind leaf) - (:global-function t)))))) + (:global-function (let ((name (leaf-source-name leaf))) + (eq (symbol-package (fun-name-block-name name)) + *cl-package*)))))))) ;;; If we have a non-set LET var with a single use, then (if possible) ;;; replace the variable reference's CONT with the arg continuation. @@ -1313,6 +1348,7 @@ (let* ((ref (first (leaf-refs var))) (cont (node-cont ref)) (cont-atype (continuation-asserted-type cont)) + (cont-ctype (continuation-type-to-check cont)) (dest (continuation-dest cont))) (when (and (eq (continuation-use cont) ref) dest @@ -1329,7 +1365,7 @@ (lexenv-policy (node-lexenv (continuation-dest arg))))) (aver (member (continuation-kind arg) '(:block-start :deleted-block-start :inside-block))) - (assert-continuation-type arg cont-atype) + (set-continuation-type-assertion arg cont-atype cont-ctype) (setf (node-derived-type ref) *wild-type*) (change-ref-leaf ref (find-constant nil)) (substitute-continuation arg cont)