CTFE and Static If Question

jmh530 john.michael.hall at gmail.com
Thu May 7 19:32:20 UTC 2020


On Thursday, 7 May 2020 at 17:59:30 UTC, Paul Backus wrote:
> On Thursday, 7 May 2020 at 15:00:18 UTC, jmh530 wrote:
>> Does foo!y0(rt) generate the same code as foo(rt, y0)?
>>
>> How is the code generated by foo(rt, x0) different from 
>> foo(rt,y0)?
>
> You can look at the generated code using the Compiler Explorer 
> at d.godbolt.org. Here's a link to your example, compiled with 
> ldc, with optimizations enabled:
>
> https://d.godbolt.org/z/x5K7P6
>
> As you can see, the non-static-if version has a runtime 
> comparison and a conditional jump, and the static-if version 
> does not. However, it doesn't make a difference in the end, 
> because the calls have been optimized out, leaving an empty 
> main function.

Thanks for that. I forgot how much nicer godbolt is for looking 
assembly than run.dlang.org. Or maybe it's just that the 
optimized assembly for ldc looks a lot simpler than dmd?

I eventually played around with it for a bit and ended up with 
what's below. When compiled with ldc -O -release, some of the 
functions have code that are generated a little differently than 
the one above (the assembly looks a little prettier when using 
ints than doubles). It looks like there is a little bit of 
template bloat too, in that it generates something like four 
different versions of the run-time function that all basically do 
the same thing (some slight differences I don't really 
understand). Anyway, I think that's the first time I've ever used 
__traits compiles with a static if and I don't think I've ever 
used an template alias bool before, but I thought it was kind of 
cool.


int foo(alias bool rtct)(int[] x) {
     static if (__traits(compiles, {static if (rtct) { enum val = 
rtct;}})) {
         static if (rtct) {
             return bar(x) / cast(int) x.length;
         } else {
             return bar(x) / cast(int) (x.length - 1);
         }
     } else {
         if (rtct)
             return bar(x) / cast(int) x.length;
         else
             return bar(x) / cast(int) (x.length - 1);
     }
}

int foo(int[] x, bool rtct) {
     if (rtct)
	    return foo!true(x);
     else
         return foo!false(x);
}

int bar(int[] x) {
     return x[0] + x[1];
}


void main() {
     import std.stdio: writeln;

     int[] a = [1, 2, 3, 4, 5];
     bool x0 = true;
     bool x1 = false;
     int result0 = foo(a, x0);
     int result1 = foo(a, x1);
     int result2 = foo!x0(a);
     int result3 = foo!x1(a);

     enum y0 = true;
     enum y1 = false;
     int result0_ = foo(a, y0);
     int result1_ = foo(a, y1);
     int result2_ = foo!y0(a);
     int result3_ = foo!y1(a);
}


More information about the Digitalmars-d-learn mailing list