\f
;;;; 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))
;;; 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
\f
;;;; 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 (+ <int> <single>)
+ ;; 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)