On Tue, 19 Nov 2024, Jakub Jelinek wrote: > On Tue, Nov 19, 2024 at 09:35:06AM +0100, Richard Biener wrote: > > > This all seems excessively complicated; can't it be simplified a bit? > > > > I'd like to second this - I don't see value in adding the "intermediate" > > state which we never had. We for quite some time had two extremes, if > > we want to have a separate flag controlling this besides -fallocation-dce > > the go with dual-state please. I'd even say we don't need any new > > flag but can use the -fallocation-dce umbrella to control how the > > middle-end interprets new/delete semantically since the ability to > > elide new/delete implies that the user at least doesn't care about > > side-effects. Documenting the behavior clearly is of course good. > > The problem with the two states we had/have is that they are too extreme. > > Our old one (i.e. those "mC" etc.) is too strong and doesn't have any > backup in the standard, I think the PR101480 testcase is perfectly > valid C++ and so it probably isn't a good idea to enable such behavior > by default; with an extra switch sure, user promises not to rely on it > and the optimization can be done. > > The current one (i.e. those "m " etc.) are too weak, otherwise we wouldn't > be discussing this PR, it really penalizes too much code in the wild. > > The proposed intermediate one is what LLVM clearly implements and as I wrote > my reading of the standard is that while the user replaced global operators > certainly can modify visible global state, the callers can't really rely > on it because there is no guarantee it will be called at all and so I hope > we can do that by default. > > I think the step from the no optimizations to the intermediate state is > much more important for C++ code in the wild, by making the operators have > pure-ish behavior one doesn't need to reread everything from memory, typical > C++ has data in classes, many of those escape somewhere and having to reread > everything after every new/delete operator just in case those have changed > those is expensive. > > The step from intermediate state to the full optimization one is primarily > about DSE of global stores before the operators, but I think the most > important from those (stores to the memory actually being deleted) we can > already delete anyway if it is call from delete because there are > destructors happening before that and so the operators can't expect > some particular values in that memory. > > Anyway, I wonder what Jason/Jonathan think about this from the C++ standard > POV.
I think it's pretty clear and easy to describe to users what "m " and what "mC" do. But with "pure" this is an odd intermediate state. For both "m " and "mP" you suggest above the new/delete might modify their global state but as you can't rely on the new/delete pair to prevail you cannot rely on the modification to happen. But how do you explain that state = 1; p = new X; delete p; cout << state; "works" but cout << state; p = new X; cout << state; delete p; cout << state; behaves differently from p = new X; cout << state; delete p; cout << state; when the allocation is not elided and using "mP"? I think the actual behavior with "mP" is "weird", actual new/delete that really just inspect global memory but not modify it are not going to be important. Richard. > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)