(defun ir1-optimize (component)
(declare (type component component))
(setf (component-reoptimize component) nil)
- (do-blocks (block component)
- (cond
- ;; 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.
- ((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 (singleton-p 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 ((and (block-delete-p block) (block-component block))
- (delete-block block))
- ((and (block-flush-p block) (block-component block))
- (flush-dead-code block))))))
+ (loop with block = (block-next (component-head component))
+ with tail = (component-tail component)
+ for last-block = block
+ until (eq block tail)
+ do (cond
+ ;; 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.
+ ((or (block-delete-p block)
+ (null (block-pred block)))
+ (delete-block-lazily block)
+ (setq block (clean-component component 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)
+ (setq block (clean-component component block)))
+ (t
+ (loop
+ (let ((succ (block-succ block)))
+ (unless (singleton-p 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 ((and (block-delete-p block) (block-component block))
+ (setq block (clean-component component block)))
+ ((and (block-flush-p block) (block-component block))
+ (flush-dead-code block)))))
+ do (when (eq block last-block)
+ (setq block (block-next block))))
(values))
(when (block-start next) ; NEXT is not an END-OF-COMPONENT marker
(cond ( ;; We cannot combine with a successor block if:
(or
- ;; The successor has more than one predecessor.
+ ;; the successor has more than one predecessor;
(rest (block-pred next))
- ;; The successor is the current block (infinite loop).
+ ;; the successor is the current block (infinite loop);
(eq next block)
- ;; The next block has a different cleanup, and thus
+ ;; the next block has a different cleanup, and thus
;; we may want to insert cleanup code between the
- ;; two blocks at some point.
+ ;; two blocks at some point;
(not (eq (block-end-cleanup block)
(block-start-cleanup next)))
- ;; The next block has a different home lambda, and
+ ;; the next block has a different home lambda, and
;; thus the control transfer is a non-local exit.
(not (eq (block-home-lambda block)
- (block-home-lambda next))))
+ (block-home-lambda next)))
+ ;; Stack analysis phase wants ENTRY to start a block.
+ (entry-p (block-start-node next)))
nil)
(t
(join-blocks block next)
(delete-ref node)
(unlink-node node))
(combination
- (let ((info (combination-kind node)))
- (when (fun-info-p info)
+ (let ((kind (combination-kind node))
+ (info (combination-fun-info node)))
+ (when (and (eq kind :known) (fun-info-p info))
(let ((attr (fun-info-attributes info)))
(when (and (not (ir1-attributep attr call))
;; ### For now, don't delete potentially
(lambda-tail-set (combination-lambda use))))
(when (combination-p use)
(when (nth-value 1 (maybe-convert-tail-local-call use))
- (return-from find-result-type (values)))))
+ (return-from find-result-type t))))
(t
(use-union (node-derived-type use))))))
(let ((int
;; )
))
(setf (return-result-type node) int))))
- (values))
+ nil)
;;; Do stuff to realize that something has changed about the value
;;; delivered to a return node. Since we consider the return values of
;;; results of the calls.
(defun ir1-optimize-return (node)
(declare (type creturn node))
- (let* ((tails (lambda-tail-set (return-lambda node)))
- (funs (tail-set-funs tails)))
- (collect ((res *empty-type* values-type-union))
- (dolist (fun funs)
- (let ((return (lambda-return fun)))
- (when return
- (when (node-reoptimize return)
- (setf (node-reoptimize return) nil)
- (find-result-type return))
- (res (return-result-type return)))))
-
- (when (type/= (res) (tail-set-type tails))
- (setf (tail-set-type tails) (res))
- (dolist (fun (tail-set-funs tails))
- (dolist (ref (leaf-refs fun))
- (reoptimize-lvar (node-lvar ref)))))))
+ (tagbody
+ :restart
+ (let* ((tails (lambda-tail-set (return-lambda node)))
+ (funs (tail-set-funs tails)))
+ (collect ((res *empty-type* values-type-union))
+ (dolist (fun funs)
+ (let ((return (lambda-return fun)))
+ (when return
+ (when (node-reoptimize return)
+ (setf (node-reoptimize return) nil)
+ (when (find-result-type return)
+ (go :restart)))
+ (res (return-result-type return)))))
+
+ (when (type/= (res) (tail-set-type tails))
+ (setf (tail-set-type tails) (res))
+ (dolist (fun (tail-set-funs tails))
+ (dolist (ref (leaf-refs fun))
+ (reoptimize-lvar (node-lvar ref))))))))
(values))
\f
(propagate-fun-change node)
(maybe-terminate-block node nil))
(let ((args (basic-combination-args node))
- (kind (basic-combination-kind node)))
- (case kind
+ (kind (basic-combination-kind node))
+ (info (basic-combination-fun-info node)))
+ (ecase kind
(:local
(let ((fun (combination-lambda node)))
(if (eq (functional-kind fun) :let)
(propagate-let-args node fun)
(propagate-local-call-args node fun))))
- ((:full :error)
+ (:error
(dolist (arg args)
(when arg
(setf (lvar-reoptimize arg) nil))))
- (t
+ (:full
+ (dolist (arg args)
+ (when arg
+ (setf (lvar-reoptimize arg) nil)))
+ (when info
+ (let ((fun (fun-info-derive-type info)))
+ (when fun
+ (let ((res (funcall fun node)))
+ (when res
+ (derive-node-type node (coerce-to-values res))
+ (maybe-terminate-block node nil)))))))
+ (:known
+ (aver info)
(dolist (arg args)
(when arg
(setf (lvar-reoptimize arg) nil)))
- (let ((attr (fun-info-attributes kind)))
+ (let ((attr (fun-info-attributes info)))
(when (and (ir1-attributep attr foldable)
;; KLUDGE: The next test could be made more sensitive,
;; only suppressing constant-folding of functions with
(constant-fold-call node)
(return-from ir1-optimize-combination)))
- (let ((fun (fun-info-derive-type kind)))
+ (let ((fun (fun-info-derive-type info)))
(when fun
(let ((res (funcall fun node)))
(when res
(derive-node-type node (coerce-to-values res))
(maybe-terminate-block node nil)))))
- (let ((fun (fun-info-optimizer kind)))
+ (let ((fun (fun-info-optimizer info)))
(unless (and fun (funcall fun node))
- (dolist (x (fun-info-transforms kind))
+ (dolist (x (fun-info-transforms info))
#!+sb-show
(when *show-transforms-p*
(let* ((lvar (basic-combination-fun node))
(defined-fun-inlinep leaf)
:no-chance)))
(cond
- ((eq inlinep :notinline) (values nil nil))
+ ((eq inlinep :notinline)
+ (let ((info (info :function :info (leaf-source-name leaf))))
+ (when info
+ (setf (basic-combination-fun-info call) info))
+ (values nil nil)))
((not (and (global-var-p leaf)
(eq (global-var-kind leaf) :global-function)))
(values leaf nil))
(t
(let ((info (info :function :info (leaf-source-name leaf))))
(if info
- (values leaf (setf (basic-combination-kind call) info))
+ (values leaf
+ (progn
+ (setf (basic-combination-kind call) :known)
+ (setf (basic-combination-fun-info call) info)))
(values leaf nil)))))))
;;; Check whether CALL satisfies TYPE. If so, apply the type to the
(recognize-known-call call ir1-converting-not-optimizing-p))
((valid-fun-use call type
:argument-test #'always-subtypep
- :result-test #'always-subtypep
+ :result-test nil
;; KLUDGE: Common Lisp is such a dynamic
;; language that all we can do here in
;; general is issue a STYLE-WARNING. It
(() (null (rest sets)) :exit-if-null)
(set-use (principal-lvar-use (set-value set)))
(() (and (combination-p set-use)
- (fun-info-p (combination-kind set-use))
+ (eq (combination-kind set-use) :known)
+ (fun-info-p (combination-fun-info set-use))
+ (not (node-to-be-deleted-p set-use))
(eq (combination-fun-source-name set-use) '+))
:exit-if-null)
(+-args (basic-combination-args set-use))
(unlink-node call)
(unlink-node (lambda-bind clambda))
(setf (lambda-bind clambda) nil))
+ (setf (functional-kind clambda) :zombie)
+ (let ((home (lambda-home clambda)))
+ (setf (lambda-lets home) (delete clambda (lambda-lets home))))
(values))
;;; This function is called when one of the arguments to a LET
(deftransform values ((&rest vals) * * :node node)
(unless (lvar-single-value-p (node-lvar node))
(give-up-ir1-transform))
- (setf (node-derived-type node) *wild-type*)
+ (setf (node-derived-type node)
+ (make-short-values-type (list (single-value-type
+ (node-derived-type node)))))
(principal-lvar-single-valuify (node-lvar node))
(if vals
(let ((dummies (make-gensym-list (length (cdr vals)))))
(immediately-used-p value use))
(unless next-block
(when ctran (ensure-block-start ctran))
- (setq next-block (first (block-succ (node-block cast)))))
+ (setq next-block (first (block-succ (node-block cast))))
+ (ensure-block-start (node-prev cast)))
(%delete-lvar-use use)
(add-lvar-use use lvar)
(unlink-blocks (node-block use) (node-block cast))
(maybe-terminate-block (lvar-uses value) nil)
;; FIXME: Is it necessary?
(aver (null (block-pred (node-block cast))))
- (setf (block-delete-p (node-block cast)) t)
+ (delete-block-lazily (node-block cast))
(return-from ir1-optimize-cast)))
(when (eq (node-derived-type cast) *empty-type*)
(maybe-terminate-block cast nil))