Platform-independent Exception Handling

Greetings,

I'm trying to implement exception handling in my front end. I have a
prototype working using the Itanium ABI on Linux x86_64, but I'm not
sure how to proceed for other platforms.

So I was wondering: which OS/architecture combinations support
zero-cost EH, and which support SJLJ?

My main concern is keeping the IR for call sites platform independent.
Right now, it looks like to do that I might have to write my own
exception handling system (i.e. without invoke/landingpad) using just
setjmp(), longjmp(), and some thread local variables - which I have a
working prototype for, but it's quite inefficient. If LLVM's zero-cost
handling is viable for all platforms, I'd much rather use that.

Any help would be appreciated.

Thanks,
Anthony Bryant.

Hi Anthony,

As far as which OS/architectures support zero-cost EH and which support SJLJ, LLVM is designed to assume that Intel supports zero-cost exceptions and ARM supports SjLj exceptions. However, it's all in the personality function and unwind library. So it's not required that ARM use only SJLJ, it's just how it works because of the personality function and unwind library. :slight_smile:

The invoke/landingpad/resume instructions are meant to be platform independent. However, there is a "lowering" phase that occurs before code generation that converts those instructions into the form needed for the EH support on the architecture we're compiling for. And during code generation, we generate different EH tables based on that decision. So basically it's converted into platform-specific code right before code generation happens.

That's a long-winded way of saying that you should use our current EH model and assume zero-cost exceptions unless you're on ARM (there is an ARM EABI which isn't SJLJ-based (from my understanding), but I don't know the status of that in LLVM) or have been proven otherwise.

-bw

The ARM EHABI (zero-cost) implementation is in progress, but not complete.
Some basic cases are reported to work, but also some simple cases are
reported to fail.

http://llvm.org/bugs/show_bug.cgi?id=7187

Anton and Logan are working on it, but replying to the bug is best.

cheers,
--renato

Hi Bill,

Thanks for the response, I just have a couple more questions.

As far as which OS/architectures support zero-cost EH and which
support SJLJ, LLVM is designed to assume that Intel supports zero-cost
exceptions and ARM supports SjLj exceptions. However, it's all in the
personality function and unwind library. So it's not required that ARM
use only SJLJ, it's just how it works because of the personality
function and unwind library. :slight_smile:

So it sounds like it's completely OS independent, but I just want to
confirm - do the COFF and Mach-O outputs use the same system? Do I need
to do anything special in order to get them to work?
For example, do they generate different exception handling tables (using
something other than the DWARF format), meaning that I'd have to write
separate personality functions?

The invoke/landingpad/resume instructions are meant to be platform
independent. However, there is a "lowering" phase that occurs before
code generation that converts those instructions into the form needed
for the EH support on the architecture we're compiling for. And during
code generation, we generate different EH tables based on that
decision. So basically it's converted into platform-specific code
right before code generation happens.

That's a long-winded way of saying that you should use our current EH
model and assume zero-cost exceptions unless you're on ARM (there is
an ARM EABI which isn't SJLJ-based (from my understanding), but I
don't know the status of that in LLVM) or have been proven otherwise.

Do I need to do anything different to generate SJLJ exception-handling
bitcode? There are some intrinsics documented at
Exception Handling in LLVM — LLVM 16.0.0git documentation - but
there doesn't seem to be any documentation about how to use them. Are
calls to them generated by an LLVM pass, or do I need to call them
myself?

My problem is that I want my bitcode to be platform independent, so if
SJLJ requires me to generate special calls to intrinsics then I can't
use LLVM's exception handling at all until LLVM supports one way of
doing it on all platforms.

Thanks,
Anthony.

Hi Bill,

Thanks for the response, I just have a couple more questions.

As far as which OS/architectures support zero-cost EH and which
support SJLJ, LLVM is designed to assume that Intel supports zero-cost
exceptions and ARM supports SjLj exceptions. However, it’s all in the
personality function and unwind library. So it’s not required that ARM
use only SJLJ, it’s just how it works because of the personality
function and unwind library. :slight_smile:

So it sounds like it’s completely OS independent,

That was the intention, anyway. :slight_smile:

but I just want to
confirm - do the COFF and Mach-O outputs use the same system? Do I need
to do anything special in order to get them to work?

They should use the same system. The code to emit DWARF exceptions and debug information is in one place and doesn’t have code in it that’s target-dependent.

For example, do they generate different exception handling tables (using
something other than the DWARF format), meaning that I’d have to write
separate personality functions?

I’m not familiar with COFF, but no we would generate the same EH tables regardless of the file format.

The invoke/landingpad/resume instructions are meant to be platform
independent. However, there is a “lowering” phase that occurs before
code generation that converts those instructions into the form needed
for the EH support on the architecture we’re compiling for. And during
code generation, we generate different EH tables based on that
decision. So basically it’s converted into platform-specific code
right before code generation happens.

That’s a long-winded way of saying that you should use our current EH
model and assume zero-cost exceptions unless you’re on ARM (there is
an ARM EABI which isn’t SJLJ-based (from my understanding), but I
don’t know the status of that in LLVM) or have been proven otherwise.

Do I need to do anything different to generate SJLJ exception-handling
bitcode? There are some intrinsics documented at
http://llvm.org/docs/ExceptionHandling.html#llvm-eh-sjlj-setjmp - but
there doesn’t seem to be any documentation about how to use them. Are
calls to them generated by an LLVM pass, or do I need to call them
myself?

Some of the intrinsics are generated by the front-end and the rest are generated during code-generation. The one that the front-end generates is the [llvm.eh.typeid.for](http://llvm.org/docs/ExceptionHandling.html#llvm-eh-typeid-for) intrinsic.
However, that intrinsic is used by both DWARF and SjLj exceptions.

My problem is that I want my bitcode to be platform independent, so if
SJLJ requires me to generate special calls to intrinsics then I can’t
use LLVM’s exception handling at all until LLVM supports one way of
doing it on all platforms.

That’s a problem, because bitcode isn’t platform independent. :slight_smile: But as far as the exception handling in LLVM, it should be platform independent until you get to the code-generation phase.

-bw