June 25, 2018
On Monday, 25 June 2018 at 08:05:53 UTC, Mr.Bingo wrote:
> On Monday, 25 June 2018 at 07:02:24 UTC, Jonathan M Davis wrote:
>> On Monday, June 25, 2018 05:47:30 Mr.Bingo via Digitalmars-d-learn wrote:
>>> The problem then, if D can't arbitrarily use ctfe, means that there should be a way to force ctfe optionally!
>>
>> If you want to use CTFE, then give an enum the value of the expression you want calculated. If you want to do it in place, then use a template such as
>>
>> template ctfe(alias exp)
>> {
>>     enum ctfe = exp;
>> }
>>
>> so that you get stuff like func(ctfe!(foo(42))). I would be extremely surprised if the compiler is ever changed to just try CTFE just in case it will work as an optimization. That would make it harder for the programmer to understand what's going on, and it would balloon compilation times. If you want to write up a DIP on the topic and argue for rules on how CTFE could and should function with the compiler deciding to try CTFE on some basis rather than it only being done when it must be done, then you're free to do so.
>>
>> https://github.com/dlang/DIPs
>>
>> But I expect that you will be sorely disappointed if you ever expect the compiler to start doing CTFE as an optimization. It's trivial to trigger it explicitly on your own, and compilation time is valued far too much to waste it on attempting CTFE when in the vast majority of cases, it's going to fail. And it's worked quite well thus far to have it work only cases when it's actually needed - especially with how easy it is to make arbitrary code run during CTFE simply by doing something like using an enum.
>>
>> - Jonathan M Davis
>
> You still don't get it!
>
> It is not trivial! It is impossible to trigger it! You are focused far too much on the optimization side when it is only an application that takes advantage of the ability for rtfe to become ctfe when told, if it is possible.
>
> I don't know how to make this any simpler, sorry... I guess we'll end it here.

I am not sure that I understood it right, but there is a way to detect the status of a parameter:

My question was different, but I wished to get a ctRegex! or regex used depending on the expression:

 import std.regex:replaceAll,ctRegex,regex;

 auto reg(alias var)(){
       static if (__traits(compiles, {enum ctfeFmt = var;}) ){
                // "Promotion" to compile time value
                enum ctfeReg =  var ;
                pragma(msg, "ctRegex used");
                return(ctRegex!ctfeReg);

       }else{
                return(regex(var));
                pragma(msg,"regex used");
                }
       }
}
So now I can always use reg!("....") and let the compiler decide.

To speed up compilation I made an additional switch, that when using DMD (for development)
alway the runtime version is used.

The trick is to use the alias var in the declaration and check if it can be assigned to enum.
The only thing is now, that you now always use the !() compile time parameter to call the function. Even, when in the end is translated to an runtime call.

reg!("....") and not reg("...").





June 25, 2018
On 06/25/2018 07:47 AM, Mr.Bingo wrote:
> The docs say that CTFE is used only when explicit, I was under the impression that it would attempt to optimize functions if they could be computed at compile time. The halting problem has nothing to do with this. The ctfe engine already complains when one recurses to deep, it is not difficult to have a time out function that cancels the computation within some user definable time limit... and since fail can simply fall through and use the rtfe, it is not a big deal.
> 
> The problem then, if D can't arbitrarily use ctfe, means that there should be a way to force ctfe optionally!

A D compiler is free to precompute whatever it sees fit, as an optimization. It's just not called "CTFE" then, and `__ctfe` will be false during that kind of precomputation.

For example, let's try compiling this code based on an earlier example of yours:

----
int main()
{
    return foo(3) + foo(8);
}
int foo(int i)
{
   return __ctfe && i == 3 ? 1 : 2;
}
----

`dmd -O -inline` compiles that to:

----
0000000000000000 <_Dmain>:
   0:   55                      push   rbp
   1:   48 8b ec                mov    rbp,rsp
   4:   b8 04 00 00 00          mov    eax,0x4
   9:   5d                      pop    rbp
   a:   c3                      ret
----

As expected, `ldc2 -O` is even smarter:

----
0000000000000000 <_Dmain>:
   0:   b8 04 00 00 00          mov    eax,0x4
   5:   c3                      ret
----

Both compilers manage to eliminate the calls to `foo`. They have been precomputed. `__ctfe` was false, though, because the term "CTFE" only covers the forced/guaranteed kind of precomputation, not the optimization.
June 25, 2018
On Monday, 25 June 2018 at 09:36:45 UTC, Martin Tschierschke wrote:
> I am not sure that I understood it right, but there is a way to detect the status of a parameter:
>
> My question was different, but I wished to get a ctRegex! or regex used depending on the expression:
>
>  import std.regex:replaceAll,ctRegex,regex;
>
>  auto reg(alias var)(){
>        static if (__traits(compiles, {enum ctfeFmt = var;}) ){
>                 // "Promotion" to compile time value
>                 enum ctfeReg =  var ;
>                 pragma(msg, "ctRegex used");
>                 return(ctRegex!ctfeReg);
>
>        }else{
>                 return(regex(var));
>                 pragma(msg,"regex used");
>                 }
>        }
> }
> So now I can always use reg!("....") and let the compiler decide.
>
> To speed up compilation I made an additional switch, that when using DMD (for development)
> alway the runtime version is used.
>
> The trick is to use the alias var in the declaration and check if it can be assigned to enum.
> The only thing is now, that you now always use the !() compile time parameter to call the function. Even, when in the end is translated to an runtime call.
>
> reg!("....") and not reg("...").

Now try reg!("prefix" ~ var) or reg!(func(var)). This works in some limited cases, but falls apart when you try something more involved. It can sorta be coerced into working by passing lambdas:


template ctfe(T...) if (T.length == 1) {
    import std.traits : isCallable;
    static if (isCallable!(T[0])) {
        static if (is(typeof({enum a = T[0]();}))) {
            enum ctfe = T[0]();
        } else {
            alias ctfe = T[0];
        }
    } else {
        static if (is(typeof({enum a = T[0];}))) {
            enum ctfe = T[0];
        } else {
            alias ctfe = T[0];
        }
    }
}

string fun(string s) { return s; }

unittest {
    auto a = ctfe!"a";
    string b = "a";
    auto c = ctfe!"b";
    auto d = ctfe!("a" ~ b); // Error: variable b cannot be read at compile time
    auto e = ctfe!(() => "a" ~ b);
    auto f = ctfe!(fun(b)); // Error: variable b cannot be read at compile time
    auto g = ctfe!(() => fun(b));
}

--
  Simen
June 25, 2018
On Monday, 25 June 2018 at 10:49:26 UTC, Simen Kjærås wrote:
> On Monday, 25 June 2018 at 09:36:45 UTC, Martin Tschierschke wrote:
>> I am not sure that I understood it right, but there is a way to detect the status of a parameter:
>>
>> My question was different, but I wished to get a ctRegex! or regex used depending on the expression:
>>
>>  import std.regex:replaceAll,ctRegex,regex;
>>
>>  auto reg(alias var)(){
>>        static if (__traits(compiles, {enum ctfeFmt = var;}) ){
>>                 // "Promotion" to compile time value
>>                 enum ctfeReg =  var ;
>>                 pragma(msg, "ctRegex used");
>>                 return(ctRegex!ctfeReg);
>>
>>        }else{
>>                 return(regex(var));
>>                 pragma(msg,"regex used");
>>                 }
>>        }
>> }
>> So now I can always use reg!("....") and let the compiler decide.
>>
>> To speed up compilation I made an additional switch, that when using DMD (for development)
>> alway the runtime version is used.
>>
>> The trick is to use the alias var in the declaration and check if it can be assigned to enum.
>> The only thing is now, that you now always use the !() compile time parameter to call the function. Even, when in the end is translated to an runtime call.
>>
>> reg!("....") and not reg("...").
>
> Now try reg!("prefix" ~ var) or reg!(func(var)). This works in some limited cases, but falls apart when you try something more involved. It can sorta be coerced into working by passing lambdas:
>
>
> template ctfe(T...) if (T.length == 1) {
>     import std.traits : isCallable;
>     static if (isCallable!(T[0])) {
>         static if (is(typeof({enum a = T[0]();}))) {
>             enum ctfe = T[0]();
>         } else {
>             alias ctfe = T[0];
>         }
>     } else {
>         static if (is(typeof({enum a = T[0];}))) {
>             enum ctfe = T[0];
>         } else {
>             alias ctfe = T[0];
>         }
>     }
> }
>
> string fun(string s) { return s; }
>
> unittest {
>     auto a = ctfe!"a";
>     string b = "a";
>     auto c = ctfe!"b";
>     auto d = ctfe!("a" ~ b); // Error: variable b cannot be read at compile time
>     auto e = ctfe!(() => "a" ~ b);
>     auto f = ctfe!(fun(b)); // Error: variable b cannot be read at compile time
>     auto g = ctfe!(() => fun(b));
> }
>
> --
>   Simen

This doesn't work, the delegate only hides the error until you call it.

auto also does not detect enum. Ideally it should be a manifest constant if precomputed... this allows chaining of optimizations.

auto x = 3;
auto y = foo(x);


the compiler realizes x is an enum int and then it can also precompute foo(x).

Since it converts to a runtime type immediately it prevents any optimizations and template tricks.




1 2
Next ›   Last »