double->single float conversion isn't a no-op on x87 anymore
authorPaul Khuong <pvk@pvk.ca>
Fri, 28 Jun 2013 05:45:49 +0000 (01:45 -0400)
committerPaul Khuong <pvk@pvk.ca>
Fri, 28 Jun 2013 05:45:49 +0000 (01:45 -0400)
 The conversion can result in overflow, so pass through a stack
 temporary to force a truncation.

 Test case by Peter Keller on sbcl-devel, 2013-06-26.

src/compiler/x86/float.lisp
tests/compiler.pure.lisp

index 0d20e7f..5372116 100644 (file)
   #!+long-float
   (frob %long-float/unsigned %long-float long-reg long-float))
 
-;;; These should be no-ops but the compiler might want to move some
-;;; things around.
-(macrolet ((frob (name translate from-sc from-type to-sc to-type)
+(macrolet ((frob (name translate from-sc from-type to-sc to-type
+                  &optional to-stack-sc store-inst load-inst)
              `(define-vop (,name)
                (:args (x :scs (,from-sc) :target y))
+                ,@(and to-stack-sc
+                       `((:temporary (:sc ,to-stack-sc) temp)))
                (:results (y :scs (,to-sc)))
                (:arg-types ,from-type)
                (:result-types ,to-type)
                (:vop-var vop)
                (:save-p :compute-only)
                (:generator 2
-                (note-this-location vop :internal-error)
-                (unless (location= x y)
-                  (cond
-                   ((zerop (tn-offset x))
-                    ;; x is in ST0, y is in another reg. not ST0
-                    (inst fst  y))
-                   ((zerop (tn-offset y))
-                    ;; y is in ST0, x is in another reg. not ST0
-                    (copy-fp-reg-to-fr0 x))
-                   (t
-                    ;; Neither x or y are in ST0, and they are not in
-                    ;; the same reg.
-                    (inst fxch x)
-                    (inst fst  y)
-                    (inst fxch x))))))))
-
-  (frob %single-float/double-float %single-float double-reg
-        double-float single-reg single-float)
+                 (note-this-location vop :internal-error)
+                ,(if to-stack-sc
+                     `(progn
+                        (with-tn@fp-top (x)
+                          (inst ,store-inst temp))
+                        (with-empty-tn@fp-top (y)
+                          (inst ,load-inst temp)))
+                     `(unless (location= x y)
+                        (cond
+                          ((zerop (tn-offset x))
+                           ;; x is in ST0, y is in another reg. not ST0
+                           (inst fst  y))
+                          ((zerop (tn-offset y))
+                           ;; y is in ST0, x is in another reg. not ST0
+                           (copy-fp-reg-to-fr0 x))
+                          (t
+                           ;; Neither x or y are in ST0, and they are not in
+                           ;; the same reg.
+                           (inst fxch x)
+                           (inst fst  y)
+                           (inst fxch x)))))))))
+
+  (frob %single-float/double-float %single-float double-reg double-float
+        single-reg single-float
+        single-stack fst fld)
   #!+long-float
   (frob %single-float/long-float %single-float long-reg
-        long-float single-reg single-float)
+        long-float single-reg single-float
+        single-stack fst fld)
   (frob %double-float/single-float %double-float single-reg single-float
         double-reg double-float)
   #!+long-float
   (frob %double-float/long-float %double-float long-reg long-float
-        double-reg double-float)
+        double-reg double-float
+        double-stack fstd fldd)
   #!+long-float
   (frob %long-float/single-float %long-float single-reg single-float
         long-reg long-float)
index 8f8d4c3..48d413d 100644 (file)
                         ((some (lambda (c)
                                  (digit-char-p c))
                                string))))))
+
+;; the x87 backend used to sometimes signal FP errors during boxing,
+;; because converting between double and single float values was a
+;; noop (fixed), and no doubt many remaining issues.  We now store
+;; the value outside pseudo-atomic, so any SIGFPE should be handled
+;; corrrectly.
+;;
+;; When it fails, this test lands into ldb.
+(with-test (:name :no-overflow-during-allocation)
+  (handler-case (eval '(cosh 90))
+    (floating-point-overflow ()
+      t)))