1.0.30.25: deftransform for ARRAY-IN-BOUNDS-P
[sbcl.git] / tests / compiler.pure.lisp
index b261254..1c49450 100644 (file)
@@ -13,6 +13,8 @@
 
 (cl:in-package :cl-user)
 
+(load "compiler-test-util.lisp")
+
 ;; The tests in this file assume that EVAL will use the compiler
 (when (eq sb-ext:*evaluator-mode* :interpret)
   (invoke-restart 'run-tests::skip-file))
               (+ 81535869 (the (member 17549.955 #:g35917) p2))))
            17549.955)
           (+ 81535869 17549.955)))
+
+;;; misc.654
+(assert (eql 2
+             (let ((form '(lambda (p2)
+                           (declare (optimize (speed 0) (safety 2) (debug 0) (space 2))
+                            (type (member integer eql) p2))
+                           (coerce 2 p2))))
+               (funcall (compile nil form) 'integer))))
+
+;;; misc.656
+(assert (eql 2
+             (let ((form '(lambda (p2)
+                           (declare (optimize (speed 0) (safety 2) (debug 0) (space 2))
+                            (type (member integer mod) p2))
+                           (coerce 2 p2))))
+               (funcall (compile nil form) 'integer))))
+
+;;; misc.657
+(assert (eql 2
+         (let ((form '(lambda (p2)
+                       (declare (optimize (speed 0) (safety 2) (debug 0) (space 2))
+                        (type (member integer values) p2))
+                       (coerce 2 p2))))
+           (funcall (compile nil form) 'integer))))
+
+(with-test (:name :string-aref-type)
+ (assert (eq 'character
+             (funcall (compile nil
+                               '(lambda (s)
+                                 (ctu:compiler-derived-type (aref (the string s) 0))))
+                      "foo"))))
+
+(with-test (:name :base-string-aref-type)
+ (assert (eq #+sb-unicode 'base-char
+             #-sb-unicode 'character
+             (funcall (compile nil
+                               '(lambda (s)
+                                 (ctu:compiler-derived-type (aref (the base-string s) 0))))
+                      (coerce "foo" 'base-string)))))
+
+(with-test (:name :dolist-constant-type-derivation)
+  (assert (equal '(integer 1 3)
+                 (funcall (compile nil
+                                   '(lambda (x)
+                                     (dolist (y '(1 2 3))
+                                       (when x
+                                         (return (ctu:compiler-derived-type y))))))
+                          t))))
+
+(with-test (:name :dolist-simple-list-type-derivation)
+  (assert (equal '(integer 1 3)
+                 (funcall (compile nil
+                                   '(lambda (x)
+                                     (dolist (y (list 1 2 3))
+                                       (when x
+                                         (return (ctu:compiler-derived-type y))))))
+                          t))))
+
+(with-test (:name :dolist-dotted-constant-list-type-derivation)
+  (let* ((warned nil)
+         (fun (handler-bind ((style-warning (lambda (c) (push c warned))))
+                (compile nil
+                         '(lambda (x)
+                           (dolist (y '(1 2 3 . 4) :foo)
+                             (when x
+                               (return (ctu:compiler-derived-type y)))))))))
+    (assert (equal '(integer 1 3) (funcall fun t)))
+    (assert (= 1 (length warned)))
+    (multiple-value-bind (res err) (ignore-errors (funcall fun nil))
+      (assert (not res))
+      (assert (typep err 'type-error)))))
+
+(with-test (:name :constant-list-destructuring)
+  (handler-bind ((sb-ext:compiler-note #'error))
+    (progn
+      (assert (= 10
+                 (funcall
+                  (compile nil
+                           '(lambda ()
+                             (destructuring-bind (a (b c) d) '(1 (2 3) 4)
+                               (+ a b c d)))))))
+      (assert (eq :feh
+                  (funcall
+                   (compile nil
+                            '(lambda (x)
+                              (or x
+                               (destructuring-bind (a (b c) d) '(1 "foo" 4)
+                                 (+ a b c d)))))
+                   :feh))))))
+
+;;; Functions with non-required arguments used to end up with
+;;; (&OPTIONAL-DISPATCH ...) as their names.
+(with-test (:name :hairy-function-name)
+  (assert (eq 'read-line (nth-value 2 (function-lambda-expression #'read-line))))
+  (assert (equal "#<FUNCTION READ-LINE>" (princ-to-string #'read-line))))
+
+;;; PROGV + RESTRICT-COMPILER-POLICY
+(with-test (:name :progv-and-restrict-compiler-policy)
+  (let ((sb-c::*policy-restrictions* sb-c::*policy-restrictions*))
+    (restrict-compiler-policy 'debug 3)
+    (let ((fun (compile nil '(lambda (x)
+                              (let ((i x))
+                                (declare (special i))
+                                (list i
+                                      (progv '(i) (list (+ i 1))
+                                        i)
+                                      i))))))
+      (assert (equal '(1 2 1) (funcall fun 1))))))
+
+;;; It used to be possible to confuse the compiler into
+;;; IR2-converting such a call to CONS
+(with-test (:name :late-bound-primitive)
+  (compile nil `(lambda ()
+                  (funcall 'cons 1))))
+
+(with-test (:name :hairy-array-element-type-derivation)
+  (compile nil '(lambda (x)
+                 (declare (type (and simple-string (satisfies array-has-fill-pointer-p)) x))
+                 (array-element-type x))))
+
+(with-test (:name :rest-list-type-derivation)
+  (multiple-value-bind (type derivedp)
+      (funcall (compile nil `(lambda (&rest args)
+                               (ctu:compiler-derived-type args)))
+               nil)
+    (assert (eq 'list type))
+    (assert derivedp)))
+
+(with-test (:name :base-char-typep-elimination)
+  (assert (eq (funcall (lambda (ch)
+                         (declare (type base-char ch) (optimize (speed 3) (safety 0)))
+                         (typep ch 'base-char))
+                       t)
+              t)))
+
+(with-test (:name :regression-1.0.24.37)
+  (compile nil '(lambda (&key (test (constantly t)))
+                 (when (funcall test)
+                   :quux))))
+
+;;; Attempt to test a decent cross section of conditions
+;;; and values types to move conditionally.
+(macrolet
+    ((test-comparison (comparator type x y)
+       `(progn
+          ,@(loop for (result-type a b)
+                    in '((nil t   nil)
+                         (nil 0   1)
+                         (nil 0.0 1.0)
+                         (nil 0d0 0d0)
+                         (nil 0.0 0d0)
+                         (nil #c(1.0 1.0) #c(2.0 2.0))
+
+                         (t      t  nil)
+                         (fixnum 0 1)
+                         ((unsigned-byte #.sb-vm:n-word-bits)
+                          (1+ most-positive-fixnum)
+                          (+ 2 most-positive-fixnum))
+                         ((signed-byte #.sb-vm:n-word-bits)
+                          -1 (* 2 most-negative-fixnum))
+                         (single-float 0.0 1.0)
+                         (double-float 0d0 1d0))
+                  for lambda = (if result-type
+                                   `(lambda (x y a b)
+                                      (declare (,type x y)
+                                               (,result-type a b))
+                                      (if (,comparator x y)
+                                          a b))
+                                   `(lambda (x y)
+                                      (declare (,type x y))
+                                      (if (,comparator x y)
+                                          ,a ,b)))
+                  for args = `(,x ,y ,@(and result-type
+                                            `(,a ,b)))
+                  collect
+                  `(progn
+                     (eql (funcall (compile nil ',lambda)
+                                   ,@args)
+                          (eval '(,lambda ,@args))))))))
+  (sb-vm::with-float-traps-masked
+      (:divide-by-zero :overflow :inexact :invalid)
+    (let ((sb-ext:*evaluator-mode* :interpret))
+      (declare (sb-ext:muffle-conditions style-warning))
+      (test-comparison eql t t nil)
+      (test-comparison eql t t t)
+
+      (test-comparison =   t 1 0)
+      (test-comparison =   t 1 1)
+      (test-comparison =   t (1+ most-positive-fixnum) (+ 2 most-positive-fixnum))
+      (test-comparison =   fixnum 1 0)
+      (test-comparison =   fixnum 0 0)
+      (test-comparison =   (unsigned-byte #.sb-vm:n-word-bits) 1 0)
+      (test-comparison =   (unsigned-byte #.sb-vm:n-word-bits) 0 0)
+      (test-comparison =   (signed-byte #.sb-vm:n-word-bits)   1 0)
+      (test-comparison =   (signed-byte #.sb-vm:n-word-bits)   1 1)
+
+      (test-comparison =   single-float 0.0 1.0)
+      (test-comparison =   single-float 1.0 1.0)
+      (test-comparison =   single-float (/ 1.0 0.0) (/ 1.0 0.0))
+      (test-comparison =   single-float (/ 1.0 0.0) 1.0)
+      (test-comparison =   single-float (/ 0.0 0.0) (/ 0.0 0.0))
+      (test-comparison =   single-float (/ 0.0 0.0) 0.0)
+
+      (test-comparison =   double-float 0d0 1d0)
+      (test-comparison =   double-float 1d0 1d0)
+      (test-comparison =   double-float (/ 1d0 0d0) (/ 1d0 0d0))
+      (test-comparison =   double-float (/ 1d0 0d0) 1d0)
+      (test-comparison =   double-float (/ 0d0 0d0) (/ 0d0 0d0))
+      (test-comparison =   double-float (/ 0d0 0d0) 0d0)
+
+      (test-comparison <   t 1 0)
+      (test-comparison <   t 0 1)
+      (test-comparison <   t 1 1)
+      (test-comparison <   t (1+ most-positive-fixnum)  (+ 2 most-positive-fixnum))
+      (test-comparison <   t (+ 2 most-positive-fixnum) (1+ most-positive-fixnum))
+      (test-comparison <   fixnum 1 0)
+      (test-comparison <   fixnum 0 1)
+      (test-comparison <   fixnum 0 0)
+      (test-comparison <   (unsigned-byte #.sb-vm:n-word-bits) 1 0)
+      (test-comparison <   (unsigned-byte #.sb-vm:n-word-bits) 0 1)
+      (test-comparison <   (unsigned-byte #.sb-vm:n-word-bits) 0 0)
+      (test-comparison <   (signed-byte #.sb-vm:n-word-bits)   1 0)
+      (test-comparison <   (signed-byte #.sb-vm:n-word-bits)   0 1)
+      (test-comparison <   (signed-byte #.sb-vm:n-word-bits)   1 1)
+
+      (test-comparison <   single-float 0.0 1.0)
+      (test-comparison <   single-float 1.0 0.0)
+      (test-comparison <   single-float 1.0 1.0)
+      (test-comparison <   single-float (/ 1.0 0.0) (/ 1.0 0.0))
+      (test-comparison <   single-float (/ 1.0 0.0) 1.0)
+      (test-comparison <   single-float 1.0 (/ 1.0 0.0))
+      (test-comparison <   single-float (/ 0.0 0.0) (/ 0.0 0.0))
+      (test-comparison <   single-float (/ 0.0 0.0) 0.0)
+
+      (test-comparison <   double-float 0d0 1d0)
+      (test-comparison <   double-float 1d0 0d0)
+      (test-comparison <   double-float 1d0 1d0)
+      (test-comparison <   double-float (/ 1d0 0d0) (/ 1d0 0d0))
+      (test-comparison <   double-float (/ 1d0 0d0) 1d0)
+      (test-comparison <   double-float 1d0 (/ 1d0 0d0))
+      (test-comparison <   double-float (/ 0d0 0d0) (/ 0d0 0d0))
+      (test-comparison <   double-float (/ 0d0 0d0) 0d0)
+      (test-comparison <   double-float 0d0 (/ 0d0 0d0))
+
+      (test-comparison >   t 1 0)
+      (test-comparison >   t 0 1)
+      (test-comparison >   t 1 1)
+      (test-comparison >   t (1+ most-positive-fixnum)  (+ 2 most-positive-fixnum))
+      (test-comparison >   t (+ 2 most-positive-fixnum) (1+ most-positive-fixnum))
+      (test-comparison >   fixnum 1 0)
+      (test-comparison >   fixnum 0 1)
+      (test-comparison >   fixnum 0 0)
+      (test-comparison >   (unsigned-byte #.sb-vm:n-word-bits) 1 0)
+      (test-comparison >   (unsigned-byte #.sb-vm:n-word-bits) 0 1)
+      (test-comparison >   (unsigned-byte #.sb-vm:n-word-bits) 0 0)
+      (test-comparison >   (signed-byte #.sb-vm:n-word-bits)   1 0)
+      (test-comparison >   (signed-byte #.sb-vm:n-word-bits)   0 1)
+      (test-comparison >   (signed-byte #.sb-vm:n-word-bits)   1 1)
+
+      (test-comparison >   single-float 0.0 1.0)
+      (test-comparison >   single-float 1.0 0.0)
+      (test-comparison >   single-float 1.0 1.0)
+      (test-comparison >   single-float (/ 1.0 0.0) (/ 1.0 0.0))
+      (test-comparison >   single-float (/ 1.0 0.0) 1.0)
+      (test-comparison >   single-float 1.0 (/ 1.0 0.0))
+      (test-comparison >   single-float (/ 0.0 0.0) (/ 0.0 0.0))
+      (test-comparison >   single-float (/ 0.0 0.0) 0.0)
+
+      (test-comparison >   double-float 0d0 1d0)
+      (test-comparison >   double-float 1d0 0d0)
+      (test-comparison >   double-float 1d0 1d0)
+      (test-comparison >   double-float (/ 1d0 0d0) (/ 1d0 0d0))
+      (test-comparison >   double-float (/ 1d0 0d0) 1d0)
+      (test-comparison >   double-float 1d0 (/ 1d0 0d0))
+      (test-comparison >   double-float (/ 0d0 0d0) (/ 0d0 0d0))
+      (test-comparison >   double-float (/ 0d0 0d0) 0d0)
+      (test-comparison >   double-float 0d0 (/ 0d0 0d0)))))
+
+(with-test (:name :car-and-cdr-type-derivation-conservative)
+  (let ((f1 (compile nil
+                     `(lambda (y)
+                        (declare (optimize speed))
+                        (let ((x (the (cons fixnum fixnum) (cons 1 2))))
+                          (declare (type (cons t fixnum) x))
+                          (rplaca x y)
+                          (+ (car x) (cdr x))))))
+        (f2 (compile nil
+                     `(lambda (y)
+                        (declare (optimize speed))
+                        (let ((x (the (cons fixnum fixnum) (cons 1 2))))
+                          (setf (cdr x) y)
+                          (+ (car x) (cdr x)))))))
+    (flet ((test-error (e value)
+             (assert (typep e 'type-error))
+             (assert (eq 'number (type-error-expected-type e)))
+             (assert (eq value (type-error-datum e)))))
+      (let ((v1 "foo")
+            (v2 "bar"))
+        (multiple-value-bind (res err) (ignore-errors (funcall f1 v1))
+          (assert (not res))
+          (test-error err v1))
+        (multiple-value-bind (res err) (ignore-errors (funcall f2 v2))
+          (assert (not res))
+          (test-error err v2))))))
+
+(with-test (:name :array-dimension-derivation-conservative)
+  (let ((f (compile nil
+                    `(lambda (x)
+                       (declare (optimize speed))
+                       (declare (type (array * (4 4)) x))
+                       (let ((y x))
+                         (setq x (make-array '(4 4)))
+                         (adjust-array y '(3 5))
+                         (array-dimension y 0))))))
+    (assert (= 3 (funcall f (make-array '(4 4) :adjustable t))))))
+
+(with-test (:name :with-timeout-code-deletion-note)
+  (handler-bind ((sb-ext:code-deletion-note #'error))
+    (compile nil `(lambda ()
+                    (sb-ext:with-timeout 0
+                      (sleep 1))))))
+
+(with-test (:name :full-warning-for-undefined-type-in-cl)
+  (assert (eq :full
+              (handler-case
+                  (compile nil `(lambda (x) (the replace x)))
+                (style-warning ()
+                  :style)
+                (warning ()
+                  :full)))))
+
+(with-test (:name :single-warning-for-single-undefined-type)
+  (let ((n 0))
+    (handler-bind ((warning (lambda (c)
+                              (declare (ignore c))
+                              (incf n))))
+      (compile nil `(lambda (x) (the #:no-type x)))
+      (assert (= 1 n))
+      (compile nil `(lambda (x) (the 'fixnum x)))
+      (assert (= 2 n)))))
+
+(with-test (:name :complex-subtype-dumping-in-xc)
+  (assert
+   (= sb-vm:complex-single-float-widetag
+      (sb-kernel:widetag-of
+       (sb-vm:saetp-initial-element-default (sb-c::find-saetp '(complex single-float))))))
+  (assert
+   (= sb-vm:complex-double-float-widetag
+      (sb-kernel:widetag-of
+       (sb-vm:saetp-initial-element-default (sb-c::find-saetp '(complex double-float)))))))
+
+(with-test (:name :complex-single-float-fill)
+  (assert (every (lambda (x) (= #c(1.0 2.0) x))
+                 (funcall
+                  (compile nil
+                           `(lambda (n x)
+                              (make-array (list n)
+                                          :element-type '(complex single-float)
+                                          :initial-element x)))
+                  10
+                  #c(1.0 2.0)))))
+
+(with-test (:name :regression-1.0.28.21)
+  (let ((fun (compile nil `(lambda (x) (typep x '(simple-array * 1))))))
+    (assert (funcall fun (vector 1 2 3)))
+    (assert (funcall fun "abc"))
+    (assert (not (funcall fun (make-array '(2 2)))))))
+
+(with-test (:name :no-silly-compiler-notes-from-character-function)
+  (let (current)
+    (handler-bind ((compiler-note (lambda (e) (error "~S: ~A" current e))))
+      (dolist (name '(char-code char-int character char-name standard-char-p
+                      graphic-char-p alpha-char-p upper-case-p lower-case-p
+                      both-case-p digit-char-p alphanumericp digit-char-p))
+        (setf current name)
+        (compile nil `(lambda (x)
+                        (declare (character x) (optimize speed))
+                        (,name x))))
+      (dolist (name '(char= char/= char< char> char<= char>= char-equal
+                      char-not-equal char-lessp char-greaterp char-not-greaterp
+                      char-not-lessp))
+        (setf current name)
+        (compile nil `(lambda (x y)
+                        (declare (character x y) (optimize speed))
+                        (,name x y)))))))
+
+;;; optimizing make-array
+(with-test (:name (make-array :open-code-initial-contents))
+  (assert (not (ctu:find-named-callees
+                (compile nil
+                         `(lambda (x y z)
+                            (make-array '(3) :initial-contents (list x y z)))))))
+  (assert (not (ctu:find-named-callees
+                (compile nil
+                         `(lambda (x y z)
+                            (make-array '3 :initial-contents (vector x y z)))))))
+  (assert (not (ctu:find-named-callees
+                (compile nil
+                         `(lambda (x y z)
+                            (make-array '3 :initial-contents `(,x ,y ,z))))))))
+
+;;; optimizing array-in-bounds-p
+(with-test (:name :optimize-array-in-bounds-p)
+  (locally
+    (macrolet ((find-callees (&body body)
+                 `(ctu:find-named-callees
+                    (compile nil
+                             '(lambda ()
+                                ,@body))
+                    :name 'array-in-bounds-p))
+               (must-optimize (&body exprs)
+                 `(progn
+                    ,@(loop for expr in exprs
+                            collect `(assert (not (find-callees
+                                                   ,expr))))))
+               (must-not-optimize (&body exprs)
+                 `(progn
+                    ,@(loop for expr in exprs
+                            collect `(assert (find-callees
+                                              ,expr))))))
+      (must-optimize
+        ;; in bounds
+        (let ((a (make-array '(1))))
+          (array-in-bounds-p a 0))
+        ;; exceeds upper bound (constant)
+        (let ((a (make-array '(1))))
+          (array-in-bounds-p a 1))
+        ;; exceeds upper bound (interval)
+        (let ((a (make-array '(1))))
+          (array-in-bounds-p a (+ 1 (random 2))))
+        ;; negative lower bound (constant)
+        (let ((a (make-array '(1))))
+          (array-in-bounds-p a -1))
+        ;; negative lower bound (interval)
+        (let ((a (make-array 3))
+              (i (- (random 1) 20)))
+          (array-in-bounds-p a i))
+        ;; multiple known dimensions
+        (let ((a (make-array '(1 1))))
+          (array-in-bounds-p a 0 0))
+        ;; union types
+        (let ((s (the (simple-string 10) (eval "0123456789"))))
+          (array-in-bounds-p s 9)))
+      (must-not-optimize
+       ;; don't trust non-simple array length in safety=1
+       (let ((a (the (array * (10)) (make-array 10 :adjustable t))))
+         (eval `(adjust-array ,a 0))
+         (array-in-bounds-p a 9))
+       ;; same for a union type
+       (let ((s (the (string 10) (make-array 10
+                                             :element-type 'character
+                                             :adjustable t))))
+         (eval `(adjust-array ,s 0))
+         (array-in-bounds-p s 9))
+       ;; single unknown dimension
+       (let ((a (make-array (random 20))))
+         (array-in-bounds-p a 10))
+       ;; multiple unknown dimensions
+       (let ((a (make-array (list (random 20) (random 5)))))
+         (array-in-bounds-p a 5 2))
+       ;; some other known dimensions
+       (let ((a (make-array (list 1 (random 5)))))
+         (array-in-bounds-p a 0 2))
+       ;; subscript might be negative
+       (let ((a (make-array 5)))
+         (array-in-bounds-p a (- (random 3) 2)))
+       ;; subscript might be too large
+       (let ((a (make-array 5)))
+         (array-in-bounds-p a (random 6)))
+       ;; unknown upper bound
+       (let ((a (make-array 5)))
+         (array-in-bounds-p a (get-universal-time)))
+       ;; unknown lower bound
+       (let ((a (make-array 5)))
+         (array-in-bounds-p a (- (get-universal-time))))
+       ;; in theory we should be able to optimize
+       ;; the following but the current implementation
+       ;; doesn't cut it because the array type's
+       ;; dimensions get reported as (* *).
+       (let ((a (make-array (list (random 20) 1))))
+         (array-in-bounds-p a 5 2))))))
+
+;;; optimizing (EXPT -1 INTEGER)
+(test-util:with-test (:name (expt minus-one integer))
+  (dolist (x '(-1 -1.0 -1.0d0))
+    (let ((fun (compile nil `(lambda (x) (expt ,x (the fixnum x))))))
+      (assert (not (ctu:find-named-callees fun)))
+      (dotimes (i 12)
+        (if (oddp i)
+            (assert (eql x (funcall fun i)))
+            (assert (eql (- x) (funcall fun i))))))))
+
+(with-test (:name (load-time-value :type-derivation))
+  (flet ((test (type form value-cell-p)
+           (let ((derived (funcall (compile
+                                    nil
+                                    `(lambda ()
+                                       (ctu:compiler-derived-type
+                                        (load-time-value ,form)))))))
+             (unless (equal type derived)
+              (error "wanted ~S, got ~S" type derived)))))
+    (let ((* 10))
+      (test '(integer 11 11) '(+ * 1) nil))
+    (let ((* "fooo"))
+      (test '(integer 4 4) '(length *) t))))
+
+(with-test (:name :float-division-using-exact-reciprocal)
+  (flet ((test (lambda-form arg res &key (check-insts t))
+           (let* ((fun (compile nil lambda-form))
+                  (disassembly (with-output-to-string (s)
+                                  (disassemble fun :stream s))))
+             ;; Let's make sure there is no division at runtime: for x86 and
+             ;; x86-64 that implies an FDIV, DIVSS, or DIVSD instruction, so
+             ;; look for DIV in the disassembly. It's a terrible KLUDGE, but
+             ;; it works.
+             #+(or x86 x86-64)
+             (when check-insts
+               (assert (not (search "DIV" disassembly))))
+             ;; No generic arithmetic!
+             (assert (not (search "GENERIC" disassembly)))
+             (assert (eql res (funcall fun arg))))))
+    (dolist (c '(128 64 32 16 8 4 2 1 1/2 1/4 1/8 1/16 1/32 1/64))
+      (dolist (type '(single-float double-float))
+        (let* ((cf (coerce c type))
+               (arg (- (random (* 2 cf)) cf))
+               (r1 (eval `(/ ,arg ,cf)))
+               (r2 (eval `(/ ,arg ,(- cf)))))
+          (test `(lambda (x) (declare (,type x)) (/ x ,cf)) arg r1)
+          (test `(lambda (x) (declare (,type x)) (/ x ,(- cf))) arg r2)
+          ;; rational args should get optimized as well
+          (test `(lambda (x) (declare (,type x)) (/ x ,c)) arg r1)
+          (test `(lambda (x) (declare (,type x)) (/ x ,(- c))) arg r2))))
+    ;; Also check that inexact reciprocals (1) are not used by default (2) are
+    ;; used with FLOAT-ACCURACY=0.
+    (dolist (type '(single-float double-float))
+      (let ((trey (coerce 3 type))
+            (one (coerce 1 type)))
+        (test `(lambda (x) (declare (,type x)) (/ x 3)) trey one
+              :check-insts nil)
+        (test `(lambda (x)
+                 (declare (,type x)
+                          (optimize (sb-c::float-accuracy 0)))
+                 (/ x 3))
+              trey (eval `(* ,trey (/ ,trey))))))))
+
+(with-test (:name :float-multiplication-by-one)
+  (flet ((test (lambda-form arg &optional (result arg))
+           (let* ((fun1 (compile nil lambda-form))
+                  (fun2 (funcall (compile nil `(lambda ()
+                                                 (declare (optimize (sb-c::float-accuracy 0)))
+                                                 ,lambda-form))))
+                  (disassembly1 (with-output-to-string (s)
+                                  (disassemble fun1 :stream s)))
+                  (disassembly2 (with-output-to-string (s)
+                                  (disassemble fun2 :stream s))))
+             ;; Multiplication at runtime should be eliminated only with
+             ;; FLOAT-ACCURACY=0. (To catch SNaNs.)
+             #+(or x86 x86-64)
+             (assert (and (search "MUL" disassembly1)
+                          (not (search "MUL" disassembly2))))
+             ;; Not generic arithmetic, please!
+             (assert (and (not (search "GENERIC" disassembly1))
+                          (not (search "GENERIC" disassembly2))))
+             (assert (eql result (funcall fun1 arg)))
+             (assert (eql result (funcall fun2 arg))))))
+    (dolist (type '(single-float double-float))
+      (let* ((one (coerce 1 type))
+             (arg (random (* 2 one)))
+             (-r (- arg)))
+        (test `(lambda (x) (declare (,type x)) (* x 1)) arg)
+        (test `(lambda (x) (declare (,type x)) (* x -1)) arg -r)
+        (test `(lambda (x) (declare (,type x)) (* x ,one)) arg)
+        (test `(lambda (x) (declare (,type x)) (* x ,(- one))) arg -r)))))
+
+(with-test (:name :float-addition-of-zero)
+  (flet ((test (lambda-form arg &optional (result arg))
+           (let* ((fun1 (compile nil lambda-form))
+                  (fun2 (funcall (compile nil `(lambda ()
+                                                 (declare (optimize (sb-c::float-accuracy 0)))
+                                                 ,lambda-form))))
+                  (disassembly1 (with-output-to-string (s)
+                                  (disassemble fun1 :stream s)))
+                  (disassembly2 (with-output-to-string (s)
+                                  (disassemble fun2 :stream s))))
+             ;; Let's make sure there is no addition at runtime: for x86 and
+             ;; x86-64 that implies an FADD, ADDSS, or ADDSD instruction, so
+             ;; look for the ADDs in the disassembly. It's a terrible KLUDGE,
+             ;; but it works. Unless FLOAT-ACCURACY is zero, we leave the
+             ;; addition in to catch SNaNs.
+             #+x86
+             (assert (and (search "FADD" disassembly1)
+                          (not (search "FADD" disassembly2))))
+             #+x86-64
+             (let ((inst (if (typep result 'double-float)
+                             "ADDSD" "ADDSS")))
+               (assert (and (search inst disassembly1)
+                            (not (search inst disassembly2)))))
+             (assert (eql result (funcall fun1 arg)))
+             (assert (eql result (funcall fun2 arg))))))
+    (test `(lambda (x) (declare (single-float x)) (+ x 0)) 123.45)
+    (test `(lambda (x) (declare (single-float x)) (+ x 0.0)) 543.21)
+    (test `(lambda (x) (declare (single-float x)) (+ x 0.0d0)) 42.00 42.d0)
+    (test `(lambda (x) (declare (double-float x)) (+ x 0)) 123.45d0)
+    (test `(lambda (x) (declare (double-float x)) (+ x 0.0)) 543.21d0)
+    (test `(lambda (x) (declare (double-float x)) (+ x 0.0d0)) 42.d0)))
+
+(with-test (:name :float-substraction-of-zero)
+  (flet ((test (lambda-form arg &optional (result arg))
+           (let* ((fun1 (compile nil lambda-form))
+                  (fun2 (funcall (compile nil `(lambda ()
+                                                 (declare (optimize (sb-c::float-accuracy 0)))
+                                                 ,lambda-form))))
+                  (disassembly1 (with-output-to-string (s)
+                                  (disassemble fun1 :stream s)))
+                  (disassembly2 (with-output-to-string (s)
+                                  (disassemble fun2 :stream s))))
+             ;; Let's make sure there is no substraction at runtime: for x86
+             ;; and x86-64 that implies an FSUB, SUBSS, or SUBSD instruction,
+             ;; so look for SUB in the disassembly. It's a terrible KLUDGE,
+             ;; but it works. Unless FLOAT-ACCURACY is zero, we leave the
+             ;; substraction in in to catch SNaNs.
+             #+x86
+             (assert (and (search "FSUB" disassembly1)
+                          (not (search "FSUB" disassembly2))))
+             #+x86-64
+             (let ((inst (if (typep result 'double-float)
+                             "SUBSD" "SUBSS")))
+               (assert (and (search inst disassembly1)
+                            (not (search inst disassembly2)))))
+             (assert (eql result (funcall fun1 arg)))
+             (assert (eql result (funcall fun2 arg))))))
+    (test `(lambda (x) (declare (single-float x)) (- x 0)) 123.45)
+    (test `(lambda (x) (declare (single-float x)) (- x 0.0)) 543.21)
+    (test `(lambda (x) (declare (single-float x)) (- x 0.0d0)) 42.00 42.d0)
+    (test `(lambda (x) (declare (double-float x)) (- x 0)) 123.45d0)
+    (test `(lambda (x) (declare (double-float x)) (- x 0.0)) 543.21d0)
+    (test `(lambda (x) (declare (double-float x)) (- x 0.0d0)) 42.d0)))
+
+(with-test (:name :float-multiplication-by-two)
+  (flet ((test (lambda-form arg &optional (result arg))
+           (let* ((fun1 (compile nil lambda-form))
+                  (fun2 (funcall (compile nil `(lambda ()
+                                                 (declare (optimize (sb-c::float-accuracy 0)))
+                                                 ,lambda-form))))
+                  (disassembly1 (with-output-to-string (s)
+                                  (disassemble fun1 :stream s)))
+                  (disassembly2 (with-output-to-string (s)
+                                  (disassemble fun2 :stream s))))
+             ;; Let's make sure there is no multiplication at runtime: for x86
+             ;; and x86-64 that implies an FMUL, MULSS, or MULSD instruction,
+             ;; so look for MUL in the disassembly. It's a terrible KLUDGE,
+             ;; but it works.
+             #+(or x86 x86-64)
+             (assert (and (not (search "MUL" disassembly1))
+                          (not (search "MUL" disassembly2))))
+             (assert (eql result (funcall fun1 arg)))
+             (assert (eql result (funcall fun2 arg))))))
+    (test `(lambda (x) (declare (single-float x)) (* x 2)) 123.45 246.9)
+    (test `(lambda (x) (declare (single-float x)) (* x 2.0)) 543.21 1086.42)
+    (test `(lambda (x) (declare (single-float x)) (* x 2.0d0)) 42.00 84.d0)
+    (test `(lambda (x) (declare (double-float x)) (* x 2)) 123.45d0 246.9d0)
+    (test `(lambda (x) (declare (double-float x)) (* x 2.0)) 543.21d0 1086.42d0)
+    (test `(lambda (x) (declare (double-float x)) (* x 2.0d0)) 42.0d0 84.0d0)))