[WinEH] Add cleanupendpad instruction
authorJoseph Tremoulet <jotrem@microsoft.com>
Thu, 3 Sep 2015 09:09:43 +0000 (09:09 +0000)
committerJoseph Tremoulet <jotrem@microsoft.com>
Thu, 3 Sep 2015 09:09:43 +0000 (09:09 +0000)
Summary:
Add a `cleanupendpad` instruction, used to mark exceptional exits out of
cleanups (for languages/targets that can abort a cleanup with another
exception).  The `cleanupendpad` instruction is similar to the `catchendpad`
instruction in that it is an EH pad which is the target of unwind edges in
the handler and which itself has an unwind edge to the next EH action.
The `cleanupendpad` instruction, similar to `cleanupret` has a `cleanuppad`
argument indicating which cleanup it exits.  The unwind successors of a
`cleanuppad`'s `cleanupendpad`s must agree with each other and with its
`cleanupret`s.

Update WinEHPrepare (and docs/tests) to accomodate `cleanupendpad`.

Reviewers: rnk, andrew.w.kaylor, majnemer

Subscribers: llvm-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246751 91177308-0d34-0410-b5e6-96231b3b80d8

31 files changed:
docs/ExceptionHandling.rst
docs/LangRef.rst
include/llvm-c/Core.h
include/llvm/Bitcode/LLVMBitCodes.h
include/llvm/IR/IRBuilder.h
include/llvm/IR/InstVisitor.h
include/llvm/IR/InstrTypes.h
include/llvm/IR/Instruction.def
include/llvm/IR/Instruction.h
include/llvm/IR/Instructions.h
lib/Analysis/ValueTracking.cpp
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLParser.h
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
lib/CodeGen/TargetLoweringBase.cpp
lib/CodeGen/WinEHPrepare.cpp
lib/IR/AsmWriter.cpp
lib/IR/Instruction.cpp
lib/IR/Instructions.cpp
lib/IR/Verifier.cpp
lib/Transforms/Instrumentation/MemorySanitizer.cpp
lib/Transforms/Utils/InlineFunction.cpp
test/Assembler/invalid-OperatorConstraint.ll
test/Feature/exception.ll
test/Transforms/MergeFunc/call-and-invoke-with-ranges.ll
tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp

index fce875b9b8ab46a0aa7b40bbbeebd9388022d45b..2f09155dff2f3b8fbc0e716ac7f30f70eb505ea1 100644 (file)
@@ -614,19 +614,32 @@ 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.
 
 a ``noexcept`` function should transitively unwind to a terminateblock. Throw
 specifications are not implemented by MSVC, and are not yet supported.
 
+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.  A catch or cleanup
+handler which is exited by another exception being raised during its execution will
+unwind through a ``catchendpad`` or ``cleanuupendpad`` (respectively).  The
+``catchendpad`` and ``cleanupendpad`` instructions are considered "exception
+handling pads" in the same sense that ``catchpad``, ``cleanuppad``, and
+``terminatepad`` are.
+
 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 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. The code inside a cleanuppad runs before transferring control to the
 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 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. 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.
+next action, so the ``cleanupret`` and ``cleanupendpad`` instructions are the
+instructions that hold a label operand and unwind 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:
 
 Putting things together, here is a hypothetical lowering of some C++ that uses
 all of the new IR instructions:
@@ -644,6 +657,7 @@ all of the new IR instructions:
       Cleanup obj;
       may_throw();
     } catch (int e) {
       Cleanup obj;
       may_throw();
     } catch (int e) {
+      may_throw();
       return e;
     }
     return 0;
       return e;
     }
     return 0;
@@ -666,7 +680,7 @@ all of the new IR instructions:
     call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind
     br label %return
 
     call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind
     br label %return
 
-  return:                                           ; preds = %invoke.cont.2, %catch
+  return:                                           ; preds = %invoke.cont.2, %invoke.cont.3
     %retval.0 = phi i32 [ 0, %invoke.cont.2 ], [ %9, %catch ]
     ret i32 %retval.0
 
     %retval.0 = phi i32 [ 0, %invoke.cont.2 ], [ %9, %catch ]
     ret i32 %retval.0
 
@@ -679,13 +693,20 @@ all of the new IR instructions:
 
   lpad.catch:                                       ; preds = %entry, %lpad.cleanup
     %catch = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e]
 
   lpad.catch:                                       ; preds = %entry, %lpad.cleanup
     %catch = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e]
-            to label %catch unwind label %lpad.terminate
+            to label %catch.body unwind label %catchend
 
 
-  catch:                                            ; preds = %lpad.catch
+  catch.body:                                       ; preds = %lpad.catch
+    invoke void @"\01?may_throw@@YAXXZ"()
+            to label %invoke.cont.3 unwind label %catchend
+
+  invoke.cont.3:                                    ; preds = %catch.body
     %9 = load i32, i32* %e, align 4
     catchret %catch label %return
 
     %9 = load i32, i32* %e, align 4
     catchret %catch label %return
 
-  lpad.terminate:
+  catchend:                                         ; preds = %lpad.catch, %catch.body
+    catchendpad unwind label %lpad.terminate
+
+  lpad.terminate:                                   ; preds = %catchend
     terminatepad [void ()* @"\01?terminate@@YAXXZ"]
             unwind to caller
   }
     terminatepad [void ()* @"\01?terminate@@YAXXZ"]
             unwind to caller
   }
index 1209e1db5a2fb134f90b5efa14327ea5f980d26c..b58fcf9b5ae190ff2ae14dea536047987288a8a1 100644 (file)
@@ -4782,6 +4782,7 @@ The terminator instructions are: ':ref:`ret <i_ret>`',
 ':ref:`resume <i_resume>`', ':ref:`catchpad <i_catchpad>`',
 ':ref:`catchendpad <i_catchendpad>`',
 ':ref:`catchret <i_catchret>`',
 ':ref:`resume <i_resume>`', ':ref:`catchpad <i_catchpad>`',
 ':ref:`catchendpad <i_catchendpad>`',
 ':ref:`catchret <i_catchret>`',
+':ref:`cleanupendpad <i_cleanupendpad>`',
 ':ref:`cleanupret <i_cleanupret>`',
 ':ref:`terminatepad <i_terminatepad>`',
 and ':ref:`unreachable <i_unreachable>`'.
 ':ref:`cleanupret <i_cleanupret>`',
 ':ref:`terminatepad <i_terminatepad>`',
 and ':ref:`unreachable <i_unreachable>`'.
@@ -5235,7 +5236,11 @@ Overview:
 The '``catchendpad``' instruction is used by `LLVM's exception handling
 system <ExceptionHandling.html#overview>`_ to communicate to the
 :ref:`personality function <personalityfn>` which invokes are associated
 The '``catchendpad``' instruction is used by `LLVM's exception handling
 system <ExceptionHandling.html#overview>`_ to communicate to the
 :ref:`personality function <personalityfn>` which invokes are associated
-with a chain of :ref:`catchpad <i_catchpad>` instructions.
+with a chain of :ref:`catchpad <i_catchpad>` instructions; propagating an
+exception out of a catch handler is represented by unwinding through its
+``catchendpad``.  Unwinding to the outer scope when a chain of catch handlers
+do not handle an exception is also represented by unwinding through their
+``catchendpad``.
 
 The ``nextaction`` label indicates where control should transfer to if
 none of the ``catchpad`` instructions are suitable for catching the
 
 The ``nextaction`` label indicates where control should transfer to if
 none of the ``catchpad`` instructions are suitable for catching the
@@ -5268,13 +5273,23 @@ The ``catchendpad`` instruction has several restrictions:
 -  A catch-end block must have a '``catchendpad``' instruction as its
    first non-PHI instruction.
 -  There can be only one '``catchendpad``' instruction within the
 -  A catch-end block must have a '``catchendpad``' instruction as its
    first non-PHI instruction.
 -  There can be only one '``catchendpad``' instruction within the
-   catch block.
+   catch-end block.
 -  A basic block that is not a catch-end block may not include a
    '``catchendpad``' instruction.
 -  Exactly one catch block may unwind to a ``catchendpad``.
 -  A basic block that is not a catch-end block may not include a
    '``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`` or
-   an inner EH pad.
+- It is undefined behavior to execute a ``catchendpad`` if none of the
+  '``catchpad``'s chained to it have been executed.
+- It is undefined behavior to execute a ``catchendpad`` twice without an
+  intervening execution of one or more of the '``catchpad``'s chained to it.
+- It is undefined behavior to execute a ``catchendpad`` if, after the most
+  recent execution of the normal successor edge of any ``catchpad`` chained
+  to it, some ``catchret`` consuming that ``catchpad`` has already been
+  executed.
+- It is undefined behavior to execute a ``catchendpad`` if, after the most
+  recent execution of the normal successor edge of any ``catchpad`` chained
+  to it, any other ``catchpad`` or ``cleanuppad`` has been executed but has
+  not had a corresponding
+  ``catchret``/``cleanupret``/``catchendpad``/``cleanupendpad`` executed.
 
 Example:
 """"""""
 
 Example:
 """"""""
@@ -5321,14 +5336,18 @@ 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.
 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`` 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``.
 
 
+It is undefined behavior to execute a ``catchret`` if, after the most recent
+execution of its ``catchpad``, some ``catchret`` or ``catchendpad`` linked
+to the same ``catchpad`` has already been executed.
+
+It is undefined behavior to execute a ``catchret`` if, after the most recent
+execution of its ``catchpad``, any other ``catchpad`` or ``cleanuppad`` has
+been executed but has not had a corresponding
+``catchret``/``cleanupret``/``catchendpad``/``cleanupendpad`` executed.
 
 Example:
 """"""""
 
 Example:
 """"""""
@@ -5337,6 +5356,79 @@ Example:
 
       catchret %catch label %continue
 
 
       catchret %catch label %continue
 
+.. _i_cleanupendpad:
+
+'``cleanupendpad``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      cleanupendpad <value> unwind label <nextaction>
+      cleanupendpad <value> unwind to caller
+
+Overview:
+"""""""""
+
+The '``cleanupendpad``' instruction is used by `LLVM's exception handling
+system <ExceptionHandling.html#overview>`_ to communicate to the
+:ref:`personality function <personalityfn>` which invokes are associated
+with a :ref:`cleanuppad <i_cleanuppad>` instructions; propagating an exception
+out of a cleanup is represented by unwinding through its ``cleanupendpad``.
+
+The ``nextaction`` label indicates where control should unwind to next, in the
+event that a cleanup is exited by means of an(other) exception being raised.
+
+If a ``nextaction`` label is not present, the instruction unwinds out of
+its parent function. The
+:ref:`personality function <personalityfn>` will continue processing
+exception handling actions in the caller.
+
+Arguments:
+""""""""""
+
+The '``cleanupendpad``' instruction requires one argument, which indicates
+which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad <i_cleanuppad>`.
+It also has an optional successor, ``nextaction``, indicating where control
+should transfer to.
+
+Semantics:
+""""""""""
+
+When and exception propagates to a ``cleanupendpad``, control is transfered to
+``nextaction`` if it is present. If it is not present, control is transfered to
+the caller.
+
+The ``cleanupendpad`` instruction has several restrictions:
+
+-  A cleanup-end block is a basic block which is the unwind destination of
+   an exceptional instruction.
+-  A cleanup-end block must have a '``cleanupendpad``' instruction as its
+   first non-PHI instruction.
+-  There can be only one '``cleanupendpad``' instruction within the
+   cleanup-end block.
+-  A basic block that is not a cleanup-end block may not include a
+   '``cleanupendpad``' instruction.
+- It is undefined behavior to execute a ``cleanupendpad`` whose ``cleanuppad``
+  has not been executed.
+- It is undefined behavior to execute a ``cleanupendpad`` if, after the most
+  recent execution of its ``cleanuppad``, some ``cleanupret`` or ``cleanupendpad``
+  consuming the same ``cleanuppad`` has already been executed.
+- It is undefined behavior to execute a ``cleanupendpad`` if, after the most
+  recent execution of its ``cleanuppad``, any other ``cleanuppad`` or
+  ``catchpad`` has been executed but has not had a corresponding
+  ``cleanupret``/``catchret``/``cleanupendpad``/``catchendpad`` executed.
+
+Example:
+""""""""
+
+.. code-block:: llvm
+
+      cleanupendpad %cleanup unwind label %terminate
+      cleanupendpad %cleanup unwind to caller
+
 .. _i_cleanupret:
 
 '``cleanupret``' Instruction
 .. _i_cleanupret:
 
 '``cleanupret``' Instruction
@@ -5371,13 +5463,18 @@ 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.
 :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`` 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``.
+
+It is undefined behavior to execute a ``cleanupret`` if, after the most recent
+execution of its ``cleanuppad``, some ``cleanupret`` or ``cleanupendpad``
+consuming the same ``cleanuppad`` has already been executed.
+
+It is undefined behavior to execute a ``cleanupret`` if, after the most recent
+execution of its ``cleanuppad``, any other ``cleanuppad`` or ``catchpad`` has
+been executed but has not had a corresponding
+``cleanupret``/``catchret``/``cleanupendpad``/``catchendpad`` executed.
 
 Example:
 """"""""
 
 Example:
 """"""""
@@ -8431,7 +8528,8 @@ The ``args`` correspond to whatever additional
 information the :ref:`personality function <personalityfn>` requires to
 execute the cleanup.
 The ``resultval`` has the type :ref:`token <t_token>` and is used to
 information the :ref:`personality function <personalityfn>` requires to
 execute the cleanup.
 The ``resultval`` has the type :ref:`token <t_token>` and is used to
-match the ``cleanuppad`` to corresponding :ref:`cleanuprets <i_cleanupret>`.
+match the ``cleanuppad`` to corresponding :ref:`cleanuprets <i_cleanupret>`
+and :ref:`cleanupendpads <i_cleanupendpad>`.
 
 Arguments:
 """"""""""
 
 Arguments:
 """"""""""
@@ -8442,14 +8540,11 @@ by the :ref:`personality function <personalityfn>`.
 Semantics:
 """"""""""
 
 Semantics:
 """"""""""
 
-The '``cleanuppad``' instruction defines the values which are set by the
-: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,
 the :ref:`personality function <personalityfn>` transfers control to the
 ``cleanuppad`` with the aid of the personality-specific arguments.
 When the call stack is being unwound due to an exception being thrown,
 the :ref:`personality function <personalityfn>` transfers control to the
 ``cleanuppad`` with the aid of the personality-specific arguments.
+As with calling conventions, how the personality function results are
+represented in LLVM IR is target specific.
 
 The ``cleanuppad`` instruction has several restrictions:
 
 
 The ``cleanuppad`` instruction has several restrictions:
 
@@ -8461,14 +8556,14 @@ The ``cleanuppad`` instruction has several restrictions:
    cleanup block.
 -  A basic block that is not a cleanup block may not include a
    '``cleanuppad``' instruction.
    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.
+-  All '``cleanupret``'s and '``cleanupendpad``'s which consume a ``cleanuppad``
+   must have the same exceptional successor.
 -  It is undefined behavior for control to transfer from a ``cleanuppad`` to a
 -  It is undefined behavior for control to transfer from a ``cleanuppad`` to a
-   ``ret`` without first executing a ``cleanupret`` that consumes the
-   ``cleanuppad`` or unwinding out of the ``cleanuppad``.
+   ``ret`` without first executing a ``cleanupret`` or ``cleanupendpad`` that
+   consumes the ``cleanuppad``.
 -  It is undefined behavior for control to transfer from a ``cleanuppad`` to
 -  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``.
+   itself without first executing a ``cleanupret`` or ``cleanupendpad`` that
+   consumes the ``cleanuppad``.
 
 Example:
 """"""""
 
 Example:
 """"""""
index 3bb8828fe849cb113503e5f0bfe5df9d11a0ec5d..146758542662fa1c8b6c6e510848c1d3bd7e9c27 100644 (file)
@@ -251,10 +251,11 @@ typedef enum {
   LLVMLandingPad     = 59,
   LLVMCleanupRet     = 61,
   LLVMCatchRet       = 62,
   LLVMLandingPad     = 59,
   LLVMCleanupRet     = 61,
   LLVMCatchRet       = 62,
-  LLVMCatchPad     = 63,
-  LLVMTerminatePad = 64,
-  LLVMCleanupPad   = 65,
-  LLVMCatchEndPad  = 66
+  LLVMCatchPad       = 63,
+  LLVMTerminatePad   = 64,
+  LLVMCleanupPad     = 65,
+  LLVMCatchEndPad    = 66,
+  LLVMCleanupEndPad  = 67
 
 } LLVMOpcode;
 
 
 } LLVMOpcode;
 
@@ -1228,6 +1229,7 @@ LLVMTypeRef LLVMX86MMXType(void);
         macro(CatchPadInst)               \
         macro(TerminatePadInst)           \
         macro(CatchEndPadInst)            \
         macro(CatchPadInst)               \
         macro(TerminatePadInst)           \
         macro(CatchEndPadInst)            \
+        macro(CleanupEndPadInst)            \
       macro(UnaryInstruction)               \
         macro(AllocaInst)                   \
         macro(CastInst)                     \
       macro(UnaryInstruction)               \
         macro(AllocaInst)                   \
         macro(CastInst)                     \
index 66bc5d21f37dbe929ac6cc0d7eea28fb95f6d15c..1d42ec08145cd64969133cef9182413e2543ca40 100644 (file)
@@ -362,6 +362,7 @@ namespace bitc {
     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#]
     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#]
+    FUNC_CODE_INST_CLEANUPENDPAD = 54, // CLEANUPENDPAD: [val] or [val,bb#]
   };
 
   enum UseListCodes {
   };
 
   enum UseListCodes {
index 044b5c59f7ced58fd9f0ba144d30b6753e46c676..b7299dd3a453cf2770ca7d0755fe4e42d0de7c30 100644 (file)
@@ -681,6 +681,11 @@ public:
     return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB));
   }
 
     return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB));
   }
 
+  CatchEndPadInst *CreateCleanupEndPad(CleanupPadInst *CleanupPad,
+                                       BasicBlock *UnwindBB = nullptr) {
+    return Insert(CleanupEndPadInst::Create(CleanupPad, UnwindBB));
+  }
+
   CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest,
                                ArrayRef<Value *> Args, const Twine &Name = "") {
     return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name);
   CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest,
                                ArrayRef<Value *> Args, const Twine &Name = "") {
     return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name);
index b63220446241da6636381bad2f54161feb8d3698..0fe88980b41fc997e5ea9f556b3199080a2e582f 100644 (file)
@@ -170,7 +170,8 @@ public:
   RetTy visitResumeInst(ResumeInst &I)            { DELEGATE(TerminatorInst);}
   RetTy visitUnreachableInst(UnreachableInst &I)  { DELEGATE(TerminatorInst);}
   RetTy visitCleanupReturnInst(CleanupReturnInst &I) { DELEGATE(TerminatorInst);}
   RetTy visitResumeInst(ResumeInst &I)            { DELEGATE(TerminatorInst);}
   RetTy visitUnreachableInst(UnreachableInst &I)  { DELEGATE(TerminatorInst);}
   RetTy visitCleanupReturnInst(CleanupReturnInst &I) { DELEGATE(TerminatorInst);}
-  RetTy visitCatchReturnInst(CatchReturnInst &I)  { DELEGATE(TerminatorInst);}
+  RetTy visitCleanupEndPadInst(CleanupEndPadInst &I) { DELEGATE(TerminatorInst); }
+  RetTy visitCatchReturnInst(CatchReturnInst &I)  { DELEGATE(TerminatorInst); }
   RetTy visitCatchPadInst(CatchPadInst &I)    { DELEGATE(TerminatorInst);}
   RetTy visitCatchEndPadInst(CatchEndPadInst &I) { DELEGATE(TerminatorInst); }
   RetTy visitTerminatePadInst(TerminatePadInst &I) { DELEGATE(TerminatorInst);}
   RetTy visitCatchPadInst(CatchPadInst &I)    { DELEGATE(TerminatorInst);}
   RetTy visitCatchEndPadInst(CatchEndPadInst &I) { DELEGATE(TerminatorInst); }
   RetTy visitTerminatePadInst(TerminatePadInst &I) { DELEGATE(TerminatorInst);}
index 189c5bc63275039ef2bcfe7a8617596cb6117b9e..d84e66c50a3e798dadc064b6f891634a6a0c3bda 100644 (file)
@@ -82,6 +82,7 @@ public:
     case Instruction::CatchPad:
     case Instruction::CatchEndPad:
     case Instruction::CatchRet:
     case Instruction::CatchPad:
     case Instruction::CatchEndPad:
     case Instruction::CatchRet:
+    case Instruction::CleanupEndPad:
     case Instruction::CleanupRet:
     case Instruction::Invoke:
     case Instruction::Resume:
     case Instruction::CleanupRet:
     case Instruction::Invoke:
     case Instruction::Resume:
index 9af666204da6553cc4dfac77b24e33aea109197f..72263f06ef4112d583c0e495f1c8c0a049516d78 100644 (file)
@@ -103,83 +103,84 @@ HANDLE_TERM_INST  ( 6, Resume        , ResumeInst)
 HANDLE_TERM_INST  ( 7, Unreachable   , UnreachableInst)
 HANDLE_TERM_INST  ( 8, CleanupRet    , CleanupReturnInst)
 HANDLE_TERM_INST  ( 9, CatchRet      , CatchReturnInst)
 HANDLE_TERM_INST  ( 7, Unreachable   , UnreachableInst)
 HANDLE_TERM_INST  ( 8, CleanupRet    , CleanupReturnInst)
 HANDLE_TERM_INST  ( 9, CatchRet      , CatchReturnInst)
-HANDLE_TERM_INST  (10, CatchPad    , CatchPadInst)
-HANDLE_TERM_INST  (11, TerminatePad, TerminatePadInst)
-HANDLE_TERM_INST  (12, CatchEndPad , CatchEndPadInst)
-  LAST_TERM_INST  (12)
+HANDLE_TERM_INST  (10, CatchPad      , CatchPadInst)
+HANDLE_TERM_INST  (11, TerminatePad  , TerminatePadInst)
+HANDLE_TERM_INST  (12, CatchEndPad   , CatchEndPadInst)
+HANDLE_TERM_INST  (13, CleanupEndPad , CleanupEndPadInst)
+  LAST_TERM_INST  (13)
 
 // Standard binary operators...
 
 // Standard binary operators...
- FIRST_BINARY_INST(13)
-HANDLE_BINARY_INST(13, Add  , BinaryOperator)
-HANDLE_BINARY_INST(14, FAdd , BinaryOperator)
-HANDLE_BINARY_INST(15, Sub  , BinaryOperator)
-HANDLE_BINARY_INST(16, FSub , BinaryOperator)
-HANDLE_BINARY_INST(17, Mul  , BinaryOperator)
-HANDLE_BINARY_INST(18, FMul , BinaryOperator)
-HANDLE_BINARY_INST(19, UDiv , BinaryOperator)
-HANDLE_BINARY_INST(20, SDiv , BinaryOperator)
-HANDLE_BINARY_INST(21, FDiv , BinaryOperator)
-HANDLE_BINARY_INST(22, URem , BinaryOperator)
-HANDLE_BINARY_INST(23, SRem , BinaryOperator)
-HANDLE_BINARY_INST(24, FRem , BinaryOperator)
+ FIRST_BINARY_INST(14)
+HANDLE_BINARY_INST(14, Add  , BinaryOperator)
+HANDLE_BINARY_INST(15, FAdd , BinaryOperator)
+HANDLE_BINARY_INST(16, Sub  , BinaryOperator)
+HANDLE_BINARY_INST(17, FSub , BinaryOperator)
+HANDLE_BINARY_INST(18, Mul  , BinaryOperator)
+HANDLE_BINARY_INST(19, FMul , BinaryOperator)
+HANDLE_BINARY_INST(20, UDiv , BinaryOperator)
+HANDLE_BINARY_INST(21, SDiv , BinaryOperator)
+HANDLE_BINARY_INST(22, FDiv , BinaryOperator)
+HANDLE_BINARY_INST(23, URem , BinaryOperator)
+HANDLE_BINARY_INST(24, SRem , BinaryOperator)
+HANDLE_BINARY_INST(25, FRem , BinaryOperator)
 
 // Logical operators (integer operands)
 
 // Logical operators (integer operands)
-HANDLE_BINARY_INST(25, Shl  , BinaryOperator) // Shift left  (logical)
-HANDLE_BINARY_INST(26, LShr , BinaryOperator) // Shift right (logical)
-HANDLE_BINARY_INST(27, AShr , BinaryOperator) // Shift right (arithmetic)
-HANDLE_BINARY_INST(28, And  , BinaryOperator)
-HANDLE_BINARY_INST(29, Or   , BinaryOperator)
-HANDLE_BINARY_INST(30, Xor  , BinaryOperator)
-  LAST_BINARY_INST(30)
+HANDLE_BINARY_INST(26, Shl  , BinaryOperator) // Shift left  (logical)
+HANDLE_BINARY_INST(27, LShr , BinaryOperator) // Shift right (logical)
+HANDLE_BINARY_INST(28, AShr , BinaryOperator) // Shift right (arithmetic)
+HANDLE_BINARY_INST(29, And  , BinaryOperator)
+HANDLE_BINARY_INST(30, Or   , BinaryOperator)
+HANDLE_BINARY_INST(31, Xor  , BinaryOperator)
+  LAST_BINARY_INST(31)
 
 // Memory operators...
 
 // Memory operators...
- FIRST_MEMORY_INST(31)
-HANDLE_MEMORY_INST(31, Alloca, AllocaInst)  // Stack management
-HANDLE_MEMORY_INST(32, Load  , LoadInst  )  // Memory manipulation instrs
-HANDLE_MEMORY_INST(33, Store , StoreInst )
-HANDLE_MEMORY_INST(34, GetElementPtr, GetElementPtrInst)
-HANDLE_MEMORY_INST(35, Fence , FenceInst )
-HANDLE_MEMORY_INST(36, AtomicCmpXchg , AtomicCmpXchgInst )
-HANDLE_MEMORY_INST(37, AtomicRMW , AtomicRMWInst )
-  LAST_MEMORY_INST(37)
+ FIRST_MEMORY_INST(32)
+HANDLE_MEMORY_INST(32, Alloca, AllocaInst)  // Stack management
+HANDLE_MEMORY_INST(33, Load  , LoadInst  )  // Memory manipulation instrs
+HANDLE_MEMORY_INST(34, Store , StoreInst )
+HANDLE_MEMORY_INST(35, GetElementPtr, GetElementPtrInst)
+HANDLE_MEMORY_INST(36, Fence , FenceInst )
+HANDLE_MEMORY_INST(37, AtomicCmpXchg , AtomicCmpXchgInst )
+HANDLE_MEMORY_INST(38, AtomicRMW , AtomicRMWInst )
+  LAST_MEMORY_INST(38)
 
 // Cast operators ...
 // NOTE: The order matters here because CastInst::isEliminableCastPair 
 // NOTE: (see Instructions.cpp) encodes a table based on this ordering.
 
 // Cast operators ...
 // NOTE: The order matters here because CastInst::isEliminableCastPair 
 // NOTE: (see Instructions.cpp) encodes a table based on this ordering.
- FIRST_CAST_INST(38)
-HANDLE_CAST_INST(38, Trunc   , TruncInst   )  // Truncate integers
-HANDLE_CAST_INST(39, ZExt    , ZExtInst    )  // Zero extend integers
-HANDLE_CAST_INST(40, SExt    , SExtInst    )  // Sign extend integers
-HANDLE_CAST_INST(41, FPToUI  , FPToUIInst  )  // floating point -> UInt
-HANDLE_CAST_INST(42, FPToSI  , FPToSIInst  )  // floating point -> SInt
-HANDLE_CAST_INST(43, UIToFP  , UIToFPInst  )  // UInt -> floating point
-HANDLE_CAST_INST(44, SIToFP  , SIToFPInst  )  // SInt -> floating point
-HANDLE_CAST_INST(45, FPTrunc , FPTruncInst )  // Truncate floating point
-HANDLE_CAST_INST(46, FPExt   , FPExtInst   )  // Extend floating point
-HANDLE_CAST_INST(47, PtrToInt, PtrToIntInst)  // Pointer -> Integer
-HANDLE_CAST_INST(48, IntToPtr, IntToPtrInst)  // Integer -> Pointer
-HANDLE_CAST_INST(49, BitCast , BitCastInst )  // Type cast
-HANDLE_CAST_INST(50, AddrSpaceCast, AddrSpaceCastInst)  // addrspace cast
-  LAST_CAST_INST(50)
+ FIRST_CAST_INST(39)
+HANDLE_CAST_INST(39, Trunc   , TruncInst   )  // Truncate integers
+HANDLE_CAST_INST(40, ZExt    , ZExtInst    )  // Zero extend integers
+HANDLE_CAST_INST(41, SExt    , SExtInst    )  // Sign extend integers
+HANDLE_CAST_INST(42, FPToUI  , FPToUIInst  )  // floating point -> UInt
+HANDLE_CAST_INST(43, FPToSI  , FPToSIInst  )  // floating point -> SInt
+HANDLE_CAST_INST(44, UIToFP  , UIToFPInst  )  // UInt -> floating point
+HANDLE_CAST_INST(45, SIToFP  , SIToFPInst  )  // SInt -> floating point
+HANDLE_CAST_INST(46, FPTrunc , FPTruncInst )  // Truncate floating point
+HANDLE_CAST_INST(47, FPExt   , FPExtInst   )  // Extend floating point
+HANDLE_CAST_INST(48, PtrToInt, PtrToIntInst)  // Pointer -> Integer
+HANDLE_CAST_INST(49, IntToPtr, IntToPtrInst)  // Integer -> Pointer
+HANDLE_CAST_INST(50, BitCast , BitCastInst )  // Type cast
+HANDLE_CAST_INST(51, AddrSpaceCast, AddrSpaceCastInst)  // addrspace cast
+  LAST_CAST_INST(51)
 
 // Other operators...
 
 // Other operators...
- FIRST_OTHER_INST(51)
-HANDLE_OTHER_INST(51, ICmp   , ICmpInst   )  // Integer comparison instruction
-HANDLE_OTHER_INST(52, FCmp   , FCmpInst   )  // Floating point comparison instr.
-HANDLE_OTHER_INST(53, PHI    , PHINode    )  // PHI node instruction
-HANDLE_OTHER_INST(54, Call   , CallInst   )  // Call a function
-HANDLE_OTHER_INST(55, Select , SelectInst )  // select instruction
-HANDLE_OTHER_INST(56, UserOp1, Instruction)  // May be used internally in a pass
-HANDLE_OTHER_INST(57, UserOp2, Instruction)  // Internal to passes only
-HANDLE_OTHER_INST(58, VAArg  , VAArgInst  )  // vaarg instruction
-HANDLE_OTHER_INST(59, ExtractElement, ExtractElementInst)// extract from vector
-HANDLE_OTHER_INST(60, InsertElement, InsertElementInst)  // insert into vector
-HANDLE_OTHER_INST(61, ShuffleVector, ShuffleVectorInst)  // shuffle two vectors.
-HANDLE_OTHER_INST(62, ExtractValue, ExtractValueInst)// extract from aggregate
-HANDLE_OTHER_INST(63, InsertValue, InsertValueInst)  // insert into aggregate
-HANDLE_OTHER_INST(64, LandingPad, LandingPadInst)  // Landing pad instruction.
-HANDLE_OTHER_INST(65, CleanupPad, CleanupPadInst)
-  LAST_OTHER_INST(65)
+ FIRST_OTHER_INST(52)
+HANDLE_OTHER_INST(52, ICmp   , ICmpInst   )  // Integer comparison instruction
+HANDLE_OTHER_INST(53, FCmp   , FCmpInst   )  // Floating point comparison instr.
+HANDLE_OTHER_INST(54, PHI    , PHINode    )  // PHI node instruction
+HANDLE_OTHER_INST(55, Call   , CallInst   )  // Call a function
+HANDLE_OTHER_INST(56, Select , SelectInst )  // select instruction
+HANDLE_OTHER_INST(57, UserOp1, Instruction)  // May be used internally in a pass
+HANDLE_OTHER_INST(58, UserOp2, Instruction)  // Internal to passes only
+HANDLE_OTHER_INST(59, VAArg  , VAArgInst  )  // vaarg instruction
+HANDLE_OTHER_INST(60, ExtractElement, ExtractElementInst)// extract from vector
+HANDLE_OTHER_INST(61, InsertElement, InsertElementInst)  // insert into vector
+HANDLE_OTHER_INST(62, ShuffleVector, ShuffleVectorInst)  // shuffle two vectors.
+HANDLE_OTHER_INST(63, ExtractValue, ExtractValueInst)// extract from aggregate
+HANDLE_OTHER_INST(64, InsertValue, InsertValueInst)  // insert into aggregate
+HANDLE_OTHER_INST(65, LandingPad, LandingPadInst)  // Landing pad instruction.
+HANDLE_OTHER_INST(66, CleanupPad, CleanupPadInst)
+  LAST_OTHER_INST(66)
 
 #undef  FIRST_TERM_INST
 #undef HANDLE_TERM_INST
 
 #undef  FIRST_TERM_INST
 #undef HANDLE_TERM_INST
index 1ddccd3caaab222874898a3d132e625ff728967d..000e8545836e1e616786fa6448dabaaf119da70a 100644 (file)
@@ -396,6 +396,7 @@ public:
     case Instruction::CatchPad:
     case Instruction::CatchEndPad:
     case Instruction::CleanupPad:
     case Instruction::CatchPad:
     case Instruction::CatchEndPad:
     case Instruction::CleanupPad:
+    case Instruction::CleanupEndPad:
     case Instruction::LandingPad:
     case Instruction::TerminatePad:
       return true;
     case Instruction::LandingPad:
     case Instruction::TerminatePad:
       return true;
index f9dce102787f575f3714628e2ac8e3a80653d50e..d979b393066f5a13fc7fa180d3577a755864b582 100644 (file)
@@ -4019,6 +4019,93 @@ struct OperandTraits<CatchReturnInst>
 
 DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchReturnInst, Value)
 
 
 DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchReturnInst, Value)
 
+//===----------------------------------------------------------------------===//
+//                               CleanupEndPadInst Class
+//===----------------------------------------------------------------------===//
+
+class CleanupEndPadInst : public TerminatorInst {
+private:
+  CleanupEndPadInst(const CleanupEndPadInst &CEPI);
+
+  void init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB);
+  CleanupEndPadInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB,
+                    unsigned Values, Instruction *InsertBefore = nullptr);
+  CleanupEndPadInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB,
+                    unsigned Values, BasicBlock *InsertAtEnd);
+
+protected:
+  // Note: Instruction needs to be a friend here to call cloneImpl.
+  friend class Instruction;
+  CleanupEndPadInst *cloneImpl() const;
+
+public:
+  static CleanupEndPadInst *Create(CleanupPadInst *CleanupPad,
+                                   BasicBlock *UnwindBB = nullptr,
+                                   Instruction *InsertBefore = nullptr) {
+    unsigned Values = UnwindBB ? 2 : 1;
+    return new (Values)
+        CleanupEndPadInst(CleanupPad, UnwindBB, Values, InsertBefore);
+  }
+  static CleanupEndPadInst *Create(CleanupPadInst *CleanupPad,
+                                   BasicBlock *UnwindBB,
+                                   BasicBlock *InsertAtEnd) {
+    unsigned Values = UnwindBB ? 2 : 1;
+    return new (Values)
+        CleanupEndPadInst(CleanupPad, UnwindBB, Values, InsertAtEnd);
+  }
+
+  /// Provide fast operand accessors
+  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+
+  bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; }
+  bool unwindsToCaller() const { return !hasUnwindDest(); }
+
+  unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; }
+
+  /// Convenience accessors
+  CleanupPadInst *getCleanupPad() const {
+    return cast<CleanupPadInst>(Op<-1>());
+  }
+  void setCleanupPad(CleanupPadInst *CleanupPad) {
+    assert(CleanupPad);
+    Op<-1>() = CleanupPad;
+  }
+
+  BasicBlock *getUnwindDest() const {
+    return hasUnwindDest() ? cast<BasicBlock>(Op<-2>()) : nullptr;
+  }
+  void setUnwindDest(BasicBlock *NewDest) {
+    assert(hasUnwindDest());
+    assert(NewDest);
+    Op<-2>() = NewDest;
+  }
+
+  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const Instruction *I) {
+    return (I->getOpcode() == Instruction::CleanupEndPad);
+  }
+  static inline bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+
+private:
+  BasicBlock *getSuccessorV(unsigned Idx) const override;
+  unsigned getNumSuccessorsV() const override;
+  void setSuccessorV(unsigned Idx, BasicBlock *B) override;
+
+  // Shadow Instruction::setInstructionSubclassData with a private forwarding
+  // method so that subclasses cannot accidentally use it.
+  void setInstructionSubclassData(unsigned short D) {
+    Instruction::setInstructionSubclassData(D);
+  }
+};
+
+template <>
+struct OperandTraits<CleanupEndPadInst>
+    : public VariadicOperandTraits<CleanupEndPadInst, /*MINARITY=*/1> {};
+
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupEndPadInst, Value)
+
 //===----------------------------------------------------------------------===//
 //                               CleanupReturnInst Class
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 //                               CleanupReturnInst Class
 //===----------------------------------------------------------------------===//
index 7de719579ad19bd43d82b340142b555f319293e1..7000210e1faad76c8276c643217256e63673e82d 100644 (file)
@@ -3207,6 +3207,7 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
   case Instruction::CatchEndPad:
   case Instruction::CatchRet:
   case Instruction::CleanupPad:
   case Instruction::CatchEndPad:
   case Instruction::CatchRet:
   case Instruction::CleanupPad:
+  case Instruction::CleanupEndPad:
   case Instruction::CleanupRet:
   case Instruction::TerminatePad:
     return false; // Misc instructions which have effects
   case Instruction::CleanupRet:
   case Instruction::TerminatePad:
     return false; // Misc instructions which have effects
index af7705c56664ffa00d63ab381f63d251ed7da2fc..b166c17b124d0ba6692114b88636d8468ebbf64f 100644 (file)
@@ -757,6 +757,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   INSTKEYWORD(terminatepad, TerminatePad);
   INSTKEYWORD(cleanuppad,   CleanupPad);
   INSTKEYWORD(catchendpad,  CatchEndPad);
   INSTKEYWORD(terminatepad, TerminatePad);
   INSTKEYWORD(cleanuppad,   CleanupPad);
   INSTKEYWORD(catchendpad,  CatchEndPad);
+  INSTKEYWORD(cleanupendpad, CleanupEndPad);
 #undef INSTKEYWORD
 
 #define DWKEYWORD(TYPE, TOKEN)                                                 \
 #undef INSTKEYWORD
 
 #define DWKEYWORD(TYPE, TOKEN)                                                 \
index c8390d44cca088a66f7d0db3b18a27049bc7e0b5..df34ba8697faee42ca4c0da9c25582057d88f886 100644 (file)
@@ -4686,6 +4686,7 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,
   case lltok::kw_terminatepad: return ParseTerminatePad(Inst, PFS);
   case lltok::kw_cleanuppad: return ParseCleanupPad(Inst, PFS);
   case lltok::kw_catchendpad: return ParseCatchEndPad(Inst, PFS);
   case lltok::kw_terminatepad: return ParseTerminatePad(Inst, PFS);
   case lltok::kw_cleanuppad: return ParseCleanupPad(Inst, PFS);
   case lltok::kw_catchendpad: return ParseCatchEndPad(Inst, PFS);
+  case lltok::kw_cleanupendpad: return ParseCleanupEndPad(Inst, PFS);
   // Binary Operators.
   case lltok::kw_add:
   case lltok::kw_sub:
   // Binary Operators.
   case lltok::kw_add:
   case lltok::kw_sub:
@@ -5243,6 +5244,35 @@ bool LLParser::ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS) {
   return false;
 }
 
   return false;
 }
 
+/// ParseCatchEndPad
+///   ::= 'cleanupendpad' Value unwind ('to' 'caller' | TypeAndValue)
+bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) {
+  Value *CleanupPad = nullptr;
+
+  if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad))
+    return true;
+
+  if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad"))
+    return true;
+
+  BasicBlock *UnwindBB = nullptr;
+  if (Lex.getKind() == lltok::kw_to) {
+    Lex.Lex();
+    if (Lex.getKind() == lltok::kw_caller) {
+      Lex.Lex();
+    } else {
+      return true;
+    }
+  } else {
+    if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
+      return true;
+    }
+  }
+
+  Inst = CleanupEndPadInst::Create(cast<CleanupPadInst>(CleanupPad), UnwindBB);
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Binary Operators.
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 // Binary Operators.
 //===----------------------------------------------------------------------===//
index 8b7e9560a69f478782044102b6b97ea948400cc5..e161f95248ce7a6cb65a387846672dd242c8662d 100644 (file)
@@ -475,6 +475,7 @@ namespace llvm {
     bool ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS);
     bool ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS);
     bool ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS);
     bool ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS);
     bool ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS);
     bool ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS);
+    bool ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS);
 
     bool ParseArithmetic(Instruction *&I, PerFunctionState &PFS, unsigned Opc,
                          unsigned OperandType);
 
     bool ParseArithmetic(Instruction *&I, PerFunctionState &PFS, unsigned Opc,
                          unsigned OperandType);
index 19bf7e4e4c11be019f7b1d6b5721d0680ee8bc62..b83ca2c652fc1f2e0e823d172e15e49a6af2427c 100644 (file)
@@ -179,7 +179,7 @@ namespace lltok {
 
     kw_ret, kw_br, kw_switch, kw_indirectbr, kw_invoke, kw_resume,
     kw_unreachable, kw_cleanupret, kw_catchret, kw_catchpad,
 
     kw_ret, kw_br, kw_switch, kw_indirectbr, kw_invoke, kw_resume,
     kw_unreachable, kw_cleanupret, kw_catchret, kw_catchpad,
-    kw_terminatepad, kw_cleanuppad, kw_catchendpad,
+    kw_terminatepad, kw_cleanuppad, kw_catchendpad, kw_cleanupendpad,
 
     kw_alloca, kw_load, kw_store, kw_fence, kw_cmpxchg, kw_atomicrmw,
     kw_getelementptr,
 
     kw_alloca, kw_load, kw_store, kw_fence, kw_cmpxchg, kw_atomicrmw,
     kw_getelementptr,
index b9604af3bc89d5ab05bd0de29687b9921b03b374..be39b88b822aefecc38cca4d02f158072b0901e6 100644 (file)
@@ -3999,6 +3999,25 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
       InstructionList.push_back(I);
       break;
     }
       InstructionList.push_back(I);
       break;
     }
+    case bitc::FUNC_CODE_INST_CLEANUPENDPAD: { // CLEANUPENDPADINST: [val] or [val,bb#]
+      if (Record.size() != 1 && Record.size() != 2)
+        return error("Invalid record");
+      unsigned Idx = 0;
+      Value *CleanupPad = getValue(Record, Idx++, NextValueNo,
+                                   Type::getTokenTy(Context), OC_CleanupPad);
+      if (!CleanupPad)
+        return error("Invalid record");
+
+      BasicBlock *BB = nullptr;
+      if (Record.size() == 2) {
+        BB = getBasicBlock(Record[Idx++]);
+        if (!BB)
+          return error("Invalid record");
+      }
+      I = CleanupEndPadInst::Create(cast<CleanupPadInst>(CleanupPad), BB);
+      InstructionList.push_back(I);
+      break;
+    }
     case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...]
       // Check magic
       if ((Record[0] >> 16) == SWITCH_INST_MAGIC) {
     case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...]
       // Check magic
       if ((Record[0] >> 16) == SWITCH_INST_MAGIC) {
index c0eb5d497bc504bb7118d27f28e6eaee5839b0da..9986718f08b0eef56a3e19b665920cf4e8f4a439 100644 (file)
@@ -1906,6 +1906,14 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
       Vals.push_back(VE.getValueID(CEPI.getUnwindDest()));
     break;
   }
       Vals.push_back(VE.getValueID(CEPI.getUnwindDest()));
     break;
   }
+  case Instruction::CleanupEndPad: {
+    Code = bitc::FUNC_CODE_INST_CLEANUPENDPAD;
+    const auto &CEPI = cast<CleanupEndPadInst>(I);
+    pushValue(CEPI.getCleanupPad(), InstID, Vals, VE);
+    if (CEPI.hasUnwindDest())
+      Vals.push_back(VE.getValueID(CEPI.getUnwindDest()));
+    break;
+  }
   case Instruction::Unreachable:
     Code = bitc::FUNC_CODE_INST_UNREACHABLE;
     AbbrevToUse = FUNCTION_INST_UNREACHABLE_ABBREV;
   case Instruction::Unreachable:
     Code = bitc::FUNC_CODE_INST_UNREACHABLE;
     AbbrevToUse = FUNCTION_INST_UNREACHABLE_ABBREV;
index 7c1706f6edca2e8127d0f84f6a0183170e5c3d44..9aa9755796d449c4ceb79488043a63d834bfabf1 100644 (file)
@@ -1205,6 +1205,10 @@ void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
   report_fatal_error("visitCleanupRet not yet implemented!");
 }
 
   report_fatal_error("visitCleanupRet not yet implemented!");
 }
 
+void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) {
+  report_fatal_error("visitCleanupEndPad not yet implemented!");
+}
+
 void SelectionDAGBuilder::visitTerminatePad(const TerminatePadInst &TPI) {
   report_fatal_error("visitTerminatePad not yet implemented!");
 }
 void SelectionDAGBuilder::visitTerminatePad(const TerminatePadInst &TPI) {
   report_fatal_error("visitTerminatePad not yet implemented!");
 }
index 3b97d469f5e62e38871d4b117f62cb2f3ca483d8..2331127a966a943c86fa08328abf35b651296595 100644 (file)
@@ -740,6 +740,7 @@ private:
   void visitSwitch(const SwitchInst &I);
   void visitIndirectBr(const IndirectBrInst &I);
   void visitUnreachable(const UnreachableInst &I);
   void visitSwitch(const SwitchInst &I);
   void visitIndirectBr(const IndirectBrInst &I);
   void visitUnreachable(const UnreachableInst &I);
+  void visitCleanupEndPad(const CleanupEndPadInst &I);
   void visitCleanupRet(const CleanupReturnInst &I);
   void visitCatchEndPad(const CatchEndPadInst &I);
   void visitCatchRet(const CatchReturnInst &I);
   void visitCleanupRet(const CleanupReturnInst &I);
   void visitCatchEndPad(const CatchEndPadInst &I);
   void visitCatchRet(const CatchReturnInst &I);
index d7a58f9686d4048342bc8e12ed5fc9a46c8b6847..7250fdc9385a3064aa48d2b5c240e6ea3effe445 100644 (file)
@@ -1574,6 +1574,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   case Invoke:         return 0;
   case Resume:         return 0;
   case Unreachable:    return 0;
   case Invoke:         return 0;
   case Resume:         return 0;
   case Unreachable:    return 0;
+  case CleanupEndPad:  return 0;
   case CleanupRet:     return 0;
   case CatchEndPad:  return 0;
   case CatchRet:       return 0;
   case CleanupRet:     return 0;
   case CatchEndPad:  return 0;
   case CatchRet:       return 0;
index 8c15b7e4413b7e3ba25c0addca6e153e04168c1b..c333c0749004d9a6e77b1d7d880fa6f1d9fa3cae 100644 (file)
@@ -403,7 +403,7 @@ bool WinEHPrepare::runOnFunction(Function &Fn) {
     } else if (First->isEHPad()) {
       if (!ForExplicitEH)
         EntryBlocks.push_back(&Fn.getEntryBlock());
     } else if (First->isEHPad()) {
       if (!ForExplicitEH)
         EntryBlocks.push_back(&Fn.getEntryBlock());
-      if (!isa<CatchEndPadInst>(First))
+      if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
         EntryBlocks.push_back(&BB);
       ForExplicitEH = true;
     }
         EntryBlocks.push_back(&BB);
       ForExplicitEH = true;
     }
@@ -2965,6 +2965,8 @@ static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
   if (isa<CatchPadInst>(TI) || isa<CatchEndPadInst>(TI) ||
       isa<TerminatePadInst>(TI))
     return BB;
   if (isa<CatchPadInst>(TI) || isa<CatchEndPadInst>(TI) ||
       isa<TerminatePadInst>(TI))
     return BB;
+  if (auto *CEPI = dyn_cast<CleanupEndPadInst>(TI))
+    return CEPI->getCleanupPad()->getParent();
   return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent();
 }
 
   return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent();
 }
 
@@ -3035,18 +3037,27 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
   for (const BasicBlock &BB : *ParentFn) {
     if (!BB.isEHPad())
       continue;
   for (const BasicBlock &BB : *ParentFn) {
     if (!BB.isEHPad())
       continue;
+    const Instruction *FirstNonPHI = BB.getFirstNonPHI();
+    // Skip cleanupendpads; they are exits, not entries.
+    if (isa<CleanupEndPadInst>(FirstNonPHI))
+      continue;
     // Check if the EH Pad has no exceptional successors (i.e. it unwinds to
     // caller).  Cleanups are a little bit of a special case because their
     // control flow cannot be determined by looking at the pad but instead by
     // the pad's users.
     bool HasNoSuccessors = false;
     // Check if the EH Pad has no exceptional successors (i.e. it unwinds to
     // caller).  Cleanups are a little bit of a special case because their
     // control flow cannot be determined by looking at the pad but instead by
     // the pad's users.
     bool HasNoSuccessors = false;
-    const Instruction *FirstNonPHI = BB.getFirstNonPHI();
     if (FirstNonPHI->mayThrow()) {
       HasNoSuccessors = true;
     } else if (auto *CPI = dyn_cast<CleanupPadInst>(FirstNonPHI)) {
     if (FirstNonPHI->mayThrow()) {
       HasNoSuccessors = true;
     } else if (auto *CPI = dyn_cast<CleanupPadInst>(FirstNonPHI)) {
-      HasNoSuccessors =
-          CPI->use_empty() ||
-          cast<CleanupReturnInst>(CPI->user_back())->unwindsToCaller();
+      if (CPI->use_empty()) {
+        HasNoSuccessors = true;
+      } else {
+        const Instruction *User = CPI->user_back();
+        if (auto *CRI = dyn_cast<CleanupReturnInst>(User))
+          HasNoSuccessors = CRI->unwindsToCaller();
+        else
+          HasNoSuccessors = cast<CleanupEndPadInst>(User)->unwindsToCaller();
+      }
     }
 
     if (!HasNoSuccessors)
     }
 
     if (!HasNoSuccessors)
@@ -3096,7 +3107,8 @@ void WinEHPrepare::colorFunclets(Function &F,
     BasicBlock *Color;
     std::tie(Visiting, Color) = Worklist.pop_back_val();
     Instruction *VisitingHead = Visiting->getFirstNonPHI();
     BasicBlock *Color;
     std::tie(Visiting, Color) = Worklist.pop_back_val();
     Instruction *VisitingHead = Visiting->getFirstNonPHI();
-    if (VisitingHead->isEHPad() && !isa<CatchEndPadInst>(VisitingHead)) {
+    if (VisitingHead->isEHPad() && !isa<CatchEndPadInst>(VisitingHead) &&
+        !isa<CleanupEndPadInst>(VisitingHead)) {
       // Mark this as a funclet head as a member of itself.
       FuncletBlocks[Visiting].insert(Visiting);
       // Queue exits with the parent color.
       // Mark this as a funclet head as a member of itself.
       FuncletBlocks[Visiting].insert(Visiting);
       // Queue exits with the parent color.
@@ -3132,7 +3144,8 @@ void WinEHPrepare::colorFunclets(Function &F,
       FuncletBlocks[Color].insert(Visiting);
       TerminatorInst *Terminator = Visiting->getTerminator();
       if (isa<CleanupReturnInst>(Terminator) ||
       FuncletBlocks[Color].insert(Visiting);
       TerminatorInst *Terminator = Visiting->getTerminator();
       if (isa<CleanupReturnInst>(Terminator) ||
-          isa<CatchReturnInst>(Terminator)) {
+          isa<CatchReturnInst>(Terminator) ||
+          isa<CleanupEndPadInst>(Terminator)) {
         // These block's successors have already been queued with the parent
         // color.
         continue;
         // These block's successors have already been queued with the parent
         // color.
         continue;
@@ -3288,11 +3301,16 @@ bool WinEHPrepare::prepareExplicitEH(
       bool IsUnreachableCatchret = false;
       if (auto *CRI = dyn_cast<CatchReturnInst>(TI))
         IsUnreachableCatchret = CRI->getCatchPad() != CatchPad;
       bool IsUnreachableCatchret = false;
       if (auto *CRI = dyn_cast<CatchReturnInst>(TI))
         IsUnreachableCatchret = CRI->getCatchPad() != CatchPad;
-      // The token consumed by a CleanupPadInst must match the funclet token.
+      // The token consumed by a CleanupReturnInst must match the funclet token.
       bool IsUnreachableCleanupret = false;
       if (auto *CRI = dyn_cast<CleanupReturnInst>(TI))
         IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad;
       bool IsUnreachableCleanupret = false;
       if (auto *CRI = dyn_cast<CleanupReturnInst>(TI))
         IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad;
-      if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) {
+      // The token consumed by a CleanupEndPadInst must match the funclet token.
+      bool IsUnreachableCleanupendpad = false;
+      if (auto *CEPI = dyn_cast<CleanupEndPadInst>(TI))
+        IsUnreachableCleanupendpad = CEPI->getCleanupPad() != CleanupPad;
+      if (IsUnreachableRet || IsUnreachableCatchret ||
+          IsUnreachableCleanupret || IsUnreachableCleanupendpad) {
         new UnreachableInst(BB->getContext(), TI);
         TI->eraseFromParent();
       }
         new UnreachableInst(BB->getContext(), TI);
         TI->eraseFromParent();
       }
index 86d923e5d83aa8025eb16f2a1037b6c0b895dbea..db7fd7a23247f5f810112556323d009735731748 100644 (file)
@@ -2884,6 +2884,15 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
     else
       Out << "to caller";
   } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(&I)) {
     else
       Out << "to caller";
   } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(&I)) {
+    Out << " unwind ";
+    if (CEPI->hasUnwindDest())
+      writeOperand(CEPI->getUnwindDest(), /*PrintType=*/true);
+    else
+      Out << "to caller";
+  } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(&I)) {
+    Out << ' ';
+    writeOperand(CEPI->getCleanupPad(), /*PrintType=*/false);
+
     Out << " unwind ";
     if (CEPI->hasUnwindDest())
       writeOperand(CEPI->getUnwindDest(), /*PrintType=*/true);
     Out << " unwind ";
     if (CEPI->hasUnwindDest())
       writeOperand(CEPI->getUnwindDest(), /*PrintType=*/true);
index 0dc8633ac2ac5a256d9fd95ca806ce57abb90acb..908e79039b51eafe78cdcfe2ed6c088cd90f1b64 100644 (file)
@@ -196,6 +196,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
   case Invoke: return "invoke";
   case Resume: return "resume";
   case Unreachable: return "unreachable";
   case Invoke: return "invoke";
   case Resume: return "resume";
   case Unreachable: return "unreachable";
+  case CleanupEndPad: return "cleanupendpad";
   case CleanupRet: return "cleanupret";
   case CatchEndPad: return "catchendpad";
   case CatchRet: return "catchret";
   case CleanupRet: return "cleanupret";
   case CatchEndPad: return "catchendpad";
   case CatchRet: return "catchret";
@@ -467,6 +468,8 @@ bool Instruction::mayThrow() const {
     return !CI->doesNotThrow();
   if (const auto *CRI = dyn_cast<CleanupReturnInst>(this))
     return CRI->unwindsToCaller();
     return !CI->doesNotThrow();
   if (const auto *CRI = dyn_cast<CleanupReturnInst>(this))
     return CRI->unwindsToCaller();
+  if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(this))
+    return CEPI->unwindsToCaller();
   if (const auto *CEPI = dyn_cast<CatchEndPadInst>(this))
     return CEPI->unwindsToCaller();
   if (const auto *TPI = dyn_cast<TerminatePadInst>(this))
   if (const auto *CEPI = dyn_cast<CatchEndPadInst>(this))
     return CEPI->unwindsToCaller();
   if (const auto *TPI = dyn_cast<TerminatePadInst>(this))
index 6b2cd6dac229317c572aec09a19a8a5650638f48..ff681401b509defbc78f8f0e7554c80dd3a8e4c7 100644 (file)
@@ -673,6 +673,61 @@ BasicBlock *ResumeInst::getSuccessorV(unsigned idx) const {
   llvm_unreachable("ResumeInst has no successors!");
 }
 
   llvm_unreachable("ResumeInst has no successors!");
 }
 
+//===----------------------------------------------------------------------===//
+//                        CleanupEndPadInst Implementation
+//===----------------------------------------------------------------------===//
+
+CleanupEndPadInst::CleanupEndPadInst(const CleanupEndPadInst &CEPI)
+    : TerminatorInst(CEPI.getType(), Instruction::CleanupEndPad,
+                     OperandTraits<CleanupEndPadInst>::op_end(this) -
+                         CEPI.getNumOperands(),
+                     CEPI.getNumOperands()) {
+  setInstructionSubclassData(CEPI.getSubclassDataFromInstruction());
+  setCleanupPad(CEPI.getCleanupPad());
+  if (BasicBlock *UnwindDest = CEPI.getUnwindDest())
+    setUnwindDest(UnwindDest);
+}
+
+void CleanupEndPadInst::init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB) {
+  setCleanupPad(CleanupPad);
+  if (UnwindBB) {
+    setInstructionSubclassData(getSubclassDataFromInstruction() | 1);
+    setUnwindDest(UnwindBB);
+  }
+}
+
+CleanupEndPadInst::CleanupEndPadInst(CleanupPadInst *CleanupPad,
+                                     BasicBlock *UnwindBB, unsigned Values,
+                                     Instruction *InsertBefore)
+    : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()),
+                     Instruction::CleanupEndPad,
+                     OperandTraits<CleanupEndPadInst>::op_end(this) - Values,
+                     Values, InsertBefore) {
+  init(CleanupPad, UnwindBB);
+}
+
+CleanupEndPadInst::CleanupEndPadInst(CleanupPadInst *CleanupPad,
+                                     BasicBlock *UnwindBB, unsigned Values,
+                                     BasicBlock *InsertAtEnd)
+    : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()),
+                     Instruction::CleanupEndPad,
+                     OperandTraits<CleanupEndPadInst>::op_end(this) - Values,
+                     Values, InsertAtEnd) {
+  init(CleanupPad, UnwindBB);
+}
+
+BasicBlock *CleanupEndPadInst::getSuccessorV(unsigned Idx) const {
+  assert(Idx == 0);
+  return getUnwindDest();
+}
+unsigned CleanupEndPadInst::getNumSuccessorsV() const {
+  return getNumSuccessors();
+}
+void CleanupEndPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
+  assert(Idx == 0);
+  setUnwindDest(B);
+}
+
 //===----------------------------------------------------------------------===//
 //                        CleanupReturnInst Implementation
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 //                        CleanupReturnInst Implementation
 //===----------------------------------------------------------------------===//
@@ -3902,6 +3957,10 @@ InvokeInst *InvokeInst::cloneImpl() const {
 
 ResumeInst *ResumeInst::cloneImpl() const { return new (1) ResumeInst(*this); }
 
 
 ResumeInst *ResumeInst::cloneImpl() const { return new (1) ResumeInst(*this); }
 
+CleanupEndPadInst *CleanupEndPadInst::cloneImpl() const {
+  return new (getNumOperands()) CleanupEndPadInst(*this);
+}
+
 CleanupReturnInst *CleanupReturnInst::cloneImpl() const {
   return new (getNumOperands()) CleanupReturnInst(*this);
 }
 CleanupReturnInst *CleanupReturnInst::cloneImpl() const {
   return new (getNumOperands()) CleanupReturnInst(*this);
 }
index 51058cd5ab03bb182b27d36175171c769e5f5df8..44158afeb0707b32006367118bf58dfdc89f56a2 100644 (file)
@@ -388,6 +388,7 @@ private:
   void visitCatchPadInst(CatchPadInst &CPI);
   void visitCatchEndPadInst(CatchEndPadInst &CEPI);
   void visitCleanupPadInst(CleanupPadInst &CPI);
   void visitCatchPadInst(CatchPadInst &CPI);
   void visitCatchEndPadInst(CatchEndPadInst &CEPI);
   void visitCleanupPadInst(CleanupPadInst &CPI);
+  void visitCleanupEndPadInst(CleanupEndPadInst &CEPI);
   void visitCleanupReturnInst(CleanupReturnInst &CRI);
   void visitTerminatePadInst(TerminatePadInst &TPI);
 
   void visitCleanupReturnInst(CleanupReturnInst &CRI);
   void visitTerminatePadInst(TerminatePadInst &TPI);
 
@@ -2832,6 +2833,8 @@ void Verifier::visitEHPadPredecessors(Instruction &I) {
       ;
     else if (isa<CleanupReturnInst>(TI))
       ;
       ;
     else if (isa<CleanupReturnInst>(TI))
       ;
+    else if (isa<CleanupEndPadInst>(TI))
+      ;
     else if (isa<TerminatePadInst>(TI))
       ;
     else
     else if (isa<TerminatePadInst>(TI))
       ;
     else
@@ -2962,21 +2965,56 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
          "CleanupPadInst not the first non-PHI instruction in the block.",
          &CPI);
 
          "CleanupPadInst not the first non-PHI instruction in the block.",
          &CPI);
 
-  CleanupReturnInst *FirstCRI = nullptr;
-  for (User *U : CPI.users())
+  User *FirstUser = nullptr;
+  BasicBlock *FirstUnwindDest = nullptr;
+  for (User *U : CPI.users()) {
+    BasicBlock *UnwindDest;
     if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) {
     if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) {
-      if (!FirstCRI)
-        FirstCRI = CRI;
-      else
-        Assert(CRI->getUnwindDest() == FirstCRI->getUnwindDest(),
-               "Cleanuprets from same cleanuppad have different exceptional "
-               "successors.",
-               FirstCRI, CRI);
+      UnwindDest = CRI->getUnwindDest();
+    } else {
+      UnwindDest = cast<CleanupEndPadInst>(U)->getUnwindDest();
     }
 
     }
 
+    if (!FirstUser) {
+      FirstUser = U;
+      FirstUnwindDest = UnwindDest;
+    } else {
+      Assert(UnwindDest == FirstUnwindDest,
+             "Cleanuprets/cleanupendpads from the same cleanuppad must "
+             "have the same unwind destination",
+             FirstUser, U);
+    }
+  }
+
   visitInstruction(CPI);
 }
 
   visitInstruction(CPI);
 }
 
+void Verifier::visitCleanupEndPadInst(CleanupEndPadInst &CEPI) {
+  visitEHPadPredecessors(CEPI);
+
+  BasicBlock *BB = CEPI.getParent();
+  Function *F = BB->getParent();
+  Assert(F->hasPersonalityFn(),
+         "CleanupEndPadInst needs to be in a function with a personality.",
+         &CEPI);
+
+  // The cleanupendpad instruction must be the first non-PHI instruction in the
+  // block.
+  Assert(BB->getFirstNonPHI() == &CEPI,
+         "CleanupEndPadInst not the first non-PHI instruction in the block.",
+         &CEPI);
+
+  if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) {
+    Instruction *I = UnwindDest->getFirstNonPHI();
+    Assert(
+        I->isEHPad() && !isa<LandingPadInst>(I),
+        "CleanupEndPad must unwind to an EH block which is not a landingpad.",
+        &CEPI);
+  }
+
+  visitTerminatorInst(CEPI);
+}
+
 void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) {
   if (BasicBlock *UnwindDest = CRI.getUnwindDest()) {
     Instruction *I = UnwindDest->getFirstNonPHI();
 void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) {
   if (BasicBlock *UnwindDest = CRI.getUnwindDest()) {
     Instruction *I = UnwindDest->getFirstNonPHI();
index eb2a5b3653c6bfef6e53171f36d9513971a440ff..be8e25505ca76ff09f74b54323416bbe768507e3 100644 (file)
@@ -2698,6 +2698,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
     // Nothing to do here.
   }
 
     // Nothing to do here.
   }
 
+  void visitCleanupEndPadInst(CleanupEndPadInst &I) {
+    DEBUG(dbgs() << "CleanupEndPad: " << I << "\n");
+    // Nothing to do here.
+  }
+
   void visitGetElementPtrInst(GetElementPtrInst &I) {
     handleShadowOr(I);
   }
   void visitGetElementPtrInst(GetElementPtrInst &I) {
     handleShadowOr(I);
   }
index 22d86c4fdc0be2af41dea9260415da2df80a5114..e884176093f6cf9be0bc9d22d4a81abefa12a056 100644 (file)
@@ -328,6 +328,12 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock,
           CEPI->eraseFromParent();
           UpdatePHINodes(BB);
         }
           CEPI->eraseFromParent();
           UpdatePHINodes(BB);
         }
+      } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(I)) {
+        if (CEPI->unwindsToCaller()) {
+          CleanupEndPadInst::Create(CEPI->getCleanupPad(), UnwindDest, CEPI);
+          CEPI->eraseFromParent();
+          UpdatePHINodes(BB);
+        }
       } else if (auto *TPI = dyn_cast<TerminatePadInst>(I)) {
         if (TPI->unwindsToCaller()) {
           SmallVector<Value *, 3> TerminatePadArgs;
       } else if (auto *TPI = dyn_cast<TerminatePadInst>(I)) {
         if (TPI->unwindsToCaller()) {
           SmallVector<Value *, 3> TerminatePadArgs;
index e21586a51bd2a41787a6a71f25e844cac26db6ce..fa90c96c803c44eef1f6689aa73b51ea1f918f84 100644 (file)
@@ -4,6 +4,9 @@
 ; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s
 ; RUN: sed -e s/.T5:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK5 %s
 ; RUN: sed -e s/.T6:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s
 ; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s
 ; RUN: sed -e s/.T5:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK5 %s
 ; RUN: sed -e s/.T6:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s
+; RUN: sed -e s/.T7:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK7 %s
+; RUN: sed -e s/.T8:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK8 %s
+; RUN: sed -e s/.T9:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK9 %s
 
 ;T1: define void @f() {
 ;T1:   entry:
 
 ;T1: define void @f() {
 ;T1:   entry:
 ;T6:   next:
 ;T6:     %x = catchpad [] to label %entry unwind label %next
 ;T6: }
 ;T6:   next:
 ;T6:     %x = catchpad [] to label %entry unwind label %next
 ;T6: }
+
+;T7: define void @f() {
+;T7:   entry:
+;T7:     ; operator constraint requires an operator
+;T7:     cleanupendpad undef unwind to caller
+;T7:     ; CHECK7: [[@LINE-1]]:20: error: Cleanuppad value required in this position
+;T7: }
+
+;T8: define void @f() {
+;T8:   entry:
+;T8:     %x = catchpad []
+;T8:             to label %next unwind label %entry
+;T8:   next:
+;T8:     ; cleanupret first operand's operator must be cleanuppad
+;T8:     cleanupendpad %x unwind label next
+;T8:     ; CHECK8: [[@LINE-1]]:20: error: '%x' is not a cleanuppad
+;T8: }
+
+;T9: define void @f() {
+;T9:   entry:
+;T9:     ; cleanupret's first operand's operator must be cleanuppad
+;T9:     ; (forward reference case)
+;T9:     cleanupendpad %x unwind label %next
+;T9:     ; CHECK9: [[@LINE-1]]:20: error: '%x' is not a cleanuppad
+;T9:   next:
+;T9:     %x = catchpad [] to label %entry unwind label %next
+;T9: }
index de458bb7e4e72b337ccdb9a1676c24e7293fed58..c6c436ae83de966e0812bfde8cfa347938221f9a 100644 (file)
@@ -179,3 +179,53 @@ try.cont:
 bb:
   catchendpad unwind to caller
 }
 bb:
   catchendpad unwind to caller
 }
+
+define void @cleanupendpad0() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+  invoke void @_Z3quxv() optsize
+          to label %exit unwind label %pad
+pad:
+  %cp = cleanuppad [i7 4]
+  invoke void @_Z3quxv() optsize
+          to label %stop unwind label %endpad
+stop:
+  unreachable
+endpad:
+  cleanupendpad %cp unwind label %pad
+exit:
+  ret void
+}
+
+; forward ref by name
+define void @cleanupendpad1() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+  invoke void @_Z3quxv() optsize
+          to label %exit unwind label %pad
+endpad:
+  cleanupendpad %cp unwind to caller
+pad:
+  %cp = cleanuppad []
+  invoke void @_Z3quxv() optsize
+          to label %stop unwind label %endpad
+stop:
+  unreachable
+exit:
+  ret void
+}
+
+; forward ref by ID
+define void @cleanupendpad2() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+  invoke void @_Z3quxv() optsize
+          to label %exit unwind label %pad
+endpad:
+  cleanupendpad %0 unwind label %pad
+pad:
+  %0 = cleanuppad []
+  invoke void @_Z3quxv() optsize
+          to label %stop unwind label %endpad
+stop:
+  unreachable
+exit:
+  ret void
+}
index 806ca3c17a6af578e51ee8b511738f7a13cf6a96..f138ac429144ebd948ccbc9527a39ea14b9af3de 100644 (file)
@@ -63,6 +63,14 @@ lpad:
   resume { i8*, i32 } zeroinitializer
 }
 
   resume { i8*, i32 } zeroinitializer
 }
 
+define i8 @call_with_same_range() {
+; CHECK-LABEL: @call_with_same_range
+; CHECK: tail call i8 @call_with_range
+  bitcast i8 0 to i8
+  %out = call i8 @dummy(), !range !0
+  ret i8 %out
+}
+
 define i8 @invoke_with_same_range() personality i8* undef {
 ; CHECK-LABEL: @invoke_with_same_range()
 ; CHECK: tail call i8 @invoke_with_range()
 define i8 @invoke_with_same_range() personality i8* undef {
 ; CHECK-LABEL: @invoke_with_same_range()
 ; CHECK: tail call i8 @invoke_with_range()
@@ -76,14 +84,6 @@ lpad:
   resume { i8*, i32 } zeroinitializer
 }
 
   resume { i8*, i32 } zeroinitializer
 }
 
-define i8 @call_with_same_range() {
-; CHECK-LABEL: @call_with_same_range
-; CHECK: tail call i8 @call_with_range
-  bitcast i8 0 to i8
-  %out = call i8 @dummy(), !range !0
-  ret i8 %out
-}
-
 
 
 declare i8 @dummy();
 
 
 declare i8 @dummy();
index 33b876e266cf85032251b7d5013301ee9f972ac0..dd0d5f48498b3c14797b64935e9047a054a128aa 100644 (file)
@@ -244,6 +244,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
       STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
       STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)
       STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD)
       STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
       STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)
       STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD)
+      STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPENDPAD)
       STRINGIFY_CODE(FUNC_CODE, INST_CATCHENDPAD)
       STRINGIFY_CODE(FUNC_CODE, INST_TERMINATEPAD)
       STRINGIFY_CODE(FUNC_CODE, INST_PHI)
       STRINGIFY_CODE(FUNC_CODE, INST_CATCHENDPAD)
       STRINGIFY_CODE(FUNC_CODE, INST_TERMINATEPAD)
       STRINGIFY_CODE(FUNC_CODE, INST_PHI)