[llvm-commits] [llvm] r129235 - in /llvm/trunk: include/llvm/BasicBlock.h include/llvm/Bitcode/LLVMBitCodes.h lib/AsmParser/LLLexer.cpp lib/AsmParser/LLParser.cpp lib/AsmParser/LLToken.h lib/Bitcode/Reader/BitcodeReader.cpp lib/Bitcode/Writer/BitcodeWriter.cpp lib/VMCore/AsmWriter.cpp lib/VMCore/BasicBlock.cpp test/Feature/bb_attrs.ll

Bill Wendling isanbard at gmail.com
Sat Apr 9 21:38:03 PDT 2011


On Apr 9, 2011, at 7:50 PM, Chris Lattner wrote:

> Hi Bill,
> 
> This sounds very interesting.  Do you have a description of what you're angling for?  I'd really like to understand and digest the model before you write too much code.
> 
Hi Chris,

Here was the initial proposal (replicated below):

	http://lists.cs.uiuc.edu/pipermail/llvmdev/2010-December/036692.html

There were many comments on it, some fixes, and some clarifications. But in general, what I sent out originally is the basic idea.

A quick summary: It involves creating a new "dispatch" instruction, that in essence takes the place of the current llvm.eh.selector/llvm.eh.typeid.for/etc. calls. Because it's an IR-level instruction, all of the passes can reason about it much better than they can with intrinsic calls. Also, it has a direct link back to the landing pad basic block (the patch I submitted). This one-to-one-ness makes inlining and culling the AST for EH information much easier.

-bw


This is a revision of the second exception handling proposal I sent out. You can see it here:

	http://lists.cs.uiuc.edu/pipermail/llvmdev/2010-November/036484.html

After much discussion, there are some changes to the proposal – some significant and some minor. One major point, this proposal does not address the issue of catching an exception thrown from a non-invoke instruction. However if done properly, it should form the foundation for that.

General Model
=============

The unwind edge from an invoke instruction jumps to a landing pad. That landing pad contains code which performs optional cleanups, and then determines which catch handler to call (if any). If no catch handlers are applicable, the exception resumes propagation either to the next enclosing region or out of the function.


Basic Block Attributes
======================

A basic block can be given an attribute.

General Syntax:

 label: attr1 attr2 ... attrn

For exception handling, we introduce the `landingpad' attribute.

 lp: landingpad

A basic block that has the `landingpad' attribute is considered a (surprise!) "landing pad".

• It may be branched to only by the unwind edge of an invoke instruction or by
 the resume edge of a dispatch instruction.

• A landing pad must have exactly one dispatch instruction associated with it,
 and it must dominate that instruction.

• If a landing pad is split, only the section containing the start of the basic
 block retains the `landingpad' attribute.

• The critical edges may not be split.

• The attribute may not be removed.


Dispatch Instruction
====================

The dispatch instruction is the work horse of the exception handling design. It replaces the llvm.eh.selector and llvm.eh.typeid.for intrinsics.

Syntax:

 dispatch resume to label <resumedest>
   catches [
     <type> <val>, label <dest1>
     ...
   ]
   catchall [ <type> <val>, label <dest> ]
   personality [<type> <value>]
   filters [
     <type> <val>, <type> <val>, ...
   ]

The `catches', `catchall', and `filters' clauses are optional. If neither `catches' nor `catchall' is specified, then the landing pad is implicitly a cleanup.

• The `<resumedest>' basic block is the destination to unwind to if the
 exception cannot be handled by this landing pad.

• The `catches' clause is a list of types which the landing pad can handle and
 the destinations to jump to for each type.

• The `catchall' clause is the place to jump to if the exception type doesn't
 match any of the types in the `catches' clause.

• The `personality' clause indicates the personality function for the landing
 pad.

• The `filters' clause lists the types of exceptions which may be thrown by the
 region.


Invoke Instruction
==================

The "invoke" instruction will not change. :-)


Examples
========

Consider this program:

$ cat t.cpp
#include <cstdio>

extern void foo();

struct A { ~A(); };
struct B { ~B(); };
struct C { ~C(); };

void bar() {
 try {
   foo();
   A a;
   foo();
   B b;
   foo();
   C c;
   foo();
 } catch (int i) {
   printf("caught int: %d\n", i);
 } catch (const char *c) {
   printf("caught string: %s\n", c);
 } catch (...) {
   printf("catchall\n");
 }
}

Here's a simplified example of what code would be generated for this (there may be subtle errors...it's handcrafted):

$ llvm-g++ -o - -emit-llvm -S t.cpp -Os

@.str = private constant [16 x i8] c"caught int: %d\0A\00", align 1
@.str1 = private constant [19 x i8] c"caught string: %s\0A\00", align 1
@.str2 = private constant [9 x i8] c"catchall\00", align 1
@_ZTIi = external constant %struct.__fundamental_type_info_pseudo
@_ZTIPKc = external constant %struct.__pointer_type_info_pseudo

define void @_Z3barv() optsize ssp {
entry:
 %a = alloca %struct.A, align 8
 %b = alloca %struct.B, align 8
 %c = alloca %struct.C, align 8
 invoke void @_Z3foov()
         to label %invcont unwind label %catch.handlers

invcont:
 invoke void @_Z3foov()
         to label %invcont1 unwind label %a.dtor

invcont1:
 invoke void @_Z3foov()
         to label %invcont2 unwind label %b.dtor

invcont2:
 invoke void @_Z3foov()
         to label %bb1 unwind label %c.dtor

bb1:
 invoke void @_ZN1CD1Ev(%struct.C* %c)
         to label %bb2 unwind label %b.dtor

bb2:
 invoke void @_ZN1BD1Ev(%struct.B* %b)
         to label %bb3 unwind label %a.dtor

bb3:
 invoke void @_ZN1AD1Ev(%struct.A* %a)
         to label %return unwind label %catch.handlers

return:
 ret void

;; Catch Handlers
catch.handlers: landingpad
 %eh_ptr = call i8* @llvm.eh.exception()
 dispatch resume to label %...
   catches [
     %struct.__fundamental_type_info_pseudo* @_ZTIi, label %ch.int
     %struct.__pointer_type_info_pseudo* @_ZTIPKc, label %ch.str
   ]
   catchall [i8* null, label % ch.ca]

ch.int:
 %t0 = call i8* @__cxa_begin_catch(i8* %eh_ptr) nounwind
 %t1 = bitcast i8* %t0 to i32*
 %t2 = load i32* %t1, align 4
 %t3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([16 x i8]* @.str, i64 0, i64 0), i32 %t2)
 call void @__cxa_end_catch()
 ret void

ch.string:
 %t4 = call i8* @__cxa_begin_catch(i8* %eh_ptr) nounwind
 %t5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([19 x i8]* @.str1, i64 0, i64 0), i8* %t4)
 call void @__cxa_end_catch()
 ret void

ch.ca:
 %t6 = call i8* @__cxa_begin_catch(i8* %eh_ptr) nounwind
 %t7 = call i32 @puts(i8* getelementptr inbounds ([9 x i8]* @.str2, i64 0, i64 0))
 call void @__cxa_end_catch()
 ret void

;; C's d'tor
c.dtor:
 invoke void @_ZN1CD1Ev(%struct.C* %c)
         to label %b.dtor unwind label %lpad.c.dtor

;; B's d'tor
b.dtor:
 invoke void @_ZN1BD1Ev(%struct.B* %b)
         to label %a.dtor unwind label %lpad.b.dtor

;; A's d'tor
a.dtor: landingpad
 invoke void @_ZN1AD1Ev(%struct.A* %a)
         to label %onto.catch.handlers unwind label %lpad.a.dtor

onto.catch.handlers:
 dispatch resume to %lpad

;; Desperate times...
lpad.c.dtor: landingpad
 dispatch resume to %yikes

lpad.b.dtor: landingpad
 dispatch resume to %yikes

lpad.a.dtor: landingpad
 dispatch resume to %yikes

yikes:
 call void @_ZSt9terminatev() noreturn nounwind
 unreachable
}

Because of the invariant that a landing pad must dominate a dispatch and because a landing pad may be branched to only by an invoke and dispatch instructions, the CFG now has enough information in it to collect the information needed to create the exception handling tables.

Well? What do you think? Pretty cool, eh? :-)

-bw


_______________________________________________
LLVM Developers mailing list
LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev



More information about the llvm-commits mailing list