<div dir="ltr"><div>Hi all,<br><br>I feel that there are two problems with the existing infrastructure:<br><br>* The nounwind attribute is ambiguous for (1) not throwing exceptions and (2) not performing stack unwinding. I feel that it will be better to separate this in two different attributes<br>
<br>* There is some problem when the function has both uwtable and nounwind. Although, I think it fine to keep the current definition of nounwind, however, the uwtable attribute will be much useless to its user. Besides, even if we wish to keep the current definition, to avoid the undefined behavior, we have to slightly change the code generator to emit [can't unwind] whenever there is a nounwind attribute.<br>
<br>I am writing my thoughts in detail below, please have a look, and feel free to challenge or send me the feedback. Thanks.<br><br>Sincerely,<br>Logan<br><br>tl;dr<br><br></div>(HTML version: <a href="http://loganchien.github.io/llvm/nounwind.html">http://loganchien.github.io/llvm/nounwind.html</a> )<br>
<br>Notations<br>---------<br><br>To make my argument clear, I would like to use a different notation from LLVM IR:<br><br>* The no-throw attribute guarantees that the function will not throw any exception object.<br><br>
* The no-unwind attribute guarantees that the function won't read the prior calling sequence with the stack unwinder.<br><br>For simplification, if the function is not tagged with no-throw then it is may-throw. Similarly, if the function is not tagged with no-unwind, then it is may-unwind.<br>
<br>* The ehtable attribute guarantees that the exception handling table, such as the LSDA handler data and (by implementation) the stack unwinding information for exception, will be generated for exception handling. If the table includes stack unwinding infomration, then it is guaranteed that the unwinding information is sufficient enough to go back to previous propagation barrier (landingpad, cleanup filter, or can't unwind.)<br>
<br>* The uwtable attribute guarantees that the unwind table will be generated for stack unwinding for profilers, debuggers, (possibly) exception handling mechansim and etc. This attribute guarantees that the complete stack trace can be obtained as long as the calling sequence does not contain the external function or the function marked with no-unwind.<br>
<br>It is possible for some exception handling implemenation requires uwtable to unwind the stack, it is not necessary to do so. On the other hand, even if the stack unwind information for exception handling is encoded in ehtable, it might be insufficient to implement the stack unwinder. We will come back with this later.<br>
<br>If a function has both no-uwnind and uwtable, then there must be a mechanism (might be an agreement between the compiler and the run-time library) to signal the stack unwinder to stop before passing through the function. Otherwise, the undefined behavior might be happened. Similarly, we need a similar mechanism for the function with both no-throw and ehtable<br>
<br>With these notations, we can do some simple reasoning:<br><br>* may-throw implies may-unwind — We have to unwind the stack if the exception is thrown by the function, thus the may-throw attribute will imply may-unwind.<br>
<br>* no-unwind implies no-throw — The contraposition to the previous statement.<br><br>Please notice that no-throw does not imply no-unwind. We will come back with this later.<br><br><br>Attribute Properties<br>--------------------<br>
<br>In this section, I would like to discuss the properties of no-unwind and no-throw, and the rules to infer the attributes if the programmer didn't specified them in function definition. These properties may be used by some optimization passes, such as PruneEH.<br>
<br>First, since no-unwind implies no-throw, we can add no-throw attribute to the functions which have no-unwind attribute.<br><br>Second, it is clear that the external functions should be considered as may-throw unless it is explicitly tagged with no-throw. Similarly, the external functions should be may-unwind unless it is explicitly tagged with no-unwind.<br>
<br>For function definition, we can inspect the instructions:<br><br>* If the function does not have any call or invoke instruction to a may-unwind callee function and -fasynchronous-unwind-table compiler option isn't given, then we can add the no-unwind attribute to the function.<br>
<br>* If the function does not have any call or invoke instruction to a may-throw callee function, then we can add the no-throw attribute to the function (safe approximation.)<br><br>* If we can prove that every exceptions are caught by the landing pad and the function won't re-throw the exception or won't continue the unwinding, then we can add the no-throw to the function attribute.<br>
<br>Please notice that we have to deliberately separate the attribute into no-throw and no-unwind because the landingpad instruction can't give any guarantee on no-unwind attribute.<br><br><br>Problems with Existing LLVM Infrastructure<br>
------------------------------------------<br><br>There are two function attributes related with unwinding and exception handling in the existing LLVM infrastructure. Here are the descriptions copied from the LLVM reference manual:<br>
<br>* nounwind — This function attribute indicates that the function never returns with an unwind or exceptional control flow. If the function does unwind, its runtime behavior is undefined.<br><br>* uwtable — This attribute indicates that the ABI being targeted requires that an unwind table entry be produce for this function even if we can show that no exceptions passes by it. This is normally the case for the ELF x86-64 abi, but it can be disabled for some compilation units.<br>
<br>From my interpretation, the specification for nounwind guarantees that the function will neither throw an exception nor unwind the stack, i.e. nounwind = no-throw + no-unwind. The specification for uwtable guarantees some unwind table will be generated; however, it does not specify which kind of unwind table should be generated. IIRC, the ARM backend actually implements ehtable, which has only limited capability to unwind the stack.<br>
<br># Inconsistant Interpretation of nounwind<br><br>The things are getting tricky when it comes to the implementation. There is a PruneEH pass, which will try to remove the unnecessary exception handling informantion. For example, the following code:<br>
<br>define void @foo() {<br>entry:<br> ret void<br>}<br><br>will be converted to:<br><br>define void @foo() nounwind {<br>entry:<br> ret void<br>}<br><br>Here's a much more complex example:<br><br>define void @foo() {<br>
<br>declare void @_Z3barv()<br><br>declare i32 @__gxx_personality_v0(...)<br><br>define void @_Z3foov() {<br>entry:<br> invoke void @_Z3barv() to label %try.cont unwind label %lpad<br><br>lpad:<br> %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)<br>
catch i8* null<br> ret void<br><br>try.cont:<br> ret void<br>}<br><br>is converted to<br><br>declare void @_Z3barv()<br><br>declare i32 @__gxx_personality_v0(...)<br><br>; Function Attrs: nounwind<br>define void @_Z3foov() #0 {<br>
entry:<br> invoke void @_Z3barv()<br> to label %try.cont unwind label %lpad<br><br>lpad:<br> %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)<br> catch i8* null<br>
ret void<br><br>try.cont:<br> ret void<br>}<br><br>attributes #0 = { nounwind }<br><br>Some careful reader might have noticed the problem here. The nounwind attribute is added to @_Z3foov() simply because the landingpad can catch the exception object. However, in my notation, only no-throw can be added to this function, and no-throw does not imply no-unwind. It is possible for @_Z3foov() to unwind the stack. For example, the function @_Z3barv() may call _Unwind_Backtrace() to get the backtrace.<br>
<br>Besides, some optimization might make the situation even worse. AFAIK, most of the stack unwinding implementations rely on the value in the link register or the return address on the stack. However, there is an optimization in LLVM code generation which will not save the link register if the callee function has noreturn attribute [1]. Even though the optimization will only be applied when the callee function has nounwind attribute as well, the problem still occurs because PruneEH will (incorrectly) add nounwind to some function which actually unwinds. Besides, I am in doubt about whether we can apply this optimization when the caller function has the uwtable attribute and requires the unwind table.<br>
<br># Unwind Table and Can't Unwind<br><br>The mixture of uwtable and nounwind will cause another problem.<br><br>IMO, it is incorrect to decide whether to emit [can't unwind] with !needsUnwindTableEntry() [2]. The needsUnwindTableEntry() is defined as either the function has uwtable attribute or the function does not have nounwind. Thus, !needsUnwindTableEntry() imples not having uwtable attribute and having nounwind. As the result, the [can't unwind] won't be generated for the following function:<br>
<br>define void @foo() uwtable nounwind {<br>entry:<br> call void @bar()<br> ret void<br>}<br><br>The stack unwinder might continue to unwind the stack because there isn't any mark in the unwind table to stop the stack unwinding. And, unfortunately, according to the LLVM reference manual, this will result in undefined behavior. In fact, I did encounter some real example [3] which will fall into an infinite loop during the phase 1 unwinding.<br>
Summary<br><br>In conclusion, I would like to suggest that we need to put more efforts to define a precise specification for exception handling and stack unwinding mechanism, so that the optimization passes and the run-time environment can interact with each other without problems.<br>
<br>In summary, IMO, these are the topic have to be discussed:<br><br>* Should we separate nounwind into no-throw and no-unwind?<br> - What is the impact in terms of the run-time performance?<br> - What is the impact on the code size?<br>
<br>* Should we write more implementation details about uwtable in the LLVM reference manual?<br> - What is the possible expected behavior when uwtable is used with nounwind<br><br>If we have some decision, I am willing to write the patch. :-)<br>
<br><br>Footnotes<br>---------<br><br> See <llvm>/lib/CodeGen/VirtRegMap.cpp line 290<br> See <llvm>/lib/CodeGen/AsmPrinter/ARMException.cpp line 65<br> See <libc++abi>/test/test_vector3.cpp<br>
<br><br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Feb 15, 2014 at 11:36 PM, Renato Golin <span dir="ltr"><<a href="mailto:renato.golin@linaro.org" target="_blank">renato.golin@linaro.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">On 15 February 2014 11:38, Evgeniy Stepanov <<a href="mailto:eugeni.stepanov@gmail.com">eugeni.stepanov@gmail.com</a>> wrote:<br>
> I'd love to hear more details. Are you saying that this infinite loop<br>
> is a limitation of EHABI table format, and not something that can be<br>
> fixed in the compiler?<br>
<br>
</div>I'd find it hard to believe. EHABI has been out for a long time and I<br>
don't remember any intrinsic problem like that.<br>
<br>
Remember that our EHABI implementation is *very* new, and that this<br>
problem is when mixing Dwarf unwinding with EHABI unwinding, which we<br>
have just enabled yesterday (by Keith's patch), so "here be dragons".<br>
;)<br>
<div class=""><br>
<br>
> Meanwhile, please notice that gcc behavior matches current clang<br>
> behavior that I described above. We would not want to create an<br>
> incompatibility.<br>
<br>
</div>Absolutely! We need to be extra careful.<br>
<br>
It'd be good if we had some examples compiled with GCC and LLVM<br>
intermixed and throw exceptions from different places, either on the<br>
check-all or the test-suite.<br>
<br>
cheers,<br>
--renato<br>
</blockquote></div><br></div>