[LLVMdev] RFC: New EH representation for MSVC compatibility
Joseph Tremoulet
jotrem at microsoft.com
Mon May 18 20:40:52 PDT 2015
> I want to have separate normal and exceptional codepaths
I assume you at least mean that's what you'll be doing in Clang's initial IR generation. Do you also mean to impose this as a restriction on other IR generators, and as a property that IR transformations must preserve? I.e., is this something that EH preparation can assume?
> For __finally, we outline the finally body early in clang and emit two calls to it as before, but passing in the frameaddress as an argument
But then you have to frameescape any __finally-referenced local before optimization, and doesn't that defeat the purpose of delaying funclet outlining to EH preparation?
> tail merging could kick in like you mention. Undoing this would be and currently is the job of WinEHPrepare. I guess I felt like the extra representational complexity wasn't worth the confidence that it would buy us
For one, it seems counterproductive to let tail merge think it can kick in when it's doomed to be undone.
For another, if we're talking about a setup where EH paths might mingle with non-EH paths but the funclet will only be invoked for the EH cases, then I believe this would help the "pruning as many unreachable CFG edges as possible " step be more effective -- after finding out which blocks are reachable from a catch/cleanup, you could intersect that with the set of blocks from which a corresponding resume can be reached. Any funclet blocks ending in condbr/switch that only wind up with one successor in the funclet could then have their terminators rewritten as unconditional branches, without needing to recover dataflow and chase constants through phis and resolve compares/switches and all that.
> I'm not married to reusing 'resume', other candidate names include 'unwind' and 'continue', and I'd like more ideas
The first thing that comes to mind is 'endatch/exitcatch', but to use that you'd need to rename other things since it would be confusing vis-à-vis catchendblock and lack symmetry with catchblock that isn't prefixed with begin/enter.
You could consider 'filter' (or 'filterblock') for 'catchblock', since conceptually it plays the role of a filter (typically one which consults type information; I've seen such things called "typetestfilter" before). Or 'dispatch'/'dispatchblock'/'exceptiondispatch'/'dispatchexception' (isn't that what Clang names the blocks it creates for the explicit dispatch code?); 'catchendblock' would then be something like 'unwinddispatch' or 'continuedispatch' or 'resumedispatch' and the resume that returns to normal execution could be 'exitdispatch' or 'exitcatch' or even 'uncatch'.
For the resumes that end cleanups, something like 'endcleanup' might work.
Names are hard…
Thanks
-Joseph
From: Reid Kleckner [mailto:rnk at google.com]
Sent: Monday, May 18, 2015 5:36 PM
To: Joseph Tremoulet
Cc: LLVM Developers Mailing List; Bill Wendling; Nick Lewycky; Kaylor, Andrew
Subject: Re: [LLVMdev] RFC: New EH representation for MSVC compatibility
On Mon, May 18, 2015 at 12:03 PM, Joseph Tremoulet <jotrem at microsoft.com<mailto:jotrem at microsoft.com>> wrote:
Hi,
Thanks for sending this out. We're looking forward to seeing this come about, since we need funclet separation for LLILC as well (and I have cycles to spend on it, if that would be helpful).
Some questions about the new proposal:
- Do the new forms of resume have any implied read/write side-effects, or do they work just like a branch? In particular, I'm wondering what prevents reordering a call across a resume. Is this just something that code motion optimizations are expected to check for explicitly to avoid introducing UB per the "Executing such an invoke [or call] that does not transitively unwind to the correct catchend block has undefined behavior" rule?
Yes, crossing a resume from a catchblock ends the lifetime of the exception object, so I'd say that's a "writes escaped memory" constraint. That said, a resume after a cleanupblock doesn't, but I'm not sure it's worth having this kind of fine-grained analysis. I'm OK teaching SimplifyCFG to combine cleanupblocks and leaving it at that.
- Does LLVM already have other examples of terminators that are glued to the top of their basic blocks, or will these be the first? I ask because it's a somewhat nonstandard thing (a block in the CFG that can't have instructions added to it) that any code placement algorithms (PRE, PGO probe insertion, Phi elimination, RA spill/copy placement, etc.) may need to be adjusted for. The adjustments aren't terrible (conceptually it's no worse than having unsplittable edges from each of the block's preds to each of its succs), but it's something to be aware of.
No, LLVM doesn't have anything like this yet. It does have unsplittable critical edges, which can come from indirectbr and the unwind edge of an invoke. I don't think it'll be too hard to teach transforms how to deal with one more, but maybe that's unrealistic youthful optimism. :)
- Since this will require auditing any code with special processing of resume instructions to make sure it handles the new resume forms correctly, I wonder if it might be helpful to give resume (or the new forms of it) a different name, since then it would be immediately clear which code has/hasn't been updated to the new model.
There aren't that many references to ResumeInst across LLVM, so I'm not too scared. I'm not married to reusing 'resume', other candidate names include 'unwind' and 'continue', and I'd like more ideas.
- Is the idea that a resume (of the sort that resumes normal execution) ends only one catch/cleanup, or that it can end any number of them? Did you consider having it end a single one, and giving it a source that references (in a non-flow-edge-inducing way) the related catchend? If you did that, then:
+ The code to find a funclet region could terminate with confidence when it reaches this sort of resume, and
+ Resumes which exit different catches would have different sources and thus couldn't be merged, reducing the need to undo tail-merging with code duplication in EH preparation (by blocking the tail-merging in the first place)
We already have something like this for cleanupblocks because the resume target and unwind label of the cleanupblock must match. It isn't as strong as having a reference to the catchblock itself, because tail merging could kick in like you mention. Undoing this would be and currently is the job of WinEHPrepare. I guess I felt like the extra representational complexity wasn't worth the confidence that it would buy us.
- What is the plan for cleanup/__finally code that may be executed on either normal paths or EH paths? One could imagine a number of options here:
+ require the IR producer to duplicate code for EH vs non-EH paths
+ duplicate code for EH vs non-EH paths during EH preparation
+ use resume to exit these even on the non-EH paths; code doesn't need to be duplicated (but could and often would be as an optimization for hot/non-EH paths), and normal paths could call the funclet at the end of the day
and it isn't clear to me which you're suggesting. Requiring duplication can worst-case quadratically expand the code (in that if you have n levels of cleanup-inside-cleanup-inside-cleanup-…, and each cleanup has k code bytes outside the next-inner cleanup, after duplication you'll have k*n + k*(n-1) + … or O(k*n^2) bytes total [compared to k*n before duplication]), which I'd think could potentially be a problem in pathological inputs.
I want to have separate normal and exceptional codepaths, but at -O0 all the cleanup work should be bundled up in a function that gets called from both those paths.
Today, for C++ destructors, we emit two calls to the destructor: one on the normal path and one on the EH path. For __finally, we outline the finally body early in clang and emit two calls to it as before, but passing in the frameaddress as an argument. I think this is a great place to be. It keeps our -O0 code size small, simplifies the implementation, and allows us to inline one or both call sites if we think it's profitable.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150519/f9f63a44/attachment.html>
More information about the llvm-dev
mailing list