0.7.12.1:
[sbcl.git] / src / compiler / ir1util.lisp
index 926e183..4988282 100644 (file)
                 (nsubst new old (basic-combination-args dest))))))
 
     (flush-dest old)
-    (setf (continuation-dest new) dest))
+    (setf (continuation-dest new) dest)
+    (setf (continuation-%externally-checkable-type new) nil))
   (values))
 
 ;;; Replace all uses of OLD with uses of NEW, where NEW has an
 ;;; slot values. Values for the alist slots are NCONCed to the
 ;;; beginning of the current value, rather than replacing it entirely.
 (defun make-lexenv (&key (default *lexenv*)
-                        funs vars blocks tags type-restrictions options
+                        funs vars blocks tags
+                         type-restrictions weakend-type-restrictions
                         (lambda (lexenv-lambda default))
                         (cleanup (lexenv-cleanup default))
                         (policy (lexenv-policy default)))
      (frob blocks lexenv-blocks)
      (frob tags lexenv-tags)
      (frob type-restrictions lexenv-type-restrictions)
-     lambda cleanup policy 
-     (frob options lexenv-options))))
+     (frob weakend-type-restrictions lexenv-weakend-type-restrictions)
+     lambda cleanup policy)))
+
+;;; Makes a LEXENV, suitable for using in a MACROLET introduced
+;;; macroexpander
+(defun make-restricted-lexenv (lexenv)
+  (flet ((fun-good-p (fun)
+           (destructuring-bind (name . thing) fun
+             (declare (ignore name))
+             (etypecase thing
+               (functional nil)
+               (global-var t)
+               (cons (aver (eq (car thing) 'macro))
+                     t))))
+         (var-good-p (var)
+           (destructuring-bind (name . thing) var
+             (declare (ignore name))
+             (etypecase thing
+               (leaf nil)
+               (cons (aver (eq (car thing) 'macro))
+                     t)
+               (heap-alien-info nil)))))
+    (internal-make-lexenv
+     (remove-if-not #'fun-good-p (lexenv-funs lexenv))
+     (remove-if-not #'var-good-p (lexenv-vars lexenv))
+     nil
+     nil
+     (lexenv-type-restrictions lexenv) ; XXX
+     (lexenv-weakend-type-restrictions lexenv)
+     nil
+     nil
+     (lexenv-policy lexenv))))
 \f
 ;;;; flow/DFO/component hackery
 
                      `(when (eq (,slot last) old)
                         (setf (,slot last) new))))
           (frob if-consequent)
-          (frob if-alternative))))
+          (frob if-alternative)
+           (when (eq (if-consequent last)
+                     (if-alternative last))
+             (setf (component-reoptimize (block-component block)) t)))))
       (t
        (unless (member new (block-succ block) :test #'eq)
         (link-blocks block new)))))
        (link-blocks block new-block)
        (add-to-dfo new-block block)
        (setf (component-reanalyze (block-component block)) t)
-       
+
        (do ((cont start (node-cont (continuation-next cont))))
            ((eq cont last-cont)
             (when (eq (continuation-kind last-cont) :inside-block)
 \f
 ;;;; deleting stuff
 
-;;; Deal with deleting the last (read) reference to a LAMBDA-VAR. 
+;;; Deal with deleting the last (read) reference to a LAMBDA-VAR.
 (defun delete-lambda-var (leaf)
   (declare (type lambda-var leaf))
 
       (setf (lambda-bind let) nil)
       (setf (functional-kind let) :deleted))
 
+    ;; LET may be deleted if its BIND is unreachable. Autonomous
+    ;; function may be deleted if it has no reachable references.
+    (unless (member original-kind '(:let :mv-let :assignment))
+      (dolist (ref (lambda-refs clambda))
+        (mark-for-deletion (node-block ref))))
+
     ;; (The IF test is (FUNCTIONAL-SOMEWHAT-LETLIKE-P CLAMBDA), except
     ;; that we're using the old value of the KIND slot, not the
     ;; current slot value, which has now been set to :DELETED.)
        ;; referenced, we give a note.
        (let* ((bind-block (node-block bind))
               (component (block-component bind-block))
-              (return (lambda-return clambda)))
-          (dolist (ref (lambda-refs clambda))
-            (let ((home (node-home-lambda ref)))
-              (aver (eq home clambda))))
+              (return (lambda-return clambda))
+               (return-block (and return (node-block return))))
          (unless (leaf-ever-used clambda)
            (let ((*compiler-error-context* bind))
              (compiler-note "deleting unused function~:[.~;~:*~%  ~S~]"
                             (leaf-debug-name clambda))))
-         (unlink-blocks (component-head component) bind-block)
-         (when return
-           (unlink-blocks (node-block return) (component-tail component)))
+          (unless (block-delete-p bind-block)
+            (unlink-blocks (component-head component) bind-block))
+         (when (and return-block (not (block-delete-p return-block)))
+            (mark-for-deletion return-block)
+           (unlink-blocks return-block (component-tail component)))
          (setf (component-reanalyze component) t)
          (let ((tails (lambda-tail-set clambda)))
            (setf (tail-set-funs tails)
   (unless (eq (continuation-kind cont) :deleted)
     (aver (continuation-dest cont))
     (setf (continuation-dest cont) nil)
+    (setf (continuation-%externally-checkable-type cont) nil)
     (do-uses (use cont)
       (let ((prev (node-prev use)))
        (unless (eq (continuation-kind prev) :deleted)
 ;;; blocks with the DELETE-P flag.
 (defun mark-for-deletion (block)
   (declare (type cblock block))
-  (unless (block-delete-p block)
-    (setf (block-delete-p block) t)
-    (setf (component-reanalyze (block-component block)) t)
-    (dolist (pred (block-pred block))
-      (mark-for-deletion pred)))
+  (let* ((component (block-component block))
+         (head (component-head component)))
+    (labels ((helper (block)
+               (setf (block-delete-p block) t)
+               (dolist (pred (block-pred block))
+                 (unless (or (block-delete-p pred)
+                             (eq pred head))
+                   (helper pred)))))
+      (unless (block-delete-p block)
+        (helper block)
+        (setf (component-reanalyze component) t))))
   (values))
 
 ;;; Delete CONT, eliminating both control and value semantics. We set
 
   (setf (continuation-kind cont) :deleted)
   (setf (continuation-dest cont) nil)
+  (setf (continuation-%externally-checkable-type cont) nil)
   (setf (continuation-next cont) nil)
   (setf (continuation-asserted-type cont) *empty-type*)
   (setf (continuation-%derived-type cont) *empty-type*)
+  (setf (continuation-type-to-check cont) *empty-type*)
   (setf (continuation-use cont) nil)
   (setf (continuation-block cont) nil)
   (setf (continuation-reoptimize cont) nil)
       (bind
        (let ((lambda (bind-lambda node)))
         (unless (eq (functional-kind lambda) :deleted)
-          (aver (functional-somewhat-letlike-p lambda))
           (delete-lambda lambda))))
       (exit
        (let ((value (exit-value node))
               (before-args (subseq outside-args 0 arg-position))
               (after-args (subseq outside-args (1+ arg-position))))
          (dolist (arg inside-args)
-           (setf (continuation-dest arg) outside))
+           (setf (continuation-dest arg) outside)
+            (setf (continuation-%externally-checkable-type arg) nil))
          (setf (combination-args inside) nil)
          (setf (combination-args outside)
                (append before-args inside-args after-args))
          (setf (node-derived-type inside) *wild-type*)
          (flush-dest cont)
          (setf (continuation-asserted-type cont) *wild-type*)
+          (setf (continuation-type-to-check cont) *wild-type*)
          (values))))))
 \f
 ;;;; leaf hackery
     (push ref (leaf-refs leaf))
     (delete-ref ref)
     (setf (ref-leaf ref) leaf)
+    (setf (leaf-ever-used leaf) t)
     (let ((ltype (leaf-type leaf)))
       (if (fun-type-p ltype)
          (setf (node-derived-type ref) ltype)
 
   (let ((action (event-info-action info)))
     (when action (funcall action node))))
+
+;;; It should be in locall.lisp, but is used before in ir1opt.lisp.
+(define-optimization-quality verify-arg-count
+    (if (zerop safety) 0 3)
+  ("no" "maybe" "yes" "yes"))