I was looking into this yesterday but I ran into some issues.
The first is that blindly converting each output to in+out breaks
cases where an input already overlaps with an output:

    asm ("..." : "=r" (out) : "0" (in));

This could be worked around by scanning the input list and only
converting outputs which don't already have a matching input.  But then
you could run into cases like:

    asm ("..." : "=r,m" (out) : "0,r" (in));

Which may be unlikely, but this is valid code.  Here you can never
determine during gimplification which alternative will eventually be
chosen.

The second problem is that it sets off -Wuninitialized warnings
everywhere.  Is there some way to determine in gimplify_asm_expr which
outputs have already been assigned to?


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).

Re-reading this and giving it some more thought, I must reconsider what
I previously said.
>From looking at the constraints you should be able to tell which
operands *must* be in memory, and which *may* reside in a register.
This is the only distinction that matters.  Only the must-be-memory
cases get special treatment.  Everything else can be discarded on the
exception path, this includes "=rm" and such.

> 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).

I do agree that it could potentially be useful to keep certain outputs
on the exception path, although I can't think of any real-world use
cases.  But with my current patch this is already possible, as long as
the constraints force it into memory.

The example you gave looks useful at first, but is it really?  With
exceptions, there isn't much use for this.  The fact that you get an
exception should be enough to tell the user what happened.  Having a
separate status variable could only be useful in asms with multiple
instructions that can potentially throw.  But there are probably few,
if any, such cases which couldn't be split up into multiple stmts.

> 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.
> 

Reply via email to