0.pre7.54:
[sbcl.git] / src / compiler / ir1opt.lisp
index 3c99417..a38f2fb 100644 (file)
 \f
 ;;;; interface for obtaining results of constant folding
 
-;;; Return true if the sole use of Cont is a reference to a constant leaf.
-(declaim (ftype (function (continuation) boolean) constant-continuation-p))
-(defun constant-continuation-p (cont)
-  (let ((use (continuation-use cont)))
-    (and (ref-p use)
-        (constant-p (ref-leaf use)))))
+;;; Return true for a CONTINUATION whose sole use is a reference to a
+;;; constant leaf.
+(defun constant-continuation-p (thing)
+  (and (continuation-p thing)
+       (let ((use (continuation-use thing)))
+        (and (ref-p use)
+             (constant-p (ref-leaf use))))))
 
 ;;; Return the constant value for a continuation whose only use is a
 ;;; constant node.
 (declaim (ftype (function (continuation) t) continuation-value))
 (defun continuation-value (cont)
-  (assert (constant-continuation-p cont))
+  (aver (constant-continuation-p cont))
   (constant-value (ref-leaf (continuation-use cont))))
 \f
 ;;;; interface for obtaining results of type inference
          (reoptimize-continuation (node-cont node))))))
   (values))
 
-;;; 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.
+;;; 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)
   (declare (type continuation cont) (type ctype type))
   (let ((cont-type (continuation-asserted-type cont)))
          (reoptimize-continuation cont)))))
   (values))
 
-;;; Assert that Call is to a function of the specified Type. It is
+;;; 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
 ;;; keyword positions.
 (defun assert-call-type (call type)
-  (declare (type combination call) (type function-type type))
-  (derive-node-type call (function-type-returns type))
+  (declare (type combination call) (type fun-type type))
+  (derive-node-type call (fun-type-returns type))
   (let ((args (combination-args call)))
-    (dolist (req (function-type-required type))
+    (dolist (req (fun-type-required type))
       (when (null args) (return-from assert-call-type))
       (let ((arg (pop args)))
        (assert-continuation-type arg req)))
-    (dolist (opt (function-type-optional type))
+    (dolist (opt (fun-type-optional type))
       (when (null args) (return-from assert-call-type))
       (let ((arg (pop args)))
        (assert-continuation-type arg opt)))
 
-    (let ((rest (function-type-rest type)))
+    (let ((rest (fun-type-rest type)))
       (when rest
        (dolist (arg args)
          (assert-continuation-type arg rest))))
 
-    (dolist (key (function-type-keywords type))
+    (dolist (key (fun-type-keywords type))
       (let ((name (key-info-name key)))
        (do ((arg args (cddr arg)))
            ((null arg))
 \f
 ;;;; IR1-OPTIMIZE
 
-;;; Do one forward pass over Component, deleting unreachable blocks
+;;; Do one forward pass over COMPONENT, deleting unreachable blocks
 ;;; and doing IR1 optimizations. We can ignore all blocks that don't
-;;; have the Reoptimize flag set. If Component-Reoptimize is true when
+;;; have the REOPTIMIZE flag set. If COMPONENT-REOPTIMIZE is true when
 ;;; we are done, then another iteration would be beneficial.
 ;;;
 ;;; We delete blocks when there is either no predecessor or the block
          (return)))
 
       (when (and (block-reoptimize block) (block-component block))
-       (assert (not (block-delete-p block)))
+       (aver (not (block-delete-p block)))
        (ir1-optimize-block block))
 
       (when (and (block-flush-p block) (block-component block))
-       (assert (not (block-delete-p block)))
+       (aver (not (block-delete-p block)))
        (flush-dead-code block)))))
 
   (values))
 ;;; -- With a combination, we call Propagate-Function-Change whenever
 ;;;    the function changes, and call IR1-Optimize-Combination if any
 ;;;    argument changes.
-;;; -- With an Exit, we derive the node's type from the Value's type. We don't
-;;;    propagate Cont's assertion to the Value, since if we did, this would
-;;;    move the checking of Cont's assertion to the exit. This wouldn't work
-;;;    with Catch and UWP, where the Exit node is just a placeholder for the
-;;;    actual unknown exit.
+;;; -- With an Exit, we derive the node's type from the Value's type.
+;;;    We don't propagate Cont's assertion to the Value, since if we
+;;;    did, this would move the checking of Cont's assertion to the
+;;;    exit. This wouldn't work with Catch and UWP, where the Exit
+;;;    node is just a placeholder for the actual unknown exit.
 ;;;
-;;; Note that we clear the node & block reoptimize flags *before* doing the
-;;; optimization. This ensures that the node or block will be reoptimized if
-;;; necessary. We leave the NODE-OPTIMIZE flag set going into
-;;; IR1-OPTIMIZE-RETURN, since IR1-OPTIMIZE-RETURN wants to clear the flag
-;;; itself.
+;;; Note that we clear the node & block reoptimize flags *before*
+;;; doing the optimization. This ensures that the node or block will
+;;; be reoptimized if necessary. We leave the NODE-OPTIMIZE flag set
+;;; going into IR1-OPTIMIZE-RETURN, since IR1-OPTIMIZE-RETURN wants to
+;;; clear the flag itself.
 (defun ir1-optimize-block (block)
   (declare (type cblock block))
   (setf (block-reoptimize block) nil)
 
 ;;; We cannot combine with a successor block if:
 ;;;  1. The successor has more than one predecessor.
-;;;  2. The last node's Cont is also used somewhere else.
+;;;  2. The last node's CONT is also used somewhere else.
 ;;;  3. The successor is the current block (infinite loop).
-;;;  4. The next block has a different cleanup, and thus we may want to insert
-;;;     cleanup code between the two blocks at some point.
-;;;  5. The next block has a different home lambda, and thus the control
-;;;     transfer is a non-local exit.
+;;;  4. The next block has a different cleanup, and thus we may want 
+;;;     to insert cleanup code between the two blocks at some point.
+;;;  5. The next block has a different home lambda, and thus the
+;;;     control transfer is a non-local exit.
 ;;;
 ;;; If we succeed, we return true, otherwise false.
 ;;;
-;;; Joining is easy when the successor's Start continuation is the same from
-;;; our Last's Cont. If they differ, then we can still join when the last
-;;; continuation has no next and the next continuation has no uses. In this
-;;; case, we replace the next continuation with the last before joining the
-;;; blocks.
+;;; Joining is easy when the successor's Start continuation is the
+;;; same from our Last's Cont. If they differ, then we can still join
+;;; when the last continuation has no next and the next continuation
+;;; has no uses. In this case, we replace the next continuation with
+;;; the last before joining the blocks.
 (defun join-successor-if-possible (block)
   (declare (type cblock block))
   (let ((next (first (block-succ block))))
              ((and (null (block-start-uses next))
                    (eq (continuation-kind last-cont) :inside-block))
               (let ((next-node (continuation-next next-cont)))
-                ;; If next-cont does have a dest, it must be unreachable,
-                ;; since there are no uses. DELETE-CONTINUATION will mark the
-                ;; dest block as delete-p [and also this block, unless it is
-                ;; no longer backward reachable from the dest block.]
+                ;; If next-cont does have a dest, it must be
+                ;; unreachable, since there are no uses.
+                ;; DELETE-CONTINUATION will mark the dest block as
+                ;; delete-p [and also this block, unless it is no
+                ;; longer backward reachable from the dest block.]
                 (delete-continuation next-cont)
                 (setf (node-prev next-node) last-cont)
                 (setf (continuation-next last-cont) next-node)
               nil))))))
 
 ;;; Join together two blocks which have the same ending/starting
-;;; continuation. The code in Block2 is moved into Block1 and Block2 is
-;;; deleted from the DFO. We combine the optimize flags for the two blocks so
-;;; that any indicated optimization gets done.
+;;; continuation. The code in Block2 is moved into Block1 and Block2
+;;; is deleted from the DFO. We combine the optimize flags for the two
+;;; blocks so that any indicated optimization gets done.
 (defun join-blocks (block1 block2)
   (declare (type cblock block1 block2))
   (let* ((last (block-last block2))
 
   (values))
 
-;;; Delete any nodes in Block whose value is unused and have no
+;;; Delete any nodes in BLOCK whose value is unused and have no
 ;;; side-effects. We can delete sets of lexical variables when the set
 ;;; variable has no references.
 ;;;
-;;; [### For now, don't delete potentially flushable calls when they have the
-;;; Call attribute. Someday we should look at the funcitonal args to determine
-;;; if they have any side-effects.]
+;;; [### For now, don't delete potentially flushable calls when they
+;;; have the CALL attribute. Someday we should look at the funcitonal
+;;; args to determine if they have any side-effects.]
 (defun flush-dead-code (block)
   (declare (type cblock block))
   (do-nodes-backwards (node cont block)
 \f
 ;;;; local call return type propagation
 
-;;; This function is called on RETURN nodes that have their REOPTIMIZE flag
-;;; set. It iterates over the uses of the RESULT, looking for interesting
-;;; stuff to update the TAIL-SET. If a use isn't a local call, then we union
-;;; its type together with the types of other such uses. We assign to the
-;;; RETURN-RESULT-TYPE the intersection of this type with the RESULT's asserted
-;;; type. We can make this intersection now (potentially before type checking)
-;;; because this assertion on the result will eventually be checked (if
+;;; This function is called on RETURN nodes that have their REOPTIMIZE
+;;; flag set. It iterates over the uses of the RESULT, looking for
+;;; interesting stuff to update the TAIL-SET. If a use isn't a local
+;;; call, then we union its type together with the types of other such
+;;; uses. We assign to the RETURN-RESULT-TYPE the intersection of this
+;;; type with the RESULT's asserted type. We can make this
+;;; intersection now (potentially before type checking) because this
+;;; assertion on the result will eventually be checked (if
 ;;; appropriate.)
 ;;;
-;;; We call MAYBE-CONVERT-TAIL-LOCAL-CALL on each local non-MV combination,
-;;; which may change the succesor of the call to be the called function, and if
-;;; so, checks if the call can become an assignment. If we convert to an
-;;; assignment, we abort, since the RETURN has been deleted.
+;;; We call MAYBE-CONVERT-TAIL-LOCAL-CALL on each local non-MV
+;;; combination, which may change the succesor of the call to be the
+;;; called function, and if so, checks if the call can become an
+;;; assignment. If we convert to an assignment, we abort, since the
+;;; RETURN has been deleted.
 (defun find-result-type (node)
   (declare (type creturn node))
   (let ((result (return-result node)))
       (do-uses (use result)
        (cond ((and (basic-combination-p use)
                    (eq (basic-combination-kind use) :local))
-              (assert (eq (lambda-tail-set (node-home-lambda use))
-                          (lambda-tail-set (combination-lambda use))))
+              (aver (eq (lambda-tail-set (node-home-lambda use))
+                        (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)))))
        (setf (return-result-type node) int))))
   (values))
 
-;;; Do stuff to realize that something has changed about the value delivered
-;;; to a return node. Since we consider the return values of all functions in
-;;; the tail set to be equivalent, this amounts to bringing the entire tail set
-;;; up to date. We iterate over the returns for all the functions in the tail
-;;; set, reanalyzing them all (not treating Node specially.)
+;;; Do stuff to realize that something has changed about the value
+;;; delivered to a return node. Since we consider the return values of
+;;; all functions in the tail set to be equivalent, this amounts to
+;;; bringing the entire tail set up to date. We iterate over the
+;;; returns for all the functions in the tail set, reanalyzing them
+;;; all (not treating Node specially.)
 ;;;
-;;; When we are done, we check whether the new type is different from the old
-;;; TAIL-SET-TYPE. If so, we set the type and also reoptimize all the
-;;; continuations for references to functions in the tail set. This will cause
-;;; IR1-OPTIMIZE-COMBINATION to derive the new type as the results of the
-;;; calls.
+;;; When we are done, we check whether the new type is different from
+;;; the old TAIL-SET-TYPE. If so, we set the type and also reoptimize
+;;; all the continuations for references to functions in the tail set.
+;;; This will cause IR1-OPTIMIZE-COMBINATION to derive the new type as
+;;; the results of the calls.
 (defun ir1-optimize-return (node)
   (declare (type creturn node))
   (let* ((tails (lambda-tail-set (return-lambda node)))
                   (if (continuation-value test)
                       (if-alternative node)
                       (if-consequent node)))
-                 ((not (types-intersect type (specifier-type 'null)))
+                 ((not (types-equal-or-intersect type (specifier-type 'null)))
                   (if-alternative node))
                  ((type= type (specifier-type 'null))
                   (if-consequent node)))))
 
 ;;; This function attempts to delete an exit node, returning true if
 ;;; it deletes the block as a consequence:
-;;; -- If the exit is degenerate (has no Entry), then we don't do anything,
-;;;    since there is nothing to be done.
-;;; -- If the exit node and its Entry have the same home lambda then we know
-;;;    the exit is local, and can delete the exit. We change uses of the
-;;;    Exit-Value to be uses of the original continuation, then unlink the
-;;;    node. If the exit is to a TR context, then we must do MERGE-TAIL-SETS
-;;;    on any local calls which delivered their value to this exit.
-;;; -- If there is no value (as in a GO), then we skip the value semantics.
+;;; -- If the exit is degenerate (has no Entry), then we don't do
+;;;    anything, since there is nothing to be done.
+;;; -- If the exit node and its Entry have the same home lambda then
+;;;    we know the exit is local, and can delete the exit. We change
+;;;    uses of the Exit-Value to be uses of the original continuation,
+;;;    then unlink the node. If the exit is to a TR context, then we
+;;;    must do MERGE-TAIL-SETS on any local calls which delivered
+;;;    their value to this exit.
+;;; -- If there is no value (as in a GO), then we skip the value
+;;;    semantics.
 ;;;
 ;;; This function is also called by environment analysis, since it
 ;;; wants all exits to be optimized even if normal optimization was
         (tail (component-tail (block-component block)))
         (succ (first (block-succ block))))
     (unless (or (and (eq call (block-last block)) (eq succ tail))
-               (block-delete-p block)
-               *converting-for-interpreter*)
+               (block-delete-p block))
       (when (or (and (eq (continuation-asserted-type cont) *empty-type*)
                     (not (or ir1-p (eq (continuation-kind cont) :deleted))))
                (eq (node-derived-type call) *empty-type*))
               (delete-continuation-use call)
               (cond
                ((block-last block)
-                (assert (and (eq (block-last block) call)
-                             (eq (continuation-kind cont) :block-start))))
+                (aver (and (eq (block-last block) call)
+                           (eq (continuation-kind cont) :block-start))))
                (t
                 (setf (block-last block) call)
                 (link-blocks block (continuation-starts-block cont)))))
        
        (unlink-blocks block (first (block-succ block)))
        (setf (component-reanalyze (block-component block)) t)
-       (assert (not (block-succ block)))
+       (aver (not (block-succ block)))
        (link-blocks block tail)
        (add-continuation-use call (make-continuation))
        t))))
 
-;;; Called both by IR1 conversion and IR1 optimization when they have
-;;; verified the type signature for the call, and are wondering if
-;;; something should be done to special-case the call. If Call is a
-;;; call to a global function, then see whether it defined or known:
-;;; -- If a DEFINED-FUNCTION should be inline expanded, then convert the
-;;;    expansion and change the call to call it. Expansion is enabled if
-;;;    :INLINE or if space=0. If the FUNCTIONAL slot is true, we never expand,
-;;;    since this function has already been converted. Local call analysis
-;;;    will duplicate the definition if necessary. We claim that the parent
-;;;    form is LABELS for context declarations, since we don't want it to be
-;;;    considered a real global function.
-;;; -- In addition to a direct check for the function name in the table, we
-;;;    also must check for slot accessors. If the function is a slot accessor,
-;;;    then we set the combination kind to the function info of %Slot-Setter or
-;;;    %Slot-Accessor, as appropriate.
-;;; -- If it is a known function, mark it as such by setting the Kind.
+;;; This is called both by IR1 conversion and IR1 optimization when
+;;; they have verified the type signature for the call, and are
+;;; wondering if something should be done to special-case the call. If
+;;; CALL is a call to a global function, then see whether it defined
+;;; or known:
+;;; -- If a DEFINED-FUNCTION should be inline expanded, then convert
+;;;    the expansion and change the call to call it. Expansion is
+;;;    enabled if :INLINE or if SPACE=0. If the FUNCTIONAL slot is
+;;;    true, we never expand, since this function has already been
+;;;    converted. Local call analysis will duplicate the definition if
+;;;    necessary. We claim that the parent form is LABELS for context
+;;;    declarations, since we don't want it to be considered a real
+;;;    global function.
+;;; -- In addition to a direct check for the function name in the
+;;;    table, we also must check for slot accessors. If the function
+;;;    is a slot accessor, then we set the combination kind to the
+;;;    function info of %Slot-Setter or %Slot-Accessor, as
+;;;    appropriate.
+;;; -- If it is a known function, mark it as such by setting the KIND.
 ;;;
 ;;; We return the leaf referenced (NIL if not a leaf) and the
-;;; function-info assigned.
+;;; FUNCTION-INFO assigned.
 (defun recognize-known-call (call ir1-p)
   (declare (type combination call))
   (let* ((ref (continuation-use (basic-combination-fun call)))
         (leaf (when (ref-p ref) (ref-leaf ref)))
-        (inlinep (if (and (defined-function-p leaf)
-                          (not (byte-compiling)))
+        (inlinep (if (defined-function-p leaf)
                      (defined-function-inlinep leaf)
                      :no-chance)))
     (cond
 ;;; and that checking is done by local call analysis.
 (defun validate-call-type (call type ir1-p)
   (declare (type combination call) (type ctype type))
-  (cond ((not (function-type-p type))
-        (assert (multiple-value-bind (val win)
-                    (csubtypep type (specifier-type 'function))
-                  (or val (not win))))
+  (cond ((not (fun-type-p type))
+        (aver (multiple-value-bind (val win)
+                  (csubtypep type (specifier-type 'function))
+                (or val (not win))))
         (recognize-known-call call ir1-p))
        ((valid-function-use call type
                             :argument-test #'always-subtypep
                             :result-test #'always-subtypep
-                            :error-function #'compiler-warning
+                            ;; KLUDGE: Common Lisp is such a dynamic
+                            ;; language that all we can do here in
+                            ;; general is issue a STYLE-WARNING. It
+                            ;; would be nice to issue a full WARNING
+                            ;; in the special case of of type
+                            ;; mismatches within a compilation unit
+                            ;; (as in section 3.2.2.3 of the spec)
+                            ;; but at least as of sbcl-0.6.11, we
+                            ;; don't keep track of whether the
+                            ;; mismatched data came from the same
+                            ;; compilation unit, so we can't do that.
+                            ;; -- WHN 2001-02-11
+                            ;;
+                            ;; FIXME: Actually, I think we could
+                            ;; issue a full WARNING if the call
+                            ;; violates a DECLAIM FTYPE.
+                            :error-function #'compiler-style-warning
                             :warning-function #'compiler-note)
         (assert-call-type call type)
         (maybe-terminate-block call ir1-p)
 \f
 ;;;; known function optimization
 
-;;; Add a failed optimization note to FAILED-OPTIMZATIONS for Node,
-;;; Fun and Args. If there is already a note for Node and Transform,
+;;; Add a failed optimization note to FAILED-OPTIMZATIONS for NODE,
+;;; FUN and ARGS. If there is already a note for NODE and TRANSFORM,
 ;;; replace it, otherwise add a new one.
 (defun record-optimization-failure (node transform args)
   (declare (type combination node) (type transform transform)
-          (type (or function-type list) args))
+          (type (or fun-type list) args))
   (let* ((table (component-failed-optimizations *component-being-compiled*))
         (found (assoc transform (gethash node table))))
     (if found
   (declare (type combination node) (type transform transform))
   (let* ((type (transform-type transform))
         (fun (transform-function transform))
-        (constrained (function-type-p type))
+        (constrained (fun-type-p type))
         (table (component-failed-optimizations *component-being-compiled*))
         (flame (if (transform-important transform)
                    (policy node (>= speed inhibit-warnings))
                    (policy node (> speed inhibit-warnings))))
         (*compiler-error-context* node))
     (cond ((not (member (transform-when transform)
-                       (if *byte-compiling*
-                           '(:byte   :both)
-                           '(:native :both))))
+                       '(:native :both)))
           ;; FIXME: Make sure that there's a transform for
           ;; (MEMBER SYMBOL ..) into MEMQ.
           ;; FIXME: Note that when/if I make SHARE operation to shared
           ;; '(:BOTH) tail sublists.
           (let ((when (transform-when transform)))
             (not (or (eq when :both)
-                     (eq when (if *byte-compiling* :byte :native)))))
+                     (eq when :native))))
           t)
          ((or (not constrained)
               (valid-function-use node type :strict-result t))
                      (record-optimization-failure node transform args))
                    (setf (gethash node table)
                          (remove transform (gethash node table) :key #'car)))
-               t))))
+               t)
+               (:delayed
+                 (remhash node table)
+                 nil))))
          ((and flame
                (valid-function-use node
                                    type
-                                   :argument-test #'types-intersect
-                                   :result-test #'values-types-intersect))
+                                   :argument-test #'types-equal-or-intersect
+                                   :result-test
+                                   #'values-types-equal-or-intersect))
           (record-optimization-failure node transform type)
           t)
          (t
           t))))
 
-;;; Just throw the severity and args...
+;;; When we don't like an IR1 transform, we throw the severity/reason
+;;; and args. 
+;;;
+;;; GIVE-UP-IR1-TRANSFORM is used to throw out of an IR1 transform,
+;;; aborting this attempt to transform the call, but admitting the
+;;; possibility that this or some other transform will later succeed.
+;;; If arguments are supplied, they are format arguments for an
+;;; efficiency note.
+;;;
+;;; ABORT-IR1-TRANSFORM is used to throw out of an IR1 transform and
+;;; force a normal call to the function at run time. No further
+;;; optimizations will be attempted.
+;;;
+;;; DELAY-IR1-TRANSFORM is used to throw out of an IR1 transform, and
+;;; delay the transform on the node until later. REASONS specifies
+;;; when the transform will be later retried. The :OPTIMIZE reason
+;;; causes the transform to be delayed until after the current IR1
+;;; optimization pass. The :CONSTRAINT reason causes the transform to
+;;; be delayed until after constraint propagation.
+;;;
+;;; FIXME: Now (0.6.11.44) that there are 4 variants of this (GIVE-UP,
+;;; ABORT, DELAY/:OPTIMIZE, DELAY/:CONSTRAINT) and we're starting to
+;;; do CASE operations on the various REASON values, it might be a
+;;; good idea to go OO, representing the reasons by objects, using
+;;; CLOS methods on the objects instead of CASE, and (possibly) using
+;;; SIGNAL instead of THROW.
 (declaim (ftype (function (&rest t) nil) give-up-ir1-transform))
 (defun give-up-ir1-transform (&rest args)
-  #!+sb-doc
-  "This function is used to throw out of an IR1 transform, aborting this
-  attempt to transform the call, but admitting the possibility that this or
-  some other transform will later succeed. If arguments are supplied, they are
-  format arguments for an efficiency note."
   (throw 'give-up-ir1-transform (values :failure args)))
 (defun abort-ir1-transform (&rest args)
-  #!+sb-doc
-  "This function is used to throw out of an IR1 transform and force a normal
-  call to the function at run time. No further optimizations will be
-  attempted."
   (throw 'give-up-ir1-transform (values :aborted args)))
-
-;;; Take the lambda-expression Res, IR1 convert it in the proper
+(defun delay-ir1-transform (node &rest reasons)
+  (let ((assoc (assoc node *delayed-ir1-transforms*)))
+    (cond ((not assoc)
+            (setf *delayed-ir1-transforms*
+                    (acons node reasons *delayed-ir1-transforms*))
+            (throw 'give-up-ir1-transform :delayed))
+         ((cdr assoc)
+            (dolist (reason reasons)
+              (pushnew reason (cdr assoc)))
+            (throw 'give-up-ir1-transform :delayed)))))
+
+;;; Clear any delayed transform with no reasons - these should have
+;;; been tried in the last pass. Then remove the reason from the
+;;; delayed transform reasons, and if any become empty then set
+;;; reoptimize flags for the node. Return true if any transforms are
+;;; to be retried.
+(defun retry-delayed-ir1-transforms (reason)
+  (setf *delayed-ir1-transforms*
+       (remove-if-not #'cdr *delayed-ir1-transforms*))
+  (let ((reoptimize nil))
+    (dolist (assoc *delayed-ir1-transforms*)
+      (let ((reasons (remove reason (cdr assoc))))
+       (setf (cdr assoc) reasons)
+       (unless reasons
+         (let ((node (car assoc)))
+           (unless (node-deleted node)
+             (setf reoptimize t)
+             (setf (node-reoptimize node) t)
+             (let ((block (node-block node)))
+               (setf (block-reoptimize block) t)
+               (setf (component-reoptimize (block-component block)) t)))))))
+    reoptimize))
+
+
+;;; Take the lambda-expression RES, IR1 convert it in the proper
 ;;; environment, and then install it as the function for the call
-;;; Node. We do local call analysis so that the new function is
+;;; NODE. We do local call analysis so that the new function is
 ;;; integrated into the control flow.
 (defun transform-call (node res)
   (declare (type combination node) (list res))
 \f
 ;;;; local call optimization
 
-;;; Propagate Type to Leaf and its Refs, marking things changed. If
+;;; Propagate TYPE to LEAF and its REFS, marking things changed. If
 ;;; the leaf type is a function type, then just leave it alone, since
 ;;; TYPE is never going to be more specific than that (and
 ;;; TYPE-INTERSECTION would choke.)
 (defun propagate-to-refs (leaf type)
   (declare (type leaf leaf) (type ctype type))
   (let ((var-type (leaf-type leaf)))
-    (unless (function-type-p var-type)
-      (let ((int (type-intersection var-type type)))
+    (unless (fun-type-p var-type)
+      (let ((int (type-approx-intersection2 var-type type)))
        (when (type/= int var-type)
          (setf (leaf-type leaf) int)
          (dolist (ref (leaf-refs leaf))
 ;;;    would be NIL.
 ;;; -- the var's DEST has a different policy than the ARG's (think safety).
 ;;;
-;;; We change the Ref to be a reference to NIL with unused value, and
+;;; We change the REF to be a reference to NIL with unused value, and
 ;;; let it be flushed as dead code. A side-effect of this substitution
 ;;; is to delete the variable.
 (defun substitute-single-use-continuation (arg var)
                        *empty-type*))
               (eq (lexenv-policy (node-lexenv dest))
                   (lexenv-policy (node-lexenv (continuation-dest arg)))))
-      (assert (member (continuation-kind arg)
-                     '(:block-start :deleted-block-start :inside-block)))
+      (aver (member (continuation-kind arg)
+                   '(:block-start :deleted-block-start :inside-block)))
       (assert-continuation-type arg cont-atype)
       (setf (node-derived-type ref) *wild-type*)
       (change-ref-leaf ref (find-constant nil))
 ;;; flush the FUN continuation.
 (defun delete-let (fun)
   (declare (type clambda fun))
-  (assert (member (functional-kind fun) '(:let :mv-let)))
+  (aver (member (functional-kind fun) '(:let :mv-let)))
   (note-unreferenced-vars fun)
   (let ((call (let-combination fun)))
     (flush-dest (basic-combination-fun call))
                                  this-comp)
                              t)
                             (t
-                             (assert (eq (functional-kind (lambda-home fun))
-                                         :top-level))
+                             (aver (eq (functional-kind (lambda-home fun))
+                                       :top-level))
                              nil)))
                   leaf var))
                t)))))
        ((and (null (rest (leaf-refs var)))
-            (not *byte-compiling*)
             (substitute-single-use-continuation arg var)))
        (t
        (propagate-to-refs var (continuation-type arg))))))
        (when fun-changed
         (setf (continuation-reoptimize fun) nil)
         (let ((type (continuation-type fun)))
-          (when (function-type-p type)
-            (derive-node-type node (function-type-returns type))))
+          (when (fun-type-p type)
+            (derive-node-type node (fun-type-returns type))))
         (maybe-terminate-block node nil)
         (let ((use (continuation-use fun)))
           (when (and (ref-p use) (functional-p (ref-leaf use)))
       (return-from ir1-optimize-mv-call))
 
     (multiple-value-bind (min max)
-       (function-type-nargs (continuation-type fun))
+       (fun-type-nargs (continuation-type fun))
       (let ((total-nvals
             (multiple-value-bind (types nvals)
                 (values-types (continuation-derived-type (first args)))
                              (declare (ignore ,ignore))
                              (funcall ,(ref-leaf ref) ,@dums)))))
                (change-ref-leaf ref fun)
-               (assert (eq (basic-combination-kind node) :full))
+               (aver (eq (basic-combination-kind node) :full))
                (local-call-analyze *current-component*)
-               (assert (eq (basic-combination-kind node) :local)))))))))
+               (aver (eq (basic-combination-kind node) :local)))))))))
   (values))
 
 ;;; If we see:
        `(lambda (val ,@dummies)
           (declare (ignore ,@dummies))
           val))
-      'nil))
+      nil))