RFC: INLINE defcfun and auto FTYPE declarations [with patch]

Luís Oliveira luismbo at gmail.com
Mon Nov 13 12:31:29 UTC 2017


Andrzej,

I'm convinced this is a good idea. If you have the time/budget, I
suggest you open a pull request. Sooner or later we'll need
documentation and tests.

Cheers,
Luís

On Wed, Nov 8, 2017 at 4:50 PM, Andrzej Walczak
<andrzejwalczak at google.com> wrote:
> Hello Luis,
>
> Indeed, I am guilty as well of writing a compiler-macro based Lisp-form
> compiler - as hinted in the pro at c-l.net post :)
> It was one of the motivations to add FTYPEs everywhere. Thank you for the
> interesting pointer.
>
> As stated in the quoted comment, double-float boxing is one of the reasons
> why we inline CFFI stubs.
> It's not like SBCL could chose a different call convention depending on
> known type declarations.
> Once inlined, there will be no difference for FABS-1 and FABS-2 - with or
> without type of ftype declarations.
> Thank you for the excellent example illustrating this classic issue.
>
> The FTYPEs help SBCL produce better code if the double-float function stubs
> are not inlined (for some reason).
> Also, going back to the post you have mentioned, having FTYPEs on CFFI could
> help compiler-macros
> take informed decisions about code transformations.
>
> E.g. (quickly typed - might not compile)
>
> (declaim (ftype (function (double-float double-float) (values double-float
> &optional)) pow) (inline pow))
> (defcfun pow :double (base :double) (exp :double))
>
> (defun test (&rest nums)
>    (sum (bind #'pow 2) nums))
>
> Could expand to:
>
> (defun test (&rest nums)
>   (flet ((#:f1 (#:e1)
>            (declare (double-float #:e1))
>            (pow 2 #:e1)))
>     (declare (ftype (function (double-float) (values double-float
> &optional)) #:f1)
>                   (dynamic-extent #'#:f1))
>     (let ((#:a1 (first nums)))
>       (declare (double-float #:a1))
>       (dolist (#:n1 (rest nums) #:a1)
>         (setf #:a1 (+ #:a1 (funcall #'#:f1 #:n1)))))))
>
> Which should allow the compiler to choose an unboxed representation for
> passing arguments to the internal #'#:f1.
> BTW: I am sure SBCL would do just fine with just 1/3rd of the declarations
> above - but unsure which 1/3rd ... this time of year.
>
> Cheers,
>
> On Tue, Nov 7, 2017 at 7:12 PM, Luís Oliveira <luismbo at gmail.com> wrote:
>>
>> On Mon, Nov 6, 2017 at 5:10 PM, Andrzej Walczak
>> <andrzejwalczak at google.com> wrote:
>> > After some thoughts, I agree, that the inlining control is not a
>> > fully-baked
>> > idea, yet.
>>
>> Incidentally, this recent pro at c-l.net message makes me a whole lot
>> less skeptical about your suggested approach:
>> <https://mailman.common-lisp.net/pipermail/pro/2017-November/001464.html>.
>> The introspect-environment library seems to provide a nice portable
>> API for inspecting optimization policies. Alas, there doesn't seem to
>> be away to define your own declarations; I was hoping we might be able
>> to something like (declaim (inline-cffi-functions <boolean>)) or
>> something along those lines.
>>
>>
>> > I'll split the patch into INLINE and FTYPE parts.
>>
>> Sounds like a good idea.
>>
>>
>> > You may ask why we have decided to inline (almost) every of the
>> > DEFCFUNs?
>> > CFFI interfaces to C - obviously - and a lot of code in C deals with
>> > double-floats and 64-bit integers.
>> > Without the stubs being inline, every call to C and back produces boxed
>> > values, impacting the performance.
>>
>> Right. Float boxing; that's a classic. But, I (perhaps naively) didn't
>> expect boxing to happen even without the declarations. Take the
>> following example:
>>
>> (in-package :cffi)
>>
>> (declaim (optimize (speed 3) (space 0) (safety 0) (debug 0)))
>>
>> (declaim (inline fabs-1))
>> (defun fabs-1 (x)
>>   (foreign-funcall "fabs" :double x :double))
>>
>> (declaim (inline fabs-2))
>> (defun fabs-2 (x)
>>   (declare (double-float x))
>>   (foreign-funcall "fabs" :double x :double))
>>
>> (defun foo-1 (x)
>>   (floatp (fabs-1 x)))
>>
>> (defun foo-2 (x)
>>   (floatp (fabs-2 x)))
>>
>> I expected FABS-1 and FABS-2 to be identical. (FOREIGN-FUNCALL
>> eventually expands to ALIEN-FUNCALL and I was expecting that would
>> provide all the type information SBCL's compiler might need.) The
>> disassembly shows that FAB-2 is one instruction shorter. But
>> disassembling FOO-1 and FOO-2 shows that they're identical.
>>
>> Perhaps this example is too contrived. Do you have a better one?
>>
>> Cheers,
>>
>> --
>> Luís Oliveira
>> http://kerno.org/~luis/
>
>
>
>
> --
> Andrzej Walczak
> (Google/ITA Software Engineer)
>



-- 
Luís Oliveira
http://kerno.org/~luis/



More information about the cffi-devel mailing list