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.