Throwing and catching exceptions – Advanced IR Generation-2


The difference between both instructions is that invoke has two labels associated. The first label is where execution continues in case the called function ends normally, usually with a ret instruction. In the example code, this label is called %next. If an exception occurs, then execution continues at a so-called landing pad, with a label of %lpad.

The landing pad is a basic block that must begin with a landingpad instruction. The landingpad instruction gives LLVM information about the handled exception types. For example, a possible landing pad could look like this:


lpad:
%exc = landingpad { ptr, i32 }
          cleanup
          catch ptr @_ZTIi
          filter [1 x ptr] [ptr @_ZTIi]

There are three possible types of action here:

  • cleanup: This denotes that code to clean up the current state is present. Usually, this is used to call destructors of local objects. If this marker is present, then the landing pad is always called during stack unwinding.
  • catch: This is a list of type-value pairs and denotes the exception types that can be handled. The landing pad is called if the thrown exception type is found in this list. In the case of the foo() function, the value is the pointer to the C++ runtime type information for the int type, similar to the parameter of the __cxa_throw() function.
  • filter: This specifies an array of exception types. The landing pad is called if the exception type of the current exception is not found in the array. This is used to implement the throw() specification. For the foo() function, the array has only one member – the type information for the int type.

The result type of the landingpad instruction is the { ptr, i32 } structure. The first element is a pointer to the thrown exception, while the second is a type selector. Let’s extract both from the structure:


%exc.ptr = extractvalue { ptr, i32 } %exc, 0
%exc.sel = extractvalue { ptr, i32 } %exc, 1

The type selector is a number that helps us identify the cause of why the landing pad is called. It is a positive value if the current exception type matches one of the exception types given in the catch part of the landingpad instruction. If the current exception type does not match any of the values given in the filter part, then the value is negative. It is 0 if the cleanup code should be called.

The type selector is an offset into a type information table, constructed from the values given in the catch and filter parts of the landingpad instruction. During optimization, multiple landing pads can be combined into one, which means that the structure of this table is not known at the IR level. To retrieve the type selector for a given type, we need to call the intrinsic @llvm.eh.typeid.for function. We need this to check if the type selector value corresponds to the type information for int so that we can execute the code in the catch (int e) {} block:
%tid.int = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)
%tst.int = icmp eq i32 %exc.sel, %tid.int
br i1 %tst.int, label %catchint, label %filterorcleanup

Leave a Reply

Your email address will not be published. Required fields are marked *