Skip to content

Advanced IR Generation and IT Certification Exams

  • Contact Us
Close Menu

Catching an exception – Advanced IR Generation

October 6, 2022October 6, 2022| Donna martinCatching an exception – Advanced IR Generation| 0 Comment| 03:32

Categories :
  • Adding debug metadata
  • ITCertification Exams
  • Raising an exception
  • The LLVM pass manager

To generate the IR code to catch an exception, we must add the addLandingPad() method. The generated IR extracts the type information from the exception. If it matches the C++ int type, then the exception is handled by printing Divide by zero! to the console and returning from the function. If the type does not match, we simply execute the resume instruction, which transfers control back to the runtime. As there are no other functions in the call hierarchy to handle this exception, the runtime will terminate the application. The following steps describe the code that is needed to generate the IR for catching an exception:

  1. In the generated IR, we need to call the __cxa_begin_catch() and __cxa_end_catch() functions from the C++ runtime library. To print the error message, we will generate a call to the puts() function from the C runtime library. Furthermore, to get the type information from the exception, we must generate a call to the llvm.eh.typeid.for intrinsic. We also need the FunctionType and Function instances for all of them; we will take advantage of our createFunc() method to create them:

  void addLandingPad() {
    FunctionType *TypeIdFty; Function *TypeIdFn;
    createFunc(TypeIdFty, TypeIdFn,
               “llvm.eh.typeid.for”, Int32Ty,
               {Int8PtrTy});
    FunctionType *BeginCatchFty; Function *BeginCatchFn;
    createFunc(BeginCatchFty, BeginCatchFn,
               “__cxa_begin_catch”, Int8PtrTy,
               {Int8PtrTy});
    FunctionType *EndCatchFty; Function *EndCatchFn;
    createFunc(EndCatchFty, EndCatchFn,
               “__cxa_end_catch”, VoidTy);
    FunctionType *PutsFty; Function *PutsFn;
    createFunc(PutsFty, PutsFn, “puts”, Int32Ty,
               {Int8PtrTy});

  1. The landingpad instruction is the first instruction we generate. The result type is a structure containing fields of an i8 pointer and an i32 type. This structure is generated with a call to the StructType::get() function. Moreover, since we need to handle an exception of a C++ int type, we need to also add this as a clause to the landingpad instruction, which must be a constant of an i8 pointer type. This means that generating a bitcast instruction is required to convert the TypeInfo value into this type. After, we must store the value that’s returned from the instruction for later use in the Exc variable: LandingPadInst *Exc = Builder.CreateLandingPad(
    StructType::get(Int8PtrTy, Int32Ty), 1, “exc”);
    Exc->addClause(
    ConstantExpr::getBitCast(TypeInfo, Int8PtrTy));
  1. Next, we extract the type selector from the returned value. With a call to the llvm.eh.typeid.for intrinsic, we retrieve the type ID for the TypeInfo field, representing the C++ int type. With this IR, we have generated the two values we need to compare to decide if we can handle the exception: Value *Sel =
    Builder.CreateExtractValue(Exc, {1}, “exc.sel”);
    CallInst *Id =
    Builder.CreateCall(TypeIdFty, TypeIdFn,
    {ConstantExpr::getBitCast(
    TypeInfo, Int8PtrTy)});
  1. To generate the IR for the comparison, we must call our createICmpEq() function. This function also generates two basic blocks, which we store in the TrueDest and FalseDest variables: BasicBlock *TrueDest, *FalseDest;
    createICmpEq(Sel, Id, TrueDest, FalseDest, “match”,
    “resume”);
  1. If the two values do not match, the control flow continues at the FalseDest basic block. This basic block only contains a resume instruction, to give control back to the C++ runtime: Builder.SetInsertPoint(FalseDest);
    Builder.CreateResume(Exc);
  1. If the two values are equal, the control flow continues at the TrueDest basic block. First, we generate the IR code to extract the pointer to the exception from the return value of the landingpad instruction, stored in the Exc variable. Then, we generate a call to the __cxa_begin_catch () function, passing the pointer to the exception as a parameter. This indicates the beginning of handling the exception for the runtime: Builder.SetInsertPoint(TrueDest);
    Value *Ptr =
    Builder.CreateExtractValue(Exc, {0}, “exc.ptr”);
    Builder.CreateCall(BeginCatchFty, BeginCatchFn,
    {Ptr});
  1. The exception is then handled by calling the puts() function to print a message to the console. For this, we generate a pointer to the string with a call to the CreateGlobalStringPtr() function, and then pass this pointer as a parameter in the generated call to the puts() function: Value *MsgPtr = Builder.CreateGlobalStringPtr(
    “Divide by zero!”, “msg”, 0, M);
    Builder.CreateCall(PutsFty, PutsFn, {MsgPtr});
  1. Now that we’ve handled the exception, we must generate a call to the __cxa_end_catch() function to inform the runtime about it. Finally, we return from the function with a ret instruction: Builder.CreateCall(EndCatchFty, EndCatchFn);
    Builder.CreateRet(Int32Zero);
    }

With the addThrow() and addLandingPad() functions, we can generate the IR to raise an exception and handle an exception. However, we still need to add the IR to check if the divisor is 0. We’ll cover this in the next section.

Post navigation

Previous page Raising an exception – Advanced IR Generation
Next page Integrating the exception handling code into the application – Advanced IR Generation

Leave a Reply Cancel reply

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

Related Post

Technical requirements – Optimizing IR

April 4, 2024April 4, 2024 Donna martinTechnical requirements – Optimizing IR

LLVM uses a series of passes to optimize the IR. A pass operates on a [...]

Read MoreRead More

Throwing and catching exceptions – Advanced IR Generation-1

March 7, 2022March 7, 2022 Donna martinThrowing and catching exceptions – Advanced IR Generation-1

With IR generation introduced in the previous chapters, you can already implement most of the [...]

Read MoreRead More

Adding debug metadata – Advanced IR Generation-1

June 20, 2023June 20, 2023 Donna martinAdding debug metadata – Advanced IR Generation-1

To allow source-level debugging, we have to add debug information. Support for debug information in [...]

Read MoreRead More

Search

Dropdown Categories

Archives

  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • June 2022
  • May 2022
  • March 2022
  • February 2022
  • December 2021
  • November 2021

Meta

  • Log in

Tag Cloud

Back to Top

Cookie Policy | Terms | Privacy | About Us | © Sherrieland