0.8.4.2:
authorAlexey Dejneka <adejneka@comail.ru>
Fri, 3 Oct 2003 02:51:56 +0000 (02:51 +0000)
committerAlexey Dejneka <adejneka@comail.ru>
Fri, 3 Oct 2003 02:51:56 +0000 (02:51 +0000)
        * Changes in type checking:
        ... test for NIL has zero cost;
        ... add NULL to types of optional arguments (fix bug 261);
        ... change implementation of "external type check":
            ... new kind of CAST-TYPE-CHECK;
            ... detect blocks of externally checkable CASTs by
                backward walking of a component;
            ... merge unsafe CASTs in IR1-FINALIZE ( bug 282);
            ... consider known call of a function without applicable
                :FAST-SAFE templates to be full;
        * print CTRAN numbers in component dumps;
        * fix bug 214, also reported by rydis on #lisp: in
          NOTE-REJECTED-TEMPLATES ignore :FAST-SAFE templates for
          :SAFE policy;
        * DO-NODE-BACKWARDS: stop when faced with a CTRAN with no use
          (bug reported by Paul Dietz);
        * TWO-ARG-DERIVE-TYPE: when deriving type for constant
          arguments, if the function signals an error return type NIL
          (bug reported by Paul Dietz);
        * fix TRUNCATE optimizer for (+ -) arguments (bugs 293, 294
          reported by Paul Dietz);
        * tests/compiler.impure-cload.lisp: switch to CL-USER package
          before deleting temporal one.

15 files changed:
BUGS
NEWS
src/compiler/checkgen.lisp
src/compiler/debug.lisp
src/compiler/ir1final.lisp
src/compiler/ir1util.lisp
src/compiler/ltn.lisp
src/compiler/macros.lisp
src/compiler/node.lisp
src/compiler/srctran.lisp
tests/arith.pure.lisp
tests/compiler.impure-cload.lisp
tests/compiler.pure-cload.lisp
tests/compiler.pure.lisp
version.lisp-expr

diff --git a/BUGS b/BUGS
index d417baa..688b166 100644 (file)
--- a/BUGS
+++ b/BUGS
@@ -753,20 +753,6 @@ WORKAROUND:
        (INTEGERP (CAR (MAKE-SEQUENCE '(CONS INTEGER *) 2)))
      can erroneously return T.
 
-214:
-  SBCL 0.6.12.43 fails to compile
-
-  (locally
-      (declare (optimize (inhibit-warnings 0) (compilation-speed 2)))
-    (flet ((foo (&key (x :vx x-p)) (list x x-p)))
-      (foo 1 2)))
-
-  or a more simple example:
-
-  (locally
-      (declare (optimize (inhibit-warnings 0) (compilation-speed 2)))
-    (lambda (x) (declare (fixnum x)) (if (< x 0) 0 (1- x))))
-
 215: ":TEST-NOT handling by functions"
   a. FIND and POSITION currently signal errors when given non-NIL for
      both their :TEST and (deprecated) :TEST-NOT arguments, but by
@@ -1170,16 +1156,6 @@ WORKAROUND:
   The issue seems to be that construction of a discriminating function
   calls COMPUTE-EFFECTIVE-METHOD with methods that are not all applicable.
 
-282: "type checking in full calls"
-  In current (0.8.3.6) implementation a CAST in a full call argument
-  is not checked; but the continuation between the CAST and the
-  combination has the "checked" type and CAST performs unsafe
-  coercion; this may lead to errors: if FOO is declared to take a
-  FIXNUM, this code will produce garbage on a machine with 30-bit
-  fixnums:
-
-    (foo (aref (the (array (unsigned-byte 32)) x)))
-
 283: Thread safety: libc functions
   There are places that we call unsafe-for-threading libc functions
   that we should find alternatives for, or put locks around.  Known or
@@ -1256,43 +1232,6 @@ WORKAROUND:
   the control word; however, this clobbers any change the user might
   have made.
 
-293:
-  From Paul Dietz:
-
-  (defparameter *f1*
-     (compile nil '(LAMBDA (C)
-                       (TRUNCATE (LOGORC1 -996082 C) -2))))
-
-  (defparameter *f2*
-     (compile nil '(LAMBDA (C) (DECLARE (NOTINLINE TRUNCATE))
-                       (TRUNCATE (LOGORC1 -996082 C) -2))))
-
-  (print (funcall *f1* 25337234)) ==> 13099002
-  (print (funcall *f2* 25337234)) ==> -13099001
-
-294:
-  From Paul Dietz:
-
-  * (funcall (compile nil `(lambda (c)
-                              (declare (optimize (speed 3))
-                                       (type (integer 23062188 149459656) c))
-                              (mod c (min -2 0))))
-              95019853)
-
-  debugger invoked on condition of type SB-INT:SIMPLE-PROGRAM-ERROR:
-     invalid number of arguments: 1
-
-  [...]
-
-  * (funcall (compile nil `(lambda (b)
-                              (declare (optimize (speed 3))
-                                       (type (integer 2 152044363) b))
-                               (rem b (min -16 0))))
-              108251912)
-
-  debugger invoked on condition of type SB-INT:SIMPLE-PROGRAM-ERROR:
-     invalid number of arguments: 1
-
 295:
   From Paul Dietz:
 
diff --git a/NEWS b/NEWS
index 06c04a0..729dd09 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2107,6 +2107,23 @@ changes in sbcl-0.8.4 relative to sbcl-0.8.3:
     been incremented (because of the changes to internal compiler
     data structures referred to above).
 
+changes in sbcl-0.8.5 relative to sbcl-0.8.4:
+  * in full calls compiler does not generate checks for declared
+    argument types for all arguments.
+  * fix bug 282: compiler does not trust type assertions while passing
+    arguments to a full call.
+  * fix bug 261: compiler allows NIL or "no value" to be accepted for
+    &OPTIONAL VALUES type parameter.
+  * fix bug 214: algorithm for noting rejected templates is now more
+    similar to that of template seletion. (also reported by rydis on
+    #lisp)
+  * fixed some bugs revealed by Paul Dietz' test suite:
+    ** incorrect optimization of TRUNCATE for a positive first
+       argument and negative second.
+    ** compiler failure in let-convertion during flushing dead code.
+    ** compiler failure while deriving type of TRUNCATE on an
+       interval, containing 0.
+
 planned incompatible changes in 0.8.x:
   * (not done yet, but planned:) When the profiling interface settles
     down, it might impact TRACE. They both encapsulate functions, and
index ead1ca9..2f9f907 100644 (file)
 ;;; templates in the VM definition.
 (defun type-test-cost (type)
   (declare (type ctype type))
-  (or (let ((check (type-check-template type)))
+  (or (when (eq type *universal-type*)
+        0)
+      (when (eq type *empty-type*)
+        0)
+      (let ((check (type-check-template type)))
        (if check
            (template-cost check)
            (let ((found (cdr (assoc type *backend-type-predicates*
 ;;; FIXME: I don't quite understand this, but it looks as though
 ;;; that means type checks are weakened when SPEED=3 regardless of
 ;;; the SAFETY level, which is not the right thing to do.
-(defun maybe-negate-check (lvar types original-types force-hairy)
-  (declare (type lvar lvar) (list types))
-  (multiple-value-bind (ptypes count)
-      (no-fun-values-types (lvar-derived-type lvar))
-    (if (eq count :unknown)
-        (if (and (every #'type-check-template types) (not force-hairy))
-            (values :simple types)
-            (values :hairy (mapcar (lambda (x) (list nil x x)) types)))
-        (let ((res (mapcar (lambda (p c a)
-                             (let ((diff (type-difference p c)))
-                               (if (and diff
-                                        (< (type-test-cost diff)
-                                           (type-test-cost c))
-                                        *complement-type-checks*)
-                                   (list t diff a)
-                                   (list nil c a))))
-                           ptypes types original-types)))
-          (cond ((or force-hairy (find-if #'first res))
-                 (values :hairy res))
-                ((every #'type-check-template types)
-                 (values :simple types))
-                (t
-                 (values :hairy res)))))))
+(defun maybe-negate-check (lvar types original-types force-hairy n-required)
+  (declare (type lvar lvar) (list types original-types))
+  (let ((ptypes (values-type-out (lvar-derived-type lvar) (length types))))
+    (multiple-value-bind (hairy-res simple-res)
+        (loop for p in ptypes
+              and c in types
+              and a in original-types
+              and i from 0
+              for cc = (if (>= i n-required)
+                           (type-union c (specifier-type 'null))
+                           c)
+              for diff = (type-difference p cc)
+              collect (if (and diff
+                               (< (type-test-cost diff)
+                                  (type-test-cost cc))
+                               *complement-type-checks*)
+                          (list t diff a)
+                          (list nil cc a))
+              into hairy-res
+              collect cc into simple-res
+              finally (return (values hairy-res simple-res)))
+      (cond ((or force-hairy (find-if #'first hairy-res))
+             (values :hairy hairy-res))
+            ((every #'type-check-template simple-res)
+             (values :simple simple-res))
+            (t
+             (values :hairy hairy-res))))))
 
 ;;; Determines whether CAST's assertion is:
 ;;;  -- checkable by the back end (:SIMPLE), or
 ;;;     test in type check conversion (:HAIRY), or
 ;;;  -- not reasonably checkable at all (:TOO-HAIRY).
 ;;;
-;;; A type is checkable if it either represents a fixed number of
-;;; values (as determined by VALUES-TYPES), or it is the assertion for
-;;; an MV-BIND. A type is simply checkable if all the type assertions
-;;; have a TYPE-CHECK-TEMPLATE. In this :SIMPLE case, the second value
-;;; is a list of the type restrictions specified for the leading
-;;; positional values.
+;;; We may check only fixed number of values; in any case the number
+;;; of generated values is trusted. If we know the number of produced
+;;; values, all of them are checked; otherwise if we know the number
+;;; of consumed -- only they are checked; otherwise the check is not
+;;; performed.
 ;;;
-;;; We force a check to be hairy even when there are fixed values if
-;;; we are in a context where we may be forced to use the unknown
-;;; values convention anyway. This is because IR2tran can't generate
-;;; type checks for unknown values lvars but people could still be
-;;; depending on the check being done. We only care about EXIT and
-;;; RETURN (not MV-COMBINATION) since these are the only contexts
-;;; where the ultimate values receiver
+;;; A type is simply checkable if all the type assertions have a
+;;; TYPE-CHECK-TEMPLATE. In this :SIMPLE case, the second value is a
+;;; list of the type restrictions specified for the leading positional
+;;; values.
+;;;
+;;; Old comment:
+;;;
+;;;    We force a check to be hairy even when there are fixed values
+;;;    if we are in a context where we may be forced to use the
+;;;    unknown values convention anyway. This is because IR2tran can't
+;;;    generate type checks for unknown values lvars but people could
+;;;    still be depending on the check being done. We only care about
+;;;    EXIT and RETURN (not MV-COMBINATION) since these are the only
+;;;    contexts where the ultimate values receiver
 ;;;
 ;;; In the :HAIRY case, the second value is a list of triples of
 ;;; the form:
   (declare (type cast cast))
   (let* ((ctype (coerce-to-values (cast-type-to-check cast)))
          (atype (coerce-to-values (cast-asserted-type cast)))
+         (dtype (node-derived-type cast))
          (value (cast-value cast))
-         (vtype (lvar-derived-type value))
          (lvar (node-lvar cast))
-         (dest (and lvar (lvar-dest lvar))))
+         (dest (and lvar (lvar-dest lvar)))
+         (n-consumed (cond ((not lvar)
+                            nil)
+                           ((lvar-single-value-p lvar)
+                            1)
+                           ((and (mv-combination-p dest)
+                                 (eq (mv-combination-kind dest) :local))
+                            (let ((fun-ref (lvar-use (mv-combination-fun dest))))
+                              (length (lambda-vars (ref-leaf fun-ref)))))))
+         (n-required (length (values-type-required dtype))))
     (aver (not (eq ctype *wild-type*)))
-    (multiple-value-bind (ctypes count) (no-fun-values-types ctype)
-      (multiple-value-bind (atypes acount) (no-fun-values-types atype)
-        (multiple-value-bind (vtypes vcount) (values-types vtype)
-          (declare (ignore vtypes))
-          (aver (eq count acount))
-          (cond ((not (eq count :unknown))
-                 (if (or (exit-p dest)
-                         (and (return-p dest)
-                              (multiple-value-bind (ignore count)
-                                  (values-types (return-result-type dest))
-                                (declare (ignore ignore))
-                                (eq count :unknown))))
-                     (maybe-negate-check value ctypes atypes t)
-                     (maybe-negate-check value ctypes atypes force-hairy)))
-                ((and (lvar-single-value-p lvar)
-                      (or (not (args-type-rest ctype))
-                          (eq (args-type-rest ctype) *universal-type*)))
-                 (principal-lvar-single-valuify lvar)
-                 (let ((creq (car (args-type-required ctype))))
-                   (multiple-value-setq (ctype atype)
-                     (if creq
-                         (values creq (car (args-type-required atype)))
-                         (values (car (args-type-optional ctype))
-                                 (car (args-type-optional atype)))))
-                   (maybe-negate-check value
-                                       (list ctype) (list atype)
-                                       force-hairy)))
-                ((and (mv-combination-p dest)
-                      (eq (mv-combination-kind dest) :local))
-                 (let* ((fun-ref (lvar-use (mv-combination-fun dest)))
-                        (length (length (lambda-vars (ref-leaf fun-ref)))))
-                   (maybe-negate-check value
-                                       ;; FIXME
-                                       (adjust-list (values-type-types ctype)
-                                                    length
-                                                    *universal-type*)
-                                       (adjust-list (values-type-types atype)
-                                                    length
-                                                    *universal-type*)
-                                       force-hairy)))
-                ((not (eq vcount :unknown))
-                 (maybe-negate-check value
-                                     (values-type-out ctype vcount)
-                                     (values-type-out atype vcount)
-                                     t))
-                (t
-                 (values :too-hairy nil))))))))
+    (cond ((and (null (values-type-optional dtype))
+                (not (values-type-rest dtype)))
+           ;; we [almost] know how many values are produced
+           (maybe-negate-check value
+                               (values-type-out ctype n-required)
+                               (values-type-out atype n-required)
+                               ;; backend checks only consumed values
+                               (not (eql n-required n-consumed))
+                               n-required))
+          ((lvar-single-value-p lvar)
+           ;; exactly one value is consumed
+           (principal-lvar-single-valuify lvar)
+           (let ((creq (car (args-type-required ctype))))
+             (multiple-value-setq (ctype atype)
+               (if creq
+                   (values creq (car (args-type-required atype)))
+                   (values (car (args-type-optional ctype))
+                           (car (args-type-optional atype)))))
+             (maybe-negate-check value
+                                 (list ctype) (list atype)
+                                 force-hairy
+                                 n-required)))
+          ((and (mv-combination-p dest)
+                (eq (mv-combination-kind dest) :local))
+           ;; we know the number of consumed values
+           (maybe-negate-check value
+                               (adjust-list (values-type-types ctype)
+                                            n-consumed
+                                            *universal-type*)
+                               (adjust-list (values-type-types atype)
+                                            n-consumed
+                                            *universal-type*)
+                               force-hairy
+                               n-required))
+          (t
+           (values :too-hairy nil)))))
 
 ;;; Do we want to do a type check?
-(defun worth-type-check-p (cast)
+(defun cast-externally-checkable-p (cast)
   (declare (type cast cast))
   (let* ((lvar (node-lvar cast))
          (dest (and lvar (lvar-dest lvar))))
-    (cond ((not (cast-type-check cast))
-           nil)
-          ((and (combination-p dest)
-                (call-full-like-p dest)
-                ;; The theory is that the type assertion is
-                ;; from a declaration in (or on) the callee,
-                ;; so the callee should be able to do the
-                ;; check. We want to let the callee do the
-                ;; check, because it is possible that by the
-                ;; time of call that declaration will be
-                ;; changed and we do not want to make people
-                ;; recompile all calls to a function when they
-                ;; were originally compiled with a bad
-                ;; declaration. (See also bug 35.)
-                (immediately-used-p lvar cast)
-                (values-subtypep (lvar-externally-checkable-type lvar)
-                                 (cast-type-to-check cast)))
-           nil)
-          (t
-           t))))
+    (and (combination-p dest)
+         ;; The theory is that the type assertion is from a
+         ;; declaration in (or on) the callee, so the callee should be
+         ;; able to do the check. We want to let the callee do the
+         ;; check, because it is possible that by the time of call
+         ;; that declaration will be changed and we do not want to
+         ;; make people recompile all calls to a function when they
+         ;; were originally compiled with a bad declaration. (See also
+         ;; bug 35.)
+         (or (immediately-used-p lvar cast)
+             (binding* ((ctran (node-next cast) :exit-if-null)
+                        (next (ctran-next ctran)))
+               (and (cast-p next)
+                    (eq (node-dest next) dest)
+                    (eq (cast-type-check next) :external))))
+         (values-subtypep (lvar-externally-checkable-type lvar)
+                          (cast-type-to-check cast)))))
 
 ;;; Return true if CAST's value is an lvar whose type the back end is
 ;;; likely to want to check. Since we don't know what template the
   (collect ((casts))
     (do-blocks (block component)
       (when (block-type-check block)
-       (do-nodes (node nil block)
+        ;; CAST-EXTERNALLY-CHECKABLE-P wants the backward pass
+       (do-nodes-backwards (node nil block)
           (when (and (cast-p node)
                      (cast-type-check node))
             (cast-check-uses node)
-            (cond ((worth-type-check-p node)
-                   (casts (cons node (not (probable-type-check-p node)))))
+            (cond ((cast-externally-checkable-p node)
+                   (setf (cast-%type-check node) :external))
                   (t
-                   (setf (cast-%type-check node) nil)
-                   (setf (cast-type-to-check node) *wild-type*)))))
+                   ;; it is possible that NODE was marked :EXTERNAL by
+                   ;; the previous pass
+                   (setf (cast-%type-check node) t)
+                   (casts (cons node (not (probable-type-check-p node))))))))
        (setf (block-type-check block) nil)))
     (dolist (cast (casts))
       (destructuring-bind (cast . force-hairy) cast
index e982847..9be0b07 100644 (file)
     (do ((ctran (block-start block) (node-next (ctran-next ctran))))
         ((not ctran))
       (let ((node (ctran-next ctran)))
-        (format t "~:[    ~;~:*~3D:~] "
+        (format t "~3D>~:[    ~;~:*~3D:~] "
+                (cont-num ctran)
                 (when (and (valued-node-p node) (node-lvar node))
                   (cont-num (node-lvar node))))
         (etypecase node
index d2888c5..c78d83a 100644 (file)
            (setq atype (note-fun-use dest atype)))))
       (setf (info :function :assumed-type name) atype))))
 
+;;; Merge CASTs with preceding/following nodes.
+(defun ir1-merge-casts (component)
+  (do-blocks-backwards (block component)
+    (do-nodes-backwards (node lvar block)
+      (let ((dest (when lvar (lvar-dest lvar))))
+        (cond ((and (cast-p dest)
+                    (not (cast-type-check dest))
+                    (immediately-used-p lvar node))
+               (derive-node-type node (cast-asserted-type dest)))
+              ((and (cast-p node)
+                    (eq (cast-type-check node) :external))
+               (aver (basic-combination-p dest))
+               (delete-filter node lvar (cast-value node))))))))
+
 ;;; Do miscellaneous things that we want to do once all optimization
 ;;; has been done:
 ;;;  -- Record the derived result type before the back-end trashes the
   (maphash (lambda (k v)
             (note-assumed-types component k v))
           *free-funs*)
+
+  (ir1-merge-casts component)
+
   (values))
index 57caf17..5e14d26 100644 (file)
               ;; LET-converted functionals are even worse.
               (eql (functional-kind functional) :deleted)))
     (throw 'locall-already-let-converted functional)))
+
+(defun call-full-like-p (call)
+  (declare (type combination call))
+  (let ((kind (basic-combination-kind call)))
+    (or (eq kind :full)
+        (and (fun-info-p kind)
+             (not (fun-info-ir2-convert kind))
+             (dolist (template (fun-info-templates kind) t)
+               (when (eq (template-ltn-policy template) :fast-safe)
+                 (multiple-value-bind (val win)
+                     (valid-fun-use call (template-type template))
+                   (when (or val (not win)) (return nil)))))))))
 \f
 ;;;; careful call
 
index 4e7ff47..b38fa17 100644 (file)
          (when (and (or (not guard) (funcall guard))
                     (or (not safe-p)
                         (ltn-policy-safe-p (template-ltn-policy try)))
+                     ;; :SAFE is also considered to be :SMALL-SAFE,
+                     ;; while the template cost describes time cost;
+                     ;; so the fact that (< (t-cost try) (t-cost
+                     ;; template)) does not mean that TRY is better
+                     (not (and (eq ltn-policy :safe)
+                               (eq (template-ltn-policy try) :fast-safe)))
                     (or verbose-p
                         (and (template-note try)
                              (valid-fun-use
              (ctran-next ctran))
         (ctran (node-next node) (node-next node)))
       (nil)
-    (let* ((lvar (when (valued-node-p node)
-                   (node-lvar node)))
-           (dest (and lvar (lvar-dest lvar))))
-      (when (and (cast-p dest)
-                 (not (cast-type-check dest))
-                 (immediately-used-p lvar node))
-        (derive-node-type node (cast-asserted-type dest))))
     (etypecase node
       (ref)
       (combination
index 98ab8fc..04dc8a9 100644 (file)
            `((when (block-delete-p ,n-block)
                (return)))))))
 
-;;; like DO-NODES, only iterating in reverse order
+;;; Like DO-NODES, only iterating in reverse order. Should be careful
+;;; with block being split under us.
 (defmacro do-nodes-backwards ((node-var lvar block) &body body)
   (let ((n-block (gensym))
-       (n-start (gensym))
        (n-prev (gensym)))
-    `(do* ((,n-block ,block)
-           (,n-start (block-start ,n-block))
-           (,node-var (block-last ,n-block) (ctran-use ,n-prev))
-           (,n-prev (node-prev ,node-var) (node-prev ,node-var))
-           (,lvar #1=(when (valued-node-p ,node-var) (node-lvar ,node-var))
-                  #1#))
-          (nil)
-       ,@body
-       (when (eq ,n-prev ,n-start)
-          (return nil)))))
+    `(loop with ,n-block = ,block
+           for ,node-var = (block-last ,n-block) then (ctran-use ,n-prev)
+           while ,node-var ; FIXME: this is non-ANSI
+           for ,n-prev = (node-prev ,node-var)
+           and ,lvar = (when (valued-node-p ,node-var) (node-lvar ,node-var))
+           do (progn
+                ,@body))))
 
 (defmacro do-nodes-carefully ((node-var block) &body body)
   (with-unique-names (n-block n-ctran)
index 5988f86..693b1c4 100644 (file)
                             "<deleted>"))
                       args)))
 
-(defun call-full-like-p (call)
-  (declare (type combination call))
-  (let ((kind (basic-combination-kind call)))
-    (or (eq kind :full)
-        (and (fun-info-p kind)
-             (null (fun-info-templates kind))
-             (not (fun-info-ir2-convert kind))))))
-
 ;;; An MV-COMBINATION is to MULTIPLE-VALUE-CALL as a COMBINATION is to
 ;;; FUNCALL. This is used to implement all the multiple-value
 ;;; receiving forms.
   ;; NIL
   ;;    No type check is necessary (VALUE type is a subtype of the TYPE-TO-CHECK.)
   ;;
+  ;; :EXTERNAL
+  ;;    Type check will be performed by NODE-DEST.
+  ;;
   ;; T
   ;;    A type check is needed.
-  (%type-check t :type (member t nil))
+  (%type-check t :type (member t :external nil))
   ;; the lvar which is checked
   (value (missing-arg) :type lvar))
 (defprinter (cast :identity t)
index 56439e4..e43395a 100644 (file)
 ;;; a utility for defining derive-type methods of integer operations. If
 ;;; the types of both X and Y are integer types, then we compute a new
 ;;; integer type with bounds determined Fun when applied to X and Y.
-;;; Otherwise, we use Numeric-Contagion.
+;;; Otherwise, we use NUMERIC-CONTAGION.
 (defun derive-integer-type-aux (x y fun)
   (declare (type function fun))
   (if (and (numeric-type-p x) (numeric-type-p y)
 
 ;;; simple utility to flatten a list
 (defun flatten-list (x)
-  (labels ((flatten-helper (x r);; 'r' is the stuff to the 'right'.
-            (cond ((null x) r)
-                  ((atom x)
-                   (cons x r))
-                  (t (flatten-helper (car x)
-                                     (flatten-helper (cdr x) r))))))
-    (flatten-helper x nil)))
+  (labels ((flatten-and-append (tree list)
+            (cond ((null tree) list)
+                  ((atom tree) (cons tree list))
+                  (t (flatten-and-append
+                       (car tree) (flatten-and-append (cdr tree) list))))))
+    (flatten-and-append x nil)))
 
 ;;; Take some type of lvar and massage it so that we get a list of the
 ;;; constituent types. If ARG is *EMPTY-TYPE*, return NIL to indicate
           (cond ((and (member-type-p x) (member-type-p y))
                  (let* ((x (first (member-type-members x)))
                         (y (first (member-type-members y)))
-                        (result (with-float-traps-masked
-                                    (:underflow :overflow :divide-by-zero
-                                     :invalid)
-                                  (funcall fun x y))))
-                   (cond ((null result))
+                        (result (ignore-errors
+                                   (with-float-traps-masked
+                                       (:underflow :overflow :divide-by-zero
+                                                   :invalid)
+                                     (funcall fun x y)))))
+                   (cond ((null result) *empty-type*)
                          ((and (floatp result) (float-nan-p result))
                           (make-numeric-type :class 'float
                                              :format (type-of result)
                        `(- (ash (- x) ,shift)))
                   (- (logand (- x) ,mask)))
           (values ,(if (minusp y)
-                       `(- (ash (- x) ,shift))
+                       `(ash (- ,mask x) ,shift)
                        `(ash x ,shift))
                   (logand x ,mask))))))
 
index 2d4900f..6e13aea 100644 (file)
 
 ;;; (CEILING x 2^k) was optimized incorrectly
 (loop for divisor in '(-4 4)
-   for ceiler = (compile nil `(lambda (x)
-                                (declare (fixnum x))
-                                (declare (optimize (speed 3)))
-                                (ceiling x ,divisor)))
-   do (loop for i from -5 to 5
-         for exact-q = (/ i divisor)
-         do (multiple-value-bind (q r)
-                (funcall ceiler i)
-              (assert (= (+ (* q divisor) r) i))
-              (assert (<= exact-q q))
-              (assert (< q (1+ exact-q))))))
+      for ceiler = (compile nil `(lambda (x)
+                                   (declare (fixnum x))
+                                   (declare (optimize (speed 3)))
+                                   (ceiling x ,divisor)))
+      do (loop for i from -5 to 5
+               for exact-q = (/ i divisor)
+               do (multiple-value-bind (q r)
+                      (funcall ceiler i)
+                    (assert (= (+ (* q divisor) r) i))
+                    (assert (<= exact-q q))
+                    (assert (< q (1+ exact-q))))))
+
+;;; (TRUNCATE x 2^k) was optimized incorrectly
+(loop for divisor in '(-4 4)
+      for truncater = (compile nil `(lambda (x)
+                                      (declare (fixnum x))
+                                      (declare (optimize (speed 3)))
+                                      (truncate x ,divisor)))
+      do (loop for i from -9 to 9
+               for exact-q = (/ i divisor)
+               do (multiple-value-bind (q r)
+                      (funcall truncater i)
+                    (assert (= (+ (* q divisor) r) i))
+                    (assert (<= (abs q) (abs exact-q)))
+                    (assert (< (abs exact-q) (1+ (abs q)))))))
 
 ;;; CEILING had a corner case, spotted by Paul Dietz
 (assert (= (ceiling most-negative-fixnum (1+ most-positive-fixnum)) -1))
index a81fb3f..531f1b6 100644 (file)
@@ -28,6 +28,7 @@
                          (stub avecname))
                      (paip avecname)))))
       :eexpr (lambda (south east))))
+(in-package :cl-user)
 (delete-package :bug254)
 
 ;;; bug 255
@@ -54,6 +55,7 @@
               (multiple-value-prog1
                   (progn (%pu avecname))
                 (frob)))))))
+(in-package :cl-user)
 (delete-package :bug255)
 
 ;;; bug 148
 (assert (equal (eval '(bug148-4 '(1 2 3)))
                '((1 2 3) (7 14 21) (21 14 7))))
 
+(in-package :cl-user)
 (delete-package :bug148)
 
 ;;; bug 258
 (assert (equal (u-b-sra '(4 9 7))
                '((4 9 7) (3 8 6) (6 8 3))))
 
-(delete-package :bug258)
-
 (in-package :cl-user)
+(delete-package :bug258)
 
 ;;;
 (defun bug233a (x)
         (deposit-field (%f2) (byte 11 8) -3)
         c)))
 
+;;; bug 214: compiler failure
+(defun bug214a1 ()
+  (declare (optimize (sb-ext:inhibit-warnings 0) (compilation-speed 2)))
+  (flet ((foo (&key (x :vx x-p)) (list x x-p)))
+    (foo :x 2)))
+
+(defun bug214a2 ()
+  (declare (optimize (sb-ext:inhibit-warnings 0) (compilation-speed 2)))
+  (lambda (x) (declare (fixnum x)) (if (< x 0) 0 (1- x))))
+
+;;; this one was reported by rydis on #lisp
+(defun 214b (n)
+  (declare (fixnum n))
+  (declare (optimize (speed 2) (space 3)))
+  (dotimes (k n)
+    (princ k)))
+
 \f
 (sb-ext:quit :unix-status 104)
index 854c1a5..85b484d 100644 (file)
 ;;; Verify type checking policy in full calls: the callee is supposed
 ;;; to perform check, but the results should not be used before the
 ;;; check will be actually performed.
-#+nil
 (locally
     (declare (optimize (safety 3)))
   (flet ((bar (f a)
index f1431f1..9776ae2 100644 (file)
                   (+ 359749 35728422))))
             -24076)))
 
+;;; bug 294 reported by Paul Dietz: miscompilation of REM and MOD
+(assert (= (funcall (compile nil `(lambda (b)
+                                    (declare (optimize (speed 3))
+                                             (type (integer 2 152044363) b))
+                                    (rem b (min -16 0))))
+                    108251912)
+           8))
+
+(assert (= (funcall (compile nil `(lambda (c)
+                                    (declare (optimize (speed 3))
+                                             (type (integer 23062188 149459656) c))
+                                    (mod c (min -2 0))))
+                    95019853)
+           -1))
+
+;;; bug reported by Paul Dietz: block splitting inside FLUSH-DEAD-CODE
+(compile nil
+         '(LAMBDA (A B C)
+           (BLOCK B6
+             (LOGEQV (REM C -6758)
+                     (REM B (MAX 44 (RETURN-FROM B6 A)))))))
+
+(compile nil '(lambda ()
+               (block nil
+                 (flet ((foo (x y) (if (> x y) (print x) (print y))))
+                   (foo 1 2)
+                   (bar)
+                   (foo (return 14) 2)))))
+
 ;;; bug in Alpha backend: not enough sanity checking of arguments to
 ;;; instructions
 (assert (= (funcall (compile nil 
index 93d9703..779b4ad 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.8.4.1"
+"0.8.4.2"