On 2020-03-12 20:26, Segher Boessenkool wrote: > On Thu, Mar 12, 2020 at 07:42:30PM +0100, J.W. Jagersma wrote: >> On 2020-03-12 16:32, Segher Boessenkool wrote: >>> On Thu, Mar 12, 2020 at 02:08:18PM +0100, Richard Biener wrote: >>>>> It wasn't clear from my message above, but: I was mostly worried about >>>>> requiring the asm to treat memory operands in a certain way when the >>>>> exception is thrown. IMO it would be better to say that the values of >>>>> memory operands are undefined on the exception edge. >>>> >>>> Rather unspecified. So IMHO on the exception edge the asm() should >>>> still appear as a def for all outputs so the compiler cannot derive any >>>> actual values for them. That of course also means that they must not >>>> appear to be must-defs since we may not DSE earlier stores for example. >>> >>> So make all outputs of an asm that may throw (w/ -fnon-call-exceptions) >>> inout operands instead? That works for registers exactly the same, too? >> >> Should gcc do this or would it be the user's responsibility? For >> memory operands I don't think anything changes if you replace "=m" by >> "+m". However changing each "=r" to "+r" would certainly generate less >> optimal code. > > [ "+m"(x) means exactly the same as "=m"(x) : "m"(x) ] > > Yes, but this is required for all operands that could keep their old > value on exceptions. Since this will only happen with > -fnon-call-exceptions, which already has a significant performance cost, > I don't think adding just a tiny bit more is so bad? The benefit is > that all asm will work, the user cannot do this wrong anymore.
I don't want to unnecessarily pessimize register outputs if it can be avoided. And even if you do change register outputs to in+out, they are still more likely to contain some intermediate value that you would want to discard on throwing. If you think of it in terms of a function call, the closest equivalent of register vs memory outputs would be: reg = f (); vs. f (&mem); If f() throws, then in the first case, 'reg' is never assigned to. For the second case, you can't expect 'mem' to remain unmodified. There is also the case of "=rm" and similar which have not been discussed so far, but are (in my experience) the most common operand constraint. I think these can be handled as "=r" if they end up in memory since they are never offsettable, and are unlikely (impossible?) to have side-effects if written to. So I think the following behavior is the most sensible: If the output *may* reside in a register (this covers any constraint combination that includes a register constraint, so also "=rm", etc), then it is assigned via a temporary and its value discarded after a throw. Only pure memory operands, strictly "=m", "=o", etc, are converted to in+out and assumed to be valid after throwing. Does that sound reasonable?