[LLVMdev] Inlining and exception handling in LLVM and GCC

John McCall rjmccall at apple.com
Mon Dec 6 16:01:18 PST 2010


On Dec 6, 2010, at 1:58 PM, Duncan Sands wrote:
> The poor interaction between exception handling and inlining in LLVM is one of
> the main motivations for the new exception handling models proposed recently.
> Here I give my analysis of the origin of the problem in the hope of clarifying
> the situation.

Your analysis coincides with the analysis I made when implementing EH
in clang.  I decided, however, that in the short term, given the brokenness
of the IR, I would rather ignore the known bad consequences of emitting
cleanups as catch-alls than deal with the uncertainties of whether codegen
could consistently clean up after our broken inliner.  I haven't yet regretted
this choice.

> Why does the inliner work the way it does?  The logic behind it is plausible
> but wrong, and goes something like this.  An invoke instruction does not let
> exceptions unwind through it (instead control branches to the landing pad).
> So when inlining it into another function, there is no need to do anything
> with it: it is not a throwing instruction.  This logic assumes that inlining
> does not affect whether an exception is unwound or not.  It is true that *if*
> an exception is unwound then the code produced by the LLVM inliner will
> function correctly.  But what if it is not unwound in the first place because
> whoever is doing the unwinding looks up the call stack and bases its decision
> as to whether to unwind (or potentially even what type of exception it unwinds)
> on what actions it sees there?  Then the whole LLVM approach falls apart.  And
> that's exactly what happens in the example program.

Right.  Another way of thinking about this is that the LLVM inliner generally
assumes that the call itself is not semantically relevant.  Unfortunately,
while that's often true in practice, there are actually two major semantic effects
tied to call boundaries.

The first is that function return implicitly releases stack-allocated memory;
the pathological case here is a recursive function that calls a helper with
huge stack variables, where inlining the helper makes max recursion
depth plummet.  Currently the inliner makes some effort to mitigate this
impact, but mostly by sharing allocas between different inlined functions.

The second is that inlining changes the behavior of anything that wants to
manually walk the call stack, and while most stack walkers don't rely on any
frame-specific semantics, the personality functions called by libunwind do.
And unfortunately, the inliner currently makes no effort at all to compensate
for breaking these call-specific semantics, even though they're arguably
way more important in practice than the frame-size issue.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20101206/68fa6e8d/attachment.html>


More information about the llvm-dev mailing list