<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Dec 6, 2010, at 1:58 PM, Duncan Sands wrote:</div><blockquote type="cite"><div>The poor interaction between exception handling and inlining in LLVM is one of<br>the main motivations for the new exception handling models proposed recently.<br>Here I give my analysis of the origin of the problem in the hope of clarifying<br>the situation.<br></div></blockquote><div><br></div>Your analysis coincides with the analysis I made when implementing EH</div><div>in clang. I decided, however, that in the short term, given the brokenness</div><div>of the IR, I would rather ignore the known bad consequences of emitting</div><div>cleanups as catch-alls than deal with the uncertainties of whether codegen</div><div>could consistently clean up after our broken inliner. I haven't yet regretted</div><div>this choice.</div><div><br></div><div><blockquote type="cite"><div>Why does the inliner work the way it does? The logic behind it is plausible<br>but wrong, and goes something like this. An invoke instruction does not let<br>exceptions unwind through it (instead control branches to the landing pad).<br>So when inlining it into another function, there is no need to do anything<br>with it: it is not a throwing instruction. This logic assumes that inlining<br>does not affect whether an exception is unwound or not. It is true that *if*<br>an exception is unwound then the code produced by the LLVM inliner will<br>function correctly. But what if it is not unwound in the first place because<br>whoever is doing the unwinding looks up the call stack and bases its decision<br>as to whether to unwind (or potentially even what type of exception it unwinds)<br>on what actions it sees there? Then the whole LLVM approach falls apart. And<br>that's exactly what happens in the example program.<br></div></blockquote><div><br></div>Right. Another way of thinking about this is that the LLVM inliner generally</div><div>assumes that the call itself is not semantically relevant. Unfortunately,</div><div>while that's often true in practice, there are actually two major semantic effects</div><div>tied to call boundaries.</div><div><br></div><div>The first is that function return implicitly releases stack-allocated memory;</div><div>the pathological case here is a recursive function that calls a helper with</div><div>huge stack variables, where inlining the helper makes max recursion</div><div>depth plummet. Currently the inliner makes some effort to mitigate this</div><div>impact, but mostly by sharing allocas between different inlined functions.</div><div><br></div><div>The second is that inlining changes the behavior of anything that wants to</div><div>manually walk the call stack, and while <i>most</i> stack walkers don't rely on any</div><div>frame-specific semantics, the personality functions called by libunwind <i>do</i>.</div><div>And unfortunately, the inliner currently makes no effort at all to compensate</div><div>for breaking these call-specific semantics, even though they're arguably</div><div>way more important in practice than the frame-size issue.</div><div><br></div><div>John.</div></body></html>