Skip to content

Commit

Permalink
[WinEH] Require token linkage in EH pad/ret signatures
Browse files Browse the repository at this point in the history
Summary:
WinEHPrepare is going to require that cleanuppad and catchpad produce values
of token type which are consumed by any cleanupret or catchret exiting the
pad.  This change updates the signatures of those operators to require/enforce
that the type produced by the pads is token type and that the rets have an
appropriate argument.

The catchpad argument of a `CatchReturnInst` must be a `CatchPadInst` (and
similarly for `CleanupReturnInst`/`CleanupPadInst`).  To accommodate that
restriction, this change adds a notion of an operator constraint to both
LLParser and BitcodeReader, allowing appropriate sentinels to be constructed
for forward references and appropriate error messages to be emitted for
illegal inputs.

Also add a verifier rule (noted in LangRef) that a catchpad with a catchpad
predecessor must have no other predecessors; this ensures that WinEHPrepare
will see the expected linear relationship between sibling catches on the
same try.

Lastly, remove some superfluous/vestigial casts from instruction operand
setters operating on BasicBlocks.

Reviewers: rnk, majnemer

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D12108

llvm-svn: 245797
  • Loading branch information
JosephTremoulet committed Aug 23, 2015
1 parent 0732e16 commit 8220bcc
Show file tree
Hide file tree
Showing 21 changed files with 738 additions and 532 deletions.
31 changes: 15 additions & 16 deletions llvm/docs/ExceptionHandling.rst
Expand Up @@ -614,20 +614,19 @@ 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
Each of these new EH pad instructions has a way to identify 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
``terminatepad`` instructions are terminators, and have a label operand 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.
terminator. The code inside a cleanuppad runs before transferring control to the
next action, so the ``cleanupret`` instruction is the instruction that holds a
label operand and 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.

Putting things together, here is a hypothetical lowering of some C++ that uses
all of the new IR instructions:
Expand Down Expand Up @@ -674,17 +673,17 @@ all of the new IR instructions:
; EH scope code, ordered innermost to outermost:
lpad.cleanup: ; preds = %invoke.cont
cleanuppad [label %lpad.catch]
%cleanup = cleanuppad []
call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind
cleanupret unwind label %lpad.catch
cleanupret %cleanup unwind label %lpad.catch
lpad.catch: ; preds = %entry, %lpad.cleanup
catchpad void [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e]
%catch = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e]
to label %catch unwind label %lpad.terminate
catch: ; preds = %lpad.catch
%9 = load i32, i32* %e, align 4
catchret label %return
catchret %catch label %return
lpad.terminate:
terminatepad [void ()* @"\01?terminate@@YAXXZ"]
Expand Down
94 changes: 57 additions & 37 deletions llvm/docs/LangRef.rst
Expand Up @@ -5138,7 +5138,7 @@ Syntax:

::

<resultval> = catchpad <resultty> [<args>*]
<resultval> = catchpad [<args>*]
to label <normal label> unwind label <exception label>

Overview:
Expand All @@ -5153,9 +5153,9 @@ routine requires to know if this is an appropriate place to catch the
exception. Control is tranfered to the ``exception`` label if the
``catchpad`` is not an appropriate handler for the in-flight exception.
The ``normal`` label should contain the code found in the ``catch``
portion of a ``try``/``catch`` sequence. It defines values supplied by
the :ref:`personality function <personalityfn>` upon re-entry to the
function. The ``resultval`` has the type ``resultty``.
portion of a ``try``/``catch`` sequence. The ``resultval`` has the type
:ref:`token <t_token>` and is used to match the ``catchpad`` to
corresponding :ref:`catchrets <i_catchret>`.

Arguments:
""""""""""
Expand All @@ -5170,15 +5170,11 @@ label to transfer control to if it doesn't.
Semantics:
""""""""""

The '``catchpad``' instruction defines the values which are set by the
:ref:`personality function <personalityfn>` upon re-entry to the function, and
therefore the "result type" of the ``catchpad`` instruction. As with
calling conventions, how the personality function results are
represented in LLVM IR is target specific.

When the call stack is being unwound due to an exception being thrown,
the exception is compared against the ``args``. If it doesn't match,
then control is transfered to the ``exception`` basic block.
As with calling conventions, how the personality function results are
represented in LLVM IR is target specific.

The ``catchpad`` instruction has several restrictions:

Expand All @@ -5192,19 +5188,22 @@ The ``catchpad`` instruction has several restrictions:
catch block.
- A basic block that is not a catch block may not include a
'``catchpad``' instruction.
- A catch block which has another catch block as a predecessor may not have
any other predecessors.
- It is undefined behavior for control to transfer from a ``catchpad`` to a
``cleanupret`` without first executing a ``catchret`` and a subsequent
``cleanuppad``.
- It is undefined behavior for control to transfer from a ``catchpad`` to a
``ret`` without first executing a ``catchret``.
``ret`` without first executing a ``catchret`` that consumes the
``catchpad`` or unwinding through its ``catchendpad``.
- It is undefined behavior for control to transfer from a ``catchpad`` to
itself without first executing a ``catchret`` that consumes the
``catchpad`` or unwinding through its ``catchendpad``.

Example:
""""""""

.. code-block:: llvm
;; A catch block which can catch an integer.
%res = catchpad { i8*, i32 } [i8** @_ZTIi]
%tok = catchpad [i8** @_ZTIi]
to label %int.handler unwind label %terminate
.. _i_catchendpad:
Expand Down Expand Up @@ -5264,7 +5263,8 @@ The ``catchendpad`` instruction has several restrictions:
'``catchendpad``' instruction.
- Exactly one catch block may unwind to a ``catchendpad``.
- The unwind target of invokes between a ``catchpad`` and a
corresponding ``catchret`` must be its ``catchendpad``.
corresponding ``catchret`` must be its ``catchendpad`` or
an inner EH pad.

Example:
""""""""
Expand All @@ -5284,7 +5284,7 @@ Syntax:

::

catchret <type> <value> to label <normal>
catchret <value> to label <normal>

Overview:
"""""""""
Expand All @@ -5296,8 +5296,10 @@ single successor.
Arguments:
""""""""""

The '``catchret``' instruction requires one argument which specifies
where control will transfer to next.
The first argument to a '``catchret``' indicates which ``catchpad`` it
exits. It must be a :ref:`catchpad <i_catchpad>`.
The second argument to a '``catchret``' specifies where control will
transfer to next.

Semantics:
""""""""""
Expand All @@ -5309,13 +5311,21 @@ The :ref:`personality function <personalityfn>` gets a chance to execute
arbitrary code to, for example, run a C++ destructor.
Control then transfers to ``normal``.
It may be passed an optional, personality specific, value.
It is undefined behavior to execute a ``catchret`` whose ``catchpad`` has
not been executed.
It is undefined behavior to execute a ``catchret`` if any ``catchpad`` or
``cleanuppad`` has been executed, without subsequently executing a
corresponding ``catchret``/``cleanupret`` or unwinding out of the inner
pad, following the most recent execution of the ``catchret``'s corresponding
``catchpad``.


Example:
""""""""

.. code-block:: llvm
catchret label %continue
catchret %catch label %continue
.. _i_cleanupret:

Expand All @@ -5327,8 +5337,8 @@ Syntax:

::

cleanupret <type> <value> unwind label <continue>
cleanupret <type> <value> unwind to caller
cleanupret <value> unwind label <continue>
cleanupret <value> unwind to caller

Overview:
"""""""""
Expand All @@ -5340,9 +5350,9 @@ an optional successor.
Arguments:
""""""""""

The '``cleanupret``' instruction requires one argument, which must have the
same type as the result of any '``cleanuppad``' instruction in the same
function. It also has an optional successor, ``continue``.
The '``cleanupret``' instruction requires one argument, which indicates
which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad <i_cleanuppad>`.
It also has an optional successor, ``continue``.

Semantics:
""""""""""
Expand All @@ -5351,14 +5361,21 @@ The '``cleanupret``' instruction indicates to the
:ref:`personality function <personalityfn>` that one
:ref:`cleanuppad <i_cleanuppad>` it transferred control to has ended.
It transfers control to ``continue`` or unwinds out of the function.
It is undefined behavior to execute a ``cleanupret`` whose ``cleanuppad`` has
not been executed.
It is undefined behavior to execute a ``cleanupret`` if any ``catchpad`` or
``cleanuppad`` has been executed, without subsequently executing a
corresponding ``catchret``/``cleanupret`` or unwinding out of the inner pad,
following the most recent execution of the ``cleanupret``'s corresponding
``cleanuppad``.

Example:
""""""""

.. code-block:: llvm
cleanupret void unwind to caller
cleanupret { i8*, i32 } %exn unwind label %continue
cleanupret %cleanup unwind to caller
cleanupret %cleanup unwind label %continue
.. _i_terminatepad:

Expand Down Expand Up @@ -8391,7 +8408,7 @@ Syntax:

::

<resultval> = cleanuppad <resultty> [<args>*]
<resultval> = cleanuppad [<args>*]

Overview:
"""""""""
Expand All @@ -8403,7 +8420,8 @@ transfer control to run cleanup actions.
The ``args`` correspond to whatever additional
information the :ref:`personality function <personalityfn>` requires to
execute the cleanup.
The ``resultval`` has the type ``resultty``.
The ``resultval`` has the type :ref:`token <t_token>` and is used to
match the ``cleanuppad`` to corresponding :ref:`cleanuprets <i_cleanupret>`.

Arguments:
""""""""""
Expand All @@ -8415,9 +8433,8 @@ Semantics:
""""""""""

The '``cleanuppad``' instruction defines the values which are set by the
:ref:`personality function <personalityfn>` upon re-entry to the function, and
therefore the "result type" of the ``cleanuppad`` instruction. As with
calling conventions, how the personality function results are
:ref:`personality function <personalityfn>` upon re-entry to the function.
As with calling conventions, how the personality function results are
represented in LLVM IR is target specific.

When the call stack is being unwound due to an exception being thrown,
Expand All @@ -8434,18 +8451,21 @@ The ``cleanuppad`` instruction has several restrictions:
cleanup block.
- A basic block that is not a cleanup block may not include a
'``cleanuppad``' instruction.
- All ``cleanupret``s which exit a cleanuppad must have the same
exceptional successor.
- It is undefined behavior for control to transfer from a ``cleanuppad`` to a
``catchret`` without first executing a ``cleanupret`` and a subsequent
``catchpad``.
- It is undefined behavior for control to transfer from a ``cleanuppad`` to a
``ret`` without first executing a ``cleanupret``.
``ret`` without first executing a ``cleanupret`` that consumes the
``cleanuppad`` or unwinding out of the ``cleanuppad``.
- It is undefined behavior for control to transfer from a ``cleanuppad`` to
itself without first executing a ``cleanupret`` that consumes the
``cleanuppad`` or unwinding out of the ``cleanuppad``.

Example:
""""""""

.. code-block:: llvm
%res = cleanuppad { i8*, i32 } [label %nextaction]
%tok = cleanuppad []
.. _intrinsics:

Expand Down
6 changes: 3 additions & 3 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Expand Up @@ -356,9 +356,9 @@ namespace bitc {
FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align,
// vol,ordering,synchscope]
FUNC_CODE_INST_LANDINGPAD = 47, // LANDINGPAD: [ty,val,num,id0,val0...]
FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [] or [val] or [bb#] or [val,bb#]
FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [bb#]
FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [ty,val,val,num,args...]
FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [val] or [val,bb#]
FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [val,bb#]
FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [bb#,bb#,num,args...]
FUNC_CODE_INST_TERMINATEPAD = 51, // TERMINATEPAD: [bb#,num,args...]
FUNC_CODE_INST_CLEANUPPAD = 52, // CLEANUPPAD: [num,args...]
FUNC_CODE_INST_CATCHENDPAD = 53, // CATCHENDPAD: [] or [bb#]
Expand Down
21 changes: 10 additions & 11 deletions llvm/include/llvm/IR/IRBuilder.h
Expand Up @@ -671,15 +671,14 @@ class IRBuilder : public IRBuilderBase, public Inserter {
return Insert(ResumeInst::Create(Exn));
}

CleanupReturnInst *CreateCleanupRet(BasicBlock *UnwindBB = nullptr,
Value *RetVal = nullptr) {
return Insert(CleanupReturnInst::Create(Context, RetVal, UnwindBB));
CleanupReturnInst *CreateCleanupRet(CleanupPadInst *CleanupPad,
BasicBlock *UnwindBB = nullptr) {
return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB));
}

CatchPadInst *CreateCatchPad(Type *Ty, BasicBlock *NormalDest,
BasicBlock *UnwindDest, ArrayRef<Value *> Args,
const Twine &Name = "") {
return Insert(CatchPadInst::Create(Ty, NormalDest, UnwindDest, Args), Name);
CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest,
ArrayRef<Value *> Args, const Twine &Name = "") {
return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name);
}

CatchEndPadInst *CreateCatchEndPad(BasicBlock *UnwindBB = nullptr) {
Expand All @@ -692,13 +691,13 @@ class IRBuilder : public IRBuilderBase, public Inserter {
return Insert(TerminatePadInst::Create(Context, UnwindBB, Args), Name);
}

CleanupPadInst *CreateCleanupPad(Type *Ty, ArrayRef<Value *> Args,
CleanupPadInst *CreateCleanupPad(ArrayRef<Value *> Args,
const Twine &Name = "") {
return Insert(CleanupPadInst::Create(Ty, Args), Name);
return Insert(CleanupPadInst::Create(Context, Args), Name);
}

CatchReturnInst *CreateCatchRet(BasicBlock *BB, Value *RetVal = nullptr) {
return Insert(CatchReturnInst::Create(BB, RetVal));
CatchReturnInst *CreateCatchRet(CatchPadInst *CatchPad, BasicBlock *BB) {
return Insert(CatchReturnInst::Create(CatchPad, BB));
}

UnreachableInst *CreateUnreachable() {
Expand Down

0 comments on commit 8220bcc

Please sign in to comment.