(compile nil '(lambda (x) (coerce (sqrt x) 'float))) emits WARNING in sbcl 2.1.2

Bug #1920931 reported by Andrew Berkley
10
This bug affects 2 people
Affects Status Importance Assigned to Milestone
SBCL
Fix Released
Undecided
Unassigned

Bug Description

I saw this on irc from etimmons, but no one reported it here, so putting it here just in case this works better.

(lambda (y)
  (coerce (sqrt y) 'float))

emits a WARNING

; in: LAMBDA (Y)
; (COERCE (SQRT Y) 'FLOAT)
;
; caught WARNING:
; Derived type of SB-C::X is
; (VALUES (OR (COMPLEX SINGLE-FLOAT) (COMPLEX DOUBLE-FLOAT)) &OPTIONAL),
; conflicting with its asserted type
; REAL.

coerce expands to to
  (if (floatp x)
      x
      (%single-float x)))

This warns because we know sqrt returns a float or a complex float. So %single-float is only called if s is complex, which is a code generation failure.

Note that (float (sqrt y)) does not WARN.

description: updated
description: updated
description: updated
description: updated
Revision history for this message
Andrew Berkley (ajberkley) wrote :

So far what I have is a change to typetran.lisp line 1211:

      ((csubtypep tspec (specifier-type 'float))
       (if (types-equal-or-intersect value-type (specifier-type 'float))
           `(the ,tval (if (floatp x)
                           x
                           (if (realp x)
                               (%single-float x)
                               (locally (declare (notinline coerce))
                                 (coerce x 'float))))) ;; this will emit an error always
           `(the ,tval (%single-float x))))

The realp check is deleted if it is known that x is real, which is nice.

I don't like how I handle the known error case. I don't like the locally declare notinline thing, but it was a pattern from lower down in the coerce thing. Maybe could emit a check-type-error directly there too. Either way the debugger the user gets refers to "x" which isn't that helpful. Oh well. Anyway, that is not a new problem.

Revision history for this message
Andrew Berkley (ajberkley) wrote :

Here's a better option?

      ((csubtypep tspec (specifier-type 'float))
       (if (types-equal-or-intersect value-type (specifier-type 'float))
           `(the ,tval (if (floatp x)
                           x
                           ,(if (not (eq *empty-type* (type-intersection value-type (specifier-type 'rational))))
                                `(%single-float x)
                                `(locally (declare (notinline coerce)) ;; emit an error
                                   (coerce x 'float)))))
           `(the ,tval (%single-float x))))

Revision history for this message
Andrew Berkley (ajberkley) wrote :

But (float (sqrt x)) does not warn, and it emits the same code... ???

Revision history for this message
Andrew Berkley (ajberkley) wrote :

Ah, because float is declared to take real numbers as input...

Revision history for this message
Andrew Berkley (ajberkley) wrote :

Which leads to

(defun blarg (x)
   (declare (optimize (speed 3) (safety 0)))
   (float (sqrt x)))

(blarg -4d0) -> #C(0.0d0 2.0d0)

while

(defun blarg (x)
   (declare (optimize (speed 3) (safety 0)))
   (coerce (sqrt x) 'float)) ;; with code above

(blarg -4d0) -> error #C(0.0d0 2.0d0) is not of type real

No reason for them to behave differently.

So this leads me to:

      ((csubtypep tspec (specifier-type 'float))
       (if (types-equal-or-intersect value-type (specifier-type 'float))
           `(the ,tval (locally
                           (declare (type real x))
                         (if (floatp x)
                             x
                             (%single-float x))))
           `(the ,tval (%single-float x))))

This makes (float x) and (coerce x 'float) generate the same code which I think is important.

Revision history for this message
Andrew Berkley (ajberkley) wrote :
Douglas Katzman (dougk)
Changed in sbcl:
status: New → Fix Committed
Changed in sbcl:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.