Help needed with LTO & NoUnwind (PostOrderFunctionAttrsPass)

We are implementing ARM EH in our LLVM compiler and have run into an issue when LTO is enabled. In the PostOrderFunctionAttrsPass in the LTO default pipeline, the __cxa_throw function is inferred to be NoUnwind. Subsequently, downstream the invoke to __cxa_throw gets changed to a call and the exception handling code gets yanked (the landing pads and catch code are eliminated after the call to __cxa_throw). The __cxa_throw function (from libcxxabi) calls_Unwind_RaiseException (from libunwind). That function is marked NoUnwind, so when the __cxa_throw function is analyzed in the PostOrderFunctionAttrsPass, nothing breaks the nounwind assumption. My thought is that the _Unwind_RaiseException function should not be marked NoUnwind, and therefore the call to it in __cxa_throw should return true for InstrBreaksNonThrowing(). However, it appears that _Unwind_RaiseException is always marked NoUnwind from the get go, without any optimization.

From godbolt it is apparent that other clang compilers don’t have a problem with lto and exceptions both being enabled, so perhaps we have a gap somewhere in our implementation. Any guidance on this topic would be greatly appreciated.


1 Like

This issue seems similar:

We are also compiling libunwind with -flto. In the github post it was suggested to compile libunwind with -fexceptions but that did not solve the other issue. I will try that to see if it avoids the NoUnwind on _Unwind_RaiseException.

Aside from that it looks like our options are to not compile the libunwind library with -flto, or to use the -disable-nounwind-inference flag during the lto phase.

However, it seems strange to me that the unwinding functions are marked NoUnwind.

Yup, this is unfortunate. I ended up just compiling libunwind without LTO as a workaround. The -fexceptions solution worked in a small test, but I haven’t gotten around to trying it in the actual context that led to my error yet. I’d be curious to learn if it works for you.

It turned out that we were already using the -fexceptions option, so no, that made no difference. I have not figured out why the compiler marks these functions as nounwind to begin with. I think we are also going to avoid compiling libunwind with -flto to avoid the issue. However, I think it is incorrect for the compiler to mark the unwinding functions as nounwind.

Do we deduce nounwind for that function or does clang emit it? Asked differently, what does the -save-temps output look like for the libunwind file that contains the _Unwind_RaiseException definition?