From: Martin Raspaud
Subject: Typed defun ?
Date: 
Message-ID: <ccu6k6$src$1@news.u-bordeaux.fr>
Hi all,

How should one define the type of a function ?
for example declaring that foo returns a double-float ?
Will it take away the messages like "doing float to pointer coercion 
(costs 13)" ?

Thanks

Martin

From: Paul Dietz
Subject: Re: Typed defun ?
Date: 
Message-ID: <40F2A2D0.95EC7381@motorola.com>
Martin Raspaud wrote:
> 
> Hi all,
> 
> How should one define the type of a function ?
> for example declaring that foo returns a double-float ?
> Will it take away the messages like "doing float to pointer coercion
> (costs 13)" ?

Use DECLAIM and FTYPE:

  (declaim (ftype (function (&rest t) double-float) foo))

What effect this has will depend on the implementation;
implementations are permitted to ignore ftype declarations.

	Paul
From: Raymond Toy
Subject: Re: Typed defun ?
Date: 
Message-ID: <sxdzn65dx6w.fsf@edgedsp4.rtp.ericsson.se>
>>>>> "Martin" == Martin Raspaud <········@labri.fr> writes:

    Martin> Hi all,

    Martin> How should one define the type of a function ?
    Martin> for example declaring that foo returns a double-float ?

Paul Dietz has answered this.

    Martin> Will it take away the messages like "doing float to pointer coercion
    Martin> (costs 13)" ?

From the message, you're probably using CMUCL or SBCL.  Declaring the
type of a function won't get rid of the message.  

The real question is why do you care about that message?
You might be able to get rid of the message if you use CMUCL's block
compilation.

Ray
From: Martin Raspaud
Subject: Re: Typed defun ?
Date: 
Message-ID: <cd0chl$lkq$1@news.u-bordeaux.fr>
Raymond Toy wrote:
>>>>>>"Martin" == Martin Raspaud <········@labri.fr> writes:
> 
> 
>     Martin> Hi all,
> 
>     Martin> How should one define the type of a function ?
>     Martin> for example declaring that foo returns a double-float ?
> 
> Paul Dietz has answered this.
> 
>     Martin> Will it take away the messages like "doing float to pointer coercion
>     Martin> (costs 13)" ?
> 
> From the message, you're probably using CMUCL or SBCL.  Declaring the
> type of a function won't get rid of the message.  
> 
> The real question is why do you care about that message?
> You might be able to get rid of the message if you use CMUCL's block
> compilation.

It's all about speed and thus the smaller the allocation, the better...

I try to make efficient code for my program.

Martin
From: ·········@random-state.net
Subject: Re: Typed defun ?
Date: 
Message-ID: <cd0lls$2usu1$1@midnight.cs.hut.fi>
Raymond Toy <···········@ericsson.com> wrote:

> > Will it take away the messages like "doing float to pointer coercion
> > (costs 13)" ?

> From the message, you're probably using CMUCL or SBCL.  Declaring the
> type of a function won't get rid of the message.  

For both CMUCL and SBCL declaring the function as inline should remove the
message. From my limited experience in float-munging in SBCL/CMUCL:

 * Profile, profile, profile! Spend time on the bottlenecks. Be aware
   then inlined functions will not show up in the profiling output.

 * When trying to figure out why something is slower then you'd like
   the optimization notes and DISASSEMBLE are your friends, followed
   by the relevant mailing list of the implementation you are using.

 * Use policy speed 3, debug 0, space 0 for the sensitive
   parts of the application. Safety 0 may be worth investigating as well,
   but for 99% of your application safety 3 is a better bet. During
   developent you will probably want to use a higher debug setting as
   well.

 * Inline functions returning floating point numbers (as Raymond noted
   in CMUCL block-compile should do the trick as well, in SBCL try lifting
   them into FLETs and LABELS, or pester someone into fixing block-compile):

    (defun frob-float ...)
    (defun foo () ... (frob-float x) ...)

    => (flet ((frob-float ...))
          (defun foo () ... (frob-float x) ...))

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Martin Raspaud
Subject: Re: Typed defun ?
Date: 
Message-ID: <cd0op2$q4t$1@news.u-bordeaux.fr>
·········@random-state.net wrote:
> Raymond Toy <···········@ericsson.com> wrote:
> 
> 
>>>Will it take away the messages like "doing float to pointer coercion
>>>(costs 13)" ?
> 
> 
>>From the message, you're probably using CMUCL or SBCL.  Declaring the
>>type of a function won't get rid of the message.  
> 
> 
> For both CMUCL and SBCL declaring the function as inline should remove the
> message. From my limited experience in float-munging in SBCL/CMUCL:
> 
>  * Profile, profile, profile! Spend time on the bottlenecks. Be aware
>    then inlined functions will not show up in the profiling output.
> 
>  * When trying to figure out why something is slower then you'd like
>    the optimization notes and DISASSEMBLE are your friends, followed
>    by the relevant mailing list of the implementation you are using.
> 
>  * Use policy speed 3, debug 0, space 0 for the sensitive
>    parts of the application. Safety 0 may be worth investigating as well,
>    but for 99% of your application safety 3 is a better bet. During
>    developent you will probably want to use a higher debug setting as
>    well.
> 
>  * Inline functions returning floating point numbers (as Raymond noted
>    in CMUCL block-compile should do the trick as well, in SBCL try lifting
>    them into FLETs and LABELS, or pester someone into fixing block-compile):
> 
>     (defun frob-float ...)
>     (defun foo () ... (frob-float x) ...)
> 
>     => (flet ((frob-float ...))
>           (defun foo () ... (frob-float x) ...))

Thanks very much for the tips ! This will surely help...

As for the last point, would the flet and labels work for other 
implementations as well ? (I would like my program to be portable to 
most of the implementations)

Martin
From: Raymond Toy
Subject: Re: Typed defun ?
Date: 
Message-ID: <sxdr7rgdob1.fsf@edgedsp4.rtp.ericsson.se>
>>>>> "Martin" == Martin Raspaud <········@labri.fr> writes:

    Martin> As for the last point, would the flet and labels work for other
    Martin> implementations as well ? (I would like my program to be portable to
    Martin> most of the implementations)

Yes, of course, you can use flet or labels in other implementations as
well.  But, this presupposes that that function is only used in that
one function and now where else.  Otherwise, you'll have to copy it to
all other callers, which is not such a good idea.

So declare it inline (which doesn't have to be honored), or use the
non-portable block-compile.

Ray
From: ·········@random-state.net
Subject: Re: Typed defun ?
Date: 
Message-ID: <cd0p3k$2usu1$2@midnight.cs.hut.fi>
Martin Raspaud <········@labri.fr> wrote:

> As for the last point, would the flet and labels work for other 
> implementations as well ? (I would like my program to be portable to 
> most of the implementations)

Work yes, but I've no idea about their performance characteristics
elsewhere.

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Raspaud Martin
Subject: Re: Typed defun ?
Date: 
Message-ID: <40fe6d7a$0$14223$626a14ce@news.free.fr>
·········@random-state.net wrote:
> Raymond Toy <···········@ericsson.com> wrote:
> 
> 
>>>Will it take away the messages like "doing float to pointer coercion
>>>(costs 13)" ?
> 
> 
>>From the message, you're probably using CMUCL or SBCL.  Declaring the
>>type of a function won't get rid of the message.  
> 
> 
> For both CMUCL and SBCL declaring the function as inline should remove the
> message. 

It seems it doesn't !

I tried with this code :

(declaim (inline sinc))
(defun double-float sinc (x)
   (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)))
   (declare (type double-float x))
   (if (= x 0.0d0)
       1.0d0
       (/ (sin (* pi x)) (the double-float (* pi x)))))

Any other idea ?

Thanx

Martin
From: ·········@random-state.net
Subject: Re: Typed defun ?
Date: 
Message-ID: <cdm46o$3jsfa$1@midnight.cs.hut.fi>
Raspaud Martin <········@free.fr> wrote:

> ·········@random-state.net wrote:
>> For both CMUCL and SBCL declaring the function as inline should remove the
>> message. 

> It seems it doesn't !

Hum. Seems I was wrong there, though the note should not matter anyways:
it's emitted when the function is compiled, but the call-sites don't need
to do the boxing in the presence of the inline expansion.

> I tried with this code :

> (declaim (inline sinc))
> (defun double-float sinc (x)

         ^
         something funny here...

>    (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)))
>    (declare (type double-float x))
>    (if (= x 0.0d0)
>        1.0d0
>        (/ (sin (* pi x)) (the double-float (* pi x)))))

Removing the leading DOUBLE-FLOAT from the definition, i get the following
compiler notes on SBCL:

 ; note: unable to avoid inline argument range check
 ; because the argument range (DOUBLE-FLOAT) was not within 2^64

 ; note: doing float to pointer coercion (cost 13) to "<return value>"
 ; compilation unit finished

If SINC is inline the latter should not matter at the call site. The
obvious way to avoid the first is to limit the range of acceptable inputs
to SINC eg to [-pi pi]. If the bottleneck is severe, I'd just do that:

 ...
 (declare (type (double-float #.(- pi) #.pi) x)
 ...

If the bottleneck isn't that severe, I'd try to go for a more general
solution -- something along the lines of the following, providing similar
return type semantics as CL:SIN.

 (macrolet ((def (name &optional protop)
              `(progn
                  (declaim (inline ,name))
                  (defun ,name (x)
                     (float (if (zerop x)
                            1.0d0
                            (let ((y (* x pi)))
                               (/ (sin y) y))
                     ,(if protop 'x 1.0f0))))))
   (def %sinc)
   (def %fsinc t))

 (declaim (inline sinc))
 (defun sinc (x)
   (etypecase x
     (single-float (%fsinc x))
     (double-float (%fsinc x))
     ;; Lazy with short- and long-float here: this is never selected with
     ;; SBCL at least, but there for portability.
     (float (%fsinc x))
     ;; Just a hunch that separate dispatch for fixnums pays off, maybe
     ;; more would be good, eg. (signed-byte 32) (unsigned-byte 32), but
     ;; don't know.
     (fixnum (%sinc x))
     (rational (%sinc x))))

This spews an enormous amount of optimization notes (sepending on your
SPEED setting), but that doesn't matter, as inline expansion in
SBCL and CMUCL allows type propagation "inside" the original definition:

 (defun test-sinc (x)
   (declare (double-float x))
   (sinc x))

 <ton of code-deletion notes>
   
 (disassemble 'test-sinc)

That was fun. ;-) ...but inliling (and possibly constraining the inputs)
should be sufficient. DEBUG 3 is something you'll pay for thru the nose,
though.

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Raymond Toy
Subject: Re: Typed defun ?
Date: 
Message-ID: <sxdfz7l829r.fsf@edgedsp4.rtp.ericsson.se>
>>>>> "nikodemus" == nikodemus  <·········@random-state.net> writes:

    nikodemus> Removing the leading DOUBLE-FLOAT from the definition, i get the following
    nikodemus> compiler notes on SBCL:

    nikodemus>  ; note: unable to avoid inline argument range check
    nikodemus>  ; because the argument range (DOUBLE-FLOAT) was not within 2^64


Just a note to explain what the note is trying to tell you, in case
you don't know.  (Nikodemus probably knows why.)

In CMUCL (and presumably SBCL) on x86, the Lisp trig functions will
use the built-in trig instructions if possible.  However, these are
known not to be accurate if the argument is larger than 2^64.  I think
they even return 0d0 for the answer, no matter what the arg value is.

The intent was that if the compiler could not prove the arg was small
enough, we would call out to the C function to compute it.  But I
think the C function just uses the trig instruction as well.

This is different on Sparc, where there are no trig instructions, so
it calls to C anyway.  And on sparc, the C routine assumes the arg is
infinitely precise and returns the best answer it can.

Thus,  (sin (expt 2d0 120)) => 0.37782010936075205d0.

Ray
From: Raspaud Martin
Subject: Re: Typed defun ?
Date: 
Message-ID: <41067846$0$20152$626a14ce@news.free.fr>
·········@random-state.net wrote:
> Raspaud Martin <········@free.fr> wrote:

>>I tried with this code :
> 
> 
>>(declaim (inline sinc))
>>(defun double-float sinc (x)
> 
> 
>          ^
>          something funny here...
> 

hehe... indeed, I forgot to remove this. Actually, I made a macro that 
would declaim the ftype of the function from something like (mydefun 
type name [etc...])

> 
>>   (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)))
>>   (declare (type double-float x))
>>   (if (= x 0.0d0)
>>       1.0d0
>>       (/ (sin (* pi x)) (the double-float (* pi x)))))
> 
> 
> Removing the leading DOUBLE-FLOAT from the definition, i get the following
> compiler notes on SBCL:
> 
>  ; note: unable to avoid inline argument range check
>  ; because the argument range (DOUBLE-FLOAT) was not within 2^64
> 
>  ; note: doing float to pointer coercion (cost 13) to "<return value>"
>  ; compilation unit finished
> 
> If SINC is inline the latter should not matter at the call site. The
> obvious way to avoid the first is to limit the range of acceptable inputs
> to SINC eg to [-pi pi]. If the bottleneck is severe, I'd just do that:
> 
>  ...
>  (declare (type (double-float #.(- pi) #.pi) x)
>  ...

Well, I can never be sure that x is indeed between -pi and pi... So I 
guess the second solution is better in my case.

> If the bottleneck isn't that severe, I'd try to go for a more general
> solution -- something along the lines of the following, providing similar
> return type semantics as CL:SIN.
> 
>  (macrolet ((def (name &optional protop)
>               `(progn
>                   (declaim (inline ,name))
>                   (defun ,name (x)
>                      (float (if (zerop x)
>                             1.0d0
>                             (let ((y (* x pi)))
>                                (/ (sin y) y))
>                      ,(if protop 'x 1.0f0))))))
>    (def %sinc)
>    (def %fsinc t))
> 
>  (declaim (inline sinc))
>  (defun sinc (x)
>    (etypecase x
>      (single-float (%fsinc x))
>      (double-float (%fsinc x))
>      ;; Lazy with short- and long-float here: this is never selected with
>      ;; SBCL at least, but there for portability.
>      (float (%fsinc x))
>      ;; Just a hunch that separate dispatch for fixnums pays off, maybe
>      ;; more would be good, eg. (signed-byte 32) (unsigned-byte 32), but
>      ;; don't know.
>      (fixnum (%sinc x))
>      (rational (%sinc x))))
> 
> This spews an enormous amount of optimization notes (sepending on your
> SPEED setting), but that doesn't matter, as inline expansion in
> SBCL and CMUCL allows type propagation "inside" the original definition:
> 
>  (defun test-sinc (x)
>    (declare (double-float x))
>    (sinc x))
> 
>  <ton of code-deletion notes>
>    
>  (disassemble 'test-sinc)
> 
> That was fun. ;-) ...but inliling (and possibly constraining the inputs)
> should be sufficient. DEBUG 3 is something you'll pay for thru the nose,
> though.


Thanks a lot for the hints.

Martin
From: Iain Little
Subject: Re: Typed defun ?
Date: 
Message-ID: <87isch30qo.fsf@yahoo.com>
Raspaud Martin <········@free.fr> writes:

> ·········@random-state.net wrote:
>> Raymond Toy <···········@ericsson.com> wrote:
>>
>>>>Will it take away the messages like "doing float to pointer coercion
>>>>(costs 13)" ?
>>
>>>From the message, you're probably using CMUCL or SBCL.  Declaring the
>>> type of a function won't get rid of the message.
>> For both CMUCL and SBCL declaring the function as inline should
>> remove the
>> message.
>
> It seems it doesn't !
>
> I tried with this code :
>
> (declaim (inline sinc))
> (defun double-float sinc (x)
>    (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)))
>    (declare (type double-float x))
>    (if (= x 0.0d0)
>        1.0d0
>        (/ (sin (* pi x)) (the double-float (* pi x)))))
>
> Any other idea ?

If you can't get rid of a cmucl note, but don't want to be bothered by
it, then you can always just turn off the feedback messages for that
function:

(defun sinc (x)
  (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)
		     (ext:inhibit-warnings 3))
	   (type double-float x) (inline))
  (if (= x 0.0d0)
      1.0d0
      (/ (sin (* pi x))
	 (the double-float (* pi x)))))

[Note: A quick google search suggests that sbcl has a slightly
different way of doing this; check the manual...]


Iain
From: Raspaud Martin
Subject: Re: Typed defun ?
Date: 
Message-ID: <40fe812a$0$1900$636a15ce@news.free.fr>
Iain Little wrote:
> Raspaud Martin <········@free.fr> writes:
> 
> 
>>·········@random-state.net wrote:
>>
>>>Raymond Toy <···········@ericsson.com> wrote:
>>>
>>>
>>>>>Will it take away the messages like "doing float to pointer coercion
>>>>>(costs 13)" ?
>>>
>>>>From the message, you're probably using CMUCL or SBCL.  Declaring the
>>>
>>>>type of a function won't get rid of the message.
>>>
>>>For both CMUCL and SBCL declaring the function as inline should
>>>remove the
>>>message.
>>
>>It seems it doesn't !
>>
>>I tried with this code :
>>
>>(declaim (inline sinc))
>>(defun double-float sinc (x)
>>   (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)))
>>   (declare (type double-float x))
>>   (if (= x 0.0d0)
>>       1.0d0
>>       (/ (sin (* pi x)) (the double-float (* pi x)))))
>>
>>Any other idea ?
> 
> 
> If you can't get rid of a cmucl note, but don't want to be bothered by
> it, then you can always just turn off the feedback messages for that
> function:
> 
> (defun sinc (x)
>   (declare (optimize (speed 3) (space 0) (debug 3) (safety 3)
> 		     (ext:inhibit-warnings 3))
> 	   (type double-float x) (inline))
>   (if (= x 0.0d0)
>       1.0d0
>       (/ (sin (* pi x))
> 	 (the double-float (* pi x)))))
> 
> [Note: A quick google search suggests that sbcl has a slightly
> different way of doing this; check the manual...]

Thanks for the tip.

It seems also that putting the result in a variable takes the note 
away... but I guess then I cons more, don't I ?

Martin