March 14, 2014
On 2014-03-14 17:57:59 +0000, Jacob Carlborg <doob@me.com> said:

>> int output = mixin func(10); // the 'mixin' keyword seems to kinda 'get
> 
> I think this is the best syntax of these three alternatives.

Maybe, but what does it do? Should it just inline the call to func? Or should it inline recursively every call inside func? Or maybe something in the middle?

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

March 14, 2014
On 3/13/14, 11:21 PM, Manu wrote:
> My feeling is that an ideal solution would be something like an
> enhancement which would allow the 'mixin' keyword to be used with
> regular function calls.
> What this would do is 'mix in' the function call at this location, ie,
> effectively inline that particular call, and it leverages a keyword and
> concept that we already have. It would obviously produce a compile error
> of the code is not available.
>
> I quite like this idea, but there is a potential syntactical problem;
> how to assign the return value?
>
> int func(int y) { return y*y+10; }
>
> int output = mixin func(10); // the 'mixin' keyword seems to kinda 'get
> in the way' if the output
> int output = mixin(func(10)); // now i feel paren spammy...
> mixin(int output = func(10)); // this doesn't feel right...
>
> My feeling is the first is the best, but I'm not sure about that
> grammatically.

Is there already some trait for getting the string value of a function including its code? If so then a mixin plus a small helper function might do the job. If not then is such a trait feasible?
March 14, 2014
Am 14.03.2014 19:09, schrieb David Gileadi:
> On 3/13/14, 11:21 PM, Manu wrote:
>> My feeling is that an ideal solution would be something like an
>> enhancement which would allow the 'mixin' keyword to be used with
>> regular function calls.
>> What this would do is 'mix in' the function call at this location, ie,
>> effectively inline that particular call, and it leverages a keyword and
>> concept that we already have. It would obviously produce a compile error
>> of the code is not available.
>>
>> I quite like this idea, but there is a potential syntactical problem;
>> how to assign the return value?
>>
>> int func(int y) { return y*y+10; }
>>
>> int output = mixin func(10); // the 'mixin' keyword seems to kinda 'get
>> in the way' if the output
>> int output = mixin(func(10)); // now i feel paren spammy...
>> mixin(int output = func(10)); // this doesn't feel right...
>>
>> My feeling is the first is the best, but I'm not sure about that
>> grammatically.
>
> Is there already some trait for getting the string value of a function
> including its code? If so then a mixin plus a small helper function
> might do the job. If not then is such a trait feasible?

Might be problematic with modules delivered only in .di + binary form.

--
Paulo
March 14, 2014
On 3/14/14, 1:42 PM, Paulo Pinto wrote:
> Am 14.03.2014 19:09, schrieb David Gileadi:
>> On 3/13/14, 11:21 PM, Manu wrote:
>>> My feeling is that an ideal solution would be something like an
>>> enhancement which would allow the 'mixin' keyword to be used with
>>> regular function calls.
>>> What this would do is 'mix in' the function call at this location, ie,
>>> effectively inline that particular call, and it leverages a keyword and
>>> concept that we already have. It would obviously produce a compile error
>>> of the code is not available.
>>>
>>> I quite like this idea, but there is a potential syntactical problem;
>>> how to assign the return value?
>>>
>>> int func(int y) { return y*y+10; }
>>>
>>> int output = mixin func(10); // the 'mixin' keyword seems to kinda 'get
>>> in the way' if the output
>>> int output = mixin(func(10)); // now i feel paren spammy...
>>> mixin(int output = func(10)); // this doesn't feel right...
>>>
>>> My feeling is the first is the best, but I'm not sure about that
>>> grammatically.
>>
>> Is there already some trait for getting the string value of a function
>> including its code? If so then a mixin plus a small helper function
>> might do the job. If not then is such a trait feasible?
>
> Might be problematic with modules delivered only in .di + binary form.
>
> --
> Paulo

Quite, but as Manu says about his proposed solution,

> It would obviously produce a compile error
> of (sic) the code is not available.

This would need to behave similarly.
March 14, 2014
On 2014-03-14 19:02, Michel Fortin wrote:

> Maybe, but what does it do? Should it just inline the call to func? Or
> should it inline recursively every call inside func? Or maybe something
> in the middle?

I guess Manu needs to answer this one.

-- 
/Jacob Carlborg
March 14, 2014
On 3/14/2014 8:37 AM, Manu wrote:
> On 14 March 2014 22:02, John Colvin <john.loughran.colvin@gmail.com> wrote:
>>
>> I don't know how good compilers are at taking this sort of thing into
>> account already.
>>
>
> I don't know if they try or not, but I can say from experience that results
> are generally unreliable.
> I would never depend on the inliner to get this right.
>

I don't know how this compares to other inliners, but FWIW, DMD's inliner is pretty simple (By coincidence, I was just digging into it the other day):

Every expression node (ie non-statement, non-declaration) in the function's AST adds 1 to the cost of inlining (so ex: 1+2*3 would have a cost of 2 - one mult, plus one addition). If the total cost is under 250, the function is inlined.

Also, any type of AST node that isn't explicitly handled in inline.c will prevent a function from ever being inlined (since the ijnliner doesn't know how to inline it). I assume this is probably after lowerings are done, though, so more advanced constructs probably don't need to be explicitly handled.

There is one other minor difficulty worth noting: When DMD wants to inline a function call, and the function's return value is actually used (ex: "auto x = foo();" or "1 + foo()"), the function must get inlined as an expression. Unfortunately, AIUI, a lot of D's statements can't be implemented inside an expression ATM (such as loops), so these would currently prevent such a function call from being inlined.

I don't know how easy or difficult that would be to fix. Conceptually it should be simple: Create an Expression type StatementExp to wrap a Statement as an expression. But other parts of the backend would probably need to know about it, and I'm unfamiliar with the rest of the backend, so have no idea what that would/wouldn't entail.

Not that it can't be done (AFAIK), but since the subject came up I thought I'd give a brief overview of the current DMD inliner, just FWIW.

March 14, 2014
On Friday, 14 March 2014 at 22:12:38 UTC, Nick Sabalausky wrote:
> On 3/14/2014 8:37 AM, Manu wrote:
>> On 14 March 2014 22:02, John Colvin <john.loughran.colvin@gmail.com> wrote:
>>>
>>> I don't know how good compilers are at taking this sort of thing into
>>> account already.
>>>
>>
>> I don't know if they try or not, but I can say from experience that results
>> are generally unreliable.
>> I would never depend on the inliner to get this right.
>>
>
> I don't know how this compares to other inliners, but FWIW, DMD's inliner is pretty simple (By coincidence, I was just digging into it the other day):
>
> Every expression node (ie non-statement, non-declaration) in the function's AST adds 1 to the cost of inlining (so ex: 1+2*3 would have a cost of 2 - one mult, plus one addition). If the total cost is under 250, the function is inlined.
>
> Also, any type of AST node that isn't explicitly handled in inline.c will prevent a function from ever being inlined (since the ijnliner doesn't know how to inline it). I assume this is probably after lowerings are done, though, so more advanced constructs probably don't need to be explicitly handled.
>
> There is one other minor difficulty worth noting: When DMD wants to inline a function call, and the function's return value is actually used (ex: "auto x = foo();" or "1 + foo()"), the function must get inlined as an expression. Unfortunately, AIUI, a lot of D's statements can't be implemented inside an expression ATM (such as loops), so these would currently prevent such a function call from being inlined.
>
> I don't know how easy or difficult that would be to fix. Conceptually it should be simple: Create an Expression type StatementExp to wrap a Statement as an expression. But other parts of the backend would probably need to know about it, and I'm unfamiliar with the rest of the backend, so have no idea what that would/wouldn't entail.
>
> Not that it can't be done (AFAIK), but since the subject came up I thought I'd give a brief overview of the current DMD inliner, just FWIW.

Probably one easy adjustment that would result in a lot of gain in optimization would be to bump the lower bound of 250 if the function is an operator overload.
March 15, 2014
On 15 March 2014 03:57, Jacob Carlborg <doob@me.com> wrote:

> On 2014-03-14 07:21, Manu wrote:
>
>> So, I'm constantly running into issues with not having control over
>> inline.
>> I've run into it again doing experiments in preparation for my dconf
>> talk...
>>
>> I have identified 2 cases which come up regularly:
>>   1. A function that should always be inline unconditionally (std.simd
>> is effectively blocked on this)
>>   2. A particular invocation of a function should be inlined for this
>> call only
>>
>> The first case it just about having control over code gen. Some functions should effectively be macros or pseudo-intrinsics (ie, intrinsic wrappers in std.simd, beauty wrappers around asm code, etc), and I don't ever want to see a symbol appear in the binary.
>>
>> My suggestion is introduction of __forceinline or something like it. We need this.
>>
>
> Haven't we already agreed a pragma for force inline should be implemented. Or is that something I have dreamed?


It's been discussed. I never agreed to it (I _really_ don't like it), but I'll take it if it's the best I'm gonna get.

I don't like stateful attributes like that. I think it's error prone,
especially when it's silent.
'private:' for instance will complain if you write a new function in an
area influenced by the private state and try and call it from elsewhere;
ie, you know you made the mistake.
If you write a new function in an area influenced by the forceinline state
which wasn't intended to be inlined, you won't know. I think that's
dangerous.

 The second case is interesting, and I've found it comes up a few times
>> on different occasions.
>> In my current instance, I'm trying to build generic framework to perform
>> efficient composable data processing, and a basic requirement is that
>> the components are inlined, such that the optimiser can interleave the
>> work properly.
>>
>> Let's imagine I have a template which implements a work loop, which
>> wants to call a bunch of work elements it receives by alias. The issue
>> is, each of those must be inlined, for this call instance only, and
>> there's no way to do this.
>> I'm gonna draw the line at stringified code to use with mixin; I hate
>> that, and I don't want to encourage use of mixin or stringified code in
>> user-facing API's as a matter of practise. Also, some of these work
>> elements might be useful functions in their own right, which means they
>> can indeed be a function existing somewhere else that shouldn't itself
>> be attributed as __forceinline.
>>
>> What are the current options to force that some code is inlined?
>>
>> My feeling is that an ideal solution would be something like an
>> enhancement which would allow the 'mixin' keyword to be used with
>> regular function calls.
>> What this would do is 'mix in' the function call at this location, ie,
>> effectively inline that particular call, and it leverages a keyword and
>> concept that we already have. It would obviously produce a compile error
>> of the code is not available.
>>
>> I quite like this idea, but there is a potential syntactical problem; how to assign the return value?
>>
>> int func(int y) { return y*y+10; }
>>
>> int output = mixin func(10); // the 'mixin' keyword seems to kinda 'get
>>
>
> I think this is the best syntax of these three alternatives.
>
>
>  in the way' if the output
>> int output = mixin(func(10)); // now i feel paren spammy...
>>
>
> This syntax can't work. It's already interpreted calling "func" and use the result as a string mixin.
>
>
>  mixin(int output = func(10)); // this doesn't feel right...
>>
>
> No.
>
>
>  My feeling is the first is the best, but I'm not sure about that
>> grammatically.
>>
>
> Yeah, I agree.


So you think it's grammatically okay?

 The other thing that comes to mind is that it seems like this might make
>> a case for AST macros... but I think that's probably overkill for this situation, and I'm not confident we're ever gonna attempt to crack that nut. I'd like to see something practical and unobjectionable preferably.
>>
>
> AST macros would solve it. It could solve the first use case as well. I would not implement AST macros just to support force inline but we have many other uses cases as well. I would have implement AST macros a long time ago. Hopefully this would avoid the need to create new language features in some cases.
>
> First use case, just define a macro that returns the AST for the content of the function you would create.
>
> macro func (Ast!(int) a)
> {
>     return <[ $a * $a; ]>;
> }
>
> int output = func(10); // always inlined
>
> Second use case, define a macro, "inline", that takes the function you want to call as a parameter. The macro will basically inline the body.
>
> macro inline (T, U...) (Ast!(T function (U) func)
> {
>     // this would probably be more complicated
>     return func.body;
> }
>
> int output = func(10); // not inlined
> int output = inline(func(10)); // always inlined
>
>
>  This problem is fairly far reaching; phobos receives a lot of lambdas
>> these days, which I've found don't reliably inline and interfere with the optimisers ability to optimise the code.
>>
>
> I thought since lambdas are passed as template parameters they would always be inlined.


Maybe... (and not in debug builds). Without explicit control of the
inliner, you just never know.


March 15, 2014
On 15 March 2014 04:02, Michel Fortin <michel.fortin@michelf.ca> wrote:

> On 2014-03-14 17:57:59 +0000, Jacob Carlborg <doob@me.com> said:
>
>  int output = mixin func(10); // the 'mixin' keyword seems to kinda 'get
>>>
>>
>> I think this is the best syntax of these three alternatives.
>>
>
> Maybe, but what does it do? Should it just inline the call to func? Or should it inline recursively every call inside func? Or maybe something in the middle?


I'd say it should inline only func. Any sub-calls are subject to the regular inline heuristics.


March 15, 2014
"Manu" <turkeyman@gmail.com> wrote in message news:mailman.128.1394856947.23258.digitalmars-d@puremagic.com...

> > Haven't we already agreed a pragma for force inline should be implemented. Or is
> > that something I have dreamed?
>
> It's been discussed. I never agreed to it (I _really_ don't like it), but I'll take it if it's the best
> I'm gonna get.
>
> I don't like stateful attributes like that. I think it's error prone, especially when it's silent.
> 'private:' for instance will complain if you write a new function in an area influenced by the
> private state and try and call it from elsewhere; ie, you know you made the mistake.
> If you write a new function in an area influenced by the forceinline state which wasn't intended
> to be inlined, you won't know. I think that's dangerous.

Huh?  The pragma could easily be restricted to apply to exactly one function declaration, if that's what's desired.