| Thread overview | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
May 17, 2008 How does inlining work for ref parameters? | ||||
|---|---|---|---|---|
| ||||
I get how inlining works for non-ref parameters. If I do
int foo(int x, int y)
{
return x + y;
}
int a = ...;
int b = ...;
int c = foo(a,b);
Then this can turn into
int a = ...;
int b = ...;
int x = a;
int y = b;
int t = a + b;
int c = t;
which can subsequently be optimised to
int a = ...;
int b = ...;
int c = a + b;
But I don't get how it all hangs together with reference arguments. Here's an example:
int bar(ref int* p, ref int* q)
{
return *p++ + *q++;
}
int* ap = ...;
int* bp = ...;
int c = bar(ap,bp);
My complete lack of understanding of how inlining works suggests to me that this would translate into
int* ap = ...;
int* bp = ...;
int** p = ≈
int** q = &bp;
int t = *(*p)++ + *(*q)++;
int c = t;
which doesn't really optimise, except for the elimination of t. And yet, we would /hope/ to end up with is:
int* ap = ...;
int* bp = ...;
int c = *ap++ + *bp++;
This can certainly be achieved by another means. Specifically:
string bar(string r, string p, string q)
{
return r~"= *"~p~"++ + *"~q~"++;"
}
int* ap = ...;
int* bp = ...;
int c;
mixin(bar("c","ap","bp"));
But to my mind, the code is less readable.
So - can someone tell me - if a function takes lots of parameters declared "ref", and that function is inlined, is the "ref" part (passing the address and then dereferencing when needed) completely eliminated, or not? Does anyone have a definitive answer?
| ||||
May 17, 2008 Re: How does inlining work for ref parameters? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | Janice Caron wrote: > I get how inlining works for non-ref parameters. If I do > > int foo(int x, int y) > { > return x + y; > } > > int a = ...; > int b = ...; > int c = foo(a,b); > > Then this can turn into > > int a = ...; > int b = ...; > int x = a; > int y = b; > int t = a + b; > int c = t; > > which can subsequently be optimised to > > int a = ...; > int b = ...; > int c = a + b; > > But I don't get how it all hangs together with reference arguments. > Here's an example: > > int bar(ref int* p, ref int* q) > { > return *p++ + *q++; > } > > int* ap = ...; > int* bp = ...; > int c = bar(ap,bp); > > My complete lack of understanding of how inlining works suggests to me > that this would translate into > > int* ap = ...; > int* bp = ...; > int** p = ≈ > int** q = &bp; > int t = *(*p)++ + *(*q)++; > int c = t; > > which doesn't really optimise, except for the elimination of t. IANACG, but a reference parameter is pretty much like passing an alias to the original value, so I'm not sure the optimizer would need to make those intermediate p,q arguments. It can just go straight to the version below where ap and bp are substituted in directly. But either way, inlining does eliminate a function call. I believe that's mostly the point of inlining. That's orthogonal to the other sorts of optimization tricks you can do after the code is inlined. > And yet, we would /hope/ to end up with is: > > int* ap = ...; > int* bp = ...; > int c = *ap++ + *bp++; > [...] > So - can someone tell me - if a function takes lots of parameters > declared "ref", and that function is inlined, is the "ref" part > (passing the address and then dereferencing when needed) completely > eliminated, or not? Does anyone have a definitive answer? Sadly, I believe what I have heard mentioned here on the NG is that DMD does *not* currently inline *any* functions that have ref args. Which is a serious problem, since performance is one reason you would switch to ref args in the first place. (To avoid passing large structs by value.) This is heresay, though. Can anyone confirm? It really would be nice to get a "performance tips" page up somewhere describing what sorts of things DMD can and cannot inline. --bb | |||
May 19, 2008 GDC does. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote:
> Sadly, I believe what I have heard mentioned here on the NG is that DMD
> does *not* currently inline *any* functions that have ref args. Which
> is a serious problem, since performance is one reason you would switch
> to ref args in the first place. (To avoid passing large structs by value.)
>
FWIW, GDC does inline ref-arg functions.
Proof:
gentoo-pc ~ $ cat test42.d && echo "----" && gdc test42.d -o test42 -O3 -frelease && ./test42
module test42;
import std.stdio;
void test() {
void* foo; asm { mov foo, ESP; }
writefln("SP: ", foo);
}
void rtest(ref int x) { x++; test(); }
void main() {
int i = 0;
test();
rtest(i);
}
----
SP: BFC57840
SP: BFC57840
--downs
| |||
May 19, 2008 Re: GDC does. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to downs | == Quote from downs (default_357-line@yahoo.de)'s article
> Bill Baxter wrote:
> > Sadly, I believe what I have heard mentioned here on the NG is that DMD
> > does *not* currently inline *any* functions that have ref args. Which
> > is a serious problem, since performance is one reason you would switch
> > to ref args in the first place. (To avoid passing large structs by value.)
> >
> FWIW, GDC does inline ref-arg functions.
> Proof:
> gentoo-pc ~ $ cat test42.d && echo "----" && gdc test42.d -o test42 -O3 -frelease && ./test42
> module test42;
> import std.stdio;
> void test() {
> void* foo; asm { mov foo, ESP; }
> writefln("SP: ", foo);
> }
> void rtest(ref int x) { x++; test(); }
> void main() {
> int i = 0;
> test();
> rtest(i);
> }
> ----
> SP: BFC57840
> SP: BFC57840
It apparently inlines functions containing asm blocks as well. Score two points for GDC.
Sean
| |||
May 21, 2008 Re: GDC does. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote:
> == Quote from downs (default_357-line@yahoo.de)'s article
>> FWIW, GDC does inline ref-arg functions.
>> Proof:
>> gentoo-pc ~ $ cat test42.d && echo "----" && gdc test42.d -o test42 -O3 -frelease && ./test42
>> module test42;
>> import std.stdio;
>> void test() {
>> void* foo; asm { mov foo, ESP; }
>> writefln("SP: ", foo);
>> }
>> void rtest(ref int x) { x++; test(); }
>> void main() {
>> int i = 0;
>> test();
>> rtest(i);
>> }
>> ----
>> SP: BFC57840
>> SP: BFC57840
>
> It apparently inlines functions containing asm blocks as well. Score
> two points for GDC.
Not necessarily. Inlining just 'rtest' will produce the same ESP value for both invocations of 'test' as well, even though it's not inlined. (since both invocations of test() have the same stack frame size they get decremented equally from the same base value).
To really test that, you'd need to also manually inline test() into main and compare against the other two results. I just tried this, and it seems test() is indeed NOT inlined (at least, on x86-64 with Ubuntu's GDC).
I seem to remember gcc's extended asm syntax being claimed to be more inlining-friendly. GDC is supposed to support it, so you could try that.
| |||
May 21, 2008 Re: GDC does. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Frits van Bommel | Frits van Bommel wrote: > Sean Kelly wrote: >> == Quote from downs (default_357-line@yahoo.de)'s article >>> FWIW, GDC does inline ref-arg functions. >>> Proof: >>> gentoo-pc ~ $ cat test42.d && echo "----" && gdc test42.d -o test42 -O3 -frelease && ./test42 >>> module test42; >>> import std.stdio; >>> void test() { >>> void* foo; asm { mov foo, ESP; } >>> writefln("SP: ", foo); >>> } >>> void rtest(ref int x) { x++; test(); } >>> void main() { >>> int i = 0; >>> test(); >>> rtest(i); >>> } >>> ---- >>> SP: BFC57840 >>> SP: BFC57840 >> >> It apparently inlines functions containing asm blocks as well. Score >> two points for GDC. > > Not necessarily. Inlining just 'rtest' will produce the same ESP value for both invocations of 'test' as well, even though it's not inlined. (since both invocations of test() have the same stack frame size they get decremented equally from the same base value). > To really test that, you'd need to also manually inline test() into main and compare against the other two results. I just tried this, and it seems test() is indeed NOT inlined (at least, on x86-64 with Ubuntu's GDC). Oops, you're right. > I seem to remember gcc's extended asm syntax being claimed to be more inlining-friendly. GDC is supposed to support it, so you could try that. Yes, I remember the same thing. I had thought that perhaps GDC converted the asm code under the covers before GCCs inlining took place, but perhaps not. Sean | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply