www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - pragma(__ctfe)

reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
I have need of the ability to suppress the code generation of 
functions for using mixin generation functions with dcompute. 
Below is a link to a PR to implement that functionality.

https://github.com/dlang/dmd/pull/15636

What are peoples thoughts on this?
Sep 27 2023
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
I certainly would prefer ``assert(__ctfe);``.

It would opt-in existing code (correctly). That alone is a pretty 
convincing argument.

Not having to learn additional things, and having what appears like it 
should work work is always a good design choice.
Sep 27 2023
next sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Thu, Sep 28, 2023 at 04:35:10PM +1300, Richard (Rikki) Andrew Cattermole via
Digitalmars-d wrote:
 I certainly would prefer ``assert(__ctfe);``.
+1. Maybe also detect code of the following form? auto func(Args args) { if (__ctfe) { ... } else assert(0); } T -- If it breaks, you get to keep both pieces. -- Software disclaimer notice
Sep 27 2023
prev sibling next sibling parent reply Bruce Carneal <bcarneal gmail.com> writes:
On Thursday, 28 September 2023 at 03:35:10 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 I certainly would prefer ``assert(__ctfe);``.

 It would opt-in existing code (correctly). That alone is a 
 pretty convincing argument.

 Not having to learn additional things, and having what appears 
 like it should work work is always a good design choice.
The assert hack is useful but limited. It will not fail at compile time, will not prevent all code/symbol generation, will not enable compile time understanding that the function is restricted to use at compile time (if that's useful apart from the other ...). I think we can do better in this area (eliminating/controlling spew to the linker) and in target enumeration generally {CT, generic CPU, CPU specializations, dcompute variants} but not without quite a bit more effort for the generality and/or soup-free analysis.
Sep 27 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 28/09/2023 5:58 PM, Bruce Carneal wrote:
 The assert hack is useful but limited. It will not fail at compile time, 
 will not prevent all code/symbol generation, will not enable compile 
 time understanding that the function is restricted to use at compile 
 time (if that's useful apart from the other ...).
This proposal (should this PR changed to it) would restrict that function to CTFE only.
Sep 27 2023
parent Bruce Carneal <bcarneal gmail.com> writes:
On Thursday, 28 September 2023 at 06:02:05 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 28/09/2023 5:58 PM, Bruce Carneal wrote:
 The assert hack is useful but limited. It will not fail at 
 compile time, will not prevent all code/symbol generation, 
 will not enable compile time understanding that the function 
 is restricted to use at compile time (if that's useful apart 
 from the other ...).
This proposal (should this PR changed to it) would restrict that function to CTFE only.
Correct.
Sep 28 2023
prev sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 28 September 2023 at 03:35:10 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 I certainly would prefer ``assert(__ctfe);``.

 It would opt-in existing code (correctly). That alone is a 
 pretty convincing argument.

 Not having to learn additional things, and having what appears 
 like it should work work is always a good design choice.
That would suffer all the same problems that `pragma(inline)` as a statement has. The information that a function should not be emitted (or should be inlined) is an outward facing attribute of that function, not an internal facing attribute. It will screw up .di generation, and make separate compilation more difficult. You also can't flip a switch to change if from not emitting to emitting it if you want to debug the function at runtime.
Sep 28 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 28/09/2023 8:36 PM, Nicholas Wilson wrote:
 It will screw up .di generation, and make separate compilation more 
 difficult.
No not really, think about the constraints of CTFE. You can't elide a function body which is to be used from CTFE. Since you have to have the function body to CTFE it. So where the annotation exists, doesn't matter too much.
Sep 28 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/28/23 4:02 AM, Richard (Rikki) Andrew Cattermole wrote:
 On 28/09/2023 8:36 PM, Nicholas Wilson wrote:
 It will screw up .di generation, and make separate compilation more 
 difficult.
No not really, think about the constraints of CTFE. You can't elide a function body which is to be used from CTFE. Since you have to have the function body to CTFE it. So where the annotation exists, doesn't matter too much.
I think what Nic means is if you have a function: ```d string genMixin(string param) { assert(__ctfe); return "int " ~ param ~ " = 5;"; } ``` Now, if that doesn't go into the binary, what happens with the di generated file? ```d string genMixin(string param); ``` oops, there's the function, but it can't be called for CTFE, *and* it doesn't exist in the object file. Personally, I don't see the problem here. Don't use .di files generation for d files that contain those functions. Or the compiler can detect it, and omit the function, but meh. -Steve
Sep 28 2023
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 29/09/2023 6:08 AM, Steven Schveighoffer wrote:
 On 9/28/23 4:02 AM, Richard (Rikki) Andrew Cattermole wrote:
 On 28/09/2023 8:36 PM, Nicholas Wilson wrote:
 It will screw up .di generation, and make separate compilation more 
 difficult.
No not really, think about the constraints of CTFE. You can't elide a function body which is to be used from CTFE. Since you have to have the function body to CTFE it. So where the annotation exists, doesn't matter too much.
I think what Nic means is if you have a function: ```d string genMixin(string param) {    assert(__ctfe);    return "int " ~ param ~ " = 5;"; } ``` Now, if that doesn't go into the binary, what happens with the di generated file? ```d string genMixin(string param); ``` oops, there's the function, but it can't be called for CTFE, *and* it doesn't exist in the object file. Personally, I don't see the problem here. Don't use .di files generation for d files that contain those functions. Or the compiler can detect it, and omit the function, but meh. -Steve
Yeah, I got it. Don't elide the function body of a CTFE only function, or one called from it and it will work fine, which is what I said :)
Sep 28 2023
prev sibling next sibling parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Thursday, 28 September 2023 at 03:30:01 UTC, Nicholas Wilson 
wrote:
 I have need of the ability to suppress the code generation of 
 functions for using mixin generation functions with dcompute. 
 Below is a link to a PR to implement that functionality.

 https://github.com/dlang/dmd/pull/15636

 What are peoples thoughts on this?
Why couldn't the compiler already guess this? To me a simple static analysis would be enough and better, or is it too slow? time saved not generating what's not used could offset time spent on the analysis?
Sep 27 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 28/09/2023 6:04 PM, ryuukk_ wrote:
 Why couldn't the compiler already guess this?
 
 To me a simple static analysis would be enough and better, or is it too 
 slow? time saved not generating what's not used could offset time spent 
 on the analysis?
When you do multi-step builds (which are common), this would result in link failures. Since you don't have all the code, you can't do any analysis without failures being possible. It would make druntime and Phobos fail to link correctly with a giant list of missing symbols.
Sep 27 2023
parent reply Bruce Carneal <bcarneal gmail.com> writes:
On Thursday, 28 September 2023 at 06:04:51 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 28/09/2023 6:04 PM, ryuukk_ wrote:
 Why couldn't the compiler already guess this?
 
 To me a simple static analysis would be enough and better, or 
 is it too slow? time saved not generating what's not used 
 could offset time spent on the analysis?
When you do multi-step builds (which are common), this would result in link failures. Since you don't have all the code, you can't do any analysis without failures being possible. It would make druntime and Phobos fail to link correctly with a giant list of missing symbols.
Correct. If the function is intended to actually be ctfe only, as marked, and a reference somehow gets emitted to be linked against, then you will see a link time error.
Sep 28 2023
parent Basile B. <b2.temp gmx.com> writes:
On Thursday, 28 September 2023 at 11:05:07 UTC, Bruce Carneal 
wrote:
 Correct.  If the function is intended to actually be ctfe only, 
 as marked, and a reference somehow gets emitted to be linked 
 against, then you will see a link time error.
Yes but that should be trivial to add a check during CallExp sema to emit a proper error message. There's a "are we in CTFE" flag in DMD `Scope`.
Nov 26 2023
prev sibling next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Thursday, 28 September 2023 at 03:30:01 UTC, Nicholas Wilson 
wrote:
 I have need of the ability to suppress the code generation of 
 functions for using mixin generation functions with dcompute. 
 Below is a link to a PR to implement that functionality.

 https://github.com/dlang/dmd/pull/15636

 What are peoples thoughts on this?
It's a good idea in general, but what alternatives exists? Could the compiler infer it some other way?
Sep 28 2023
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/27/23 11:30 PM, Nicholas Wilson wrote:
 I have need of the ability to suppress the code generation of functions 
 for using mixin generation functions with dcompute. Below is a link to a 
 PR to implement that functionality.
 
 https://github.com/dlang/dmd/pull/15636
 
 What are peoples thoughts on this?
Have you tried immediately-called lambdas? What I need is for this to work: ```d void foo() nogc { int[] buf; if (__ctfe) { buf = new int[10000]; } else { buf = (cast(int*)malloc(int.sizeof * 10000))[0 .. 10000]; } scope(exit) if(!__ctfe) free(buf.ptr); ... // use buf } ``` We need the compiler to back-off when it comes to enforcing runtime attributes in compile-time-only blocks. Without it, reasonable backup plans don't exist for what seems like obvious allowances. BetterC CTFE code becomes impossible, etc. I'd also like to see `assert(__ctfe)` just suppress code generation, as mentioned. -Steve
Sep 28 2023
parent reply Dave P. <dave287091 gmail.com> writes:
On Thursday, 28 September 2023 at 17:04:00 UTC, Steven 
Schveighoffer wrote:
 On 9/27/23 11:30 PM, Nicholas Wilson wrote:
 I have need of the ability to suppress the code generation of 
 functions for using mixin generation functions with dcompute. 
 Below is a link to a PR to implement that functionality.
 
 https://github.com/dlang/dmd/pull/15636
 
 What are peoples thoughts on this?
Have you tried immediately-called lambdas? What I need is for this to work: ```d void foo() nogc { int[] buf; if (__ctfe) { buf = new int[10000]; } else { buf = (cast(int*)malloc(int.sizeof * 10000))[0 .. 10000]; } scope(exit) if(!__ctfe) free(buf.ptr); ... // use buf } ``` We need the compiler to back-off when it comes to enforcing runtime attributes in compile-time-only blocks. Without it, reasonable backup plans don't exist for what seems like obvious allowances. BetterC CTFE code becomes impossible, etc. I'd also like to see `assert(__ctfe)` just suppress code generation, as mentioned. -Steve
As far as I can tell, this already works. ```d import core.stdc.stdlib; import core.stdc.stdio; int foo() nogc { int[] buf; if (__ctfe) { buf = new int[10000]; } else { buf = (cast(int*)malloc(int.sizeof * 10000))[0 .. 10000]; } scope(exit) if(!__ctfe) free(buf.ptr); foreach(ref b; buf){ b = 2; } int x = 0; foreach(b; buf){ x += b; } return x; } enum z = foo(); pragma(msg, z); void d_main(){ int y = foo(); printf("%d\n", y); printf("%d\n", z); } version(D_BetterC){ extern(C) int main(){ d_main(); return 0; } } else { void main(){ d_main(); } } ``` works with betterC, normal D, works at compile time, runtime. It works as this bug was resolved: https://issues.dlang.org/show_bug.cgi?id=21492
Sep 28 2023
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/28/23 3:56 PM, Dave P. wrote:

 It works as this bug was resolved: 
 https://issues.dlang.org/show_bug.cgi?id=21492
Oh nice! Since 2.103, I hadn't realized. -Steve
Sep 28 2023