<div dir="ltr">First, thanks for the help in this area. :)<div><br></div><div>I agree there's a big conceptual mismatch between the table-driven EH strategy MSVC uses control-driven landing pad strategy used in the Itanium C++ EH document. We need some way to represent these tables in IR, or we ask the backend for too much.</div><div><br></div><div>I think your IR extension is insufficient. I'm looking at the 'nested.ll' case, and I think I see a problem:</div><div><br></div><div><div>void test() {</div><div> try {</div><div> Outer outer;</div><div> try {</div><div> Inner inner;</div><div> do_inner_thing();</div><div> } catch (int) {</div><div> handle_int();</div><div> }</div><div> } catch (float) {</div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> handle_float();</span><br></div><div> }</div><div> keep_going();</div><div>}</div></div><div><br></div><div>This is the landing pad for the do_inner_thing() invoke:</div><div><div><div>lpad3: ; preds = %invoke.cont2</div><div> %8 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)</div><div> cleanup at @_Z4testv.unwind.1 ; ~Inner</div><div> catch i8* bitcast (i8** @_ZTIi to i8*) at @_Z4testv.catch.1 ; handle_int()</div><div> catch i8* bitcast (i8** @_ZTIf to i8*) at @_Z4testv.catch.0 ; handle_float()</div></div></div><div><br></div><div>The @_Z4testv.unwind.1 helper just calls ~Inner(), but not ~Outer.</div><div><br></div><div>I think we'd need something more complex like this:</div><div><br></div><div>
<div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div><div>lpad3: ; preds = %invoke.cont2</div><div> %8 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)</div><div> cleanup at @_Z4testv.unwind.1 ; ~Inner</div><div> catch i8* bitcast (i8** @_ZTIi to i8*) at @_Z4testv.catch.1 ; handle_int(), returns to code before non-exceptional call to ~Outer</div><div>
<span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> cleanup at @_Z4testv.unwind.0 ; ~Outer</span><br></div><div> catch i8* bitcast (i8** @_ZTIf to i8*) at @_Z4testv.catch.0 ; handle_float()</div></div><div><br></div><div>Maybe we could make these changes, but once we do that it's not clear to me that we should be using the same landing pad instruction anymore.</div><div><br></div><div>Even if we did make these changes, we'll have landing pads like:</div><div><br></div><div> invoke @do_inner_thing() ... unwind label %lpad1</div><div>
<span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> invoke @~Inner() ... unwind label %lpad2</span><br></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)">
<span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> invoke @~Outer() ... unwind label %lpad3</span><br></span></div><div><br></div><div>lpad1:</div><div> landingpad ...</div><div> cleanup at ~Inner</div><div> catch @"typeinfo for int" at @handle_int</div><div>
<span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> cleanup at ~Outer</span><br></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)">
<span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> catch @"typeinfo for float" at @handle_float</span></span></div><div>
<div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)">lpad2:</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"> landingpad ...</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"> catch @"typeinfo for int" at @handle_int</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> cleanup at ~Outer</span><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important;background-color:rgb(255,255,255)"> catch @"typeinfo for float" at @handle_float</span><br></span></div><div>
<div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)">lpad3:</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"> landingpad ...</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"> catch @"typeinfo for float" at @handle_float</div></div></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)">This is still pretty far away from the tables that _CxxFrameHandler3 wants.</div><div><br></div><div>I'm starting to think that what we really want to do is build an internal LLVM global constant representing the action table at preparation time. I don't fully understand the .xdata that MSVC emits for _CxxFrameHandler3 yet, but I suspect that 90% of it can be prepared ahead of time without using PC values. All landing pads can be assigned a state number, and we can insert a call to an intrinsic (@llvm.eh.state(i32 %n) maybe?) in each landingpad. After that, we can truncate the block with unreachable and prune away any unreachable blocks. Now all the backend has to do is fill in a table mapping PC to state.</div><div><br></div><div>What do you think? One downside is that ConstantStructs are kind of expensive.</div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jan 26, 2015 at 2:27 PM, Kaylor, Andrew <span dir="ltr"><<a href="mailto:andrew.kaylor@intel.com" target="_blank">andrew.kaylor@intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div lang="EN-US" link="blue" vlink="purple">
<div>
<p class="MsoNormal">I am working on adding support for C++ exception handling when compiling for a native Windows target (that is a target with "MSVC" specified as the environment). Because of differences between how the native Windows runtime handles exceptions
and the Itanium-based model used by current LLVM exception handling code, I believe this will require some extensions to the LLVM IR, though I'm trying to leverage the existing mechanisms as much as possible.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">I'll discuss this below in more detail, but the summary is that I'm going to propose an extension to the syntax of the landing pad instruction to enable landing pad clauses to be outlined as external functions, and I'd like to introduce
two new intrsinsics, llvm.eh.begin.catch and llvm.eh.end.catch, to replace calls to the libc++abi __cxa_begin_catch and __cxa_end_catch functions.
<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Currently, LLVM supports 64-bit Windows exception handling for MinGW targets using a custom personality function and the libc++abi library. There are also LLVM clients, such as ldc, that provide Windows exception handling similar to what
I am proposing by providing their own custom personality function. However, what I would like is to support Windows C++ exception handling using the __CxxFrameHandler3 function provided by the native Windows runtime library.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Some of the primary challenges in supporting native Windows C++ exception handling are:<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">1. Catch and unwind handlers are called in a different frame context than the original function in which they are defined.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">2. Windows exception handling is state driven rather than landing pad based. The compiler must generate a table for each function mapping IP addresses within that function to the EH state at that address. When an exception is thrown the
runtime uses this table to determine which unwind and catch handlers should be invoked.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">3. Windows catch and unwind handling is implemented using a series of calls to discrete handlers rather than a jump to a landing pad which uses runtime decisions to reach all relevant handler blocks as is done in LLVM's existing implementations.
LLVM's current landing pad structure frequently results in in catch handling blocks and cleanup blocks which are shared by multiple landing pads. Windows expects each catch handler and unwind handler to be defined in a single location. The runtime then determines
which handlers should be called based on the EH state when an exception is thrown and makes a series of calls when multiple handlers are needed.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">The first challenge is relatively easy to address. The Microsoft C++ compiler creates a psuedo-function for handlers which it embeds in the body of the parent function, but for LLVM I would like to try simply outlining the handler bodies
into fully external functions. The task of outlining the handler code is somewhat straightforward and can be done with the existing IR. However, I need a way to link the landing pads from the parent function to the outlined handlers. I propose doing this
by extending the syntax of the landing pad instruction to allow the address of an outlined handler to be attached to catch and cleanup clauses.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">The current syntax for landingpad is:<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"> <resultval> = landingpad <resultty> personality <type> <pers_fn> <clause>+<u></u><u></u></p>
<p class="MsoNormal"> <resultval> = landingpad <resultty> personality <type> <pers_fn> cleanup <clause>*<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"> <clause> := catch <type> <value><u></u><u></u></p>
<p class="MsoNormal"> <clause> := filter <array constant type> <array constant><u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">I'd like to change that to:<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"> <resultval> = landingpad <resultty> personality <type> <pers_fn> <clause>+<u></u><u></u></p>
<p class="MsoNormal"> <resultval> = landingpad <resultty> personality <type> <pers_fn> cleanup [at handler] <clause>*<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"> <clause> := catch <type> <value> [at handler]<u></u><u></u></p>
<p class="MsoNormal"> <clause> := filter <array constant type> <array constant><u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Outlined handlers will reference frame variables from the parent function using the llvm.frameallocate and llvm.framerecover functions. Any frame variable which must be referenced from a catch or cleanup handler will be moved into a block
allocated by llvm.frameallocate. When the handlers are called, the parent function's frame pointer is passed as the second argument to the call. The handlers will use this frame pointer to find the frame allocation block from the parent function. The frame
allocation block will also contain space for an exception state variable and an exception object pointer. These values are maintained by the runtime library.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Current LLVM landing blocks use calls to __Cxa_begin_catch to get a pointer to the object associated with the exception. This function is provided by the libc++abi library and is specific to the personality function being used. I would
like to introduce a new intrinsic (llvm.eh.being.catch) which accomplishes the same result in a personality-function independent way. For consistency, I also propose introducing llvm.eh.end.catch to replace calls to __cxa_end_catch.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">I am attaching several examples showing the outlining transformation I am proposing. Note that for simplicity I've used Linux type information in these examples, but the final implementation will need to use Microsoft-style RTTI. I believe
clang already has support for that.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">The 'simple.ll' example shows a function with a single catch-all handler. The 'catch-type.ll' example shows a function which catches a specific type of exception. The 'min-unwind.ll' example shows a function which has no exception handlers
but which requires an unwind handler. The 'nested.ll' example shows a function which has nested try blocks.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">The nested example illustrates the challenge mentioned above with regard to inter-mingled handlers. I think I know how I will accomplish the outlining shown in that example and generate the state tables needed by the __CxxFrameHandler3
personality function, but I'm going to skip discussion of the details for now.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">However, I do want to at least open discussion of the problem of EH state handling. The native Windows C++ exception handling essentially needs an EH state assigned to each basic block. I have an idea for how I might be able to infer
the EH states based on the targets of invoke instructions. I think I can make this work in a way that will produce correct results for synchronous C++ exception handling. However, I don't think I can get it to map exactly to the actual C++ scopes in the
original source code. For this reason, assuming we would like to support asynchronous C++ exception handling at some future time, I think it may be preferable to have the EH states embedded by the front end, possibly as metadata. I haven't thought through
all of the possible problems here, and I am open to suggestions.<u></u><u></u></p>
</div>
</div>
<br>_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:LLVMdev@cs.uiuc.edu">LLVMdev@cs.uiuc.edu</a> <a href="http://llvm.cs.uiuc.edu" target="_blank">http://llvm.cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev</a><br>
<br></blockquote></div><br></div>