On 3/3/18 5:47 PM, Peter Bergner wrote:
> On 3/3/18 10:29 AM, Jeff Law wrote:
>> Here's the comment from regstat.c:
>>
>>               /* We have a problem with any pseudoreg that lives
>>                  across the setjmp.  ANSI says that if a user variable
>>                  does not change in value between the setjmp and the
>>                  longjmp, then the longjmp preserves it.  This
>>                  includes longjmp from a place where the pseudo
>>                  appears dead.  (In principle, the value still exists
>>                  if it is in scope.)  If the pseudo goes in a hard
>>                  reg, some other value may occupy that hard reg where
>>                  this pseudo is dead, thus clobbering the pseudo.
>>                  Conclusion: such a pseudo must not go in a hard
>>                  reg.  */
> 
> I can't argue with anything in that comment, other than the conclusion. :-)
> It's not the compiler's job to implement the setjmp/longjmp save/restore.
> Maybe Kenny was working around a problem with some target's buggy setjmp
> and spilling everything "fixed" it?

The only observable difference I can see between a variable that has been
spilled to memory versus one that is assigned to a non-volatile hard reg
is if it is modified between the setjmp and the longjmp.  In the case
where the variable is spilled to memory, the "new" updated value is the
value you _may_ see on the return from setjmp (the return caused by the
call to longjmp), whereas if it is assigned to a non-volatile register,
then you _will_ see the "old" value that was saved by the setjmp call.
I say _may_ see above, because there are cases were we might not store
the "new" updated value to memory, even if we've spilled the pseudo.
Examples would be spill code optimization, or the variable has been
broken into separate live ranges/pseudos. etc. etc.  I guess I can even
think of cases where we could see both "old" and "new" values of a
variable.  Think of a variable that has been spilled/split like below:

    a = <old value> [start of live range, a assigned to non-volatile reg]
    spill store a
    ...
    setjmp()
    ...
1)  ... = ... a ...     [end of live range]
    ...                 [a not assigned to a reg in this region]
    spill load a        [start of live range]
2)  ... = ... a ...     [end of live range]
    ...
    if (...)
       a = <new value>  [start of live range]
3)     spill store a    [end of live range]
    ...                 [a not assigned to a reg in this region]
    longjmp()


On return from setjmp (the return caused by the call to longjmp),
the use of "a" at "1)" will use the non-volatile hard register
that was saved by the initial call to setjmp, so it will see the
"old" value of "a".  However, since the use of "a" at "2)" loads
the value from memory, it will use the "new" value stored by
the spill load at "3)"!

That said, the comment above only talks about variables that do not
change between the setjmp and the longjmp and in that case, you will
see the same "old" value (which is the only value, since it wasn't
modified) regardless of whether it was spilled or not.

What does ANSI (or any spec) say about what should happen to variables
that are modified between the setjmp and longjmp calls?  Maybe all bets
are off, given the example above, since even spilling a variable live
across a setjmp can still lead to strange behavior unless you don't
allow spill/split optimization and I don't think we'd want that at all.

Peter


Reply via email to