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)

Reply via email to