X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fir1opt.lisp;h=e4c633b9e178d6258ba2f71090224e236eb442f5;hb=148e3820ad314a9b59d0133c1d60eaac4af9118b;hp=5626039e676f49e7a499a1c1e3c752137ff12c32;hpb=1fdd787fcdac403f92d121701aee8738f710f048;p=sbcl.git diff --git a/src/compiler/ir1opt.lisp b/src/compiler/ir1opt.lisp index 5626039..e4c633b 100644 --- a/src/compiler/ir1opt.lisp +++ b/src/compiler/ir1opt.lisp @@ -118,6 +118,43 @@ (declaim (ftype (function (continuation) ctype) continuation-type)) (defun continuation-type (cont) (single-value-type (continuation-derived-type cont))) + +;;; If CONT is an argument of a function, return a type which the +;;; function checks CONT for. +#!-sb-fluid (declaim (inline continuation-externally-checkable-type)) +(defun continuation-externally-checkable-type (cont) + (or (continuation-%externally-checkable-type cont) + (%continuation-%externally-checkable-type cont))) +(defun %continuation-%externally-checkable-type (cont) + (declare (type continuation cont)) + (let ((dest (continuation-dest cont))) + (if (not (and dest (combination-p dest))) + ;; TODO: MV-COMBINATION + (setf (continuation-%externally-checkable-type cont) *wild-type*) + (let* ((fun (combination-fun dest)) + (args (combination-args dest)) + (fun-type (continuation-type fun))) + (if (or (not (fun-type-p fun-type)) + ;; FUN-TYPE might be (AND FUNCTION (SATISFIES ...)). + (fun-type-wild-args fun-type)) + (progn (dolist (arg args) + (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) + (let ((rest (list (or (fun-type-rest fun-type) + *wild-type*)))) + (setf (cdr rest) rest))))) + ;; TODO: &KEY + (loop + for arg of-type continuation in args + and type of-type ctype in arg-types + do (when arg + (setf (continuation-%externally-checkable-type arg) + type))) + (continuation-%externally-checkable-type cont))))))) ;;;; interface routines used by optimizers @@ -152,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))) @@ -179,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 @@ -203,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))) @@ -224,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 @@ -247,9 +297,9 @@ ;; 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)) + (unless (or (block-delete-p pred) + (eq (component-head (block-component pred)) + pred)) (setf (block-delete-p pred) t) (mark-blocks pred))))) (mark-blocks block) @@ -441,13 +491,28 @@ (let ((info (combination-kind node))) (when (fun-info-p info) (let ((attr (fun-info-attributes info))) - (when (and (ir1-attributep attr flushable) + (when (and (not (ir1-attributep attr call)) ;; ### For now, don't delete potentially ;; flushable calls when they have the CALL ;; attribute. Someday we should look at the ;; functional args to determine if they have ;; any side effects. - (not (ir1-attributep attr call))) + (if (policy node (= safety 3)) + (and (ir1-attributep attr flushable) + (every (lambda (arg) + ;; FIXME: when bug 203 + ;; will be fixed, remove + ;; this check + (member (continuation-type-check arg) + '(nil :deleted))) + (basic-combination-args node)) + (valid-fun-use node + (info :function :type + (leaf-source-name (ref-leaf (continuation-use (basic-combination-fun node))))) + :result-test #'always-subtypep + :lossage-fun nil + :unwinnage-fun nil)) + (ir1-attributep attr unsafely-flushable))) (flush-dest (combination-fun node)) (dolist (arg (combination-args node)) (flush-dest arg)) @@ -615,6 +680,7 @@ (new-block (continuation-starts-block new-cont))) (link-node-to-previous-continuation new-node new-cont) (setf (continuation-dest new-cont) new-node) + (setf (continuation-%externally-checkable-type new-cont) nil) (add-continuation-use new-node dummy-cont) (setf (block-last new-block) new-node) @@ -935,31 +1001,31 @@ (continuation-use (basic-combination-fun call)) call)) ((not leaf)) - ((or (info :function :source-transform (leaf-source-name leaf)) - (and info - (ir1-attributep (fun-info-attributes info) - predicate) - (let ((dest (continuation-dest (node-cont call)))) - (and dest (not (if-p dest)))))) - (when (and (leaf-has-source-name-p leaf) - ;; FIXME: This SYMBOLP is part of a literal - ;; translation of a test in the old CMU CL - ;; source, and it's not quite clear what - ;; the old source meant. Did it mean "has a - ;; valid name"? Or did it mean "is an - ;; ordinary function name, not a SETF - ;; function"? Either way, the old CMU CL - ;; code probably didn't deal with SETF - ;; functions correctly, and neither does - ;; this new SBCL code, and that should be fixed. - (symbolp (leaf-source-name leaf))) - (let ((dummies (make-gensym-list (length - (combination-args call))))) - (transform-call call - `(lambda ,dummies - (,(leaf-source-name leaf) - ,@dummies)) - (leaf-source-name leaf)))))))))) + ((and (leaf-has-source-name-p leaf) + (or (info :function :source-transform (leaf-source-name leaf)) + (and info + (ir1-attributep (fun-info-attributes info) + predicate) + (let ((dest (continuation-dest (node-cont call)))) + (and dest (not (if-p dest))))))) + ;; FIXME: This SYMBOLP is part of a literal + ;; translation of a test in the old CMU CL + ;; source, and it's not quite clear what + ;; the old source meant. Did it mean "has a + ;; valid name"? Or did it mean "is an + ;; ordinary function name, not a SETF + ;; function"? Either way, the old CMU CL + ;; code probably didn't deal with SETF + ;; functions correctly, and neither does + ;; this new SBCL code, and that should be fixed. + (when (symbolp (leaf-source-name leaf)) + (let ((dummies (make-gensym-list + (length (combination-args call))))) + (transform-call call + `(lambda ,dummies + (,(leaf-source-name leaf) + ,@dummies)) + (leaf-source-name leaf)))))))))) (values)) ;;;; known function optimization @@ -1228,7 +1294,7 @@ (derive-node-type node (continuation-type (set-value node))) (values)) -;;; Return true if the value of Ref will always be the same (and is +;;; Return true if the value of REF will always be the same (and is ;;; thus legal to substitute.) (defun constant-reference-p (ref) (declare (type ref ref)) @@ -1262,6 +1328,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 @@ -1278,7 +1345,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) @@ -1603,7 +1670,8 @@ (flush-dest (combination-fun use)) (let ((fun-cont (basic-combination-fun call))) (setf (continuation-dest fun-cont) use) - (setf (combination-fun use) fun-cont)) + (setf (combination-fun use) fun-cont) + (setf (continuation-%externally-checkable-type fun-cont) nil)) (setf (combination-kind use) :local) (setf (functional-kind fun) :let) (flush-dest (first (basic-combination-args call))) @@ -1633,7 +1701,8 @@ (setf (combination-kind node) :full) (let ((args (combination-args use))) (dolist (arg args) - (setf (continuation-dest arg) node)) + (setf (continuation-dest arg) node) + (setf (continuation-%externally-checkable-type arg) nil)) (setf (combination-args use) nil) (flush-dest list) (setf (combination-args node) args))