On 2020-03-19 18:06, Michael Matz wrote:
> Hello,
> 
> On Wed, 18 Mar 2020, J.W. Jagersma via Gcc-patches wrote:
> 
>>> Well, it's both: on the exception path the compiler has to assume that the 
>>> the value wasn't changed (so that former defines are regarded as dead) or 
>>> that it already has changed (so that the effects the throwing 
>>> "instruction" had on the result (if any) aren't lost).  The easiest for 
>>> this is to regard the result place as also being an input.
>>
>> The way I see it, there are two options: either you use the outputs
>> when an exception is thrown, or you don't.
> 
> Assuming by "use the outputs" you mean "transform them implicitely to 
> in-out operands", not "the source code uses the output operands after the 
> asm on except and no-except paths".
> 
>> The first option is more or less what my first patch did, but it was
>> incomplete.  Changing each output to in+out would make that work
>> correctly.
> 
> Right.
> 
>> The second is what I have implemented now, each output is assigned via
>> a temporary which is then assigned back to the variable bound to this
>> output.  On exception, this temporary is discarded.  However this is
>> not possible for asms that write directly to memory, so those cases are
>> treated like option #1.
> 
> Right again, somewhat.  Except that the determination of which outputs are 
> going into memory is a fuzzy notion until reload/LRA (which is very late 
> in the compile pipeline).  You can infer some things from the constraint 
> letters, but gimple might still put things into memory (e.g. when the 
> output place is address taken), even though the constraint only allows a 
> register (in which case reloads will be generated), or place something 
> into a register, even though the constraint only allows memory (again, 
> reloads will be generated).
> 
> Some of these reloads will be done early in the gimple pipeline to help 
> optimizations (they basically look like the insns that you generate for 
> copy-out), some of them will be generated only very late.
> 
>> I think the second option is easier on optimization since any previous
>> assignments can be removed from the normal code path, and registers
>> don't need to be loaded with known-valid values before the asm.
> 
> True (easier to optimizations) but immaterial (see below).
> 
>> The first option is more consistent since all outputs are treated the 
>> same, but more dangerous, as the asm may write incomplete values before 
>> throwing.
> 
> You have to assume that the author of the asm and its surrounding code is 
> written by a knowledgable person, so if the asm possibly writes partially 
> to outputs and then throws, then the output must not be accessed on the 
> exception path.  If the asm does not write partially, then the author can 
> access it.  So, what can or cannot be accessed on the exception path 
> really is an inherent property of the contents of the asm.
> 
> Now, your second case tries to create additional guarantees: it makes it 
> so that for some operands the user can depend on certain behaviour, namely 
> that the old value before the asm was entered is available on the except 
> path.  As you can't ensure this for all operands (those in memory are the 
> problem) you want to tighten the definition to only include the operands 
> where you can guarantee it, but this is fairly brittle, as above, because 
> some decisions are taken very late.
> 
> There's another case to consider: assume I'm writing an asm that writes 
> meaningful values to an output before and after a potential exception is 
> thrown, ala this:
> 
> asm (" mov %2, %0
>        xyz %2, %1
>        mov $0, %0" : "=r" (status), "+r" (a) : "r" (b));
> 
> Assume 'xyz' can fault depending on input.  The intention above would be 
> that on the exception path 'status' would contain a meaningful value (here 
> the value of input b, and on the non-except path would contain zero.
> 
> Your proposal of copyin/out for register values would make the above 
> impossible.  (Basically you wouldn't be able to output any reliable 
> information out of the asm in the except path).
> 
> Given that, and the complication of determining what the safe-for-copy-out 
> operands really are, and the fact that being easier on optimizations in 
> connection with asms and -fnon-call-exceptions isn't a high priority it 
> seems best to opt for the option that is guaranteed to work correctly in 
> most cases, and in fact allows more freedom in using the asm.
> 
> 
> Ciao,
> Michael.

Thanks.  You bring up some good points which I hadn't yet considered,
and I don't have any counter-arguments.
So using the outputs on exception looks to be the best option then.  I
think the test cases can then also be reduced to a single function, as
all operand types should behave the same.  I will implement this and
resubmit.

Reply via email to