Optimizing delegates

Ary Borenszweig ary at esperanto.org.ar
Sun Dec 19 08:57:21 PST 2010


On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
> On 12/19/10 10:35 AM, Ary Borenszweig wrote:
>> On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
>>> On 12/19/10 9:32 AM, Ary Borenszweig wrote:
>>>> I have this code:
>>>>
>>>> ---
>>>> import std.stdio;
>>>>
>>>> int foobar(int delegate(int) f) {
>>>> return f(1);
>>>> }
>>>>
>>>> int foobar2(string s)() {
>>>> int x = 1;
>>>> mixin("return " ~ s ~ ";");
>>>> }
>>>>
>>>> void main() {
>>>> writefln("%d", foobar((int x) { return 2*x; }));
>>>> writefln("%d", foobar2!("9876*x"));
>>>> }
>>>> ---
>>>>
>>>> When I compile it with -O -inline I can see with obj2asm that for the
>>>> first writefln the delegate is being called. However, for the second
>>>> it just passes
>>>> 9876 to writefln.
>>>>
>>>> From this I can say many things:
>>>> - It seems that if I want hyper-high performance in my code I must use
>>>> string mixins because delegate calls, even if they are very simple and
>>>> the
>>>> functions that uses them are also very simple, are not inlined. This
>>>> has the drawback that each call to foobar2 with a different string
>>>> will generate a
>>>> different method in the object file.
>>>
>>> You forgot:
>>>
>>> writefln("%d", foobar2!((x) { return 2*x; })());
>>>
>>> That's a real delegate, not a string, but it will be inlined.
>>>
>>>
>>> Andrei
>>
>> Sorry, I don't understand. I tried these:
>>
>> 1.
>> int foobar3(int delegate(int) f)() {
>> return f(1);
>> }
>>
>> writefln("%d", foobar3!((int x) { return 2*x; })());
>>
>> => foo.d(12): Error: arithmetic/string type expected for
>> value-parameter, not int delegate(int)
>>
>> 2.
>> int foobar3()(int delegate(int) f) {
>> return f(1);
>> }
>>
>> writefln("%d", foobar3!()((int x) { return 2*x; }));
>>
>> => Works, but it doesn't get inlined.
>>
>> And I tried that "(x) { ... }" syntax and it doesn't work.
>>
>> Sorry, it must be my fault I'm doing something wrong. What's the correct
>> way of writing optimized code in D, code that I'm sure the compiler will
>> know how to optimize?
>
> void foobar3(alias fun)() {
> return fun(1);
> }
>
>
> Andrei

foo.d
---
import std.stdio;

int foobar3(alias f)() {
    return f(1);
}

void main() {
    writefln("%d", foobar3!((x) { return 9876*x; })());
}

asterite at deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline
asterite at deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi -
(line 530)
_Dmain:
		push	EBP
		mov	EBP,ESP
		mov	EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File at SYM32
		push	dword ptr _TMP0 at SYM32[0Eh]
		push	dword ptr _TMP0 at SYM32[010h]
		push	02694h
		call	  _D3std5stdio4File19__T8writeflnTAyaTiZ8writeflnMFAyaiZv at PC32
		xor	EAX,EAX
		pop	EBP
		ret
		nop
		nop

No, it doesn't seem to get inlined. Luckily. Because if it did get 
inlined then I would improve DMD by giving an error on this line:

int foobar(int delegate(int) f) {
  ...
}

foo.d(3): Error: Hey man, what are you doing? Don't you know that if you 
pass delegates that way they don't get inlined? You should write it this 
way: "int foobar(alias f)()". That is, of course, if you want your code 
to be more performant.


More information about the Digitalmars-d mailing list