February 11, 2013
On Monday, 11 February 2013 at 12:16:14 UTC, Namespace wrote:
> I see. Nice idea. But what is the criterion for the compiler to pass 'a' by ref?
> I'm still therefor, to mark such paramters with '&' or something but that's maybe my C++ background.
> I'm curious to see if Walter or Andrei say something to the idea.

A good rule of thumb to know when to pass by ref for perf is :
 - The struct is big, or contains mixed entities (floats and ints). 2*size_t seems like a good heuristic from my experience.
 - The struct have a postblit.

The compiler doing it is superior to the user marking everything :
 - The user may forget, getting slow down for nothing.
 - The user can get it wrong the other way around (pass by ref when it isn't appropriate).
 - This is really hard to get right in generic code.
 - This is relatively easy to automate.

The obvious drawback is possible code bloat, but that isn't that bad (and can be used as heuristic by the compiler to decide if it should pass by ref or not).
February 11, 2013
On Monday, 11 February 2013 at 14:54:48 UTC, kinke wrote:
> I'd propose a small change so that suited structs are passed transparently byref only if the parameter is not mutable, e.g., for a function foo(const BigStruct s). The compiler would therefore not need to analyze the code flow in the callee to determine if the parameter is modified and hence a copy is needed.
>

That is overly restrictive. See sample code given in this thread, foo couldn't get the struct by ref in such a case if A contains any indirection.
February 11, 2013
On Monday, 11 February 2013 at 15:12:07 UTC, deadalnix wrote:
> On Monday, 11 February 2013 at 14:54:48 UTC, kinke wrote:
>> I'd propose a small change so that suited structs are passed transparently byref only if the parameter is not mutable, e.g., for a function foo(const BigStruct s). The compiler would therefore not need to analyze the code flow in the callee to determine if the parameter is modified and hence a copy is needed.
>
> That is overly restrictive. See sample code given in this thread, foo couldn't get the struct by ref in such a case if A contains any indirection.

Not sure what you mean by A containing any indirections, but I'd simply rewrite your example as follows:

void foo(const A a) { // byref passing desirable
    bar(a); // bar's parameter is mutable => pass a copy (byval)
}

void bar(A a) { // byval passing
    a.member = 5;
}
February 11, 2013
On 2013-02-11 06:52:28 +0000, "deadalnix" <deadalnix@gmail.com> said:

> When a function accept a struct, the compiler is free to use that function, or an altered one taking a reference as parameter.

When designing the ABI, you can either create the copy on the caller's side, or the callee's side. If I'm understanding well, you want to have two versions of each function, one copying on the caller's side, one copying on the callee's side, and the caller's codegen would choose which one to use. Copying on the caller's side is better if you're passing rvalues (because the caller can just always skip the copying), while copying on the callee's side is better when you're passing lvalues, because the caller may decide to skip copying if it doesn't need a copy.

I'm not sure creating two versions of each function will fly well with Walter. Actually, you say *two* are needed, but that's for a function with one struct parameter; it's more 2^(number of structs parameters) versions you'd need in the general case.


-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/

February 11, 2013
> A good rule of thumb to know when to pass by ref for perf is :
>  - The struct is big, or contains mixed entities (floats and ints). 2*size_t seems like a good heuristic from my experience.
>  - The struct have a postblit.
>
> The compiler doing it is superior to the user marking everything :
>  - The user may forget, getting slow down for nothing.
>  - The user can get it wrong the other way around (pass by ref when it isn't appropriate).
>  - This is really hard to get right in generic code.
>  - This is relatively easy to automate.

I thought of something like this:

void foo(A& a) { // the compiler choose if A should pass by ref or by value.

}

void bar(A a) { // normal behaviour.

}

That is identical with 'inline' in C++. You _can_ declare a function as inline, but finally the compiler choose if he really inline the function or not.
February 11, 2013
> I'm not sure creating two versions of each function will fly well with Walter. Actually, you say *two* are needed, but that's for a function with one struct parameter; it's more 2^(number of structs parameters) versions you'd need in the general case.

That's how 'auto ref' currently works. But I do not think that code bloat was the intention of deadalnix. Quite the contrary.
February 11, 2013
On Monday, 11 February 2013 at 15:48:32 UTC, Michel Fortin wrote:
> On 2013-02-11 06:52:28 +0000, "deadalnix" <deadalnix@gmail.com> said:
>
>> When a function accept a struct, the compiler is free to use that function, or an altered one taking a reference as parameter.
>
> When designing the ABI, you can either create the copy on the caller's side, or the callee's side. If I'm understanding well, you want to have two versions of each function, one copying on the caller's side, one copying on the callee's side,

That is blatantly wrong.

You don't have, the compiler is allowed to, and the copy on callee side isn't mandatory.
February 11, 2013
On Monday, 11 February 2013 at 16:27:29 UTC, Namespace wrote:
> That is identical with 'inline' in C++. You _can_ declare a function as inline, but finally the compiler choose if he really inline the function or not.

Compiler now inline even when inline isn't present, and don't inline when inline is present but this don't make sense.

In other terms, inline is the perfect example of why defining stuff like that explicitly make no sense.
February 11, 2013
On Mon, 11 Feb 2013 10:08:52 -0500, deadalnix <deadalnix@gmail.com> wrote:

> A good rule of thumb to know when to pass by ref for perf is :
>   - The struct is big, or contains mixed entities (floats and ints). 2*size_t seems like a good heuristic from my experience.

Array slices are 2*sizeof(size_t).  I would expect them to be always copied and not ref'd.

-Steve
February 11, 2013
On Monday, 11 February 2013 at 16:51:22 UTC, Steven Schveighoffer wrote:
> On Mon, 11 Feb 2013 10:08:52 -0500, deadalnix <deadalnix@gmail.com> wrote:
>
>> A good rule of thumb to know when to pass by ref for perf is :
>>  - The struct is big, or contains mixed entities (floats and ints). 2*size_t seems like a good heuristic from my experience.
>
> Array slices are 2*sizeof(size_t).  I would expect them to be always copied and not ref'd.
>

First, they alway appears to be copied from the dev perspective. That why I put bunch of restrictions in the proposal.

Second, slice are 2*size_t and are not mixed entities (from CPU perspective, pointer are integers). So I don't have numbers, but I expect slice to be faster when passed by copy than when passed by ref.