February 08, 2013
On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
> On 02/08/13 01:33, Jonathan M Davis wrote:
> > Hmmm. I wouldn't have thought that you could get the function pointer at compiler time. Regardless, you lose any possibility of inlining the function call, which is the main problem AFAIK, though I don't know if they would have been an option in the case of dup anyway.
> 
> It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc)

How could it not affect inlining? You're using a pointer to a function instead of the function itself, so it can't be inlined. Do you mean that dup in particular doens't get inlined even when called directly? That's quite possible, but in the general case, using a function pointer rather than calling a function directly risks taking a small efficiency hit due to the fact that the function can no longer be inlined.

- Jonathan M Davis
February 08, 2013
On 02/08/13 10:32, Jonathan M Davis wrote:
> On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
>> On 02/08/13 01:33, Jonathan M Davis wrote:
>>> Hmmm. I wouldn't have thought that you could get the function pointer at compiler time. Regardless, you lose any possibility of inlining the function call, which is the main problem AFAIK, though I don't know if they would have been an option in the case of dup anyway.
>>
>> It doesn't affect inlining. (Obviously, that's compiler dependent, but there's no reason why it should and indeed does not w/ gdc)
> 
> How could it not affect inlining? You're using a pointer to a function instead of the function itself, so it can't be inlined. Do you mean that dup in

"&f" is an expression that evaluates to a constant, known at compile time
(modulo link-/run-time relocation/offset fixups, but that's irrelevant here).
"(&f)()" is trivially recognizable (for the compiler) as equivalent to "f()".
Not unlike the "int i; auto j = *&i, k = i;" case where you can expect the
compiler to optimize away the address-of and dereferencing, and evaluate the
first expression just like the second one.

> of the function itself, so it can't be inlined. Do you mean that dup in particular doens't get inlined even when called directly? That's quite possible, but in the general case, using a function pointer rather than calling a function directly risks taking a small efficiency hit due to the fact that the function can no longer be inlined.

It makes no difference. I actually checked, because I was wondering if the reinterpret cast wasn't confusing the compiler - it doesn't and inlining happens as it should even with that cast in the mix.

artur
February 08, 2013
On Friday, 8 February 2013 at 09:33:19 UTC, Jonathan M Davis wrote:
> On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
>> On 02/08/13 01:33, Jonathan M Davis wrote:
>> > Hmmm. I wouldn't have thought that you could get the function pointer at
>> > compiler time. Regardless, you lose any possibility of inlining the
>> > function call, which is the main problem AFAIK, though I don't know if
>> > they would have been an option in the case of dup anyway.
>> 
>> It doesn't affect inlining. (Obviously, that's compiler dependent, but
>> there's no reason why it should and indeed does not w/ gdc)
>
> How could it not affect inlining? You're using a pointer to a function instead
> of the function itself, so it can't be inlined. Do you mean that dup in
> particular doens't get inlined even when called directly? That's quite
> possible, but in the general case, using a function pointer rather than
> calling a function directly risks taking a small efficiency hit due to the fact
> that the function can no longer be inlined.
>
> - Jonathan M Davis

Well, aren't you saying that because usually, function pointers aren't obtained at compile time?

In any case, I also tested it, and the disassemble seems to give the exact same code (inlined, as far as I can tell) for calling via function or function pointer:
http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29\n{\n%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20fun%28%29%3B\n%20%20%2F%2Ffoo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]}

http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29\n{\n%20%20%2F%2Fenum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20%2F%2Ffun%28%29%3B\n%20%20foo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]}

And a third version, after adding the "nothrow" keyword. Slight changes, but I can't tell if they are "true" changes:
http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29%20nothrow\n{\n%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20fun%28%29%3B\n%20%20%2F%2Ffoo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]}

That said, when everything is said and done, the try catch version also generates the same inline code
http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nint%20i%3B\n\nvoid%20foo%28%29\n{\n%20%20%2B%2Bi%3B\n}\n\nvoid%20bar%28%29%20nothrow\n{\n%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20fun%28%29%3B\n%20%20%2F%2Ffoo%28%29%3B\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28i%20%3D%3D%201%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]}

But in this case, the compiler has access to the call, so it can *tell* exceptions won't get thrown.

Finally, in this last version, which calls dup, we can see the "cast" version takes less intructions that the try/catch version.

http://d.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22%2F%2F%20Type%20your%20code%20here%2C%20or%20load%20an%20example.\n\nchar[]%20s%3B\n\nvoid%20foo%28%29\n{\n%20%20s%20%3D%20\%22hello\%22.dup%3B\n}\n\nversion%28all%29\n{\n%20%20void%20bar%28%29%20nothrow\n%20%20{\n%20%20%20%20enum%20fun%20%3D%20cast%28void%20function%28%29%20nothrow%29%20%26foo%3B\n%20%20%20%20fun%28%29%3B\n%20%20}\n}\nelse\n{\n%20%20void%20bar%28%29%20nothrow\n%20%20{\n%20%20%20%20try{\n%20%20%20%20%20%20foo%28%29%3B\n%20%20%20%20}catch{}\n%20%20}\n}\n\nvoid%20main%28%29\n{\n%20%20bar%28%29%3B\n%20%20assert%28s%20%3D%3D%20\%22hello\%22%29%3B\n}%22%2C%22compiler%22%3A%22%2Fusr%2Fbin%2Fgdc%22%2C%22options%22%3A%22-O2%20-march%3Dnative%20-inline%22}]}

But at the end of the day, it is a dangerous semantic for not that much gain.
February 08, 2013
On 02/08/2013 01:32 AM, Jonathan M Davis wrote:
> On Friday, February 08, 2013 09:30:41 Artur Skawina wrote:
>> On 02/08/13 01:33, Jonathan M Davis wrote:
>>> Hmmm. I wouldn't have thought that you could get the function pointer at
>>> compiler time. Regardless, you lose any possibility of inlining the
>>> function call, which is the main problem AFAIK, though I don't know if
>>> they would have been an option in the case of dup anyway.
>>
>> It doesn't affect inlining. (Obviously, that's compiler dependent, but
>> there's no reason why it should and indeed does not w/ gdc)
>
> How could it not affect inlining? You're using a pointer to a function instead
> of the function itself, so it can't be inlined.

Taking the address of a function ensures that the function exists but it does not preclude inlining the code of that function.

Ali

1 2
Next ›   Last »