www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Testing Return Value Optimization (RVO)

reply chmike <christophe meessen.net> writes:
Hello,

Sorry if this question is a bit naive or shows a misunderstanding 
of RVO.
I was trying to see if my C compiler was doing RVO with struct, 
but after testing it at is apparently not the case.

Since I have heard that D supports RVO I wanted to give it a try 
in D. But apparently it doesn't do RVO as I expected it would do 
it.

Here is the D code. It is very similar to the C code I tested 
with gcc and clang :
---
#!/usr/bin/rdmd -O

import std.stdio;

struct S { int a, b; };

S foo(S* p) {
     S v = {1, 2};
     writeln("foo: return value optimization: ", p == &v);
     return v;
}

void main()
{
     S x;
     x = foo(&x);
}
---

My assumption is the following. x is the target variable where to 
store the result of foo. I expected that with RVO foo() would 
receive the address where to store its result as hidden argument.

Inside foo(), the optimizer would detect that v, its returned 
value, will be stored at the location given as hidden argument. 
It may then optimize out v so that foo() uses x as storage for v.

My code is testing if this is the case and it is apparently not.

Can someone please explain me why this doesn't work as I would 
expect RVO to work ?
Sep 27 2015
parent reply Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Sunday, 27 September 2015 at 13:55:02 UTC, chmike wrote:
 Can someone please explain me why this doesn't work as I would 
 expect RVO to work ?
I'm not an expert on the subject so this may contain some inaccuracies, but the gist of it is: As the name implies, NRVO is an optimization and therefore generally not guaranteed. The compiler is free to use NRVO or not, as it sees fit. In D there is one case where NRVO is required for correct semantics and therefore guaranteed: returning a struct with disabled postblit. For example: import std.stdio; struct S { int i; disable this(this); } S foo() { S rv; writeln(&rv); return rv; } void main() { auto s = foo(); writeln(&s); } This will print the same address twice even without optimizations. If the postblit isn't disabled the compiler will not use NRVO for returning S in this case. Which makes sense, because S is only four bytes, so writing through a pointer will actually be slower. On the other hand if S is large enough, the compiler will switch to using NRVO when possible: struct S { int[16] i; // I just used some large value, didn't test the threshold } S foo() { S rv; writeln(&rv); return rv; } void main() { auto s = foo(); writeln(&s); }
Sep 27 2015
parent reply chmike <christophe meessen.net> writes:
I tried your code as this and it doesn't work.

#!/usr/bin/rdmd -O

import std.stdio;

struct S {
     int a;
      disable this(this);
};

S foo() {
     S v;
     v.a = 1;
     writeln(&v);
     return v;
}


void main()
{
     S x;
     x = foo();
     writeln(&x);
}

I even tried with dmd -O without success.

What am I doing wrong ?
Sep 28 2015
parent chmike <christophe meessen.net> writes:
Oops found it my self.

I had to use

auto x = foo();
Sep 28 2015