From: Dave Roberts
Subject: Declaimation help
Date: 
Message-ID: <HUuac.145183$Cb.1521356@attbi_s51>
I'm trying to understand declarations and declaimations and I'm not really
sure I get it. Specifically, I understand how to declare variable types
with DECLARE within a function. No biggie there. My confusion is with
global type declarations, specifically for functions.

For instance, is there any value in a (DECLAIM (FTYPE (FUNCTION (<type>...)
<ret-type>) <function-name>)) for particular often-used functions? Would I
have to put this declaration in every file which makes a call to
<function-name>, or would just doing it once in a common file and the using
a defsystem like ASDF handle that correctly? My confusion is sort of around
how similar a (DECLAIM (FTYPE...)) is to a C .h file declaration.

For instance, can SBCL uses this to more effectively deal with calls to the
that function from other functions? If not, is there anything that will
help, or do you just rely on the compiler type inferencing being so
fantastic that it's able to deduce all the type info, including return type
info?

For instance, this is some code from the DNS resolver code I'm working on.
It uses UFFI to interface to Linux's resolver.so library. The GET-BYTE
function is called tremendously often to read bytes from the buffer. I have
declared types for the GET-BYTE function parameters and I have actually
declared the function inline in the DECLAIM. I also added the DECLAIM
FTYPE, but I'm not sure what the correct usage should be.

(uffi:def-type byte-ptr (* :unsigned-byte))
(deftype buffer-index () `(integer 0 ,(1- (expt 2 14))))
(deftype uint8 () '(unsigned-byte 8))
(deftype uint16 () '(unsigned-byte 16))
(deftype uint32 () '(unsigned-byte 32))
(deftype dns-pointer () `(integer 0  ,(1- (expt 2 14))))

(declaim (inline get-byte)
         (ftype (function (byte-ptr buffer-index buffer-index) uint8) 
                get-byte))

(defun get-byte (buffer size index)
  "Get a byte from the foreign object array at the specified index."
  (declare (optimize (speed 3) (safety 0) (space 0))
           (byte-ptr buffer)
           (buffer-index size)
           (buffer-index index))
  (assert (and (<= 0 index) (< index size)))
  (the uint8 (uffi:deref-array buffer :unsigned-byte index)))

-- 
Dave Roberts
·············@re-move.droberts.com

From: Barry Margolin
Subject: Re: Declaimation help
Date: 
Message-ID: <barmar-6D775C.03153931032004@comcast.ash.giganews.com>
In article <·······················@attbi_s51>,
 Dave Roberts <·············@re-move.droberts.com> wrote:

> I'm trying to understand declarations and declaimations and I'm not really
> sure I get it. Specifically, I understand how to declare variable types
> with DECLARE within a function. No biggie there. My confusion is with
> global type declarations, specifically for functions.
> 
> For instance, is there any value in a (DECLAIM (FTYPE (FUNCTION (<type>...)
> <ret-type>) <function-name>)) for particular often-used functions? Would I
> have to put this declaration in every file which makes a call to
> <function-name>, or would just doing it once in a common file and the using
> a defsystem like ASDF handle that correctly? My confusion is sort of around
> how similar a (DECLAIM (FTYPE...)) is to a C .h file declaration.

As long as the compiler processes the declamation before it processes 
any of the callers, it doesn't matter where it's located.  You can use 
DEFSYSTEM to declare this dependency, so that the common file is 
processed before any of the dependant files.

> For instance, can SBCL uses this to more effectively deal with calls to the
> that function from other functions? If not, is there anything that will
> help, or do you just rely on the compiler type inferencing being so
> fantastic that it's able to deduce all the type info, including return type
> info?

I don't know anything specific about SBCL's use of declarations.  It 
probably can't hurt to have them.

> 
> For instance, this is some code from the DNS resolver code I'm working on.
> It uses UFFI to interface to Linux's resolver.so library. The GET-BYTE
> function is called tremendously often to read bytes from the buffer. I have
> declared types for the GET-BYTE function parameters and I have actually
> declared the function inline in the DECLAIM. I also added the DECLAIM
> FTYPE, but I'm not sure what the correct usage should be.
> 
> (uffi:def-type byte-ptr (* :unsigned-byte))
> (deftype buffer-index () `(integer 0 ,(1- (expt 2 14))))
> (deftype uint8 () '(unsigned-byte 8))
> (deftype uint16 () '(unsigned-byte 16))
> (deftype uint32 () '(unsigned-byte 32))
> (deftype dns-pointer () `(integer 0  ,(1- (expt 2 14))))
> 
> (declaim (inline get-byte)
>          (ftype (function (byte-ptr buffer-index buffer-index) uint8) 
>                 get-byte))
> 
> (defun get-byte (buffer size index)
>   "Get a byte from the foreign object array at the specified index."
>   (declare (optimize (speed 3) (safety 0) (space 0))
>            (byte-ptr buffer)
>            (buffer-index size)
>            (buffer-index index))
>   (assert (and (<= 0 index) (< index size)))
>   (the uint8 (uffi:deref-array buffer :unsigned-byte index)))

My guess is that if the function is expanded inline, the argument type 
declarations within the function definition should be sufficient.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Dave Roberts
Subject: Re: Declaimation help
Date: 
Message-ID: <FsNac.156619$po.931420@attbi_s52>
Barry Margolin wrote:

 
> As long as the compiler processes the declamation before it processes
> any of the callers, it doesn't matter where it's located.  You can use
> DEFSYSTEM to declare this dependency, so that the common file is
> processed before any of the dependant files.

Thanks. That's what I figured, but it wasn't quite clear.

> I don't know anything specific about SBCL's use of declarations.  It
> probably can't hurt to have them.

Well, the question is really whether it generally helps. Specifically, what
are the semantics of declaring FTYPEs at a global level? What am I really
telling the compiler at that point? Is the alternative to declaiming a
global FTYPE that the compiler must see the function ahead of time,
otherwise it assumes generic return types? And if it sees it ahead of time,
will it, using type inference, deduce the parameters (possibly using
DECLARations inside the function) and return type that can then be used to
optimize future calls?

Now, I'm assuming that DECLAIMing something INLINE automatically helps
matters, since the function then must be seen before any function that uses
it.

-- 
Dave Roberts
·············@re-move.droberts.com
From: Barry Margolin
Subject: Re: Declaimation help
Date: 
Message-ID: <barmar-138080.02265001042004@comcast.ash.giganews.com>
In article <······················@attbi_s52>,
 Dave Roberts <·············@re-move.droberts.com> wrote:

> Well, the question is really whether it generally helps. Specifically, what
> are the semantics of declaring FTYPEs at a global level? What am I really
> telling the compiler at that point? Is the alternative to declaiming a
> global FTYPE that the compiler must see the function ahead of time,
> otherwise it assumes generic return types? And if it sees it ahead of time,
> will it, using type inference, deduce the parameters (possibly using
> DECLARations inside the function) and return type that can then be used to
> optimize future calls?

It's implementation-dependent.  Some compilers make use of type 
declarations to optimize calls, others don't.  Some will even use them 
to insert automatic CHECK-TYPE calls when you declare high safety.

If neither the function nor an FTYPE declaration is seen before 
compiling a caller, it *must* assume generic argument and return types; 
what else could it possibly do?

> Now, I'm assuming that DECLAIMing something INLINE automatically helps
> matters, since the function then must be seen before any function that uses
> it.

It can't hurt, but it isn't guaranteed to help.  Compilers aren't 
required to support inlining.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Dave Roberts
Subject: Re: Declaimation help
Date: 
Message-ID: <UXWac.54761$K91.133103@attbi_s02>
Barry Margolin wrote:

> If neither the function nor an FTYPE declaration is seen before
> compiling a caller, it *must* assume generic argument and return types;
> what else could it possibly do?

That was exactly my reasoning, but I just wanted to make sure. What I wasn't
clear about was how smart most of the compilers were and whether seeing the
function ahead of time would allow them to do things like deduce the
function return type.

> It can't hurt, but it isn't guaranteed to help.  Compilers aren't
> required to support inlining.

Right. Got it.

-- 
Dave Roberts
·············@re-move.droberts.com
From: Damien Kick
Subject: Re: Declaimation help
Date: 
Message-ID: <8yf53dqp.fsf@email.mot.com>
Dave Roberts <·············@re-move.droberts.com> writes:

> > It can't hurt, but it isn't guaranteed to help.  Compilers aren't
> > required to support inlining.
> 
> Right. Got it.

One can always use DISASSEMBLE to see whether or not declarations are
making a difference...
From: Joe Marshall
Subject: Re: Declaimation help
Date: 
Message-ID: <lllgrwau.fsf@comcast.net>
Dave Roberts <·············@re-move.droberts.com> writes:

> Well, the question is really whether it generally helps. Specifically, what
> are the semantics of declaring FTYPEs at a global level? What am I really
> telling the compiler at that point? 

You are promising to the compiler that the function will return
something in its range when given something in its domain.  And you
are promising that the compiler can assume that this will not change.

> Is the alternative to declaiming a global FTYPE that the compiler
> must see the function ahead of time, otherwise it assumes generic
> return types? And if it sees it ahead of time, will it, using type
> inference, deduce the parameters (possibly using DECLARations inside
> the function) and return type that can then be used to optimize
> future calls?

No, because you can redefine the function.



-- 
~jrm
From: Barry Margolin
Subject: Re: Declaimation help
Date: 
Message-ID: <barmar-FC9FDC.02571701042004@comcast.ash.giganews.com>
In article <············@comcast.net>,
 Joe Marshall <·············@comcast.net> wrote:

> Dave Roberts <·············@re-move.droberts.com> writes:
> > Is the alternative to declaiming a global FTYPE that the compiler
> > must see the function ahead of time, otherwise it assumes generic
> > return types? And if it sees it ahead of time, will it, using type
> > inference, deduce the parameters (possibly using DECLARations inside
> > the function) and return type that can then be used to optimize
> > future calls?
> 
> No, because you can redefine the function.

If the callee and caller are in the same compilation unit, the standard 
gives the implementation license to assume that the signature won't 
change, unless you explicitly declare it NOTINLINE.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Christophe Rhodes
Subject: Re: Declaimation help
Date: 
Message-ID: <sqlllgdpkm.fsf@lambda.dyndns.org>
Barry Margolin <······@alum.mit.edu> writes:

> In article <············@comcast.net>,
>  Joe Marshall <·············@comcast.net> wrote:
>> No, because you can redefine the function.
>
> If the callee and caller are in the same compilation unit, the standard 
> gives the implementation license to assume that the signature won't 
> change, unless you explicitly declare it NOTINLINE.

No, no, no.

If the callee and caller are in the same _file_ as processed by
compile-file, the standard gives the implementation licence to assume
that the signature won't change.  It would have been nice had the
standard said this about compilation units, but in fact it explicitly
disallows this:

  Implementations are forbidden from attaching additional meaning to a
  use of this macro which involves either no keywords or just the
  keyword :override.
  [ CLHS WITH-COMPILATION-UNIT; see also CLHS 3.2.2.3 ]

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Dave Roberts
Subject: Re: Declaimation help
Date: 
Message-ID: <l_Wac.55425$JO3.35395@attbi_s04>
Joe Marshall wrote:

> Dave Roberts <·············@re-move.droberts.com> writes:
> 
>> Well, the question is really whether it generally helps. Specifically,
>> what are the semantics of declaring FTYPEs at a global level? What am I
>> really telling the compiler at that point?
> 
> You are promising to the compiler that the function will return
> something in its range when given something in its domain.  And you
> are promising that the compiler can assume that this will not change.

Right. Got it.

>> Is the alternative to declaiming a global FTYPE that the compiler
>> must see the function ahead of time, otherwise it assumes generic
>> return types? And if it sees it ahead of time, will it, using type
>> inference, deduce the parameters (possibly using DECLARations inside
>> the function) and return type that can then be used to optimize
>> future calls?
> 
> No, because you can redefine the function.

Ah, of course. I hadn't thought about that. Thanks. That makes it more
clear.

-- 
Dave Roberts
·············@re-move.droberts.com