<div dir="ltr">On Tue, Mar 3, 2015 at 7:16 AM, Joerg Sonnenberger <span dir="ltr"><<a href="mailto:joerg@britannica.bec.de" target="_blank">joerg@britannica.bec.de</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="">On Tue, Mar 03, 2015 at 12:05:53AM -0800, John McCall wrote:<br></span><span class="">> GCC implements this builtin with much more generality than we do,<br>
> probably because GCC predates widespread adoption of libUnwind and we<br>
> don't.  Hal's comment about not trying to match GCC on PPC aside (and<br>
> I find that comment pretty troubling!), my understanding of the general<br>
> intent of this builtin is that's for implementing extremely lightweight<br>
> context-saving (on the assumption that the platform doesn't have that<br>
> many callee-save registers; it would probably be awful on e.g. AArch64)<br>
> and that the amount of state it saves is so small (PC, SP, FP if it's<br>
> not rederivable from SP) that there's no reason [i]not[/i] to match GCC.<br>
<br>
</span>Actually, it is a bit more complicated. A good setjmp/longjmp<br>
implementation in libc saves exactly the same set of registers. The only<br>
reason the GCC implementation can be better is that it forces register<br>
spilling to fixed locations and makes longjmp depend on that. I'm not<br>
even sure there is any optimisation for detecting that longjmp doesn't<br>
need to restore all registers.<br></blockquote><div><br></div><div>This is not how __builtin_setjmp / __builtin_longjmp work at all.</div><div>__builtin_longjmp only restores enough to restore the original call</div><div>frame and IP; the __builtin_setjmp site is responsible for restoring</div><div>the other registers, at its own pace and with its own function-specific</div><div>information.</div><div><br></div><div>setjmp and longjmp are also specced to preserve more than just</div><div>register state.  A target that decides to use the library function should</div><div>at least be lowering to _setjmp/_longjmp.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">"Implement it" comes with a quite a cost as it requires implementing a<br>
good chunk of SJ/LJ functionality AND detecting when the landing pads<br>
need to be added, even if no exceptions are used. That's why ARM fails<br>
currently even on Darwin, which does use SJ/LJ for exception handling.<br></blockquote><div><br></div><div>Okay.  I'm quite ready to believe that the current intrinsics are excessively</div><div>tied to the needs of EH lowering.  If implementing this properly on ARM</div><div>is unreasonable in the current representation, so be it.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
>From what I have seen, I don't believe in a performance benefit compared<br>
to a proper libc implementation. That was already a fallacity of HP's<br>
libunwind -- for the platforms at the time, only Itanium had an insane<br>
enough callee-save register set, mostly the FP registert. But that's not<br>
gong to help with SJ/LJ in this context either.<br></blockquote><div><br></div><div>This is not what people have found empirically, at all.  The performance</div><div>impact is quite drastic on targets with a small callee-save register set,</div><div>because every register save / restore that can be avoided or optimized</div><div>in the setjmp'ing function has a significant impact.</div><div><br></div><div>It also allows the bulk of the saves to be hoisted to the top of the</div><div>setjmp'ing function instead of being done at setjmp time.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="">> But if you can get the LLVM list to agree with Hal that compatibility<br>
> (even across compiler versions) is a non-goal, and you can show me more<br>
> convincingly that e.g. Ruby only uses this in their core implementation<br>
> and it is not used directly in the compiled code of native gems, then<br>
> I am willing to change my mind.<br>
<br>
</span>As I said, I don't care about ABI compatibility enough to spend the time<br>
to fix all backends. What I do care is that we currently silently<br>
produce obviously bad code.</blockquote><div><br></div><div>Right, I agree that this is a serious problem.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"> If the ABI contract is supposed to be "uses 6 longs or less", which even </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">GCC doesn't seem to get right, I am perfectly fine with just creating a </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">failure in this case. That should be a trivial change.</blockquote><div><br></div><div>I think the best solution is for us to not claim to support __builtin_setjmp</div><div>and __builtin_longjmp on targets that don't support them.  That way we</div><div>avoid making any particular ABI commitment in the absence of an optimized</div><div>implementation; even if you don't care about GCC compatibility, you should</div><div>care about compatibility between clang versions.  And an error here would</div><div>simply disable the feature in Ruby's configure check.</div><div><br></div><div>It sounds like you've already investigated which targets actually support</div><div>the intrinsic.  Just move that to a flag on the AST-level TargetInfo and make</div><div>the custom type-checking for __builtin_setjmp / __builtin_longjmp in</div><div>SemaChecking.cpp reject calls on targets that don't support it.  Targets</div><div>that want to optimize this can just implement the intrinsic (or a different,</div><div>less EH-linked intrinsic) and flip the switch in their TargetInfo.</div><div><br></div><div>John.</div></div>
</div></div>