<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>