Cleanup and fix implementation of _d_array{setlengthT,catnTX}Trace#2673
Cleanup and fix implementation of _d_array{setlengthT,catnTX}Trace#2673thewilsonator merged 3 commits intodlang:masterfrom
Conversation
Signed-off-by: Dan Printzell <xwildn00bx@gmail.com>
|
Thanks for your pull request and interest in making D better, @Vild! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "master + druntime#2673" |
|
That "pure bypass technique" looks like a compiler bug. |
I don't fully understand why this "technique" exist. It (or at least the comment) was added 5 years ago: |
I can't say that I understand what that comment is trying to say. I suspect it might just be wrong. Anyway, I'm sure that we're looking at a compiler bug. Calling an impure function from a pure one can't be allowed (without a cast). |
That behavior was introduced in dlang/dmd#4344 as a fix to https://issues.dlang.org/show_bug.cgi?id=14039 |
|
@WalterBright, you filed Issue 14039 and approved and merged the fix at dlang/dmd#4344. Can you please help reconcile this? Is the technique employed in this PR a bug or a legitimate feature? |
And a PR to fix it: dlang/dmd#10172 |
|
@Vild if you use the function pointer / literal / cast bypass technique instead, does that trigger the optimizer problem? AFAIK this is the commonly used technique to bypass pure. |
|
Is there a possibility that if dlang/dmd#10172 is merged, then this PR might not be needed? |
I believe that if dlang/dmd#10172 is merged, this PR will no longer work. |
I could move back to the pointer cast method, I just felt that it looked too hacky compared to this bypass method when I found it inside of dmd's code.
I still need to apply the |
Signed-off-by: Dan Printzell <xwildn00bx@gmail.com>
Signed-off-by: Dan Printzell <xwildn00bx@gmail.com>
|
I've changed it so it uses cast instead of that other method to fake purity. |
|
|
||
| // `accumulatePure` returns the value of `size`, which can never be zero due to the | ||
| // previous 'if'. So this assert will never be triggered. | ||
| assert(0); |
There was a problem hiding this comment.
BTW, reading this I think there's may be a deeper issue whenever we have 'fake' pure code which internally calls impure code.
I guess the intent of such code is to not influence purity of the caller (i.e. completely optimizing away the caller would be fine), but the callee is not really pure, so it should not be removed on it's own. I wonder whether this can be expressed in any theoretically sound way, @tgehr any insights here?
It seems to me that the problem is that we lie to the compiler and simply tell it this function is pure. Maybe we should rather tell it Ignore purity checks for this call, but the function is not pure. Intuitively I'd say a
pure void foo()
{
__traits(forcepure, bar());
}Should work: if bar is not inlined, this would tell the compiler to keep the call, but ignore purity for purity calculation of the callee. With inlining, the compiler should be able to see the side effects anyway and should not optimize these away.
There was a problem hiding this comment.
I can see how your assert code has the same effect though: It marks the return value as used, as long as the call is not inlined. When it's inlined, the compiler may remove the assert, but it will see the impure parts of accumulatePure and keep these. This can probably also somehow solved like this: https://stackoverflow.com/questions/40122141/preventing-compiler-optimizations-while-benchmarking, but I'd prefer a compiler hook which should also work for void functions.
There was a problem hiding this comment.
I've been thinking about introducing HookCallExp or a bool in CallExp that ignore the purity and somehow allowed the code to be inline, which is disallowed right now pragma(inline, false), whilst being able to be detected as the hook (HookCompoundStatement?) so the CTFE intercept code works.
There was a problem hiding this comment.
That sounds like a great idea.
There was a problem hiding this comment.
BTW, reading this I think there's may be a deeper issue whenever we have 'fake' pure code which internally calls impure code.
I guess the intent of such code is to not influence purity of the caller (i.e. completely optimizing away the caller would be fine), but the callee is not really pure, so it should not be removed on it's own. I wonder whether this can be expressed in any theoretically sound way, @tgehr any insights here?
...
@jpf91 This was what __mutable functions were for in the original __mutable proposal. Inlining for such functions is not so easy if you want to preserve constraints on evaluation order precisely.
This should be the final fix needed to be able to get dlang/dmd#10106 to pass all the unittest.
This code uses a pure bypass technique I found inside of dmd's source code so no more ugly hacky casts are needed for calling
GC.stats()andaccumulate.I've also refactored the two previous *Trace functions into
HookTraceImplto make sure that all the Trace functions are implemented correctly and to make it easier to change in the future.The
HookTraceImplalso contains aif (...) assert(0);check to make sure that the compiler does not remove the call toaccumulate, which is what is currently happening in dlang/dmd#10106.