December 30, 2011
On 12/30/2011 04:13 AM, Walter Bright wrote:
> On 12/30/2011 12:16 AM, Vladimir Panteleev wrote:
>> I agree, but this wasn't as much about heuristics, but compiler
>> capabilities
>> (e.g. inlining assembler functions).
> 
> Adding a keyword won't fix the current problem that the compiler won't inline inline assembler functions. It's an orthogonal issue.
> 
> I know there are features on various C compilers to force inlining, I know there's a demand for them.
> 
> But I've also, over the years, spent thousands and thousands of hours optimizing the hell out of things, so I have some experience with it.
> 
> Once the compiler gets past a certain level of heuristic inlining decisions, forcing it to inline more is just chasing rainbows.
> 

When a compiler ISN'T past a certain level of heuristic inlining, then being able to tell it to inline can save one's ass.

I hit this when writing a flash game.  It was doing the slide-show thing while on a collision detection broadphase (IIRC) when it went to sort everything.  The language I was using, haXe, was pretty young at the time and the compiler probably wasn't inlining well.  BUT, it did have an inline keyword.  I plopped it down in a few select places and BAM,the broadphase is ~100x faster and life goes on.  Things were going to get really damn ugly if I couldn't do that.  (haXe is a pretty cool language, just not as featureful as D.)

Nonetheless, this is the less important issue...

> And if one really wants to force an inline, one can do things like the C memcpy using the preprocessor, or string mixins in D, or even cut&paste. If you need to do that in more than a couple places in the code, something else is wrong (that old saw about only a tiny percentage of the code being a bottleneck is true).
> 
> Also, if you are tweaking at such a level, every compiler is different enough that your tweaks are likely to be counterproductive on another compiler. Having a portable syntax for such tweaking is not going to help.

This is striking me as becoming a human factors problem.  People want a way to tell the compiler to inline things.  They are /going/ to get that, one way or another.  It /will/ happen, regardless of how experienced /you/ are.  They also may not go about it in entirely reasonable ways, and then you end up with code optimized for one compiler that doesn't compile at all on another.  This sucks really bad for people compiling a program that they didn't write.

And to me, that's what I worry about most.

...

As an aside, I think that people want forced inlining because it gives them another tool to tweak with.  My experiences with optimization tend to suggest I can usually optimize things really well with a few short cycles of profile->experiment->profile.  I don't think I've ever really /needed/ to dive into assembly yet.  My ventures into the assembler have been either purely recreational or academic in nature.  Now, something like an inline feature can help a lot with the "experiment" part of the cycle.  It's just another knob to twist and see if it gives the result you want.  Portability be damned, if it gets the thing out the door, I'm using it!  But, I kind of hate that attitude.  So it's much more comforting to be able to twist that knob without sacrificing portability too.  I wouldn't expect it to run as fast on other compilers; I /would/ expect it to compile and run correctly on other compilers.  And if enregistering variables is more important, then we might want to have a way to enregister variables too.
December 30, 2011
On 12/30/2011 7:06 AM, so wrote:
> I agree @inline (which will probably be an extension) in D should mean
> force-inline.
> Ignoring the impossible-to-inline cases (which in time should get better),
> adding @inline is a few minutes of editing.
> It will just bypass the cost function and if it is not possible to inline, pop
> error.


Sure, but I think you'll be very disappointed in that it isn't going to deliver the goods.
December 30, 2011
On 12/30/2011 10:31 AM, Chad J wrote:
> As an aside, I think that people want forced inlining because it gives
> them another tool to tweak with.  My experiences with optimization tend
> to suggest I can usually optimize things really well with a few short
> cycles of profile->experiment->profile.  I don't think I've ever really
> /needed/ to dive into assembly yet.  My ventures into the assembler have
> been either purely recreational or academic in nature.  Now, something
> like an inline feature can help a lot with the "experiment" part of the
> cycle.  It's just another knob to twist and see if it gives the result
> you want.  Portability be damned, if it gets the thing out the door, I'm
> using it!  But, I kind of hate that attitude.  So it's much more
> comforting to be able to twist that knob without sacrificing portability
> too.  I wouldn't expect it to run as fast on other compilers; I /would/
> expect it to compile and run correctly on other compilers.  And if
> enregistering variables is more important, then we might want to have a
> way to enregister variables too.

Back in the olden days, I provided a detailed list of optimizer switches that turned on/off all sorts of optimizations. In the end it turned out that all people wanted was an "optimize" switch which is why dmd has only -O.

The reason dmd has a -inline switch is because it's hard to debug code that has been inlined.

The reason C's "register" keyword went away was because:

1. the variables after optimization transformations may be very different than before

2. programmers stunk at picking the right variables for registers

3. even if (2) was done right, as soon as the first code maintainer dinked with it, they never bothered to go fix the register declarations

4. optimizers got pretty good at automatic register allocation

5. there's nothing portable about enregistering, even with a portable syntax

6. the register keyword offered no way to hint which variables were more important to enregister than others
December 30, 2011
On 12/30/2011 02:00 PM, Walter Bright wrote:
> On 12/30/2011 10:31 AM, Chad J wrote:
>> As an aside, I think that people want forced inlining because it gives them another tool to tweak with.  My experiences with optimization tend to suggest I can usually optimize things really well with a few short cycles of profile->experiment->profile.  I don't think I've ever really /needed/ to dive into assembly yet.  My ventures into the assembler have been either purely recreational or academic in nature.  Now, something like an inline feature can help a lot with the "experiment" part of the cycle.  It's just another knob to twist and see if it gives the result you want.  Portability be damned, if it gets the thing out the door, I'm using it!  But, I kind of hate that attitude.  So it's much more comforting to be able to twist that knob without sacrificing portability too.  I wouldn't expect it to run as fast on other compilers; I /would/ expect it to compile and run correctly on other compilers.  And if enregistering variables is more important, then we might want to have a way to enregister variables too.
> 
> Back in the olden days, I provided a detailed list of optimizer switches that turned on/off all sorts of optimizations. In the end it turned out that all people wanted was an "optimize" switch which is why dmd has only -O.
> 
> The reason dmd has a -inline switch is because it's hard to debug code that has been inlined.
> 
> The reason C's "register" keyword went away was because:
> 
> 1. the variables after optimization transformations may be very different than before
> 
> 2. programmers stunk at picking the right variables for registers
> 
> 3. even if (2) was done right, as soon as the first code maintainer dinked with it, they never bothered to go fix the register declarations
> 
> 4. optimizers got pretty good at automatic register allocation
> 
> 5. there's nothing portable about enregistering, even with a portable syntax
> 
> 6. the register keyword offered no way to hint which variables were more important to enregister than others

Huh, bummer dudes.

6 seems pretty solvable.  Too bad about the other 5.  ;)
December 30, 2011
On 12/30/2011 01:48 PM, Walter Bright wrote:
> On 12/30/2011 7:06 AM, so wrote:
>> I agree @inline (which will probably be an extension) in D should mean
>> force-inline.
>> Ignoring the impossible-to-inline cases (which in time should get
>> better),
>> adding @inline is a few minutes of editing.
>> It will just bypass the cost function and if it is not possible to
>> inline, pop
>> error.
> 
> 
> Sure, but I think you'll be very disappointed in that it isn't going to deliver the goods.

Cool.  Put it in and let people use it and get disappointed.  Then maybe they will blame themselves instead of DMD.  ????.  Profit.
December 30, 2011
On 12/30/11 12:10 PM, Walter Bright wrote:
> On 12/30/2011 4:05 AM, Timon Gehr wrote:
>> It certainly does. That is how all my code generation looks like. The
>> fact that
>> I am using string mixins to solve some problems shows that those are not
>> 'problems in D string mixins'.
>
> I your solution to parameterized strings is very nice. Can you write a
> brief article about it? This should be more widely known.

The idea is good, but nonhygienic: the macro's expansion picks up symbols from the expansion context.

Timon, to move from good to great, you may want to add parameters to the expansion process such that you replace the argument values during expansion.


Andrei
December 30, 2011
On 12/30/2011 07:10 PM, Walter Bright wrote:
> On 12/30/2011 4:05 AM, Timon Gehr wrote:
>> It certainly does. That is how all my code generation looks like. The
>> fact that
>> I am using string mixins to solve some problems shows that those are not
>> 'problems in D string mixins'.
>
> I your solution to parameterized strings is very nice. Can you write a
> brief article about it? This should be more widely known.

Ok.
December 30, 2011
On 12/30/2011 09:51 PM, Andrei Alexandrescu wrote:
> On 12/30/11 12:10 PM, Walter Bright wrote:
>> On 12/30/2011 4:05 AM, Timon Gehr wrote:
>>> It certainly does. That is how all my code generation looks like. The
>>> fact that
>>> I am using string mixins to solve some problems shows that those are not
>>> 'problems in D string mixins'.
>>
>> I your solution to parameterized strings is very nice. Can you write a
>> brief article about it? This should be more widely known.
>
> The idea is good, but nonhygienic: the macro's expansion picks up
> symbols from the expansion context.
>

What the template 'X' currently achieves is an improvement in syntax:

string generated = "foo!\""~x~"\"(\""~bar(y)~"\")";

vs

string generated = mixin(X!q{
   foo!"@(x)"("@(bar(y))")
});

i.e. it is assumed that the generated code that results in a string expression will be mixed in right away. Kenji Hara's string mixin template proposal could be pulled to be able to enforce this at the same time as improving the syntax further:

mixin template X(string s){enum X = XImpl(s);}

string generated = X!q{
    foo!"@(x)"("@(bar(y))")
}



> Timon, to move from good to great, you may want to add parameters to the
> expansion process such that you replace the argument values during
> expansion.
>


I like this:

string QUX(string param1, string op, string param2){
    return mixin(X!q{
        @("__"~param1) @(op) @(param2~"__");
    };
}

a lot more than this:

string QUX(string param1, string op, string param2){
    return mixin(X!(q{
        @1 @2 @3
    },"__"~param1, op, param2~"__"));
}

In an ideal world, I think the macro could be defined like this (using the new anonymous function syntax on a named function):

string QUX(string param1, string op, string param2) => X!q{
    @("__"~param1) @(op) @(param2~"__");
};

and expanded like this:

mixin(QUX("foo","+","bar"));


I think what you have in mind is that macros are defined similar to this:

enum QUX = q{@("__"~#1) @2 @(#3~"__")};

And then would be expanded like this

mixin(X!(QUX, "foo", "+", "bar"));


Is this better? I think it makes it more difficult to write and use such a macro, because there are no parameter names to document what the parameters are for.







December 30, 2011
On 12/30/11 3:51 PM, Timon Gehr wrote:
> On 12/30/2011 09:51 PM, Andrei Alexandrescu wrote:
>> On 12/30/11 12:10 PM, Walter Bright wrote:
>>> On 12/30/2011 4:05 AM, Timon Gehr wrote:
>>>> It certainly does. That is how all my code generation looks like. The
>>>> fact that
>>>> I am using string mixins to solve some problems shows that those are
>>>> not
>>>> 'problems in D string mixins'.
>>>
>>> I your solution to parameterized strings is very nice. Can you write a
>>> brief article about it? This should be more widely known.
>>
>> The idea is good, but nonhygienic: the macro's expansion picks up
>> symbols from the expansion context.
>>
>
> What the template 'X' currently achieves is an improvement in syntax:
>
> string generated = "foo!\""~x~"\"(\""~bar(y)~"\")";
>
> vs
>
> string generated = mixin(X!q{
> foo!"@(x)"("@(bar(y))")
> });

I understand that. But the whole system must be redesigned. Quoting from my email (please let's continue here so as to avoid duplication):

The macro facility should be very simple: any compile-time string can be a macro "body".

The key is the expansion facility, which replaces parameter placeholders (e.g. in the simplest instance $1, $2 etc) with actual parameters. This is missing. Also, there must be expansion of other already-defined macro names. This is already present.

The library has a simple interface:

enum myMacro = q{... $1 $2 $(anotherMacro($1))... };

// To mixin
mixin(expand(myMacro, "argument one", "argument two"));


Andrei


December 30, 2011
On 12/31/2011 12:02 AM, Andrei Alexandrescu wrote:
> On 12/30/11 3:51 PM, Timon Gehr wrote:
>> On 12/30/2011 09:51 PM, Andrei Alexandrescu wrote:
>>> On 12/30/11 12:10 PM, Walter Bright wrote:
>>>> On 12/30/2011 4:05 AM, Timon Gehr wrote:
>>>>> It certainly does. That is how all my code generation looks like. The
>>>>> fact that
>>>>> I am using string mixins to solve some problems shows that those are
>>>>> not
>>>>> 'problems in D string mixins'.
>>>>
>>>> I your solution to parameterized strings is very nice. Can you write a
>>>> brief article about it? This should be more widely known.
>>>
>>> The idea is good, but nonhygienic: the macro's expansion picks up
>>> symbols from the expansion context.
>>>
>>
>> What the template 'X' currently achieves is an improvement in syntax:
>>
>> string generated = "foo!\""~x~"\"(\""~bar(y)~"\")";
>>
>> vs
>>
>> string generated = mixin(X!q{
>> foo!"@(x)"("@(bar(y))")
>> });
>
> I understand that. But the whole system must be redesigned. Quoting from
> my email (please let's continue here so as to avoid duplication):
>
> The macro facility should be very simple: any compile-time string can be
> a macro "body".
>
> The key is the expansion facility, which replaces parameter placeholders
> (e.g. in the simplest instance $1, $2 etc) with actual parameters. This
> is missing. Also, there must be expansion of other already-defined macro
> names. This is already present.
>
> The library has a simple interface:
>
> enum myMacro = q{... $1 $2 $(anotherMacro($1))... };
>
> // To mixin
> mixin(expand(myMacro, "argument one", "argument two"));
>
>
> Andrei
>
>

I understand, but compared to how I solved the issue

1. it invents an (arguably inferior) parameter passing system, even though there is one in the language.
2. it picks up all symbols used in $(...) from the caller's context rather than the callee's context and there is no way to get rid of that default, because the macro is unscoped.