X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=docs%2FExceptionHandling.rst;h=74827c02a272963a6e2b704a20d30700544d7055;hb=01ab2e44cacfe48cf141e438666bb2f368a3c76f;hp=87465343dfefba0a9c0259a212c2f095b293dda5;hpb=cf166560f51c44dce23173ed5ca37745cddfdc22;p=oota-llvm.git diff --git a/docs/ExceptionHandling.rst b/docs/ExceptionHandling.rst index 87465343dfe..74827c02a27 100644 --- a/docs/ExceptionHandling.rst +++ b/docs/ExceptionHandling.rst @@ -162,11 +162,11 @@ pad to the back end. For C++, the ``landingpad`` instruction returns a pointer and integer pair corresponding to the pointer to the *exception structure* and the *selector value* respectively. -The ``landingpad`` instruction takes a reference to the personality function to -be used for this ``try``/``catch`` sequence. The remainder of the instruction is -a list of *cleanup*, *catch*, and *filter* clauses. The exception is tested -against the clauses sequentially from first to last. The clauses have the -following meanings: +The ``landingpad`` instruction looks for a reference to the personality +function to be used for this ``try``/``catch`` sequence in the parent +function's attribute list. The instruction contains a list of *cleanup*, +*catch*, and *filter* clauses. The exception is tested against the clauses +sequentially from first to last. The clauses have the following meanings: - ``catch @ExcType`` @@ -401,6 +401,20 @@ intrinsic serves as a placeholder to delimit code before a catch handler is outlined. After the handler is outlined, this intrinsic is simply removed. +.. _llvm.eh.exceptionpointer: + +``llvm.eh.exceptionpointer`` +---------------------------- + +.. code-block:: llvm + + i8 addrspace(N)* @llvm.eh.padparam.pNi8(token %catchpad) + + +This intrinsic retrieves a pointer to the exception caught by the given +``catchpad``. + + SJLJ Intrinsics --------------- @@ -508,16 +522,12 @@ table. Exception Handling using the Windows Runtime ================================================= -(Note: Windows C++ exception handling support is a work in progress and is not -yet fully implemented. The text below describes how it will work when -completed.) - Background on Windows exceptions --------------------------------- -Interacting with exceptions on Windows is significantly more complicated than on -Itanium C++ ABI platforms. The fundamental difference between the two models is -that Itanium EH is designed around the idea of "successive unwinding," while +Interacting with exceptions on Windows is significantly more complicated than +on Itanium C++ ABI platforms. The fundamental difference between the two models +is that Itanium EH is designed around the idea of "successive unwinding," while Windows EH is not. Under Itanium, throwing an exception typically involes allocating thread local @@ -604,30 +614,33 @@ purposes. The following new instructions are considered "exception handling pads", in that they must be the first non-phi instruction of a basic block that may be the -unwind destination of an invoke: ``catchpad``, ``cleanuppad``, and -``terminatepad``. As with landingpads, when entering a try scope, if the +unwind destination of an EH flow edge: +``catchswitch``, ``catchpad``, and ``cleanuppad``. +As with landingpads, when entering a try scope, if the frontend encounters a call site that may throw an exception, it should emit an -invoke that unwinds to a ``catchpad`` block. Similarly, inside the scope of a -C++ object with a destructor, invokes should unwind to a ``cleanuppad``. The -``terminatepad`` instruction exists to represent ``noexcept`` and throw -specifications with one combined instruction. All potentially throwing calls in -a ``noexcept`` function should transitively unwind to a terminateblock. Throw -specifications are not implemented by MSVC, and are not yet supported. - -Each of these new EH pad instructions has a label operand that indicates which -action should be considered after this action. The ``catchpad`` and -``terminatepad`` instructions are terminators, and this label is considered to -be an unwind destination analogous to the unwind destination of an invoke. The -``cleanuppad`` instruction is different from the other two in that it is not a -terminator, and this label operand is not an edge in the CFG. The code inside a -cleanuppad runs before transferring control to the next action, so the -``cleanupret`` instruction is the instruction that unwinds to the next EH pad. -All of these "unwind edges" may refer to a basic block that contains an EH pad -instruction, or they may simply unwind to the caller. Unwinding to the caller -has roughly the same semantics as the ``resume`` instruction in the -``landingpad`` model. When inlining through an invoke, instructions that unwind -to the caller are hooked up to unwind to the unwind destination of the call -site. +invoke that unwinds to a ``catchswitch`` block. Similarly, inside the scope of a +C++ object with a destructor, invokes should unwind to a ``cleanuppad``. + +New instructions are also used to mark the points where control is transferred +out of a catch/cleanup handler (which will correspond to exits from the +generated funclet). A catch handler which reaches its end by normal execution +executes a ``catchret`` instruction, which is a terminator indicating where in +the function control is returned to. A cleanup handler which reaches its end +by normal execution executes a ``cleanupret`` instruction, which is a terminator +indicating where the active exception will unwind to next. + +Each of these new EH pad instructions has a way to identify which action should +be considered after this action. The ``catchswitch`` instruction is a terminator +and has an unwind destination operand analogous to the unwind destination of an +invoke. The ``cleanuppad`` instruction is not +a terminator, so the unwind destination is stored on the ``cleanupret`` +instruction instead. Successfully executing a catch handler should resume +normal control flow, so neither ``catchpad`` nor ``catchret`` instructions can +unwind. All of these "unwind edges" may refer to a basic block that contains an +EH pad instruction, or they may unwind to the caller. Unwinding to the caller +has roughly the same semantics as the ``resume`` instruction in the landingpad +model. When inlining through an invoke, instructions that unwind to the caller +are hooked up to unwind to the unwind destination of the call site. Putting things together, here is a hypothetical lowering of some C++ that uses all of the new IR instructions: @@ -645,6 +658,7 @@ all of the new IR instructions: Cleanup obj; may_throw(); } catch (int e) { + may_throw(); return e; } return 0; @@ -667,26 +681,97 @@ all of the new IR instructions: call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind br label %return - return: ; preds = %invoke.cont.2, %catch - %retval.0 = phi i32 [ 0, %invoke.cont.2 ], [ %9, %catch ] + return: ; preds = %invoke.cont.3, %invoke.cont.2 + %retval.0 = phi i32 [ 0, %invoke.cont.2 ], [ %3, %invoke.cont.3 ] ret i32 %retval.0 - ; EH scope code, ordered innermost to outermost: + lpad.cleanup: ; preds = %invoke.cont.2 + %0 = cleanuppad within none [] + call void @"\01??1Cleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind + cleanupret %0 unwind label %lpad.catch - lpad.cleanup: ; preds = %invoke.cont - cleanuppad [label %lpad.catch] - call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind - cleanupret unwind label %lpad.catch + lpad.catch: ; preds = %lpad.cleanup, %entry + %1 = catchswitch within none [label %catch.body] unwind label %lpad.terminate + + catch.body: ; preds = %lpad.catch + %catch = catchpad within %1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e] + invoke void @"\01?may_throw@@YAXXZ"() + to label %invoke.cont.3 unwind label %lpad.terminate + + invoke.cont.3: ; preds = %catch.body + %3 = load i32, i32* %e, align 4 + catchret from %catch to label %return + + lpad.terminate: ; preds = %catch.body, %lpad.catch + cleanuppad within none [] + call void @"\01?terminate@@YAXXZ" + unreachable + } + +Funclet parent tokens +----------------------- - lpad.catch: ; preds = %entry, %lpad.cleanup - catchpad void [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e] - to label %catch unwind label %lpad.terminate +In order to produce tables for EH personalities that use funclets, it is +necessary to recover the nesting that was present in the source. This funclet +parent relationship is encoded in the IR using tokens produced by the new "pad" +instructions. The token operand of a "pad" or "ret" instruction indicates which +funclet it is in, or "none" if it is not nested within another funclet. - catch: ; preds = %lpad.catch - %9 = load i32, i32* %e, align 4 - catchret label %return +The ``catchpad`` and ``cleanuppad`` instructions establish new funclets, and +their tokens are consumed by other "pad" instructions to establish membership. +The ``catchswitch`` instruction does not create a funclet, but it produces a +token that is always consumed by its immediate successor ``catchpad`` +instructions. This ensures that every catch handler modelled by a ``catchpad`` +belongs to exactly one ``catchswitch``, which models the dispatch point after a +C++ try. - lpad.terminate: - terminatepad [void ()* @"\01?terminate@@YAXXZ"] - unwind to caller +Here is an example of what this nesting looks like using some hypothetical +C++ code: + +.. code-block:: c + + void f() { + try { + throw; + } catch (...) { + try { + throw; + } catch (...) { + } + } + } + +.. code-block:: llvm + + define void @f() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { + entry: + invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 + to label %unreachable unwind label %catch.dispatch + + catch.dispatch: ; preds = %entry + %0 = catchswitch within none [label %catch] unwind to caller + + catch: ; preds = %catch.dispatch + %1 = catchpad within %0 [i8* null, i32 64, i8* null] + invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 + to label %unreachable unwind label %catch.dispatch2 + + catch.dispatch2: ; preds = %catch + %2 = catchswitch within %1 [label %catch3] unwind to caller + + catch3: ; preds = %catch.dispatch2 + %3 = catchpad within %2 [i8* null, i32 64, i8* null] + catchret from %3 to label %try.cont + + try.cont: ; preds = %catch3 + catchret from %1 to label %try.cont6 + + try.cont6: ; preds = %try.cont + ret void + + unreachable: ; preds = %catch, %entry + unreachable } + +The "inner" ``catchswitch`` consumes ``%1`` which is produced by the outer +catchswitch.