<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Dec 9, 2007, at 1:01 PM, Duncan Sands wrote:</div><br><blockquote type="cite">Hi Dale,<br><br><blockquote type="cite">#include <cstdio><br></blockquote><blockquote type="cite">class A {<br></blockquote><blockquote type="cite">public:<br></blockquote><blockquote type="cite"> A() {}<br></blockquote><blockquote type="cite"> ~A() {}<br></blockquote><blockquote type="cite">};<br></blockquote><blockquote type="cite">void f() {<br></blockquote><blockquote type="cite"> A a;<br></blockquote><blockquote type="cite"> throw 5.0;<br></blockquote><blockquote type="cite">}<br></blockquote><blockquote type="cite">main() {<br></blockquote><blockquote type="cite"> try {<br></blockquote><blockquote type="cite"> f();<br></blockquote><blockquote type="cite"> } catch(...) { printf("caught\n"); }<br></blockquote><blockquote type="cite">}<br></blockquote><br>this example indeed shows the problem. Let me explain to see if we agree on what<br>the problem is. Suppose we don't artificially add catch-alls to selectors. Then<br>the above example compiles to:<br><br>define void @_Z1fv() {<br>...<br> invoke void @__cxa_throw( something ) noreturn<br> to label %somewhere unwind label %lpad<br>...<br>lpad:<br> %eh_ptr = tail call i8* @llvm.eh.exception( )<br> %eh_select8 = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32( i8* %eh_ptr, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*))</blockquote><div><br class="webkit-block-placeholder"></div><div>I wasn't advocating this; agree it is wrong.</div><br><blockquote type="cite"> tail call i32 (...)* @_Unwind_Resume( i8* %eh_ptr )<br> unreachable<br>...<br>}<br><br>define i32 @main() {<br>entry:<br> invoke void @_Z1fv( )<br> to label %somewhere2 unwind label %lpad2<br>...<br>lpad2: ; preds = %entry<br> %eh_ptr = tail call i8* @llvm.eh.exception( )<br> %eh_select14 = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32( i8* %eh_ptr, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null )<br><span class="Apple-tab-span" style="white-space:pre"> </span>print_a_message_and_exit<br>...<br>}<br><br>And this works fine: main calls _Z1fv which throws an exception. Execution branches to lpad where<br>(empty) cleanup code is run, then unwinding is resumed. The unwinder unwinds into main, and branches<br>to lpad2 (because the selector has a catch-all, the null) which prints a message and exits.<br><br>If the inliner is run, then we get:<br><br>define i32 @main() {<br>...<br> invoke void @__cxa_throw( something ) noreturn<br> to label %somewhere unwind label %lpad.i<br>...<br>lpad.i:<br> %eh_ptr.i = tail call i8* @llvm.eh.exception( ) ; <i8*> [#uses=2]<br> %eh_select8.i = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32( i8* %eh_ptr.i, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*))<br> invoke i32 (...)* @_Unwind_Resume( i8* %eh_ptr.i )<br> to label %somewhere2 unwind label %lpad2<br>...<br>lpad2: ; preds = %lpad.i<br> %eh_ptr = tail call i8* @llvm.eh.exception( ) ; <i8*> [#uses=2]<br> %eh_select14 = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32( i8* %eh_ptr, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null )<br><span class="Apple-tab-span" style="white-space:pre"> </span>print_a_message_and_exit<br>...<br>}<br><br>This is perfectly correct given LLVM invoke semantics. Unfortunately the unwinder doesn't<br>know about those :) When run, the exception is thrown but the unwinder doesn't branch<br>to lpad.i because the selector doesn't state that that (or any) exception should be caught. Thus<br>the program is terminated. </blockquote><div><br class="webkit-block-placeholder"></div><div>OK.</div><br><blockquote type="cite"> If you force a "cleanup" by changing the selector call to:<br> %eh_select8.i = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32( i8* %eh_ptr.i, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0)<br>then it doesn't work either: the unwinder observes that there is only a cleanup, and<br>using some special logic (bogus in this case) deduces that the exception will be rethrown<br>after running the cleanup code (and thus the program terminated), so doesn't bother running<br>the cleanup code and directly terminates the program (apparently terminating programs quickly<br>was important to whoever wrote the unwinder, I don't know why; the Ada unwinder doesn't do<br>this for example :) ). </blockquote><div><br class="webkit-block-placeholder"></div><div>OTOH, claiming that everything has a cleanup seems to me a correct description of what the IR code does: control reenters the throwing function to execute a possibly null cleanup, then resumes. The trouble is you can't simply copy that IR while inlining and expect things to still work, because <i>the operation of Unwind_Resume depends on what stack frame it's in</i>. I don't agree that the inlined version is correct IR. The 'invoke semantics' you're talking about are inextricably intertwined with _Unwind_Resume's semantics.</div><div><br class="webkit-block-placeholder"></div><blockquote type="cite">However if you add a catch-all to the selector instead:<br> %eh_select8.i = tail call i32 (i8*, i8*, ...)* @llvm.eh.selector.i32( i8* %eh_ptr.i, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)<br>then the unwinder does branch to lpad.i. Then the _Unwind_Resume call causes a branch to<br>lpad2 and all works perfectly.<br><br>This is why I forcably push a catch-all at the end of each selector call: because then if an<br>exception unwinds through an invoke, control always branches to the landing pad, which is what<br>LLVM invoke semantics require and the inliner has exploited.<br><br>Unfortunately it seems this breaks the Darwin unwinder.</blockquote><div><br class="webkit-block-placeholder"></div><div>Yes.</div><br><blockquote type="cite">It is true that you can imagine a solution in which the inliner knows about selector calls<br>and shuffles them around. I will think about this. That said, invoke is defined to have<br>certain semantics, and I don't much like the idea of trying to do an end-run around them<br>and around optimizers that exploit them...</blockquote></div><div><br class="webkit-block-placeholder"></div><div>I don't see much choice. I guess I'll look at getting the inliner to do what I think it should do. (I'll make it Darwin-specific at first, but it should work on Linux, and let me point out that you'll get more efficient code this way.)</div><div>I guess an easy but undesirable fallback position is to tell the inliner not to inline anything that invokes Unwind_Resume.</div><div><br class="webkit-block-placeholder"></div></body></html>