## digitalmars.D - How does inlining work for ref parameters?

• Janice Caron (55/55) May 17 2008 I get how inlining works for non-ref parameters. If I do
• Bill Baxter (16/75) May 17 2008 IANACG, but a reference parameter is pretty much like passing an alias
• downs (20/25) May 19 2008 FWIW, GDC does inline ref-arg functions.
• Sean Kelly (4/28) May 19 2008 It apparently inlines functions containing asm blocks as well. Score
• Frits van Bommel (10/32) May 21 2008 Not necessarily. Inlining just 'rtest' will produce the same ESP value
• Sean Kelly (6/40) May 21 2008 Yes, I remember the same thing. I had thought that perhaps GDC
```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 = &ap;
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
Bill Baxter <dnewsgroup billbaxter.com> writes:
```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 = &ap;
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 17 2008
downs <default_357-line yahoo.de> writes:
```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
Sean Kelly <sean invisibleduck.org> writes:
```== 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 19 2008
Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
```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
Sean Kelly <sean invisibleduck.org> writes:
```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
```
May 21 2008