On March 4, 2018 1:30:39 AM GMT+01:00, Peter Bergner <berg...@vnet.ibm.com> wrote: >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.
I think posix says you have to mark such variables volatile. So I fully agree with your analysis of why setjmp isn't special for RA. It would be only making non-conforming code work by accident. Richard. >Peter