X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Ffloat-tran.lisp;h=262f86777cae2a22f469e98076068ceda5b4af71;hb=2c06e3056fe6aa820817a927fa0e840eb7b8edb7;hp=8a3a055cb8bf7e95c9b297ac96932b167e04578f;hpb=c2431e2d0d0222a3cf20cfdfa48201bdcc65cd76;p=sbcl.git diff --git a/src/compiler/float-tran.lisp b/src/compiler/float-tran.lisp index 8a3a055..262f867 100644 --- a/src/compiler/float-tran.lisp +++ b/src/compiler/float-tran.lisp @@ -15,8 +15,8 @@ ;;;; coercions -(defknown %single-float (real) single-float (movable foldable flushable)) -(defknown %double-float (real) double-float (movable foldable flushable)) +(defknown %single-float (real) single-float (movable foldable)) +(defknown %double-float (real) double-float (movable foldable)) (deftransform float ((n f) (* single-float) *) '(%single-float n)) @@ -267,37 +267,60 @@ ;;; defined range. Quite useful if we want to convert some type of ;;; bounded integer into a float. (macrolet - ((frob (fun type) + ((frob (fun type most-negative most-positive) (let ((aux-name (symbolicate fun "-DERIVE-TYPE-AUX"))) `(progn - (defun ,aux-name (num) - ;; When converting a number to a float, the limits are - ;; the same. - (let* ((lo (bound-func (lambda (x) - (coerce x ',type)) - (numeric-type-low num))) - (hi (bound-func (lambda (x) - (coerce x ',type)) - (numeric-type-high num)))) - (specifier-type `(,',type ,(or lo '*) ,(or hi '*))))) - - (defoptimizer (,fun derive-type) ((num)) - (one-arg-derive-type num #',aux-name #',fun)))))) - (frob %single-float single-float) - (frob %double-float double-float)) + (defun ,aux-name (num) + ;; When converting a number to a float, the limits are + ;; the same. + (let* ((lo (bound-func (lambda (x) + (if (< x ,most-negative) + ,most-negative + (coerce x ',type))) + (numeric-type-low num))) + (hi (bound-func (lambda (x) + (if (< ,most-positive x ) + ,most-positive + (coerce x ',type))) + (numeric-type-high num)))) + (specifier-type `(,',type ,(or lo '*) ,(or hi '*))))) + + (defoptimizer (,fun derive-type) ((num)) + (handler-case + (one-arg-derive-type num #',aux-name #',fun) + (type-error () + nil))))))) + (frob %single-float single-float + most-negative-single-float most-positive-single-float) + (frob %double-float double-float + most-negative-double-float most-positive-double-float)) ) ; PROGN ;;;; float contagion +(defun safe-ctype-for-single-coercion-p (x) + ;; See comment in SAFE-SINGLE-COERCION-P -- this deals with the same + ;; problem, but in the context of evaluated and compiled (+ ) + ;; giving different result if we fail to check for this. + (or (not (csubtypep x (specifier-type 'integer))) + (csubtypep x (specifier-type `(integer ,most-negative-exactly-single-float-fixnum + ,most-positive-exactly-single-float-fixnum))))) + ;;; Do some stuff to recognize when the loser is doing mixed float and ;;; rational arithmetic, or different float types, and fix it up. If ;;; we don't, he won't even get so much as an efficiency note. (deftransform float-contagion-arg1 ((x y) * * :defun-only t :node node) - `(,(lvar-fun-name (basic-combination-fun node)) - (float x y) y)) + (if (or (not (types-equal-or-intersect (lvar-type y) (specifier-type 'single-float))) + (safe-ctype-for-single-coercion-p (lvar-type x))) + `(,(lvar-fun-name (basic-combination-fun node)) + (float x y) y) + (give-up-ir1-transform))) (deftransform float-contagion-arg2 ((x y) * * :defun-only t :node node) - `(,(lvar-fun-name (basic-combination-fun node)) - x (float y x))) + (if (or (not (types-equal-or-intersect (lvar-type x) (specifier-type 'single-float))) + (safe-ctype-for-single-coercion-p (lvar-type y))) + `(,(lvar-fun-name (basic-combination-fun node)) + x (float y x)) + (give-up-ir1-transform))) (dolist (x '(+ * / -)) (%deftransform x '(function (rational float) *) #'float-contagion-arg1)