Delete CLAMBDA when its BIND is detected to be unreachable.
recurses endlessly in sbcl-0.7.9.32. (Or it works if #' and
FDEFINITION are replaced by SYMBOL-FUNCTION.)
-224:
- SBCL 0.7.8 fails to compile
- (localy (declare (optimize (safety 3)))
- (ignore-errors (progn (values-list (car (list '(1 . 2)))) t)))
- (the LOCALY there is not a typo; any unknown function (e.g. FROB)
- will do).
-
228: "function-lambda-expression problems"
in sbcl-0.7.9.6x, from the REPL:
* (progn (declaim (inline foo)) (defun foo (x) x))
(res home))))
(res)))
-;;; If CLAMBDA is not already in COMPONENT, just return that
+;;; If CLAMBDA is already in COMPONENT, just return that
;;; component. Otherwise, move the code for CLAMBDA and all lambdas it
;;; physically depends on (either because of calls or because of
;;; closure relationships) into COMPONENT, or possibly into another
(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))
- (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)
- (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))
(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)
;;; 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
(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))
new-value))
(defsetf event-level %set-event-level)
-;;; Define a new kind of event. Name is a symbol which names the event
-;;; and Description is a string which describes the event. Level
+;;; Define a new kind of event. NAME is a symbol which names the event
+;;; and DESCRIPTION is a string which describes the event. Level
;;; (default 0) is the level of significance associated with this
;;; event; it is used to determine whether to print a Note when the
;;; event happens.
(declaim (type unsigned-byte *event-note-threshold*))
(defvar *event-note-threshold* 1)
-;;; Note that the event with the specified Name has happened. Node is
+;;; Note that the event with the specified NAME has happened. NODE is
;;; evaluated to determine the node to which the event happened.
(defmacro event (name &optional node)
;; Increment the counter and do any action. Mumble about the event if
#!-sb-fluid (declaim (inline find-in position-in))
-;;; Find Element in a null-terminated List linked by the accessor
-;;; function Next. Key, Test and Test-Not are the same as for generic
+;;; Find ELEMENT in a null-terminated LIST linked by the accessor
+;;; function NEXT. KEY, TEST and TEST-NOT are the same as for generic
;;; sequence functions.
(defun find-in (next
element
(when (funcall test (funcall key current) element)
(return current)))))
-;;; Return the position of Element (or NIL if absent) in a
-;;; null-terminated List linked by the accessor function Next. Key,
-;;; Test and Test-Not are the same as for generic sequence functions.
+;;; Return the position of ELEMENT (or NIL if absent) in a
+;;; null-terminated LIST linked by the accessor function NEXT. KEY,
+;;; TEST and TEST-NOT are the same as for generic sequence functions.
(defun position-in (next
element
list
x)
(assert (= (bug219-b-aux2 1)
(if *bug219-b-expanded-p* 3 1)))
+
+;;; bug 224: failure in unreachable code deletion
+(defmacro do-optimizations (&body body)
+ `(dotimes (.speed. 4)
+ (dotimes (.space. 4)
+ (dotimes (.debug. 4)
+ (dotimes (.compilation-speed. 4)
+ (proclaim `(optimize (speed , .speed.) (space , .space.)
+ (debug , .debug.)
+ (compilation-speed , .compilation-speed.)))
+ ,@body)))))
+
+(do-optimizations
+ (compile nil
+ (read-from-string
+ "(lambda () (#:localy (declare (optimize (safety 3)))
+ (ignore-errors (progn (values-list (car (list '(1 . 2)))) t))))")))
+
+(do-optimizations
+ (compile nil '(lambda ()
+ (labels ((ext ()
+ (tagbody
+ (labels ((i1 () (list (i2) (i2)))
+ (i2 () (list (int) (i1)))
+ (int () (go :exit)))
+ (list (i1) (i1) (i1)))
+ :exit (return-from ext)
+ )))
+ (list (error "nih") (ext) (ext))))))
+
+(do-optimizations
+ (compile nil '(lambda (x) (let ((y (error ""))) (list x y)))))
+
\f
;;;; tests not in the problem domain, but of the consistency of the
;;;; compiler machinery itself
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.7.10.20"
+"0.7.10.21"