[LLVMdev] Does nounwind have semantics?

Andrew Trick atrick at apple.com
Mon Jul 22 00:32:48 PDT 2013

On Jul 21, 2013, at 11:55 PM, Duncan Sands <baldrick at free.fr> wrote:

> Hi Andrew,
> On 22/07/13 02:56, Andrew Trick wrote:
>> Does 'nounwind' have semantics that inform optimization passes? It seems to in some cases, but not consistently. For example...
>> int32_t foo(int32_t* ptr) {
>>   int i = 0;
>>   int result;
>>   do {
>>     bar(ptr);
>>     result = *ptr;
>>     bar(ptr);
>>   } while (i++ < *ptr);
>>   return result;
>> }
>> Say we have a front end that declares bar as...
>> declare void @bar(i32*) readonly;
>> So 'bar' is 'readonly' and 'may-unwind'.
>> When LICM tries to hoist the load it interprets the 'may-unwind' as "MayThrow" in LICM-language and bails. However, when it tries to sink the call itself it sees the 'readonly', assumes no side effects and sinks it below the loads. Hmm...
> is your worry here about the following case?
> - the load will trap if executed
> - bar throws an exception
> Thus with the original code the trap will not occur, because an exception will
> be thrown first, while if you move the first bar call below the load then the
> tap will occur.

Essentially, yes. My takeaway from looking into it is:

- nounwind means no dwarf EH. Absence of nounwind means absence of dwarf EH. It would be unwise for optimization passes to reason about the semantics beyond that. I was momentarily mislead by the LICM code that handles MayThrow specially.

- Things that throw exceptions or trap in defined ways are not readonly.

- Runtime checks for overflow, div-by-zero, bounds checks, etc. should be implemented at the IR level as branches to noreturn calls because it can be done that way and I haven’t seen concrete evidence that it’s too expensive. Don’t try to do something fancy with intrinsics and attributes unless absolutely required.

- Optimizing readonly calls in C is a tangentially related issue, as Nick explained. My answer to that problem is that C compilers are effectively forced to assume that calls terminate, so developers should not expect otherwise. If C developers don’t want the compiler to optimize their infinite loop or infinite recursion, they need to throw in a volatile dereference.


>> There doesn't appear to be a way to declare a function that is guaranteed not to write to memory in a way that affects the caller, but may have another well-defined side effect like aborting the program.
> I'm pretty sure that exiting the program is considered to write memory, so bar
> can't do that itself.
> Ciao, Duncan.
> This is interesting, because that is the way runtime checks for safe languages would like to be defined. I'm perfectly happy telling front ends to generate control flow for well-defined traps, since I like lots of basic blocks in my IR. But I'm still curious how others deal with this.
>> -Andy
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130722/25ea056f/attachment.html>

More information about the llvm-dev mailing list